监督学习 | 决策树之Sklearn实现
文章目錄
- 1. Sklearn中決策樹的超參數
- 1.1 最大深度 max_depth
- 1.2 每片葉子的最小樣本數 min_samples_leaf
- 1.3 每次分裂的最小樣本數 min_samples_split
- 1.4 最大特征數 max_features
- 1.5 算法 criterion: string, optional (default=”gini”)
- 1.6 模型復雜度系數 ccp_alpha: non-negative float, optional (default=0.0)
- 2. 使用 Scikit-learn 實現決策樹算法
- 3. 實例:使用決策樹探索泰坦尼克號乘客存活情況?
- 3.1 數據導入
- 3.2 數據預處理
- 3.2.1 One-Hot 編碼
- 3.2.2 Pandas 實現 One-Hot 編碼
- 3.3 訓練模型
- 3.4 測試模型
- 3.5 決策樹可視化
- 3.6 預剪枝
- 參考資料
相關文章:
機器學習 | 目錄
監督學習 | ID3 決策樹原理及Python實現
監督學習 | ID3 & C4.5 決策樹原理
監督學習 | CART 分類回歸樹原理
監督學習 | 決策樹之Sklearn實現
監督學習 | 決策樹之網絡搜索
1. Sklearn中決策樹的超參數
1.1 最大深度 max_depth
-
決策樹的最大深度指樹根和葉子之間的最大長度。當決策樹的最大深度為kkk時,它最多可以擁有2k2^k2k片葉子,最大深度的設置相當于預剪枝處理。
-
較大的深度往往會導致過擬合,這是因為過深的決策樹可以記憶數據。而較小的深度會使得模型過于簡單,導致欠擬合。
1.2 每片葉子的最小樣本數 min_samples_leaf
-
在分裂節點時,很有可能一片葉子上有 99 個樣本,而另一片葉子上只有 1 個樣本。這將使我們陷入困境,并造成資源和時間的浪費。如果想避免這種問題,我們可以設置每片葉子允許的最小樣本數。
-
這個數字可以被指定為一個整數,也可以是一個浮點數。如果它是整數,它將表示這片葉子上的最小樣本數。如果它是個浮點數,它將被視作每片葉子上的最小樣本比例。比如,0.1 或 10% 表示如果一片葉子上的樣本數量小于該節點中樣本數量的 10%,這種分裂將不被允許。
-
當每片葉子的樣本數量較小時,葉子上的樣本數量也有可能過于稀少,此時模型將記憶數據,也就是過擬合。當每片葉子的樣本數量較大時,決策樹能夠獲得足夠的彈性進行構建,這也許會導致欠擬合。
1.3 每次分裂的最小樣本數 min_samples_split
- 與每片葉子上的最小樣本樹相同,只不過是應用在節點的分裂當中。
1.4 最大特征數 max_features
- 有時,我們會遇到特征數量過于龐大,而無法建立決策樹的情況。在這種狀況下,對于每一個分裂,我們都需要檢查整個數據集中的每一個特征。這種過程極為繁瑣。而解決方案之一是限制每個分裂中查找的特征數。如果這個數字足夠龐大,我們很有可能在查找的特征中找到良好特征(盡管也許并不是完美特征)。然而,如果這個數字小于特征數,這將極大加快我們的計算速度。
更多關于SKlearn決策樹算法的參數設定可以參考這篇文章:Python中決策樹分類器DecisionTreeClassifier參數和經驗總結
DecisionTreeClassifier官方文檔
1.5 算法 criterion: string, optional (default=”gini”)
-
ID3: criterion=“entropy”
-
CART: “gini”
1.6 模型復雜度系數 ccp_alpha: non-negative float, optional (default=0.0)
即后剪枝中懲罰函數的系數 α\alphaα,當 α\alphaα 確定時,子樹越大,往往與訓練數據的擬合越好,但是模型的復雜度越高;相反,子樹越小,模型復雜度就越低,但是往往與訓練數據的擬合不好,損失函數正好表示了對兩者的平衡。關于后剪枝的懲罰函數,可以參考這篇文章。
2. 使用 Scikit-learn 實現決策樹算法
from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score model = DecisionTreeClassifier(max_depth = 7, min_samples_leaf = 10) # 創建決策樹分類器 model.fit(x_values, y_values) # 模型擬合 y_pred = model.predict(X) # 模型預測 acc = accuracy_score(y,y_pred) # 模型評分3. 實例:使用決策樹探索泰坦尼克號乘客存活情況?
3.1 數據導入
數據可以在我的Github上下載
# Import libraries necessary for this project import numpy as np import pandas as pd from IPython.display import display # Allows the use of display() for DataFrames# Pretty display for notebooks %matplotlib inline# Set a random seed import random random.seed(42)# Load the dataset in_file = 'data/titanic_data.csv' full_data = pd.read_csv(in_file)# Print the first few entries of the RMS Titanic data display(full_data.head())| 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
| 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
| 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
| 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S |
| 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S |
下面是每位乘客具備的各種特征:
- PassengerID:乘客編號
- Survived:存活結果(0 = 存活;1 = 未存活)
- Pclass:社會階層(1 = 上層;2 = 中層;3 = 底層)
- Name:乘客姓名
- Sex:乘客性別
- Age:乘客年齡(某些條目為 NaN)
- SibSp:一起上船的兄弟姐妹和配偶人數
- Parch:一起上船的父母和子女人數
- Ticket:乘客的票號
- Fare:乘客支付的票價
- Cabin:乘客的客艙號(某些條目為 NaN)
- Embarked:乘客的登船港(C = 瑟堡;Q = 皇后鎮;S = 南安普頓)
因為我們對每位乘客或船員的存活情況感興趣,因此我們可以從此數據集中刪除 Survived 特征,并將其存儲在單獨的變量 outcome 中。我們將使用這些結果作為預測目標。
從數據集中刪除特征 Survived 并將其存儲到 outcome 中:
# Store the 'Survived' feature in a new variable and remove it from the dataset outcomes = full_data['Survived'] features_raw = full_data.drop('Survived', axis = 1)# Show the new dataset with 'Survived' removed display(features_raw.head())| 1 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
| 2 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
| 3 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
| 4 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S |
| 5 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S |
3.2 數據預處理
我們在之前的樸素貝葉斯之Sklearn實現中講過詞袋(Bag of Words)的概念,BOW的目的是將文本轉換為單詞頻率表,原因是Scikit-learn 只處理數字值。類似的,在決策樹中,對于“Name”、“Sex”等離散特征,其取值之間沒有大小的意義,因此可以使用獨熱編碼(One-Hot Encoding)將分類值轉換為數值型。
3.2.1 One-Hot 編碼
獨熱編碼即 One-Hot 編碼,又稱一位有效編碼。其方法是使用N位狀態寄存器來對N個狀態進行編碼,每個狀態都由他獨立的寄存器位,并且在任意時候,其中只有一位有效。
可以這樣理解,對于每一個特征,如果它有mmm個可能值,那么經過獨熱編碼后,就變成了mmm個二元特征(如成績這個特征有好,中,差變成 one-hot 就是100, 010, 001)。并且,這些特征互斥,每次只有一個激活。因此,數據會變成稀疏的。[1]
這樣做的好處主要有:
解決了分類器不好處理屬性數據的問題
在一定程度上也起到了擴充特征的作用
為什么不使用 BOW ?
BOW 適用于每一個對象內包含多個單詞,使用 BOW 后,對象內的單詞將會被分散開來。更多關于 One-Hot 編碼的知識,可以參考這一篇博文:獨熱編碼(One-Hot Encoding)和 LabelEncoder標簽編碼
3.2.2 Pandas 實現 One-Hot 編碼
- pd.get_dummies(data)
該方法可以講類別變量轉換成新增的虛擬變量/指示變量。
常用參數:
-
data(輸入的數據): array-like, Series, or DataFrame
-
prefix (轉換后列名的前綴): string, list of strings, or dict of strings, default None
-
columns(指定需要實現類別轉換的列名): list-like, default None
-
dummy_na(增加一列表示空缺值,默認忽略空缺值): True, False
-
drop_first(獲得k中的k-1個類別值,去除第一個): bool, default False
| 1 | 3 | 22.0 | 1 | 0 | 7.2500 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 2 | 1 | 38.0 | 1 | 0 | 71.2833 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
| 3 | 3 | 26.0 | 0 | 0 | 7.9250 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 4 | 1 | 35.0 | 1 | 0 | 53.1000 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 5 | 3 | 35.0 | 0 | 0 | 8.0500 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
5 rows × 1730 columns
現在用 0 填充任何空白處:
features = features.fillna(0.0) display(features.head())| 1 | 3 | 22.0 | 1 | 0 | 7.2500 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 2 | 1 | 38.0 | 1 | 0 | 71.2833 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
| 3 | 3 | 26.0 | 0 | 0 | 7.9250 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 4 | 1 | 35.0 | 1 | 0 | 53.1000 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 5 | 3 | 35.0 | 0 | 0 | 8.0500 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
5 rows × 1730 columns
3.3 訓練模型
我們已經準備好在 sklearn 中訓練模型了。首先,將數據拆分為訓練集和測試集。然后用訓練集訓練模型。
保留20%的數據作為測試集:
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(features, outcomes, test_size=0.2, random_state=42)導入決策樹模型并訓練模型:
# Import the classifier from sklearn from sklearn.tree import DecisionTreeClassifier# TODO: Define the classifier, and fit it to the data model = DecisionTreeClassifier() model.fit(X_train,y_train) DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=6,max_features=None, max_leaf_nodes=None,min_impurity_decrease=0.0, min_impurity_split=None,min_samples_leaf=6, min_samples_split=10,min_weight_fraction_leaf=0.0, presort=False,random_state=None, splitter='best')3.4 測試模型
現在看看模型的效果。我們計算下訓練集和測試集的準確率:
# Making predictions y_train_pred = model.predict(X_train) y_test_pred = model.predict(X_test)# Calculate the accuracy from sklearn.metrics import accuracy_score train_accuracy = accuracy_score(y_train, y_train_pred) test_accuracy = accuracy_score(y_test, y_test_pred) print('The training accuracy is', train_accuracy) print('The test accuracy is', test_accuracy) The training accuracy is 0.8707865168539326 The test accuracy is 0.8547486033519553可以看到訓練集準確率為100%,但測試集準確率只有81%,這是因為我們沒有對模型進行任何預剪枝處理,因此此時的模型有點過擬合了,這個模型偏向于“記住數據”,因此在測試劑上表現并不好。
我們將通過可視化決策樹來直觀的確定是否過擬合:
3.5 決策樹可視化
# 可視化 from sklearn.tree import export_graphviz export_graphviz(model,out_file="tree.dot",class_names=['Survived','Dead'],impurity=False,filled=True)# 通過 Graphviz 打開.dot文件# 或者通過terminal cd到文件夾 # 運行 dot -Tpdf Tree.dot -o output.pdf 直接輸出為pdf3.6 預剪枝
從圖片中可以看出,決策樹確實是過擬合了,因此我們可以通過預剪枝,來防止過擬合:
model = DecisionTreeClassifier(max_depth=6, min_samples_leaf=6, min_samples_split=10) model.fit(X_train,y_train) # Making predictions y_train_pred = model.predict(X_train) y_test_pred = model.predict(X_test)# Calculate the accuracy from sklearn.metrics import accuracy_score train_accuracy = accuracy_score(y_train, y_train_pred) test_accuracy = accuracy_score(y_test, y_test_pred) print('The training accuracy is', train_accuracy) print('The test accuracy is', test_accuracy) export_graphviz(model,out_file="tree.dot",class_names=['Survived','Dead'],impurity=False,filled=True) The training accuracy is 0.8707865168539326 The test accuracy is 0.8547486033519553可以看到,經過預剪枝后,該模型在測試集上的正確率已經達到了85%,如果想要更高的準確率,可以通過網絡搜索來確定最優參數。
從圖片中可以看出,在泰坦尼克號的逃生中,大多數的女性都活了下來,而大多數的男性都沒有存活下來.
full_data.groupby(['Sex','Survived']).count().Name.unstack()| 81 | 233 |
| 468 | 109 |
參考資料
[1] 理想幾歲.數據預處理:獨熱編碼(One-Hot Encoding)和 LabelEncoder標簽編碼 [EB/OL].https://www.cnblogs.com/zongfa/p/9305657.html, 2018-07-13.
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的监督学习 | 决策树之Sklearn实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 监督学习 | 线性回归 之正则线性模型原
- 下一篇: 马上开课 | 临床基因组学数据分析实战助