1,介紹
Titanic: Machine Learning from Disaster是kaggle比賽的入門訓練,具體介紹可以看鏈接,數據在官網上下載,但需要注冊登錄。訓練集在train.csv中,測試集在test.csv。這里對特征的處理主要是來自Sina的Titanic best working Classifier。
首先對訓練集的信息進行了解,從中可以看出訓練集有891個樣本,10個特征,分別是乘客姓名,船票類型,性別,年齡,兄弟姐妹在船上的人數,父母小孩在船上的人數,船票號碼,船票價格,客艙號碼,終點位置。這些特征里面有的特征存在缺失值,而且特征數據有離散型數據,連續型數據和字符串數據,需要對這些進行處理,下面通過對特征進行分析然后提取我們想要的特征。
import numpy as np import pandas as pd import re as re train = pd.read_csv('train.csv') test = pd.read_csv('test.csv') train.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 891 entries, 0 to 890 Data columns (total 12 columns): PassengerId 891 non-null int64 Survived 891 non-null int64 Pclass 891 non-null int64 Name 891 non-null object Sex 891 non-null object Age 714 non-null float64 SibSp 891 non-null int64 Parch 891 non-null int64 Ticket 891 non-null object Fare 891 non-null float64 Cabin 204 non-null object Embarked 889 non-null object dtypes: float64(2), int64(5), object(5) memory usage: 66.2+ KB
2,特征分析
看了整體數據以后,接下來對各個特征分別進行處理,看看特征對生還率的影響。
(1)船票類型Pclass
船票類型總共有三種,是離散型數據,所以沒有進行特別處理,而且可以看出不同船票類型對生還率影響挺大的。
print (train[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean()) Pclass Survived 0 1 0.629630 1 2 0.472826 2 3 0.242363
(2)性別Sex
性別對最后結果有着重要影響,可以作為一個重要的特征。這個特征為數據為字符串,后續處理需要映射為0,1。
print (train[["Sex", "Survived"]].groupby(['Sex'], as_index=False).mean()) Sex Survived 0 female 0.742038 1 male 0.188908
(3)家庭大小FamilySize
在這里,將SibSp和Parch兩個合並為一個特征,家庭大小,並同時進行擴展為是否獨自一人的特征。
train['FamilySize'] = train['SibSp'] + train['Parch'] + 1 print (train[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean()) train['IsAlone'] = 0 train.loc[train['FamilySize'] == 1, 'IsAlone'] = 1 print (train[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()) FamilySize Survived 0 1 0.303538 1 2 0.552795 2 3 0.578431 3 4 0.724138 4 5 0.200000 5 6 0.136364 6 7 0.333333 7 8 0.000000 8 11 0.000000 IsAlone Survived 0 0 0.505650 1 1 0.303538
(4)終點站Embarked
終點站這個特征有C,Q,S三個值,這個特征有缺失值,將其填充為S。同樣需要進行映射為0,1,2。
train['Embarked'] = train['Embarked'].fillna('S') print (train[['Embarked', 'Survived']].groupby(['Embarked'], as_index=False).mean()) Embarked Survived 0 C 0.553571 1 Q 0.389610 2 S 0.339009
(5)船票票價Fare
船票票價這個特征是一個連續型數據,我們對其進行處理平分為四等分,后面分別映射為0,1,2,3。
train['Fare'] = train['Fare'].fillna(train['Fare'].median()) train['CategoricalFare'] = pd.qcut(train['Fare'], 4) print (train[['CategoricalFare', 'Survived']].groupby(['CategoricalFare'], as_index=False).mean()) CategoricalFare Survived 0 [0, 7.91] 0.197309 1 (7.91, 14.454] 0.303571 2 (14.454, 31] 0.454955 3 (31, 512.329] 0.581081
(6)年齡Age
年齡這個特征同樣也是連續型數據,而且缺失值比較多,我們可以將缺失值當做一個類別進行處理,其他的年齡可以等分為五種類別,在后續的數據清理中處理,這里就總共有六種類別。
age_null_count = train['Age'].isnull().sum() print(train['Survived'][train['Age'].isnull()].mean()) train['CategoricalAge'] = pd.cut(train['Age'], 5) print (train[['CategoricalAge', 'Survived']].groupby(['CategoricalAge'], as_index=False).mean()) 0.293785310734 CategoricalAge Survived 0 (0.34, 16.336] 0.550000 1 (16.336, 32.252] 0.369942 2 (32.252, 48.168] 0.404255 3 (48.168, 64.084] 0.434783 4 (64.084, 80] 0.090909
(7)姓名Name
姓名這個特征是字符串數據,從中挖掘出特征比較難,這里采用的是從姓名中找出稱呼,並將其中較少的幾個,比如'Lady', 'Countess','Capt', 'Col'等歸為一類,總共有五類。
ef get_title(name): title_search = re.search(' ([A-Za-z]+)\.', name) #如果稱呼存在,返回稱呼 if title_search: return title_search.group(1) return "" train['Title'] = train['Name'].apply(get_title) print(pd.crosstab(train['Title'], train['Sex'])) train['Title'] = train['Title'].replace(['Lady', 'Countess','Capt', 'Col',\ 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare') train['Title'] = train['Title'].replace('Mlle', 'Miss') train['Title'] = train['Title'].replace('Ms', 'Miss') train['Title'] = train['Title'].replace('Mme', 'Mrs') print (train[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()) ex female male Title Capt 0 1 Col 0 2 Countess 1 0 Don 0 1 Dr 1 6 Jonkheer 0 1 Lady 1 0 Major 0 2 Master 0 40 Miss 182 0 Mlle 2 0 Mme 1 0 Mr 0 517 Mrs 125 0 Ms 1 0 Rev 0 6 Sir 0 1 Title Survived 0 Master 0.575000 1 Miss 0.702703 2 Mr 0.156673 3 Mrs 0.793651 4 Rare 0.347826
(8)其他
Ticket和Cabin這兩個特征沒有進行挖掘,主要Ticket這個特征對於每個乘客來說都是獨特的,從中挖掘信息比較難。而Cabin這個特征丟失值比較多,所以不對它進行處理。
train['Ticket'].head(5) 0 A/5 21171 1 PC 17599 2 STON/O2. 3101282 3 113803 4 373450 Name: Ticket, dtype: object
3,數據清理
將train和test放到一個列表中,同時對訓練集和測試集進行處理,按照上述的分析進行處理,主要包括字符型特征的映射和連續型數據的分類映射。
full_data = [train, test] for dataset in full_data: # 性別映射為0,1 dataset['Sex'] = dataset['Sex'].map( {'female': 0, 'male': 1} ).astype(int) # 將SibSp和Parch兩個合並為一個特征,家庭大小,並同時擴展為是否獨自一人的特征 dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1 dataset['IsAlone'] = 0 dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1 # 稱呼分別為0,1,2,3,4,5,5為沒有稱呼 dataset['Title'] = dataset['Name'].apply(get_title) dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\ 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare') dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss') dataset['Title'] = dataset['Title'].replace('Ms', 'Miss') dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs') title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5} dataset['Title'] = dataset['Title'].map(title_mapping) dataset['Title'] = dataset['Title'].fillna(0) # 終點站,缺失值補充為S,有三種類型 dataset['Embarked'] = dataset['Embarked'].fillna('S') dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int) # 票價,0,1,2,3四種 dataset['Fare'] = dataset['Fare'].fillna(dataset['Fare'].median()) dataset.loc[dataset['Fare'] <= 7.91, 'Fare'] = 0 dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1 dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare'] = 2 dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3 dataset['Fare'] = dataset['Fare'].astype(int) # 年齡,缺失值為類別5 dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0 dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1 dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2 dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3 dataset.loc[ dataset['Age'] > 64, 'Age'] = 4 dataset.loc[ dataset['Age'].isnull(), 'Age'] = 5 dataset['Age'] = dataset['Age'].astype(int)
4,特征選擇
把多余的特征去除,剩下我們想要的特征。最后的特征如下所示,主要包括Pclass,Sex,Age,Fare,Embarked,FamilySize,IsAlone,Title這八個特征,在訓練的時候需要將Survived這項提取出來,作為訓練集的目標值。
drop_elements = ['PassengerId', 'Name', 'Ticket', 'Cabin', 'SibSp','Parch'] train = train.drop(drop_elements, axis = 1) train = train.drop(['CategoricalAge', 'CategoricalFare'], axis = 1) test = test.drop(drop_elements, axis = 1)
print(train.head(5)) train = train.values test = test.values Survived Pclass Sex Age Fare Embarked FamilySize IsAlone Title 0 0 3 1 1 0 0 2 0 1 1 1 1 0 2 3 1 2 0 3 2 1 3 0 1 1 0 1 1 2 3 1 1 0 2 3 0 2 0 3 4 0 3 1 2 1 0 1 1 1
5,總結
到這里,對數據的處理就完成了,下面就可以用得到的特征對模型進行訓練了。