作者 | Peter
來源 | 尤而小屋
Titanic資料是一份經典資料挖掘的資料集,本文介紹的是kaggle排名第一的案例分享,原notebook地址:
https://www.kaggle.com/startupsci/titanic-data-science-solutions

排名
看下這個案例的排名情況:
![]()
第一名和第二名的差距也不是很多,而且第二名的評論遠超第一名;有空再一起學習下第二名的思路,
通過自己的整體學習第一名的原始碼,前期對欄位的處理很細致,全面;建模的程序稍微比較淺,
資料集文末會給出!
資料探索
匯入庫
匯入整個程序中需要的三類別庫:
-
資料處理
-
可視化庫
-
建模庫
# 資料處理
import pandas as pd
import numpy as np
import random as rnd
# 可視化
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
# 模型
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import Perceptron
from sklearn.linear_model import SGDClassifier
from sklearn.tree import DecisionTreeClassifier
匯入資料
匯入資料后查看資料的大小

欄位資訊
查看全部的欄位:
train.columns
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],
dtype='object')
下面是欄位的具體含義:
-
PassengerId:用戶id
-
survival:是否生還,0-否,1-是
-
pclass:艙位,1-頭等艙,2-二等,3-三等
-
name:姓名
-
sex:性別
-
Age:年齡
-
sibsp:在船上的兄弟/配偶數
-
parch:在船上父母/孩子數
-
ticket:票號
-
fare:票價
-
cabin:Cabin number;客艙號
-
embarked:登船地點
欄位分類
本案例中的資料主要是有兩種型別:
-
分型別Categorical: Survived, Sex, and Embarked. Ordinal: Pclass
-
連續型Continous: Age, Fare. Discrete: SibSp, Parch
缺失值
查看訓練集和測驗集的缺失值情況:
![]()
同時也可以通過info函式來查資料的基本資訊:

資料假設
作者基于資料的基本資訊和常識,給出了自己的一些假設和后面的資料處理和分析方向:
洗掉欄位
-
本專案主要是考察其他欄位和Survival欄位的關系
-
重點關注欄位:Age、Embarked
-
洗掉欄位:對資料分析沒有作用,直接洗掉的欄位:Ticket(票號)、Cabin(客艙號)、PassengerId(乘客號)、Name(姓名)
修改、增加欄位
-
增加Family:根據Parch(船上的兄弟姐妹個數) 和 SibSp(船上的父母小孩個數)
-
從Name欄位中提取Title作為新特征
-
將年齡Age欄位轉成有序的分類特征
-
創建一個基于票價Fare 范圍的特征
猜想
-
女人(Sex=female)更容易生還
-
小孩(Age>?)更容易生還
-
船艙等級高的乘客更容易生還(Pclass=1)
統計分析
主要是對分類的變數Sex、有序變數Pclss、離散型SibSp、Parch進行分析來驗證我們的猜想
1、船艙等級(1-頭等,2-二等,3-三等)

結論:頭等艙的人更容易生還
2、性別

結論:女人更容易生還
3、兄弟姐妹/配偶數
![]()
結論:兄弟姐妹或者配偶數量相對少的乘客更容易生還
4、父母/孩子數

結論:父母子女在3個的時候,更容易生還
可視化分析
年齡與生還
g = sns.FacetGrid(train, col="Survived")
g.map(plt.hist, 'Age', bins=20)
plt.show()

-
對于未生還的人員,大多數集中在15-25歲(左圖)
-
生還人員年齡最大為80;同時4歲以下的小孩生還率很高(右圖)
-
乘客的年齡大多數集中在15-35歲(兩圖)
艙位與生還
grid = sns.FacetGrid(
train,
col="Survived",
row="Pclass",
size=2.2,
aspect=1.6
)
grid.map(plt.hist,"Age",alpha=0.5,bins=20)
grid.add_legend()
plt.show()

-
艙位等級3的乘客最多;但是很多沒有生還
-
艙位等級1的乘客生還最多
登船地點、性別與生還的關系
grid = sns.FacetGrid(train,
row="Embarked",
size=2.2,
aspect=1.6)
grid.map(sns.pointplot,
"Pclass",
"Survived",
"Sex",
palette="deep")
grid.add_legend()
plt.show()

