決策樹(下):泰坦尼克乘客生存預測
決策樹分類的應用場景有很多,比如在金融行業用決策樹做貸款風險評估,醫療行業用決策樹生成輔助診斷,用sklearn工具解決泰坦尼克乘客生存預測:
sklearn中的決策樹模型
sklearn中自帶的決策樹分類器DecisionTreeClassifier
clf = DecisionTreeClassifier(criterion='entropy')
在構建DecisionTreeClassifier類時,其中一個參數是criterion,決定了構造的分類樹是採用ID3分類是還是CART分類樹,對應的取值分別是entropy或者gini,用criterion=‘entropy’,然後打印clf,看下決策樹在sklearn:
DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=None,
max_features=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort=False, random_state=None,
splitter='best')
criterion採用不同決策樹算法外,一般建議使用默認參數,默認參數不會限制決策樹的最大深度,不限制葉子節點數,認爲所有分類的權重都相等。
在構造決策樹分類器後,使用fit方法讓分類器進行擬合,使用predict方法對新數據進行預測,得到預測的分類結果,使用score方法得到分類器的準確率
泰坦尼克乘客生存預測
究竟有多少人遇難,可以得到部分數據< https://github.com/cystanford/Titanic_Data >,完整的項目代碼見:< https://github.com/cystanford/Titanic_Data/blob/master/titanic_analysis.py >,有兩個數據集csv
- train.csv是訓練數據集,包含特徵信息和存活與否的標籤
- test.csv測試數據集,只包含特徵信息
用決策樹分類對訓練集進行訓練,針對測試集中的乘客進行生存預測,並告知分類器的準確率,訓練集中,包括以下字段
生存預測的關鍵流程
對訓練集中乘客的生存進行預測,分爲兩個重要階段:
- 準備階段:首先對訓練集、測試集的數據進行探索,分析數據質量,對數據進行清洗,通過特徵選擇對數據進行降維
- 分類階段:首先通過訓練集的特徵矩陣、分類結果得到決策樹分類器,然後將分類器應用於測試集,然後對分類器的準確性進行分析,對決策樹模型進行可視化
模塊1:數據探索
如何進行數據探索?需要了解一些函數:
- 使用info()瞭解數據表的基本情況:行數、列數、每列的數據類型、數據完整度
- 使用describe()瞭解數據表的統計情況:總數、平均數、標準差、最小值、最大值
- 使用describe(include=[‘O’])查看字符串類型(非數字)的整體情況
- 使用head查看前幾行數據
- 使用tail查看後幾行數據
import pandas as pd
# 數據加載
train_data = pd.read_csv('./Titanic_Data/train.csv')
test_data = pd.read_csv('./Titanic_Data/test.csv')
# 數據探索
print(train_data.info())
print('-'*30)
print(train_data.describe())
print('-'*30)
print(train_data.describe(include=['O']))
print('-'*30)
print(train_data.head())
print('-'*30)
print(train_data.tail())
模塊2:數據清洗
有些字段數據缺失,比如Age年齡字段,是數值型,可以通過平均值進行補齊,Fare爲船票價格,數值型,也可以用其他人購買船票的平均值進行補齊
# 使用平均年齡來填充年齡中的nan值
train_data['Age'].fillna(train_data['Age'].mean(), inplace=True)
test_data['Age'].fillna(test_data['Age'].mean(),inplace=True)
# 使用票價的均值填充票價中的nan值
train_data['Fare'].fillna(train_data['Fare'].mean(), inplace=True)
test_data['Fare'].fillna(test_data['Fare'].mean(),inplace=True)
Cabin爲船艙,有大量缺失值,Embarked爲登錄港口
先觀察Embarked的取值print(train_data['Embarked'].value_counts())
結果如下
S 644
C 168
Q 77Name:Embarked ,dtype:int64
一共3個登錄港口,其中S港口最多,因此將其餘缺失的Embarked數值設置爲S
# 使用登錄最多的港口來填充登錄港口的nan值
train_data['Embarked'].fillna('S', inplace=True)
test_data['Embarked'].fillna('S',inplace=True)
模塊3:特徵選擇
特徵選擇是分類器的關鍵,特徵選擇不同,得到的分類器也不同
通過數據探索發現,Passengerld爲乘客編號,對分類沒用,可以放棄;
Name爲乘客姓名,對分類沒用,放棄;
Cabin字段缺失值太多,放棄;Ticket字段爲船票號碼,雜亂無章無規律,放棄;其餘的字段包含:Pclass、Sex、Age、SibSp、Parch、Fare分別表示了乘客的船票等級、性別、年齡、親戚數量、船票價格,可能會和乘客的生存預測有關係,具體什麼關係,交給分類器處理
將Pclass、Sex、Age等字段作特徵,放到特徵向量features裏
# 特徵選擇
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
train_features = train_data[features]
train_labels = train_data['Survived']
test_features = test_data[features]
特徵值裏有一些是字符串,需要轉成數值類型,比如Sex,有male和female兩種取值,把它變成Sex = male,和Sex = female兩個字段,數值用0或1來表示
同理,Embarked有S,C,O三種可能,三個字段分別是0,1,來表示
使用DictVectorizer類,將可以處理符號化的對象,將符號轉成數子0/1來表示
from sklearn.feature_extraction import DictVectorizer
dvec=DictVectorizer(sparse=False)
train_features=dvec.fit_transform(train_features.to_dict(orient='record'))
fit_transform函數可以將特徵向量轉化爲特徵值矩陣
dvec在轉化後的特徵屬性是怎樣的,即dvec的feature_names_屬性值
print(dvec.feature_names_)
[‘Age’, ‘Embarked=C’, ‘Embarked=Q’, ‘Embarked=S’, ‘Fare’, ‘Parch’, ‘Pclass’, ‘Sex=female’, ‘Sex=male’, ‘SibSp’]
原本是一列的Embarked,變成了“Embarked=C”“Embarked=Q”"Embarked=S"三列,Sex列變成了“Sex=female”"Sex=male"兩列
模塊4:決策樹模型
使用ID3算法,即在創建DecisionTreeClassifier時,設置criterion=‘entropy’,使用fit進行訓練,將特徵值矩陣和分類標識結果作爲參數傳入得到決策樹分類器
from sklearn.tree import DecisionTreeClassifier
# 構造ID3決策樹
clf = DecisionTreeClassifier(criterion='entropy')
# 決策樹訓練
clf.fit(train_features, train_labels)
模塊5 :模型預測 & 評估
預測中,需要得到測試集的特徵值矩陣,然後使用訓練好的決策樹clf進行預測,得到預測結果pred_labels:
test_features=dvec.transform(test_features.to_dict(orient='record'))
# 決策樹預測
pred_labels = clf.predict(test_features)
決策樹提供了score函數可以直接得到準確率,但是不知道真實的預測結果,無法用預測值和真實的預測結果做比較,只能使用訓練集中的數據進行模型評估,使用決策樹自帶的score函數計算:
# 得到決策樹準確率
acc_decision_tree = round(clf.score(train_features, train_labels), 6)
print(u'score準確率爲 %.4lf' % acc_decision_tree)
score準確率爲0.9820
用訓練集做訓練,再用訓練集自身做準確率評估自然很高,但是不能代表決策樹分類器的準確率
因爲我們沒有測試集的實際結果,因此無法用測試集的預測結果與實際結果作對比,如果使用score函數對訓練集的準確率進行統計,正確率會接近於100%,無法對分類器的在實際環境下做準確率的評估
如何同居決策樹分類器的準確率呢?
使用K折交叉驗證方式,交叉驗證是一種常用的驗證分類準確率的方法,原理是拿出大部分樣本進行訓練,少量的用於分類器的驗證,K折交叉驗證就是做K次交叉驗證,每次選取K分之一的數據作爲驗證,其餘作爲訓練,輪流K次,取平均值
K折交叉驗證的原理是:
- 將數據集平均分割成K個等份
- 使用1份數據作爲測試數據,其餘作爲訓練數據
- 計算測試準確率
- 使用不同的測試集,重複2,3步驟
在sklearn的model_selection模型選擇中提供cross_val_score函數,cross_val_score函數中參數cv代表對原始數據劃分成多少份,就是我們的K值,一般建議K值取10,設cv=10,對比下score和cross_val_score兩種函數的正確率和評估結果:
import numpy as np
from sklearn.model_selection import cross_val_score
# 使用K折交叉驗證 統計決策樹準確率
print(u'cross_val_score準確率爲 %.4lf' % np.mean(cross_val_score(clf, train_features, train_labels, cv=10)))
cross_val_score準確率爲 0.7835
對於不知道測試集實際結果的,使用K折交叉驗證才能知道模型的準確率
模塊6:決策樹可視化
使用Graphviz可視化工具把決策樹呈現出來
安裝Graphviz庫:
1 安裝Graphviz工具,下載地址是:< http://www.graphviz.org/download/ >
2 將 Graphviz添加到環境變量PATH中;
3 需要Graphviz庫,如果沒有可以使用pip install graphviz進行安裝
在程序裏面使用Graphviz對決策樹模型進行呈現得到一個決策樹可視化的PDF文件,可視化結果文件Source.gv.pdf在Github上下載:< https://github.com/cystanford/Titanic_Data >
總結:
import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier
# 數據加載
train_data = pd.read_csv('./train.csv')
test_data = pd.read_csv('./test.csv')
# 數據探索
print(train_data.info())
print('-'*30)
print(train_data.describe())
print('-'*30)
print(train_data.describe(include=['O']))
print('-'*30)
print(train_data.head())
print('-'*30)
print(train_data.tail())
# 數據清洗
# 使用平均年齡來填充年齡中的 nan 值
train_data['Age'].fillna(train_data['Age'].mean(), inplace=True)
test_data['Age'].fillna(test_data['Age'].mean(),inplace=True)
# 使用票價的均值填充票價中的 nan 值
train_data['Fare'].fillna(train_data['Fare'].mean(), inplace=True)
test_data['Fare'].fillna(test_data['Fare'].mean(),inplace=True)
print(train_data['Embarked'].value_counts())
# 使用登錄最多的港口來填充登錄港口的 nan 值
train_data['Embarked'].fillna('S', inplace=True)
test_data['Embarked'].fillna('S',inplace=True)
# 特徵選擇
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
train_features = train_data[features]
train_labels = train_data['Survived']
test_features = test_data[features]
dvec=DictVectorizer(sparse=False)
train_features=dvec.fit_transform(train_features.to_dict(orient='record'))
print(dvec.feature_names_)
# 構造 ID3 決策樹
clf = DecisionTreeClassifier(criterion='entropy')
# 決策樹訓練
clf.fit(train_features, train_labels)
test_features=dvec.transform(test_features.to_dict(orient='record'))
# 決策樹預測
pred_labels = clf.predict(test_features)
# 得到決策樹準確率
acc_decision_tree = round(clf.score(train_features, train_labels), 6)
print(u'score 準確率爲 %.4lf' % acc_decision_tree)
_features, train_labels)
test_features=dvec.transform(test_features.to_dict(orient=‘record’))
決策樹預測
pred_labels = clf.predict(test_features)
得到決策樹準確率
acc_decision_tree = round(clf.score(train_features, train_labels), 6)
print(u’score 準確率爲 %.4lf’ % acc_decision_tree)