数据预处理是进行机器学习的关键步骤,通常也叫做feature engineering。
这里简单提一下遇到缺失值的四种情况
- 如果缺值的样本占总数的比例较高,我们就会直接将其舍弃,作为特征加入反而会带入noise,影响结果
- 如果缺值的样本适中,而该属性非连续值特征属性(比如类目属性),那就把NaN作为一个新的类别,加到类别特征中
- 如果缺值的样本适中,而该属性为连续值特征属性,有时候我们会考虑给定一个step,然后把他离散化,之后把NaN作为一个type加到类目中
- 有些情况下,缺失的值个数不是特别多,那我们也可以试着根据已有的值,拟合一下数据,补充上
当然在数据预处理前首先需要读入数据
1 2 3 4 5 6 7 8 9 10 11
| from __future__ import print_function import pandas as pd import numpy as np from keras.models import Sequential from keras.optimizers import SGD,RMSprop,Adam from keras.layers import Dense,Activation,Dropout raw_train = pd.read_csv('train.csv', index_col=0) raw_train['is_test'] = 0 raw_test = pd.read_csv('test.csv', index_col=0) raw_test['is_test'] = 1 all_data = pd.concat((raw_train,raw_test), axis=0)
|
读入数据的时候我们做了处理,就是把训练集和测试集读到一个文件当中,并增加一列is_test,用来表征其是test还是train
处理尊称
我们发现每个名字都有一个尊称,有些只是简单的小姐或者夫人,但有时的称呼可能是大师,爵士等,我们尝试对这里的数据进行提取,方便后期作为feature加入训练
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| def get_titles(df): df['Title'] = df['Name'].map(lambda name:name.split(',')[1].split('.')[0].strip()) Title_Dictionary = { "Capt": "Officer", "Col": "Officer", "Major": "Officer", "Jonkheer": "Royalty", "Don": "Royalty", "Sir" : "Royalty", "Dr": "Officer", "Rev": "Officer", "the Countess":"Royalty", "Dona": "Royalty", "Mme": "Mrs", "Mlle": "Miss", "Ms": "Mrs", "Mr" : "Mr", "Mrs" : "Mrs", "Miss" : "Miss", "Master" : "Master", "Lady" : "Royalty"
} df['Title'] = df.Title.map(Title_Dictionary) df = df.drop(['Name'], axis=1) return df
|
首先说说lambda里面的一些东西。这里的工作就是提取尊称,下面放一张数据截图
从图中我们发现,尊称就是在逗号和点那一部分。这里的lambda函数的思路非常经典,首先以逗号分隔,取后一个,再在后一个里面用点分隔,取前一个。
之后的字典就是我们人为对其进行了一个分类处理,并直接舍弃了原先的name列,转用尊称列代替
处理客舱号
在处理客舱号的时候,由于我们只关心舱位等级而不关心具体的房间号,所以只需提取前面的客舱号就可以。数据截图如下
1 2 3 4
| def get_cabin_letter(df): df['Cabin'].fillna('Z', inplace=True) df['Cabin_letter'] = df['Cabin'].str[0] return(df)
|
在处理cabin缺失值的时候,我这里采取的策略是用’Z’填充,也就是缺失的归为一类(但其实现在想想不是很好,因为缺失的值很多,如果直接舍弃说不定效果反而更好)之后就是简单的提取第一个字母
对属性值数据进行one-hot编码
在后面的训练中,由于我现在需要所有类型都是数值型特征,所以我们通常会使用one-hot编码对数据进行处理。其实看了下图就会知道one-hot编码在干一件什么事情
1 2
| def get_dummy_cats(df): return(pd.get_dummies(df,columns=['Title','Pclass','Sex','Embarked','Cabin_letter']))
|
我们在这里使用pandas内置的get_dummies方法来实现
对上述处理进行调用
1 2 3 4 5 6 7
| def process_data(df): df = get_titles(df) df['Embarked'].fillna('S', inplace=True) df = get_cabin_letter(df) df = df.drop(['Ticket','Fare'], axis=1) df = get_dummy_cats(df) return df
|
我们这里就是分别调用了上面的一些函数,并顺便把登船的港口进行了缺失值填充
对年龄进行建模预测
这里最复杂的处理就是这个年龄了,因为他的缺失值较多但又不至于将其舍弃,并且我们根据前面的可视化分析发现年龄对获救的概率有着非常大的影响。
基于此,我们在这里尝试先利用其他的数据对缺失的年龄进行预测
数据准备
1 2 3 4 5 6 7
| proc_data = process_data(all_data) proc_train = proc_data[proc_data['is_test'] == 0] proc_test = proc_data[proc_data['is_test'] == 1]
for_age_train = proc_data.drop(['Survived','is_test'], axis=1).dropna(axis=0) X_train_age = for_age_train.drop('Age',axis=1) Y_train_age = for_age_train['Age']
|
对于处理好的数据,我们依据合并时区分的训练集和测试集,将其分成两个集合。对于训练使用的集合,我们使用dropna函数把survived和is_test去掉,这里用不到他们。那么对于去掉后的训练集,我们再把Age列也去掉,Age列单独保存
模型建立与模型训练
准备好数据之后就开始建模
1 2 3 4 5 6 7 8 9 10
| tmodel = Sequential() tmodel.add(Dense(input_dim=X_train_age.shape[1], units=128, kernel_initializer='normal', bias_initializer='zeros')) tmodel.add(Activation('relu')) for i in range(0,8): tmodel.add(Dense(units=64, kernel_initializer='normal',bias_initializer='zeros')) tmodel.add(Dropout(.25)) tmodel.add(Dense(units=1)) tmodel.add(Activation('linear')) tmodel.compile(loss='mean_squared_error', optimizer='rmsprop') tmodel.fit(X_train_age.values, Y_train_age.values,epochs=600,verbose=2)
|
我在这里采用了keras进行建模,具体建模原则与建模方式,参见博客keras部分,这里不再赘述
利用模型进行年龄预测
1 2 3 4 5 6 7 8 9 10
| train_data = proc_train train_data.loc[train_data['Age'].isnull()] to_pred = train_data.loc[train_data['Age'].isnull()].drop(['Age','Survived','is_test'], axis=1) p = tmodel.predict(to_pred.values) train_data.loc[train_data['Age'].isnull(),'Age'] = p
test_data = proc_test to_pred = test_data.loc[test_data['Age'].isnull()].drop(['Age','Survived','is_test'], axis=1) p = tmodel.predict(to_pred.values) test_data.loc[test_data['Age'].isnull(),'Age'] = p
|
这里一个关键的问题在于如何将预测的值准确填入缺失部分的空中。这里的to_pred是将无关的列去掉后再选择了age缺失的行。在利用模型进行预测之后把预测的大了的再填回去