-
女性比男性的生還情況要好
-
除了在Embarked=C,男性的生還率要高些,
-
當艙位等級都在Pclass=3,男性的在Embarked=C的生還率好于Q
票價、艙位與生還
grid = sns.FacetGrid(train,
row='Embarked',
col='Survived',
size=2.2, aspect=1.6)
grid.map(sns.barplot,
'Sex',
'Fare',
alpha=.5, ci=None)
grid.add_legend()
plt.show()

-
票價越高,生還效果越好;右側上2圖
-
生還率和登船的位置相關;明顯在Embarked=C的情況是最好的
上面都是基于簡單的統計和可視化方面的分析,下面的程序是基于各種機器學習建模的方法來進行分析,前期做了很多的預處理好特征工程的作業,
洗掉無效欄位
票價ticket和客艙號Cabin對我們分析幾乎是沒有用的,可以考慮直接洗掉:
![]()
生成新特征
主要是根據現有的特征屬性中找到一定的關系,來生成新的特征,或者進行一定的特征屬性轉化,
欄位Name處理
根據名稱Name生成找到稱謂,比如Lady、Dr、Miss等資訊,來查看這個稱謂和生還資訊之間是否存在關系
# 通過正則提取
for dataset in combine:
dataset["Title"] = dataset.Name.str.extract('([A-Za-z]+)\.', expand=False)
# 統計Title下的男女數量
train.groupby(["Sex","Title"]).size().reset_index()

使用交叉表的形式統計:
# 交叉表形式
pd.crosstab(train['Title'], train['Sex'])
![]()
將提取出來的稱謂進行整理,歸類為常見的稱謂和Rare資訊:
for dataset in combine:
dataset["Title"] = dataset["Title"].replace(['Lady', 'Countess','Capt', 'Col',\
'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')
dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')
# 根據稱謂Title求生還的均值
train[["Title","Survived"]].groupby("Title",as_index=False).mean()

稱謂本身是文本型對后期建模無用,我們直接轉成數值型:
title_mapping = {
"Mr":1,
"Miss":2,
"Mrs":3,
"Master":4,
"Rare":5
}
for dataset in combine:
# 存在資料的進行匹配
dataset['Title'] = dataset['Title'].map(title_mapping)
# 不存在則補0
dataset['Title'] = dataset['Title'].fillna(0)
train.head()
同時還需要洗掉部分欄位:
train = train.drop(['Name', 'PassengerId'], axis=1)
test = test.drop(['Name'], axis=1)
combine = [train, test]
train.shape, test.shape
# ((891, 9), (418, 9))
欄位Sex
將性別的Male和Female轉成0-Male,1-Female
for dataset in combine:
dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int)
性別、年齡、生還之間的關系:
grid = sns.FacetGrid(
train,
row='Pclass',
col='Sex',
size=2.2,
aspect=1.6)
grid.map(plt.hist,
'Age',
alpha=.5,
bins=20)
grid.add_legend()
plt.show()

欄位Age
1、首先就是欄位的缺失值處理,
我們觀察到年齡欄位是存在缺失值的,我們通過Sex(0、1)和Pclass(1、2、3)的6種組合關系來進行填充,缺失值情況:

填充的具體程序:
guess_ages = np.zeros((2,3))
for dataset in combine:
for i in range(0,2):
for j in range(0,3):
# 找到某種條件下Age欄位的缺失值并洗掉
guess_df = dataset[(dataset["Sex"] == i) & (dataset["Pclass"] == j+1)]["Age"].dropna()
age_guess = guess_df.median() # 中位數
guess_ages[i,j] = int(age_guess / 0.5 + 0.5) * 0.5
for i in range(0,2):
for j in range(0,3):
dataset.loc[(dataset.Age.isnull()) & (dataset.Sex == i) & (dataset.Pclass == j+1),"Age"] = guess_ages[i,j]
dataset["Age"] = dataset["Age"].astype(int)
# 填充后不存在缺失值
train.isnull().sum()
![]()
2、年齡分段分箱
![]()

3、轉成數值分類
-
年齡小于16用0替代
-
16到32用1替代等...
for dataset in combine:
dataset.loc[dataset["Age"] <= 16, "Age"] = 0
dataset.loc[(dataset["Age"] > 16) & (dataset["Age"] <= 32), "Age"] = 1
dataset.loc[(dataset["Age"] > 32) & (dataset["Age"] <= 48), "Age"] = 2
dataset.loc[(dataset["Age"] > 48) & (dataset["Age"] <= 64), "Age"] = 3
dataset.loc[(dataset["Age"] > 64), "Age"] = 4
# 洗掉年齡段AgeBand欄位
train = train.drop(["AgeBand"], axis=1)
combine = [train, test]
欄位處理
根據現有的欄位來生成新欄位:
生成新欄位1
首先根據Parch和SibSp兩個欄位生成一個FamilySize欄位
for dataset in combine:
dataset["FamilySize"] = dataset["SibSp"] + dataset["Parch"] + 1
# 每個FamilySize的生還均值
train[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False)
根據欄位FamilySize來判斷是否Islone:如果家庭成員FamilySize是一個人,那肯定是Islone的,用1表示,否則用0表示

