玩了好久總算是又靜下心來好好看書,通過一段時間的學習,打算稍微檢驗一下知識的掌握程度,因此去kaggle參加了久聞的泰坦尼克生還預測,如下是正文。html
-----------------------------------------------------------------------------------------算法
一、觀察數據網絡
拿到數據集後,先來了解數據的大體狀況。dom
data.info()
data_des = data.describe()
能夠得知數據集有12列,891行,其中'Age'、'Cabin'、'Embarked'列存在缺失值,全部樣本的平均生還率未0.383838;2等3等艙的人數比1等艙多;平均年齡爲29.6991歲等等。學習
同時明確了須要預測的結果,即'Survived'的預測,是個明顯的二分類問題,優先考慮邏輯迴歸、決策樹、神經網絡等算法。測試
如下爲各列的含義:優化
passengerid_乘客ID survived_是否獲救(目標) pclass_乘客等級
name_姓名 sex_性別 age_年齡(缺失) sibsp_堂兄弟/妹個數 parch_父母/小孩個數
ticket_船票信息 fare_票價 cabin_客艙號(缺失) embarked_登船港口(缺失)spa
對數據分組對比,先觀察乘客等級、年齡、性別、登船港口與是否生還的關係:rest
#性別生還率:女性生還率74.2%,男性生還率18.9% sex_survived = data.groupby(by=['Sex'])['Survived'].agg({'總人數':np.size, '生還人數':np.sum}) sex_survived['未生還人數'] = sex_survived['總人數'] - sex_survived['生還人數'] sex_survived['生還率'] = sex_survived['生還人數'] / sex_survived['總人數'] #乘客等級生還率:1級乘客生還率最高 pclass_survived = data.groupby(by=['Pclass'])['Survived'].agg({'總人數':np.size, '生還人數':np.sum}) pclass_survived['未生還人數'] = pclass_survived['總人數'] - pclass_survived['生還人數'] pclass_survived['生還率'] = pclass_survived['生還人數'] / pclass_survived['總人數'] #各年齡段生還率:0-10歲生還率最高,60歲以上生還率最低 bins = [0,10,20,30,40,50,60,70,80] data['age_cut'] = pd.cut(data['Age'],bins,right=False) age_survived = data.groupby(by=['age_cut'])['Survived'].agg({'總人數':np.size, '生還人數':np.sum}) age_survived['未生還人數'] = age_survived['總人數'] - age_survived['生還人數'] age_survived['生還率'] = age_survived['生還人數'] / age_survived['總人數'] #各登船港口生還率:C港生還率最高,S港人數最多、生還率最低 embarked_survived = data.groupby(by=['Embarked'])['Survived'].agg({'總人數':np.size, '生還人數':np.sum}) embarked_survived['未生還人數'] = embarked_survived['總人數'] - embarked_survived['生還人數'] embarked_survived['生還率'] = embarked_survived['生還人數'] / embarked_survived['總人數'] ###可視化 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] =False plt.subplot(221) #將圖形區域分紅2行*2列,將圖形設置在第1個位置 plt.bar(sex_survived.index, sex_survived['生還人數'], color='b', alpha=0.7) plt.bar(sex_survived.index, sex_survived['未生還人數'], bottom=sex_survived['生還人數'], color='lightblue') plt.title('性別獲救狀況') plt.ylabel('人數') plt.grid(b=True, which='major', axis='y') plt.subplot(222) plt.bar(pclass_survived.index, pclass_survived['生還人數'], color='b', alpha=0.7) plt.bar(pclass_survived.index, pclass_survived['未生還人數'], bottom=pclass_survived['生還人數'], color='lightblue') plt.xticks(pclass_survived.index) plt.title('乘客等級獲救狀況') plt.xlabel('乘客等級') plt.ylabel('人數') plt.grid(b=True, which='major', axis='y') plt.subplot(223) age_survived['age_index'] = age_survived.index.astype(str) plt.bar(age_survived['age_index'], age_survived['生還人數'], color='b', alpha=0.7) plt.bar(age_survived['age_index'], age_survived['未生還人數'], bottom=age_survived['生還人數'], color='lightblue') plt.xticks(age_survived['age_index']) plt.title('按年齡獲救狀況') plt.xlabel('年齡分佈') plt.ylabel('人數') plt.grid(b=True, which='major', axis='y')
使用循環優化代碼後:code
#各個維度的生還率 bins = [0,10,20,30,40,50,60,70,80] data['age_cut'] = pd.cut(data['Age'],bins,right=False) dataframe = ['sex_survived', 'pclass_survived', 'age_survived' , 'embarked_survived'] columns = ['Sex', 'Pclass', 'age_cut', 'Embarked'] for name in dataframe: for i in range(0,4): dataframe[i] = data.groupby(by=[columns[i]])['Survived'].agg({'總人數':np.size, '生還人數':np.sum}) dataframe[i]['未生還人數'] = dataframe[i]['總人數'] - dataframe[i]['生還人數'] dataframe[i]['生還率'] = dataframe[i]['生還人數'] / dataframe[i]['總人數'] print(dataframe) #畫圖 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] =False dataframe[2]['age_index'] = dataframe[2].index.astype(str) dataframe[2] = dataframe[2].set_index(dataframe[2]['age_index']) for j in range(0,4): plt.subplot(2,2,j+1) #將圖形區域分紅2行*2列,將圖形設置在第1個位置 plt.bar(dataframe[j].index, dataframe[j]['生還人數'], color='b', alpha=0.7) plt.bar(dataframe[j].index, dataframe[j]['未生還人數'], bottom=dataframe[j]['生還人數'], color='lightblue') plt.title(columns[j]) plt.ylabel('人數') plt.grid(b=True, which='major', axis='y')
獲得以下的圖形:(寶藍色爲獲救)
數據顯示:女性生還率74.2%,男性生還率18.9%;1級乘客生還率最高;0-10歲生還率最高,60歲以上生還率最低;C港生還率最高,S港人數最多、生還率最低
獲得結論:性別、年齡、乘客等級、登船港口都對是否獲救有較大影響。
另:船票價格與乘客等級相關較強,但與生還率的關係不明顯;堂兄弟、父母/小孩數量對生還結果沒有明顯影響。
二、數據處理
1)年齡的缺失項
因爲年齡對因而否生還的影響仍是比較明顯,且缺失較多(缺失177個,接近20%),因此不能直接忽略缺失項或對缺失項作簡單的均值、中位數等替換。
這裏考慮使用隨機森林對年齡進行預測填補:
https://scikit-learn.org/dev/modules/generated/sklearn.ensemble.RandomForestRegressor.html(隨機森林官方文檔)
#對年齡缺失項作隨機森林進行填補 age_data = data[['Age','Fare', 'Parch', 'SibSp', 'Pclass']] fcolumns = ['Fare', 'Parch', 'SibSp', 'Pclass'] tcolumns = ['Age'] age_data_known = age_data[age_data.Age.notnull()] age_data_unknown = age_data[age_data.Age.isnull()] fdata = age_data_known[fcolumns]#特徵變量 tdata = age_data_known[tcolumns]#目標變量 from sklearn.ensemble import RandomForestRegressor rfrmodel = RandomForestRegressor(n_jobs=-1) rfrmodel.fit(fdata, tdata ) predictedAges = rfrmodel.predict(age_data_unknown[fcolumns]) data.loc[data['Age'].isnull(), 'Age'] = predictedAges
#對登船港口的2個缺失項用衆數進行填補
data.loc[data['Embarked'].isnull(), 'Embarked'] = 'S'
2)非數值型特徵的虛擬化
因爲性別、登船港口還都是字符型數據,因此須要對這兩個特徵作虛擬變換
#設置訓練集及虛擬變量 data_train = pd.DataFrame([]) data_train[['ID', 'age', 'pclass', 'sibsp', 'parch', 'fare', 'survived']] = data[['PassengerId', 'Age','Pclass','SibSp','Parch','Fare','Survived']] #性別 data_train[['sex_female','sex_male']] = pd.get_dummies(data['Sex']) #登船港口 data_train[['embarked_C','embarked_Q','embarked_S']] = pd.get_dummies(data['Embarked']) data_train = data_train.set_index('ID')
3)數值特徵標準化
因爲年齡、船票價格兩個特徵跨度很大,因此對這兩個特徵作標準化處理
import sklearn.preprocessing as preprocessing scaler = preprocessing.MinMaxScaler() data_train['age'] = scaler.fit_transform(np.array(data_train['age']).reshape(891,-891)) data_train['fare'] = scaler.fit_transform(np.array(data_train['fare']).reshape(891,-891))
三、模型創建
首先使用邏輯迴歸模型
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html(邏輯迴歸官方文檔)
from sklearn import linear_model lrModel = linear_model.LogisticRegression(penalty='l1') inputcolumns = ['age', 'pclass', 'sibsp', 'parch', 'fare', 'sex_female', 'sex_male', 'embarked_C', 'embarked_Q', 'embarked_S'] outpucolumns = ['survived'] lrModel.fit(data_train[inputcolumns], data_train[outpucolumns]) lrModel.score(data_train[inputcolumns], data_train[outpucolumns])#模型評分0.8
四、測試集處理
data2 = pd.read_csv(r'D:\kaggle\datafile\titanic\test.csv') data2.info()#年齡缺失,船票價格存在一個缺失項 data2.loc[data2['Fare'].isnull(), 'Fare'] = data2['Fare'].mean() #年齡缺失項處理 age_data2 = data2[['Age','Fare', 'Parch', 'SibSp', 'Pclass']] age_data2_known = age_data2[age_data2.Age.notnull()] age_data2_unknown = age_data2[age_data2.Age.isnull()] fdata2 = age_data2_known[fcolumns]#特徵變量 tdata2 = age_data2_known[tcolumns]#目標變量 rfrmodel.fit(fdata2, tdata2) predictedAges2 = rfrmodel.predict(age_data2_unknown[fcolumns]) data2.loc[data2['Age'].isnull(), 'Age'] = predictedAges2
#構建訓練集 data_test = pd.DataFrame([]) data_test[['ID', 'age', 'pclass', 'sibsp', 'parch', 'fare']] = data2[['PassengerId', 'Age','Pclass','SibSp','Parch','Fare']] #虛擬變量 data_test[['sex_female','sex_male']] = pd.get_dummies(data2['Sex'])#性別 data_test[['embarked_C','embarked_Q','embarked_S']] = pd.get_dummies(data2['Embarked'])#登船港口 #數值標準化 data_test['age'] = scaler.fit_transform(np.array(data_test['age']).reshape(418,-418)) data_test['fare'] = scaler.fit_transform(np.array(data_test['fare']).reshape(418,-418)) #獲得測試集預測結果 predictions = lrModel.predict(data_test[inputcolumns]) result = pd.DataFrame({'PassengerId':data_test['PassengerId'], 'Survived':predictions})
如此就可以獲得初步預測的結果了,後續會更新後面的優化等。