【決策樹】泰坦尼克號倖存者預測項目

 項目目標

泰坦尼克號的沉沒是歷史上最著名的還難事件之一,在船上的2224名乘客和機組人員中,共造成1502人死亡。本次項目的目標是運用機器學習工具來預測哪些乘客能夠幸免於難。

項目過程

  • 導入並探索數據
  • 處理缺失值,刪除與預測無關的特徵
  • 將分類變數轉換為數值型變數
  • 實例化模型並進行交叉驗證
  • 模型預測
  • 調參,得到最好的超參數

項目程式碼(Jupyter)

import pandas as pd 
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

 

data = pd.read_csv("Taitanic data.csv")
data.head()

data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
# 這裡首先我們看看這些標籤代表著什麼

# PassengerId => 乘客ID
# Pclass => 乘客等級(1/2/3等艙位)
# Name => 乘客姓名
# Sex => 性別
# Age => 年齡
# SibSp => 堂兄弟/妹個數
# Parch => 父母與小孩個數
# Ticket => 船票資訊
# Fare => 票價
# Cabin => 客艙
# Embarked => 登船港口

 

# 刪除缺失值過多的列,以及和預測的y沒有關係的列
data.drop(["Cabin", "Name", "Ticket"], inplace=True, axis=1)

# 處理缺失值,對於缺失較多的列進行填補,對於缺失較少的列可以直接刪除該條記錄
data["Age"] = data["Age"].fillna(data["Age"].mean())
data = data.dropna()

# 刪除缺失值後重置索引
data.index = range(len(data))
data.tail()

data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 889 entries, 0 to 888
Data columns (total 9 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  889 non-null    int64  
 1   Survived     889 non-null    int64  
 2   Pclass       889 non-null    int64  
 3   Sex          889 non-null    object 
 4   Age          889 non-null    float64
 5   SibSp        889 non-null    int64  
 6   Parch        889 non-null    int64  
 7   Fare         889 non-null    float64
 8   Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(2)
memory usage: 62.6+ KB
# 將分類變數轉換為數值型變數

# 在說分類變數轉數值型變數之前,我們首先要清楚數據的類型
# 數據可以分為定量數據和定性數據,定性數據又可以分為有序數據和無序數據,定量數據可以分為離散型數據和連續型數據
# 這個項目中我們要處理的數據是Sex和Embarked,前者屬於定性數據中的無序數據,後者屬於定性數據中的有序數據
# 在sklearn中可以進行變數轉換的類有三個:OneHotEncoder\OrdinalEncoder\LableEncoder

# 三者的區別在於:
# 1.OneHotEncoder用於編碼無序數據(針對特徵)
# 2.OrdinalEncoder用於編碼有序數據(針對特徵),可以保留數據的大小意義
# 3.LableEncoder用於編碼標籤變數,不會保留數據的大小意義

 

#將分類變數轉換為數值型變數
from sklearn.preprocessing import OneHotEncoder,OrdinalEncoder

# 編碼Sex
ohe = OneHotEncoder(sparse=False)
data_Sex = ohe.fit_transform(data["Sex"].values.reshape(-1, 1))

# 查看編碼後對應的特徵名稱並轉換為DataFrame
ohe.get_feature_names()
data_Sex_df = pd.DataFrame(data_Sex, columns=["female","male"])

# 編碼Embarked並轉換為DataFrame
oe = OrdinalEncoder()
data_Embarked = oe.fit_transform(data["Embarked"].values.reshape(-1, 1))
data_Embarked_df = pd.DataFrame(data_Embarked, columns=["Embarked"])

 

print(data_Sex.shape)
print(data_Embarked.shape)
print(data.shape)
(889, 2)
(889, 1)
(889, 9)
# 刪除Sex和Embarked
data.drop(["Sex", "Embarked"], inplace=True, axis=1)

# 將編碼後的數據合併到原數據
newdata = pd.concat([data, data_Sex_df, data_Embarked_df], axis=1)
newdata

# 劃分特徵與標籤
X = newdata.iloc[:, newdata.columns != "Survived"]
y = newdata.iloc[:,newdata.columns == "Survived"]

# 劃分訓練集與測試集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y)

clf = DecisionTreeClassifier(random_state=666)
clf.fit(Xtrain, Ytrain)
score_ = clf.score(Xtest, Ytest)

score_
0.7713004484304933
# 交叉驗證
cv_score = []
for i in range(2,10):
    score = cross_val_score(clf,X,y,cv=i).mean()
    cv_score.append(score)

best_cv = cv_score.index(max(cv_score)) + 2
best_cv
5
# 網格搜索
parameters = {"splitter":('best','random')
              ,"max_depth":[*range(1,5)]
              ,"min_samples_leaf":[*range(1,10)]
             }

clf = DecisionTreeClassifier(random_state=666)
GS = GridSearchCV(clf, parameters, cv=best_cv)
GS.fit(Xtrain,Ytrain)

GS.best_score_
0.8138143867130513
GS.best_params_
{'max_depth': 3, 'min_samples_leaf': 1, 'splitter': 'best'}