目錄
一、數據摸底
1.1 數據加載
數據下載路徑:https://www.kaggle.com/c/titanic/data
import pandas as pd
data_train = pd.read_csv("../train.csv")
data_predict = pd.read_csv("../test.csv")
full = data_train.append(data_predict, ignore_index=True) #合併訓練集和測試集,對特徵統一處理
1.2 數據統計描述和可視化
1、數據類型查看
full.head()
類別變量:Cabin、Embarked、Pclass、Sex、Survived
連續數值變量:Age、Fare
離散數值變量:Parch、SibSp
2、特徵缺失值查看
full.info()
Cabin有77%的數據缺失,應捨棄;
Age有20%的數據缺失,考慮用平均值填充;
Fare、Embarked有幾條數據缺失,分別考慮用平均值、衆數填充。
3、變量統計描述
數值型變量統計描述
full.describe()
年齡在[65,80]的乘客佔比1%,full['Age'].describe(percentiles=[0.98,0.99])
票價大於500的乘客佔比小於1%,full['Fare'].describe(percentiles=[0.98,0.99])
沒有攜帶父母和孩子的乘客佔比75%;
在三等艙的乘客佔比大約50%;
攜帶配偶的乘客佔比大約30%;
類別變量統計描述
full.describe(include=['O'])
乘客登船地點有三個,主要集中在S站;
男性乘客佔比64.4%。
4、特徵變量與目標變量的相關性
類別變量與目標變量的相關性
data_train[['Pclass','Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)
data_train[['Sex','Survived']].groupby(['Sex'], as_index=False).mean().sort_values(by='Survived', ascending=False)
data_train[['Embarked','Survived']].groupby(['Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)
船艙級別越高,乘客的生還概率越大,P1>P2>P3;
女性乘客有更大的生存概率;
在C站上船的乘客有更大的生存概率。
離散數值變量與目標變量的相關性
data_train[['SibSp','Survived']].groupby(['SibSp'], as_index=False).mean().sort_values(by='Survived', ascending=False)
data_train[['Parch','Survived']].groupby(['Parch'], as_index=False).mean().sort_values(by='Survived', ascending=False)
當家人(父母、子女、配偶、兄弟姐妹)數量達到一定值時,與目標變量的相關性爲0,應構建一些組合的衍生變量。
連續數值變量與目標變量的相關性
import seaborn as sns
import matplotlib.pyplot as plt
g = sns.FacetGrid(data_train,col='Survived')
g.map(plt.hist, "Age", bins=16)
g = sns.FacetGrid(data_train,col='Survived')
g.map(plt.hist, "Fare", bins=10)
年齡:孩童(<=5)和老人(80)擁有更大的生還概率,15-25歲的乘客生還概率較小,乘客大多集中在15-35歲。
票價:票價<=50的乘客生還概率較小,當乘客的票價>100時擁有更大的生還概率。
組合特徵與目標變量的相關性
grid = sns.FacetGrid(data_train,row='Embarked', col='Survived')
grid.map(sns.barplot, 'Sex', 'Fare', alpha=0.5, ci=None)
grid.add_legend()
考慮登船地點、性別、票價與生還概率的相關性。票價越高,生還概率越大;票價與登船地點存在直接關係,應考慮票價的組合特徵。
grid = sns.FacetGrid(data_train,row='Pclass', col='Survived')
grid.map(plt.hist, 'Age', alpha=0.5, bins=20)
grid.add_legend()
考慮船艙等級、年齡和生還概率的相關性。在一級和二級船艙中,嬰孩的生還概率較大;在一級船艙中,老人的生還概率較大;在不同等級船艙中,乘客年齡分佈區別較大。應考慮年齡的組合特徵。
二、數據預處理
2.1 名字字符串提取title
從名字中獲取title:
full['Title'] = full['Name'].str.extract('([A-Za-z]+)\.', expand=False)
pd.crosstab(full['Title'], full['Sex'])
出現次數很少的title歸類到'rare',並統計title與生還概率相關性:
full['Title'] = full['Title'].replace(['Capt','Col','Countess','Don','Dona','Dr','Jonkheer','Lady','Major','Mlle','Mme','Ms','Rev','Sir'], 'Rare')
full[['Title', 'Survived']].groupby(['Title'], as_index=False).mean().sort_values(by='Survived', ascending=False)
title與生還概率存在明顯的相關關係。
2.2 缺失值填充
full.drop(['Cabin', 'Ticket'], axis=1, inplace=True)
full['Age'] = full['Age'].fillna(full['Age'].mean())
full['Fare'] = full['Fare'].fillna(full['Fare'].mean())
full['Embarked'] = full['Embarked'].fillna('S')
2.3 類別變量轉化爲數值型
full['Title'] = full['Title'].map({"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}).astype(int)
full['Sex'] = full['Sex'].map({'female':1, 'male':0}).astype(int)
full['Embarked'] = full['Embarked'].map({'S': 0, 'Q': 1,'C': 2}).astype(int)
2.4 連續變量轉化爲離散型
年齡等距分箱
full['AgeBand'] = pd.cut(full['Age'], 5)
full[['AgeBand', 'Survived']].groupby(['AgeBand'], as_index=False).mean().sort_values(by='AgeBand', ascending=True)
full.loc[full['Age'] <= 16, 'Age_discrete'] = 0
full.loc[(full['Age'] > 16) & (full['Age'] <= 32), 'Age_discrete'] = 1
full.loc[(full['Age'] > 32) & (full['Age'] <= 48), 'Age_discrete'] = 2
full.loc[(full['Age'] > 48) & (full['Age'] <= 64), 'Age_discrete'] = 3
full.loc[full['Age'] > 64, 'Age_discrete'] = 4
票價等頻分箱
full['FareBand'] = pd.qcut(full['Fare'],4)
full[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)
full.loc[full['Fare'] <= 7.896, 'Fare_discrete'] = 0
full.loc[(full['Fare'] > 7.896) & (full['Fare'] <= 14.454), 'Fare_discrete'] = 1
full.loc[(full['Fare'] > 14.454) & (full['Fare'] <= 31.275), 'Fare_discrete'] = 2
full.loc[(full['Fare'] > 31.275), 'Fare_discrete'] = 3
2.5 組合特徵變量
考慮所有家人,構建衍生變量:家庭成員數目和是否單獨一人
full['FamilySize'] = full['SibSp'] + full['Parch'] + 1
display.display(full[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False))
full['IsAlone'] = 0
full.loc[full['FamilySize'] == 1, 'IsAlone'] = 1
display.display(full[['IsAlone','Survived']].groupby(['IsAlone'], as_index=False).mean())
考慮年齡和船艙等級的組合特徵:
full['Age*Class'] = full.Age_discrete * full.Pclass
full[['Age*Class', 'Survived']].groupby(['Age*Class'], as_index=False).mean().sort_values(by='Survived', ascending=False)
考慮票價和登船地點的組合特徵:
full['Fare*Embarked'] = full.Fare_discrete * full.Embarked
full[['Fare*Embarked', 'Survived']].groupby(['Fare*Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)
三、模型構建
1、rf模型
#特徵選擇
full_features = full.loc[:,['Sex','Pclass','Embarked', 'Age', 'Fare', 'Age_discrete', 'Fare_discrete','Parch', 'SibSp', 'FamilySize', 'IsAlone', 'Title', 'Age*Class','Fare*Embarked']]
source_x = full_features.loc[0:890,:]
source_y = full.loc[0:890, 'Survived']
pred_x = full_features.loc[891:,:]
#模型構建
rf = RandomForestClassifier(n_estimators=200, max_depth=7)
rf.fit(source_x,source_y)
pred_y = rf.predict(pred_x)
pred_y = pred_y.astype(int)
display.display(rf.feature_importances_)
#預測結果提交
passenger_id = full.loc[891:, 'PassengerId']
predDF = pd.DataFrame({'PassengerId':passenger_id, 'Survived':pred_y})
display.display(predDF.head())
predDF.to_csv("../rf-submission_14_200_7.csv", index=False)
線上準確率:
參考資料:
https://www.kaggle.com/c/titanic#tutorials
https://www.kaggle.com/startupsci/titanic-data-science-solutions