最后將 Parch, SibSp, and FamilySize洗掉,僅保留是否一個人Islone:
# 將 Parch, SibSp, and FamilySize洗掉,僅保留是否一個人Islone
train = train.drop(['Parch', 'SibSp', 'FamilySize'],axis=1)
test = test.drop(['Parch', 'SibSp', 'FamilySize'],axis=1)
combine = [train, test]
train.head()
生成新欄位2
新欄位2是Age和Pclass的乘積:
![]()
Embarked欄位的分類
Embarked欄位取值有SQC,首先我們填充里面的缺失值
查看這個欄位是存在缺失值的:

處理:找出眾數、填充缺失值、查看每個取值的均值

將文本型別轉成數值型:

Fare欄位處理
訓練集這個欄位是沒有缺失值,測驗集中存在一個:

使用中值進行填充:

實行分箱操作:
# 只對FareBand欄位分箱
train['FareBand'] = pd.qcut(train['Fare'], 4) # 分成4組
# 生還的均值
train[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)

將每個段轉成數值型的資料:
# 4個分段
for dataset in combine:
dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare'] = 2
dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
dataset['Fare'] = dataset['Fare'].astype(int)
#
train = train.drop(['FareBand'], axis=1)
combine = [train, test]
test.head()
這樣我們就得到最終用于建模的欄位和資料:

建模
下面是具體的建模程序,我們先劃分資料集:
# 訓練集
X_train = train.drop("Survived", axis=1)
Y_train = train["Survived"]
# 測驗集
X_test = test.drop("PassengerId", axis=1).copy()
X_train.shape, Y_train.shape, X_test.shape
每個模型的具體程序:
-
建立模型實體化的物件
-
擬合訓練集
-
對測驗集進行預測
-
計算準確率
模型1:邏輯回歸
# 模型實體化
logreg = LogisticRegression()
# 擬合程序
logreg.fit(X_train, Y_train)
# 測驗集預測
Y_pred = logreg.predict(X_test)
# 準確率求解
acc_log = round(logreg.score(X_train, Y_train) * 100, 2)
acc_log
# 結果
81.37
邏輯回歸模型得到的系數:
# 邏輯回歸特征和系數
coeff_df = pd.DataFrame(train.columns[1:]) # 除去Survived特征
coeff_df.columns = ["Features"]
coeff_df["Correlation"] = pd.Series(logreg.coef_[0])
# 從高到低
coeff_df.sort_values(by='Correlation', ascending=False)

結論:性別對我們的生還真的是一個重要的影響因素
模型2:支持向量機SVM

模型3:KNN

模型4:樸素貝葉斯
![]()
模型5:感知機
![]()
模型6:線性支持向量分類
linear_svc = LinearSVC()
linear_svc.fit(X_train, Y_train)
Y_pred = linear_svc.predict(X_test)
acc_linear_svc = round(linear_svc.score(X_train, Y_train) * 100, 2)
acc_linear_svc
# 結果
79.46
模型7:隨機梯度下降
![]()
模型8:決策樹

模型9:隨機森林

模型對比
將上面9種模型的結果(準確率)進行對比:
models = pd.DataFrame({
'Model': ['Support Vector Machines', 'KNN', 'Logistic Regression',
'Random Forest', 'Naive Bayes', 'Perceptron',
'Stochastic Gradient Decent', 'Linear SVC',
'Decision Tree'],
'Score': [acc_svc, acc_knn, acc_log,
acc_random_forest, acc_gaussian, acc_perceptron,
acc_sgd, acc_linear_svc, acc_decision_tree]})
models.sort_values(by='Score', ascending=False)

通過對比結果:決策樹和隨機森林在這份資料集表現的效果是最好的;其次就是KNN(K近鄰)演算法,
Python學習資源傳送門:
資料集:
鏈接:https://pan.baidu.com/s/12LlkhlDSk7G50o9R0RvQKA
提取碼:swo8
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/394173.html
標籤:其他
