泰坦尼克是Kaggle上非常經(jīng)典的一個項目,首先我們從Kaggle上下載數(shù)據(jù)集(https://www.kaggle.com/c/titanic)。數(shù)據(jù)集已經(jīng)幫我們分好了訓(xùn)練集和測試集,其中訓(xùn)練集中包含了部分乘客名單、各種特征以及是否幸存的標(biāo)簽,而在測試集中是我們需要預(yù)測的乘客名單和相應(yīng)的特征,我們需要做的就是通過對訓(xùn)練集數(shù)據(jù)進(jìn)行探索,然后構(gòu)建機(jī)器學(xué)習(xí)模型,利用這個模型來預(yù)測測試集中的乘客生存情況,最后我們將預(yù)測結(jié)果提交給Kaggle就可以啦。
本次項目說明:
- 編程語言:Python
- 編譯工具:jupyter notebook
- 涉及到的庫:pandas,numpy,matplotlib,sklearn
1. 數(shù)據(jù)概覽
首先我們導(dǎo)入相關(guān)的庫以及讀取數(shù)據(jù),
# 導(dǎo)入相關(guān)庫
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 讀取數(shù)據(jù)
data_train = pd.read_csv('train.csv')
data_test = pd.read_csv('test.csv')
我們來看下數(shù)據(jù)的整體特征
data_train[:5]

部分字段解釋:
- PassengerID:乘客ID
- Survied:是否獲救
- Pclass:船艙等級
- SibSp:同行堂兄妹個數(shù)
- Parch:同行父母與小孩個數(shù)
- Ticket:船票編號
- Fare:票價
- cabin:客艙
- Embarked:登船港口
data_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: 83.6+ KB
從上面的數(shù)據(jù)我們可以發(fā)現(xiàn),訓(xùn)練集數(shù)據(jù)一共891行,其中Age和Cabin這兩列缺失值較多,Embarked列有2行缺失。
然后我們分別來來看下數(shù)值型和字符型數(shù)據(jù)的情況。
# 數(shù)值型數(shù)據(jù)的情況
data_train.describe()

從上面對數(shù)值列的統(tǒng)計可以發(fā)現(xiàn):
- 一共891名乘客,獲救的概率是38%(Survived列的均值)
- Pclass的均值是2.3就意味著2,3等級船艙的人數(shù)要多于1等倉
- 整個船的乘客年齡均值是29.6歲,最大的乘客80歲,最小的才4個月
- 最貴的票512美金,最便宜的0元,票的均價是32美金
# 字符型數(shù)據(jù)的情況
data_train.describe(include=['O'])

從上面對字符數(shù)據(jù)統(tǒng)計可以發(fā)現(xiàn):
- 891名乘客中沒有同名同姓的
- 男性乘客有577名,比女性多
- S港口登船的人最多,共計644人
2. 數(shù)據(jù)分析與可視化
每個乘客都有N項屬性,那哪些屬性和最后獲救的結(jié)果有關(guān),這些屬性和最后獲救結(jié)果(Survived)之間的關(guān)系又是怎樣的?
所以我們要對數(shù)據(jù)進(jìn)行分析,同時進(jìn)行可視化更直觀的來認(rèn)識這些數(shù)據(jù)。
2.1 乘客屬性分布
首先我們來粗略的看下乘客的各個屬性分布,比如說獲救與遇難的人數(shù)比例,各個港口的登船比例,乘客船艙分布,不同船艙的年齡分布等,來對數(shù)據(jù)有一個更加深刻的認(rèn)知!
%matplotlib notebook
fig = plt.figure()
plt.subplot2grid((2,3),(0,0))
data_train.Survived.value_counts().plot(kind='bar')
plt.ylabel(u'人數(shù)',fontproperties='SimHei')
plt.title(u'獲救/遇難人數(shù)對比',fontproperties='SimHei')
plt.subplot2grid((2,3),(0,1))
data_train.Pclass.value_counts().plot(kind='bar')
plt.ylabel(u'人數(shù)',fontproperties='SimHei')
plt.title(u'乘客船艙分布',fontproperties='SimHei')
plt.subplot2grid((2,3),(0,2))
plt.scatter(data_train.Survived,data_train.Age)
plt.ylabel(u'年齡',fontproperties='SimHei')
plt.title(u'按年齡看獲救分布',fontproperties='SimHei')
plt.subplot2grid((2,3),(1,0),colspan=2)
data_train.Age[data_train.Pclass==1].plot(kind='kde')
data_train.Age[data_train.Pclass==2].plot(kind='kde')
data_train.Age[data_train.Pclass==3].plot(kind='kde')
plt.legend((u'1',u'2',u'3'),loc='best',)
plt.ylabel(u'密度',fontproperties='SimHei')
plt.title(u'各等級船艙的乘客年齡分布',fontproperties='SimHei')
plt.subplot2grid((2,3),(1,2))
data_train.Embarked.value_counts().plot(kind='bar')
plt.ylabel(u'人數(shù)',fontproperties='SimHei')
plt.title(u'各登船口岸的上船人數(shù)',fontproperties='SimHei')

可以發(fā)現(xiàn):
- 整個泰坦尼克號中,遇難人數(shù)要多于獲救人數(shù),獲救人數(shù)只要350人不到
- 3等艙的乘客最多,讓人意外的是1等艙的乘客比2等艙的乘客還要多
- 船艙等級越高,平均年齡也越高,這個也是符合財富分布與年齡之間的關(guān)系的
- S港口登船人數(shù)最多,比其他兩個港口登船人數(shù)加一起還多
2.2 各個屬性與獲救結(jié)果之間的關(guān)系
數(shù)據(jù)集中有很多列,哪些列是影響最后獲救結(jié)果的特征呢?這些屬性具體又是怎么影響獲救的呢?
從直覺上來說,乘客的ID、姓名、船票編號這些和最后是否被獲救關(guān)系不大,所以在這里我們排除PaddengerID,Name,Ticket這幾列,然后一個一個的來看每個屬性與獲救與否是否之間的關(guān)系。
2.2.1 船艙等級與獲救結(jié)果之間的關(guān)系
%matplotlib notebook
pclass_0=data_train.Pclass[data_train.Survived==0].value_counts()
pclass_1=data_train.Pclass[data_train.Survived==1].value_counts()
df=pd.DataFrame({'Victim':pclass_0,'Survival':pclass_1})
df.plot(kind='bar',stacked=True)
plt.title('不同等級船艙的獲救/遇難人數(shù)',fontproperties='SimHei')
plt.xlabel('船艙等級',fontproperties='SimHei')
plt.ylabel('人數(shù)',fontproperties='SimHei')

1等艙的人總數(shù)很少,但是獲救的人數(shù)確實最多的,可能覺得這樣看不是很明顯,那么我們將每個船艙的獲救的概率畫出來,就更明顯了。
%matplotlib notebook
df=pd.DataFrame({'Victim':pclass_0,'Survival':pclass_1})
df = df.div(df.sum(axis=1),axis=0)
df.plot(kind='bar',stacked=True)
plt.title('不同等級船艙的獲救比例',fontproperties='SimHei')
plt.xlabel('船艙等級',fontproperties='SimHei')

船艙的等級越高,獲救的概率越大,在1等艙,有60%以上的乘客獲救了,而在2等艙,稍微低一些,大概45%左右,而在3等艙,則只有25%不到的乘客獲救,所以船艙等級一定是影響最后是否獲救的一個特征。
2.2.2 性別與獲救結(jié)果之間的關(guān)系
%matplotlib notebook
df=(data_train.Sex[data_train.Survived==1].value_counts()/data_train.Sex.value_counts())
df.plot(kind='bar')
plt.ylabel(u'在對應(yīng)性別中的比例',fontproperties='SimHei')
plt.title(u'獲救者中的性別情況',fontproperties='SimHei')

可以發(fā)現(xiàn)有女性中有70%以上獲救了,而只有20%不到的男性獲救,所以性別也是影響最后是否獲救的一個特征。
我們再來看下獲救與遇難的人數(shù)中性別的比例!
%matplotlib notebook
survived_f = data_train.Survived[data_train.Sex=='female'].value_counts()
survived_m = data_train.Survived[data_train.Sex=='male'].value_counts()
df = pd.DataFrame({'female':survived_f,'male':survived_m})
df.plot(kind='bar',stacked=True)
plt.ylabel(u'人數(shù)',fontproperties='SimHei')
plt.title(u'按性別看獲救情況',fontproperties='SimHei')

在獲救的乘客中,女性的人數(shù)要明顯多于男性乘客的人數(shù),而在遇難乘客中,男性乘客遠(yuǎn)多于女性乘客。
那么我們再進(jìn)一步,來看下不同船艙中的性別獲救情況。
#不同船艙的女性獲救情況
%matplotlib notebook
fig = plt.figure()
plt.subplot2grid((1,3),(0,0))
data_train.Survived[data_train.Sex=='female'][data_train.Pclass==1].value_counts()[[0,1]].plot(kind='bar')
plt.title(u'1等艙女性獲救情況',fontproperties='SimHei')
plt.subplot2grid((1,3),(0,1))
data_train.Survived[data_train.Sex=='female'][data_train.Pclass==2].value_counts()[[0,1]].plot(kind='bar')
plt.title(u'2等艙女性獲救情況',fontproperties='SimHei')
plt.subplot2grid((1,3),(0,2))
data_train.Survived[data_train.Sex=='female'][data_train.Pclass==3].value_counts()[[0,1]].plot(kind='bar')
plt.title(u'3等艙女性獲救情況',fontproperties='SimHei')

在所有的船艙,女性獲救的人數(shù)都是大于等于遇難的女性,尤其是在1/2等艙女性的獲救概率很高,而到了3等艙,獲救的概率就明顯下降,獲救率和死亡率各占50%。
#不同船艙的男性獲救情況
%matplotlib notebook
fig = plt.figure()
plt.subplot2grid((1,3),(0,0))
data_train.Survived[data_train.Sex=='male'][data_train.Pclass==1].value_counts().plot(kind='bar')
plt.title(u'1等艙男性獲救情況',fontproperties='SimHei')
plt.subplot2grid((1,3),(0,1))
data_train.Survived[data_train.Sex=='male'][data_train.Pclass==2].value_counts().plot(kind='bar')
plt.title(u'2等艙男性獲救情況',fontproperties='SimHei')
plt.subplot2grid((1,3),(0,2))
data_train.Survived[data_train.Sex=='male'][data_train.Pclass==3].value_counts().plot(kind='bar')
plt.title(u'3等艙男性獲救情況',fontproperties='SimHei')

在所有的船艙中,男性遇難的人數(shù)都是多于獲救的人數(shù),而且3等艙中遇難的男性人數(shù)非常多,遠(yuǎn)多于其他兩個船艙。
2.2.3 年齡與獲救結(jié)果之間的關(guān)系
由于年齡這個字段缺失值很多(缺失值處理這塊我們后面數(shù)據(jù)預(yù)處理時再說),所以我們可以先來看下有年齡記錄和沒有年齡記錄之間是否存在獲救概率的差異,然后我們再來看下有年齡數(shù)據(jù)的乘客中獲救與遇難乘客的分布是怎樣的。
%matplotlib notebook
survived_y = data_train.Survived[data_train.Age.notnull()].value_counts()
survived_n = data_train.Survived[data_train.Age.isnull()].value_counts()
df = pd.DataFrame({'yes':survived_y,'no':survived_n})
df = df.T
df.plot(kind='bar',stacked=True)
plt.title(u'有無年齡數(shù)據(jù)與是否獲救之間的關(guān)系',fontproperties='SimHei')

好像這里我們并沒有看到很明顯的關(guān)系,所以下面就來看下有年齡數(shù)據(jù)的乘客中獲救/遇難乘客的年齡分布。
%matplotlib notebook
data_train.Age[data_train.Survived==0].plot(kind='kde')
data_train.Age[data_train.Survived==1].plot(kind='kde')
plt.xticks(range(-40,125,10))
plt.legend([0,1],loc='best')
plt.title('獲救與遇難乘客的年齡的分布',fontproperties='SimHei')

從上面的密度圖可以看到,對13歲以下的小朋友來說,獲救的概率要高于死亡概率,這個可能還是和“女士和小孩先走”的口號有關(guān),而在13-30這個年齡段,死亡率要明顯高于獲救率,到了30-57歲,獲救與死亡概率基本差不太多,而在57歲-78之間,死亡率要大于獲救概率。
所以從這里可以看到其實年齡和最后獲救結(jié)果是直接相關(guān)的。
2.2.4 同行堂兄妹個數(shù)與獲救結(jié)果之間的關(guān)系
%matplotlib notebook
sibsp_0 = data_train.SibSp[data_train.Survived==0].value_counts()
sibsp_1 = data_train.SibSp[data_train.Survived==1].value_counts()
df = pd.DataFrame({'遇難':sibsp_0,'獲救':sibsp_1})
df.plot(kind='bar')
plt.legend(('Victim',u'Survival'),loc='best')
plt.title('不同堂兄妹個數(shù)的獲救人數(shù)',fontproperties='SimHei')

可以發(fā)現(xiàn)同行有1-2名堂兄妹的時候,獲救率是最高的,再多的話,獲救率又開始下降了。
我們可以更加形象一點,畫出獲救乘客在其對應(yīng)的堂兄妹數(shù)量分組中的占比。
%matplotlib notebook
arr = (data_train.SibSp[data_train.Survived==1].value_counts()/df.sum(axis=1))
arr.plot(kind='bar')
plt.title('獲救乘客在其對應(yīng)堂兄妹個數(shù)下的占比',fontproperties='SimHei')

可以看到這個圖表有點像正偏態(tài)分布,當(dāng)只有1-2名同行唐兄妹時,獲救的概率最高,人數(shù)再多的話,獲救率又開始下降了。
2.2.5 同行父母/小孩的數(shù)量與獲救結(jié)果之間的關(guān)系
%matplotlib notebook
parch_0 = data_train.Parch[data_train.Survived==0].value_counts()
parch_1 = data_train.Parch[data_train.Survived==1].value_counts()
df = pd.DataFrame({'遇難':parch_0,'獲救':parch_1})
df.plot(kind='bar')
plt.legend(('Victim',u'Survival'),loc='best')
plt.title('不同父母/子女個數(shù)的獲救人數(shù)',fontproperties='SimHei')

%matplotlib notebook
arr = (data_train.Parch[data_train.Survived==1].value_counts()/df.sum(axis=1))
arr.plot(kind='bar')
plt.title('獲救乘客在其對應(yīng)父母/子女個數(shù)下的占比',fontproperties='SimHei')

父母/子女個數(shù)和獲救概率的關(guān)系和堂兄妹和獲救率的關(guān)系有點像,都是呈一個類似于正態(tài)分布的關(guān)系,當(dāng)1-3名父母/子女個數(shù)時,獲救概率最高,過多和過少,獲救概率都呈下降趨勢。
2.2.5 票價的數(shù)量與獲救結(jié)果之間的關(guān)系
票價和船艙一樣,也是反應(yīng)乘客身份的信息之一,既然不同的船艙乘客的獲救率不同,那么不同票價的乘客獲救率也肯定不同。
我們可以先來看下整個船的票價分布情況以及不同船艙的船票價格情況。
%matplotlib notebook
data_train.Fare.plot(kind='hist',bins=70)
plt.xticks(range(0,600,50))
plt.title(u'船票價格分布',fontproperties='SimHei')

%matplotlib notebook
data_train.boxplot(column='Fare', by='Pclass',showfliers=False,grid=False,showmeans=True)
plt.title('不同船艙的票價情況',fontproperties='SimHei')

可以發(fā)現(xiàn),絕大多數(shù)乘客的票價都是在0-100之間,而且2等艙和3等艙的價格相差的不是特別多,均值都在25以下,而1等艙的價格,不管是均值還是中位數(shù)都要明顯高于2/3等艙。
那么獲救乘客與遇難乘客的船票價格分布又是怎樣的呢?是否和船艙一樣,高票價意味著更高的獲救概率?
%matplotlib notebook
data_train.boxplot(column='Fare', by='Survived',showfliers=False,grid=False,showmeans=True)

和船艙一樣,獲救乘客的票價不論是均值還是中位數(shù)都要明顯高于遇難乘客,我們可以通過密度圖來更進(jìn)一步觀察。
%matplotlib notebook
data_train.Fare[data_train.Survived==0].plot(kind='kde')
data_train.Fare[data_train.Survived==1].plot(kind='kde')
plt.xlim((0,600))
plt.xticks(range(0,600,50))
plt.legend([0,1],loc='best')
plt.title('獲救與遇難乘客的年齡的分布',fontproperties='SimHei')

當(dāng)票價在30左右時是一個分水嶺,小于30,死亡率高于獲救率,大于30,獲救的概率就要高于死亡的概率,所以和船艙等級一樣,票價也是影響最后獲救結(jié)果很重要的一個特征。
2.2.6 客艙與獲救結(jié)果之間的關(guān)系
由于客艙這一列的缺失數(shù)據(jù)非常多,而且這是數(shù)據(jù)很不集中,所以在這里我們將數(shù)據(jù)分為有無客艙信息,來看下有無客艙信息與獲救結(jié)果之間的關(guān)系。
%matplotlib notebook
survived_y = data_train.Survived[data_train.Cabin.notnull()].value_counts()
survived_n = data_train.Survived[data_train.Cabin.isnull()].value_counts()
df = pd.DataFrame({'yes':survived_y,'null':survived_n})
df = df.T
df.plot(kind='bar',stacked=True)
plt.title('按有無客艙信息查看獲救情況',fontproperties='SimHei')

%matplotlib notebook
df.div(df.sum(axis=1),axis=0).plot(kind='bar',stacked=True)
plt.title('按有無客艙查看獲救/遇難的人數(shù)比例',fontproperties='SimHei')

發(fā)現(xiàn)如果有客艙信息的話,獲救的概率確實要大一點,在有客艙信息的乘客中有超過60%都獲救了,而在沒有客艙信息的組中,只有20%多獲救了。
2.2.7 登船港口與獲救結(jié)果之間的關(guān)系
%matplotlib notebook
embarked_0 = data_train.Embarked[data_train.Survived==0].value_counts()
embarked_1 = data_train.Embarked[data_train.Survived==1].value_counts()
df = pd.DataFrame({0:embarked_0,1:embarked_1})
df.plot(kind='bar')
plt.title('不同港口登船的乘客獲救情況',fontproperties='SimHei')

可以發(fā)現(xiàn)S港口登船的乘客最多,但是只有C港口登船的乘客中獲救人數(shù)要多于遇難人數(shù),而其他兩個港口登船乘客中遇難人數(shù)都要多于獲救乘客人數(shù)。
3. 數(shù)據(jù)預(yù)處理
終于到我們最重要的一步:數(shù)據(jù)預(yù)處理,在這一步中,我們需要對數(shù)據(jù)進(jìn)行清洗(處理空值/重復(fù)值),分類數(shù)據(jù)(也就是特征因子化)以及特征縮放。
我們之前在數(shù)據(jù)概覽中看到,Name這一列沒有重復(fù),所以在這里我們就不用處理重復(fù)值了,那么第一步,我們來處理缺失值。
3.1缺失數(shù)據(jù)處理
對缺損的數(shù)據(jù)的處理可以選擇的處理可以選擇以下幾種方式:
- 直接刪除此特征(缺損數(shù)據(jù)太多的情況,防止引入噪聲)
- 直接刪除缺損數(shù)據(jù)的樣本(只用于訓(xùn)練數(shù)據(jù)集,且樣本量較大,缺損數(shù)據(jù)樣本較少的情況)
- 直接將有無數(shù)值作為新的特征(數(shù)據(jù)缺失較多,且數(shù)據(jù)有無本身是對預(yù)測是一個有用的特征)
- 中值或均值回補(缺失數(shù)據(jù)較多,不想損失此較多訓(xùn)練數(shù)據(jù),特征又比較重要的情況,是比較常用的方法)
- 參考其他特征,利用與此特征的相關(guān)性編寫算法回補數(shù)據(jù)(回補的準(zhǔn)確性可能會比較高一些,但實現(xiàn)過程復(fù)雜)
這幾種方法具體使用哪一個需要根據(jù)實際情況決定,選用復(fù)雜的方法得到的結(jié)果不一定就好。
在這里我們一共有3列數(shù)據(jù)存在缺失值,分別是Age,Cabin,Embarked。這三列我們的處理方式分別是:
- Embarked列由于缺失值很少,只有2行,所以對于Embarked列,我們選擇用眾數(shù)來填充缺失值
- Carbin列我們選擇將有無數(shù)值作為新的特征
- Age列采取最復(fù)雜的方法,使用隨機(jī)森林進(jìn)行數(shù)據(jù)回補(不是說使用算法回補,準(zhǔn)確性就一定高哈)
另外我們將Age和Fare列根據(jù)上方與獲救結(jié)果之間的關(guān)系圖表進(jìn)行離散化處理,所以也不需要特征縮放了。
# 這里我們將data_train復(fù)制一份,后面的數(shù)據(jù)處理/建模就用這個復(fù)制的變量,原始數(shù)據(jù)不去動他
train_data = data_train.copy()
Embarked列處理
train_data['Embarked'].fillna(train_data['Embarked'].mode().iloc[0],inplace=True)
Carbin列處理
def func_one(x):
if type(x)==str:
return 'yes'
else:
return 'no'
train_data['Cabin'] = train_data['Cabin'].map(func_one)
Age列處理
# 導(dǎo)入隨機(jī)森林的回歸器
from sklearn.ensemble import RandomForestRegressor
# 將已有的數(shù)值型特征都喂給隨機(jī)森林的回歸器
age_df = train_data[['Age','SibSp','Fare','Parch','Pclass']]
# 乘客分為已知年齡和未知年齡兩組
know_age = age_df[age_df['Age'].notnull()].iloc[:,:].values
unknow_age = age_df[age_df['Age'].isnull()].iloc[:,:].values
# y就是已知的年齡,x就是已知年齡的特征屬性
y = know_age[:,0]
x = know_age[:,1:]
# 生成回歸器并進(jìn)行擬合
regressor = RandomForestRegressor(random_state=0,n_estimators=2000)
regressor.fit(x,y)
# 用得到的模型對未知年齡進(jìn)行預(yù)測
age_predict = regressor.predict(unknow_age[:,1:])
# 將預(yù)測得到的數(shù)據(jù)填充給原缺失數(shù)據(jù)
train_data.Age[train_data['Age'].isnull()]=age_predict
# Age列離散化處理
def func_two(x):
if x<13:
return 'child'
elif x<30:
return 'young'
elif x<57:
return 'adult'
else:
return 'old'
train_data.Age = train_data.Age.map(func_two)
Fare列處理
# Fare列離散化處理
def func_three(x):
if x<29:
return 'poor'
else:
return 'rich'
train_data.Fare = train_data.Fare.map(func_three)
3.2 分類數(shù)據(jù)
dummies_Pclass = pd.get_dummies(train_data['Pclass'],prefix='Pclass')
dummies_Sex = pd.get_dummies(train_data['Sex'],prefix='Sex')
dummies_Carbin = pd.get_dummies(train_data['Cabin'],prefix='Carbin')
dummies_Embarked = pd.get_dummies(train_data['Embarked'],prefix='Embarked')
dummies_Age = pd.get_dummies(train_data['Age'],prefix='Age')
dummies_Fare = pd.get_dummies(train_data['Fare'],prefix='Fare')
train_data = pd.concat([train_data,dummies_Carbin,dummies_Embarked,dummies_Pclass,dummies_Sex,dummies_Age,dummies_Fare],axis=1)
train_data = train_data.drop(['Name','Ticket','Pclass','Sex','Cabin','Embarked','Age','Fare'],axis=1)
3.4 測試集數(shù)據(jù)處理
我們對訓(xùn)練集進(jìn)行處理之后,測試集也要記得進(jìn)行預(yù)處理。
數(shù)據(jù)清洗
test_data = data_test.copy()
test_data.info()
output:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
PassengerId 418 non-null int64
Pclass 418 non-null int64
Name 418 non-null object
Sex 418 non-null object
Age 332 non-null float64
SibSp 418 non-null int64
Parch 418 non-null int64
Ticket 418 non-null object
Fare 417 non-null float64
Cabin 91 non-null object
Embarked 418 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB
和訓(xùn)練集一樣,訓(xùn)練集中Age,Cabin列缺失值較多,F(xiàn)are列有1行缺失。
測試集中Fare列進(jìn)行處理
test_data.Fare.fillna(test_data.Fare.mode().iloc[0],inplace=True)
test_data.Fare = test_data.Fare.map(func_three)
測試集Carbin列處理
def func_one(x):
if type(x)==str:
return 'yes'
else:
return 'no'
test_data['Cabin'] = test_data['Cabin'].map(func_one)
測試集Age列處理
# 找到測試集中未知年齡數(shù)據(jù)的特征
tmp_df = test_data[['Age','SibSp','Fare','Parch','Pclass']]
unknow_age_test = tmp_df[tmp_df['Age'].isnull()].iloc[:,:].values
x = unknow_age_test[:,1:]
# 用訓(xùn)練集中的模型直接對測試集中的年齡進(jìn)行預(yù)測
age_predict_test = regressor.predict(x)
# 將預(yù)測得到的數(shù)據(jù)填充給測試集缺失數(shù)據(jù)
test_data.Age[test_data['Age'].isnull()] = age_predict_test
test_data.Age = test_data.Age.map(func_two)
分類數(shù)據(jù)
dummies_Pclass = pd.get_dummies(test_data['Pclass'],prefix='Pclass')
dummies_Sex = pd.get_dummies(test_data['Sex'],prefix='Sex')
dummies_Carbin = pd.get_dummies(test_data['Cabin'],prefix='Carbin')
dummies_Embarked = pd.get_dummies(test_data['Embarked'],prefix='Embarked')
dummies_Age = pd.get_dummies(test_data['Age'],prefix='Age')
dummies_Fare = pd.get_dummies(test_data['Fare'],prefix='Fare')
test_data = pd.concat([test_data,dummies_Carbin,dummies_Embarked,dummies_Pclass,dummies_Sex,dummies_Age,dummies_Fare],axis=1)
test_data = test_data.drop(['Name','Ticket','Pclass','Sex','Cabin','Embarked','Age','Fare'],axis=1)
4. 建模與調(diào)參
4.2 Kernel SVM
# 導(dǎo)入Kernel svm
from sklearn.svm import SVC
train_df = train_data.iloc[:,1:]
X_train = train_df.iloc[:,1:].values
y_train = train_df.iloc[:,0].values
classifier = SVC(kernel='rbf',random_state=0)
classifier.fit(X_train,y_train)
交叉驗證
from sklearn.model_selection import GridSearchCV, cross_val_score
svc_classifier = cross_val_score(estimator=classifier,X=X_train,y=y_train,cv=10)
print(svc_classifier.mean())
output:
0.8215438088752695
網(wǎng)格搜索調(diào)參
param = {
'C': [0.1,0.8,0.9,1,1.1,1.2,1.3,1.4,1.6,1.8,2.0],
'kernel':['rbf'],
'gamma' :[0.1,0.8,0.9,1,1.1,1.2,1.3,1.4,1.6,1.8,2.0]
}
grid_classifier = GridSearchCV(classifier, param_grid=param, scoring='accuracy', cv=10)
grid_classifier.fit(X_train,y_train)
print(grid_classifier.best_params_)
output:
{'C': 0.9, 'gamma': 0.1, 'kernel': 'rbf'}
重新建模
svc = SVC(C=0.9,gamma=0.1,kernel='rbf')
svc.fit(X_train,y_train)
X_test = test_data.iloc[:,1:].values
y_pred = svc.predict(X_test)
result = pd.DataFrame({'PassengerId':test_data['PassengerId'],'Survived':y_pred})
result.to_csv('kernel_svm.predictions.csv',index=False)
svc_val = cross_val_score(estimator=svc,X=X_train,y=y_train,cv=10)
svc_val.mean()
output:
0.8283109181704689
提交到Kaggle,可以發(fā)現(xiàn)準(zhǔn)確率0.79425,相比上此提高了0.05,排名上升到2166,說明經(jīng)過網(wǎng)格搜索調(diào)參之后,模型的性能得到了進(jìn)一步的優(yōu)化。
