練習(xí):泰坦尼克號(hào)獲救數(shù)據(jù)預(yù)測(cè)垫卤,預(yù)測(cè)人員獲救與哪些因素有關(guān)耽装。
1. 讀取數(shù)據(jù)
import pandas as pd
df = pd.read_csv('titanic_train.csv')
print(df.head())
print(df.columns)
print(df.isnull().sum())
print(df.describe())
運(yùn)行結(jié)果如圖1所示:
從圖中可以看出數(shù)據(jù)大小為891 * 12沐兵,列名有['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket','Fare', 'Cabin', 'Embarked'],有些列的數(shù)據(jù)存在著缺失,我們先看看每一列代表什么意思减宣。
'PassengerId':乘客的ID
'Survived':乘客是否獲救,0表示未獲救玩荠,1表示獲救
'Pclass':乘客艙位等級(jí)
'Name':乘客名字
'Sex':乘客性別
'Age':乘客年齡
'SibSp':乘客兄弟姐妹數(shù)
'Parch':乘客攜帶的老人以及小孩數(shù)量
'Ticket':乘客船票編號(hào)
'Fare':乘客當(dāng)前船票價(jià)格
'Cabin':缺失值太多漆腌,忽略
'Embarked':乘客上船地點(diǎn),分別有C阶冈、S闷尿、Q
2.數(shù)據(jù)預(yù)處理
- 從圖1看出數(shù)據(jù)中'Age'列和'Carbin'列存在缺失值,所以我們先要對(duì)'Age'列進(jìn)行填充女坑,這里使用均值填充填具,而'Carbin'列在分析的時(shí)候可以忽視它。
df['Age'] = df['Age'].fillna(df['Age'].median())
print(df.describe())
運(yùn)行結(jié)果如圖2所示:
從圖2可以看出匆骗,'Age'列缺失的數(shù)據(jù)已經(jīng)被填充好了劳景。
- 觀察'Sex'這一列,發(fā)現(xiàn)里面的數(shù)據(jù)是male和female碉就,分別代表男性和女性盟广,在機(jī)器學(xué)習(xí)上無(wú)法識(shí)別str,我們需要將str轉(zhuǎn)換為0,1瓮钥,即male用0表示筋量,female用1表示。
print(df['Sex'].unique())
df.loc[df['Sex'] == 'male','Sex'] = 0
df.loc[df['Sex'] == 'female','Sex'] = 1
print(df['Sex'].unique())
運(yùn)行結(jié)果如圖3所示:
從圖3可以看出碉熄,已經(jīng)將male和female轉(zhuǎn)換為0和1.
- 觀察Embarked這一列桨武,發(fā)現(xiàn)里面的數(shù)據(jù)是C、Q锈津、S呀酸,所以也要和上面的一樣,進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換琼梆。這里將S用0表示性誉,C用1表示,Q用2表示叮叹。同時(shí)發(fā)現(xiàn)Embarked列也存在著缺失值艾栋,所以需要對(duì)缺失值進(jìn)行填充,先統(tǒng)計(jì)C蛉顽、Q蝗砾、S中出現(xiàn)頻率最高的,然后將出現(xiàn)頻率最高的填入缺失值。
print(df['Embarked'].unique())
print(dict(df['Embarked'].value_counts()))
df['Embarked'] = df['Embarked'].fillna('S')
df.loc[df['Embarked'] == 'S','Embarked'] = 0
df.loc[df['Embarked'] == 'C','Embarked'] = 1
df.loc[df['Embarked'] == 'Q','Embarked'] = 2
print(df['Embarked'].unique())
運(yùn)行結(jié)果如圖4所示:
從圖4中可以看出S的頻率最高悼粮,所以這里講S填入缺失值闲勺,經(jīng)過(guò)處理后的數(shù)據(jù)變?yōu)?、1扣猫、2菜循。
3.模型建立
- 用線性回歸預(yù)測(cè)
# 利用線性回歸預(yù)測(cè)
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold
# 設(shè)置標(biāo)簽
predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
alg = LinearRegression()
kf = KFold(n_splits=3, random_state=1)
predictions = []
for train, test in kf.split(df[predictors]):
train_predictors = df[predictors].iloc[train, :]
train_target = df['Survived'].iloc[train]
alg.fit(train_predictors, train_target)
# 對(duì)測(cè)試集進(jìn)行預(yù)測(cè)
test_predictions = alg.predict(df[predictors].iloc[test, :])
predictions.append(test_predictions)
predictions = np.concatenate(predictions, axis=0)
predictions[predictions > 0.5] = 1 # 大于0.5表示獲救
predictions[predictions <= 0.5] = 0 # 小于0.5表示未獲救
accuracy = len(predictions[predictions == df['Survived']]) / len(predictions)
print(accuracy)
運(yùn)行結(jié)果為:0.7833894500561167
可見(jiàn)預(yù)測(cè)的準(zhǔn)確率并不是很高。同時(shí)還要注意申尤,由于版本的變換癌幕,KFold模塊現(xiàn)在改為從model_selection中導(dǎo)入。還有昧穿,KFold的使用方法也改了勺远,下面是之前版本的使用方式。
kf = KFold(df.shape[0], n_folds=3, random_state=1)
predictions = []
for train, test in kf:
train_predictors = (df[predictors].iloc[train, :]
- 用邏輯回歸預(yù)測(cè)
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
alg_1 = LogisticRegression(random_state=1)
scores = model_selection.cross_val_score(alg_1, df[predictors], df['Survived'], cv=3)
print(scores.mean())
運(yùn)行結(jié)果為:0.7878787878787877
可見(jiàn)預(yù)測(cè)的準(zhǔn)確率之比線性回歸高了那么一點(diǎn)點(diǎn)时鸵,但還是不高胶逢。在運(yùn)行程序時(shí)發(fā)現(xiàn)了警告,警告內(nèi)容如圖5所示:
雖然警告信息并不影響代碼運(yùn)行饰潜,但輸出窗口異常明顯的幾行紅字提醒初坠,總覺(jué)得不爽。
FutureWarning是語(yǔ)言或者庫(kù)中將來(lái)可能改變的有關(guān)警告彭雾。
根據(jù)報(bào)警信息和參考相關(guān)文檔碟刺,“Default will change from 'liblinear' to 'lbfgs' in 0.22.”,默認(rèn)的solver參數(shù)在0.22版本中冠跷,將會(huì)由“l(fā)iblinear”變?yōu)椤發(fā)bfgs”南誊,且指定solver參數(shù)可以消除該warning身诺。
這是代碼在發(fā)出警告蜜托,將來(lái)代碼運(yùn)行時(shí)如果沒(méi)有及時(shí)關(guān)注到版本的問(wèn)題,可能solver的參數(shù)會(huì)發(fā)生改變霉赡。所以橄务,最安全的方法并不是通過(guò)ignore消除警告,而是指定一個(gè)solver參數(shù)穴亏。
解決辦法:
# 版本問(wèn)題蜂挪,需要在后面添加 solver='liblinear',否則會(huì)有警告嗓化,雖然不影響運(yùn)行
alg_1 = LogisticRegression(random_state=1, solver='liblinear')
另一種思路是:
# 這種方法可以消除任何警告信息
import warnings
warnings.filterwarnings("ignore")
- 隨機(jī)森林模型進(jìn)行預(yù)測(cè)
同時(shí)我們要考慮上述標(biāo)簽中棠涮,到底是哪個(gè)標(biāo)簽的權(quán)重對(duì)獲救的概率影響高一點(diǎn),哪個(gè)權(quán)重會(huì)使得獲救的概率降低刺覆,這一點(diǎn)需要考慮严肪。這里引進(jìn)隨機(jī)森林模型,能夠綜合的利用標(biāo)簽,降低過(guò)擬合的風(fēng)險(xiǎn)驳糯,提高預(yù)測(cè)的準(zhǔn)確性篇梭。
# 使用隨機(jī)森林模型
from sklearn import model_selection
from sklearn.ensemble import RandomForestClassifier
# 設(shè)置標(biāo)簽
predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
# 通過(guò)隨機(jī)森林進(jìn)行預(yù)測(cè),這里隨機(jī)森林的參數(shù)只是隨便設(shè)定的酝枢,具體參數(shù)需要建立一個(gè)隨機(jī)森林模型
# n_estimators指樹的個(gè)數(shù)恬偷,min_samples_split指內(nèi)部節(jié)點(diǎn)再劃分所需最小樣本數(shù),min_samples_leaf葉子節(jié)點(diǎn)最少樣本數(shù)
alg_2 = RandomForestClassifier(random_state=1, n_estimators=50, min_samples_split=4, min_samples_leaf=2)
kf = model_selection.KFold(n_splits=3, random_state=1, shuffle=True)
scores_1 = model_selection.cross_val_score(alg_2, df[predictors], df['Survived'], cv=kf)
print(scores_1.mean())
運(yùn)行結(jié)果為:0.8260381593714926
從圖中的結(jié)果可以看出預(yù)測(cè)的準(zhǔn)確率又比前面的高了一些帘睦,但還是不夠袍患。由于這里的隨機(jī)森林模型是隨便設(shè)定的,沒(méi)有設(shè)定好參數(shù)竣付,所以需要對(duì)模型進(jìn)行優(yōu)化协怒,建立合適的樹模型,優(yōu)化數(shù)的個(gè)數(shù)和深度卑笨。
RandomForestClassifier用法參考:https://www.cnblogs.com/pinard/p/6160412.html
- 自己構(gòu)造特征
前面我們還有一些標(biāo)簽沒(méi)有使用上孕暇,在這里我們將剩下的一些標(biāo)簽給用上,將標(biāo)簽進(jìn)行數(shù)字化處理赤兴。其中妖滔,構(gòu)建一個(gè)FamilySize標(biāo)簽,它是由SibSp標(biāo)簽和Parch標(biāo)簽相加得到桶良;構(gòu)建一個(gè)NameLength標(biāo)簽座舍,它是乘客的名字長(zhǎng)度;再構(gòu)建Title標(biāo)簽陨帆,它是每個(gè)乘客的稱號(hào)曲秉,如Mr、Mrs疲牵、Miss埠褪、Dr...。然后將標(biāo)簽的數(shù)據(jù)轉(zhuǎn)換為數(shù)字進(jìn)行處理易桃。
# 自己構(gòu)建特征
df['FamilySize'] = df['SibSp'] + df['Parch'] # 兄弟姐妹和老人小孩
df['NameLength'] = df['Name'].apply(lambda x: len(x)) # 名字的長(zhǎng)度
import re
# 每個(gè)人都有自己的身份的詞捆姜,如Miss, Mr...
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
if title_search:
return title_search.group(1)
return ''
titles = df['Name'].apply(get_title)
print(pd.value_counts(titles))
# 將稱號(hào)用數(shù)字表示
title_mapping = {'Mr': 1, 'Miss': 2, 'Mrs': 3, 'Master': 4, 'Dr': 5, 'Rev': 6, 'Col': 7, 'Major': 8, 'Mlle': 9,
'Countess': 10, 'Ms': 11, 'Lady': 12, 'Jonkheer': 13, 'Don': 14, 'Mme': 15, 'Capt': 16, 'Sir': 17}
for k, v in title_mapping.items():
titles[titles == k] = v
print(pd.value_counts(titles))
df['Title'] = titles
運(yùn)行結(jié)果如圖6、7所示:
至此识啦,3個(gè)新的標(biāo)簽就已經(jīng)構(gòu)建好了负蚊,我們先將數(shù)據(jù)可視化,觀察哪個(gè)標(biāo)簽所占的權(quán)重較高颓哮,然后使用隨機(jī)森林模型進(jìn)行預(yù)測(cè)家妆。
from sklearn.feature_selection import SelectKBest, f_classif
predictors_new = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked', 'FamilySize', 'NameLength', 'Title']
selector = SelectKBest(f_classif, k=5)
selector.fit(df[predictors_new], df['Survived'])
scores_2 = -np.log10(selector.pvalues_)
plt.bar(range(len(predictors_new)), scores_2)
plt.xticks(range(len(predictors_new)), predictors_new, rotation='vertical')
plt.show()
SelectKBest用法參考:http://www.reibang.com/p/586ba8c96a3d
運(yùn)行結(jié)果如圖8所示:
通過(guò)上述圖8我們選擇5個(gè)最重要的標(biāo)簽,接下來(lái)用隨機(jī)森林模型進(jìn)行預(yù)測(cè)冕茅。
predictors_1 = ['Pclass', 'Sex', 'Fare', 'Title', 'NameLength']
alg_3 = RandomForestClassifier(random_state=1, n_estimators=50, min_samples_split=8, min_samples_leaf=4)
kf = model_selection.KFold(n_splits=3, random_state=1, shuffle=True)
scores_1 = model_selection.cross_val_score(alg_3, df[predictors_1], df['Survived'], cv=kf)
print(scores_1.mean())
運(yùn)行結(jié)果為:0.8215488215488215
可見(jiàn)伤极,預(yù)測(cè)的結(jié)果并沒(méi)有多大的改變腰鬼,可見(jiàn)隨機(jī)森林的預(yù)測(cè)效果還不夠好,看能否優(yōu)化一下樹結(jié)構(gòu)塑荒。