一、決策樹的介紹
決策樹是一種常見的分類模型,在金融分控、醫療輔助診斷等諸多行業具有較為廣泛的應用。決策樹的核心思想是基於樹結構對數據進行划分,這種思想是人類處理問題時的本能方法。例如在婚戀市場中,女方通常會先看男方是否有房產,如果有房產再看是否有車產,如果有車產再看是否有穩定工作……最后得出是否要深入了解的判斷。
決策樹的主要優點:
- 具有很好的解釋性,模型可以生成可以理解的規則。
- 可以發現特征的重要程度。
- 模型的計算復雜度較低。
決策樹的主要缺點:
- 模型容易過擬合,需要采用減枝技術處理。
- 不能很好利用連續型特征。
- 預測能力有限,無法達到其他強監督模型效果。
- 方差較高,數據分布的輕微改變很容易造成樹結構完全不同。
Part1 Demo實踐
- Step1:庫函數導入
- Step2:模型訓練
- Step3:數據和模型可視化
- Step4:模型預測
Part2 基於企鵝(penguins)數據集的決策樹分類實踐
- Step1:庫函數導入
- Step2:數據讀取/載入
- Step3:數據信息簡單查看
- Step4:可視化描述
- Step5:利用 決策樹模型 在二分類上 進行訓練和預測
- Step6:利用 決策樹模型 在三分類(多分類)上 進行訓練和預測
2.1Demo實踐
Step1: 庫函數導入
## 基礎函數庫 import numpy as np ## 導入畫圖庫 import matplotlib.pyplot as plt import seaborn as sns ## 導入決策樹模型函數 from sklearn.tree import DecisionTreeClassifier from sklearn import tree
Step2: 訓練模型
##Demo演示LogisticRegression分類 ## 構造數據集 x_fearures = np.array([[-1, -2], [-2, -1], [-3, -2], [1, 3], [2, 1], [3, 2]]) y_label = np.array([0, 1, 0, 1, 0, 1]) ## 調用決策樹模型 tree_clf = DecisionTreeClassifier() ## 用決策樹模型擬合構造的數據集 tree_clf = tree_clf.fit(x_fearures, y_label)
Step3: 數據和模型可視化(需要用到graphviz可視化庫)
## 可視化構造的數據樣本點 plt.figure() plt.scatter(x_fearures[:,0],x_fearures[:,1], c=y_label, s=50, cmap='viridis') plt.title('Dataset') plt.show()
## 本段代碼實際效果為本地生成PDF可視化文檔,在體驗過程中可以不運行,可能無法正常展示結果; ## 代碼生成的可視化結果會截圖展示實際效果 !pip install graphviz import graphviz dot_data = tree.export_graphviz(tree_clf, out_file=None) graph = graphviz.Source(dot_data) graph.render("pengunis") ## 'pengunis.pdf' 目前環境問題,還不能展示
Step4:模型預測
## 創建新樣本 x_fearures_new1 = np.array([[0, -1]]) x_fearures_new2 = np.array([[2, 1]]) ## 在訓練集和測試集上分布利用訓練好的模型進行預測 y_label_new1_predict = tree_clf.predict(x_fearures_new1) y_label_new2_predict = tree_clf.predict(x_fearures_new2) print('The New point 1 predict class:\n',y_label_new1_predict) print('The New point 2 predict class:\n',y_label_new2_predict) # The New point 1 predict class: # [1] # The New point 2 predict class: # [0]
全部代碼如下(已折疊):

# -*- coding: utf-8 -*- """ Created on Tue Aug 11 10:12:48 2020 @author: Admin """ #Step1: 庫函數導入 ## 基礎函數庫 import numpy as np ## 導入畫圖庫 import matplotlib.pyplot as plt import seaborn as sns ## 導入決策樹模型函數 from sklearn.tree import DecisionTreeClassifier from sklearn import tree #Step2: 訓練模型 ##Demo演示LogisticRegression分類 ## 構造數據集 x_fearures = np.array([[-1, -2], [-2, -1], [-3, -2], [1, 3], [2, 1], [3, 2]]) y_label = np.array([0, 1, 0, 1, 0, 1]) ## 調用決策樹模型 tree_clf = DecisionTreeClassifier() ## 用決策樹模型擬合構造的數據集 tree_clf = tree_clf.fit(x_fearures, y_label) #Step3: 數據和模型可視化(需要用到graphviz可視化庫) ## 可視化構造的數據樣本點 plt.figure() plt.scatter(x_fearures[:,0],x_fearures[:,1], c=y_label, s=50, cmap='viridis') plt.title('Dataset') plt.show() ## 本段代碼實際效果為本地生成PDF可視化文檔,在體驗過程中可以不運行,可能無法正常展示結果; ## 代碼生成的可視化結果會截圖展示實際效果 #!pip install graphviz 已經有啦的就不需要安裝了 import graphviz dot_data = tree.export_graphviz(tree_clf, out_file=None) graph = graphviz.Source(dot_data) graph.render("pengunis") ## 'pengunis.pdf' #Step4:模型預測 ## 創建新樣本 x_fearures_new1 = np.array([[0, -1]]) x_fearures_new2 = np.array([[2, 1]]) ## 在訓練集和測試集上分布利用訓練好的模型進行預測 y_label_new1_predict = tree_clf.predict(x_fearures_new1) y_label_new2_predict = tree_clf.predict(x_fearures_new2) print('The New point 1 predict class:\n',y_label_new1_predict) print('The New point 2 predict class:\n',y_label_new2_predict) # The New point 1 predict class: # [1] # The New point 2 predict class: # [0]
2.2基於企鵝(penguins)數據集的決策樹分類實踐
在實踐的最開始,我們首先需要導入一些基礎的函數庫包括:numpy (Python進行科學計算的基礎軟件包),pandas(pandas是一種快速,強大,靈活且易於使用的開源數據分析和處理工具),matplotlib和seaborn繪圖。
數據是在阿里雲上面跑的,我沒有企鵝的數據https://tianchi.aliyun.com/notebook-ai/notebookEdit?notebookLabId=108107&version=0&sceneId=bb2fe211e5e94017840ce42cc31fe621&env=prod
Step1:函數庫導入
## 基礎函數庫 import numpy as np import pandas as pd ## 繪圖函數庫 import matplotlib.pyplot as plt import seaborn as sns
本次我們選擇企鵝數據(palmerpenguins)進行方法的嘗試訓練,該數據集一共包含8個變量,其中7個特征變量,1個目標分類變量。共有150個樣本,目標變量為 企鵝的類別 其都屬於企鵝類的三個亞屬,分別是(Adélie, Chinstrap and Gentoo)。包含的三種種企鵝的七個特征,分別是所在島嶼,嘴巴長度,嘴巴深度,腳蹼長度,身體體積,性別以及年齡。
Step2:數據讀取/載入
## 我們利用Pandas自帶的read_csv函數讀取並轉化為DataFrame格式 data = pd.read_csv('datalab/531811/Datawhale/penguins_raw.csv') ## 為了方便我們僅選取四個簡單的特征,有興趣的同學可以研究下其他特征的含義以及使用方法 data = data[['Species','Culmen Length (mm)','Culmen Depth (mm)', 'Flipper Length (mm)','Body Mass (g)']]
Step3:數據信息簡單查看
## 利用.info()查看數據的整體信息 data.info() ## <class 'pandas.core.frame.DataFrame'> ## RangeIndex: 344 entries, 0 to 343 ## Data columns (total 5 columns): ## Species 344 non-null object ## Culmen Length (mm) 342 non-null float64 ## Culmen Depth (mm) 342 non-null float64 ## Flipper Length (mm) 342 non-null float64 ## Body Mass (g) 342 non-null float64 ## dtypes: float64(4), object(1) ## memory usage: 13.6+ KB
## 進行簡單的數據查看,我們可以利用 .head() 頭部.tail()尾部 data.head()
Species | Culmen Length (mm) | Culmen Depth (mm) | Flipper Length (mm) | Body Mass (g) | |
---|---|---|---|---|---|
0 | Adelie Penguin (Pygoscelis adeliae) | 39.1 | 18.7 | 181.0 | 3750.0 |
1 | Adelie Penguin (Pygoscelis adeliae) | 39.5 | 17.4 | 186.0 | 3800.0 |
2 | Adelie Penguin (Pygoscelis adeliae) | 40.3 | 18.0 | 195.0 | 3250.0 |
3 | Adelie Penguin (Pygoscelis adeliae) | NaN | NaN | NaN | NaN |
4 | Adelie Penguin (Pygoscelis adeliae) | 36.7 | 19.3 | 193.0 | 3450.0 |
這里我們發現數據集中存在NaN,一般的我們認為NaN在數據集中代表了缺失值,可能是數據采集或處理時產生的一種錯誤。這里我們采用-1將缺失值進行填補,還有其他例如“中位數填補、平均數填補”的缺失值處理方法有興趣的同學也可以嘗試。
data = data.fillna(-1)
data.tail()
Species | Culmen Length (mm) | Culmen Depth (mm) | Flipper Length (mm) | Body Mass (g) | |
---|---|---|---|---|---|
339 | Chinstrap penguin (Pygoscelis antarctica) | 55.8 | 19.8 | 207.0 | 4000.0 |
340 | Chinstrap penguin (Pygoscelis antarctica) | 43.5 | 18.1 | 202.0 | 3400.0 |
341 | Chinstrap penguin (Pygoscelis antarctica) | 49.6 | 18.2 | 193.0 | 3775.0 |
342 | Chinstrap penguin (Pygoscelis antarctica) | 50.8 | 19.0 | 210.0 | 4100.0 |
343 | Chinstrap penguin (Pygoscelis antarctica) | 50.2 | 18.7 | 198.0 | 3775.0 |
## 其對應的類別標簽為'Adelie Penguin', 'Gentoo penguin', 'Chinstrap penguin'三種不同企鵝的類別。 data['Species'].unique() ## array(['Adelie Penguin (Pygoscelis adeliae)', ## 'Gentoo penguin (Pygoscelis papua)', ## 'Chinstrap penguin (Pygoscelis antarctica)'], dtype=object)
## 利用value_counts函數查看每個類別數量 pd.Series(data['Species']).value_counts() ## Adelie Penguin (Pygoscelis adeliae) 152 ## Gentoo penguin (Pygoscelis papua) 124 ## Chinstrap penguin (Pygoscelis antarctica) 68 ## Name: Species, dtype: int64
## 對於特征進行一些統計描述 data.describe()
Culmen Length (mm) | Culmen Depth (mm) | Flipper Length (mm) | Body Mass (g) | |
---|---|---|---|---|
count | 344.000000 | 344.000000 | 344.000000 | 344.000000 |
mean | 43.660756 | 17.045640 | 199.741279 | 4177.319767 |
std | 6.428957 | 2.405614 | 20.806759 | 861.263227 |
min | -1.000000 | -1.000000 | -1.000000 | -1.000000 |
25% | 39.200000 | 15.500000 | 190.000000 | 3550.000000 |
50% | 44.250000 | 17.300000 | 197.000000 | 4025.000000 |
75% | 48.500000 | 18.700000 | 213.000000 | 4750.000000 |
max | 59.600000 | 21.500000 | 231.000000 | 6300.000000 |
Step4:可視化描述
## 特征與標簽組合的散點可視化 sns.pairplot(data=data, diag_kind='hist', hue= 'Species') plt.show()
從上圖可以發現,在2D情況下不同的特征組合對於不同類別的企鵝的散點分布,以及大概的區分能力。
'''為了方便我們將標簽轉化為數字 'Adelie Penguin (Pygoscelis adeliae)' ------0 'Gentoo penguin (Pygoscelis papua)' ------1 'Chinstrap penguin (Pygoscelis antarctica) ------2 ''' def trans(x): if x == data['Species'].unique()[0]: return 0 if x == data['Species'].unique()[1]: return 1 if x == data['Species'].unique()[2]: return 2 data['Species'] = data['Species'].apply(trans) for col in data.columns: if col != 'Species': sns.boxplot(x='Species', y=col, saturation=0.5, palette='pastel', data=data) plt.title(col) plt.show()
利用箱型圖我們也可以得到不同類別在不同特征上的分布差異情況。
# 選取其前三個特征繪制三維散點圖 from mpl_toolkits.mplot3d import Axes3D fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(111, projection='3d') data_class0 = data[data['Species']==0].values data_class1 = data[data['Species']==1].values data_class2 = data[data['Species']==2].values # 'setosa'(0), 'versicolor'(1), 'virginica'(2) ax.scatter(data_class0[:,0], data_class0[:,1], data_class0[:,2],label=data['Species'].unique()[0]) ax.scatter(data_class1[:,0], data_class1[:,1], data_class1[:,2],label=data['Species'].unique()[1]) ax.scatter(data_class2[:,0], data_class2[:,1], data_class2[:,2],label=data['Species'].unique()[2]) plt.legend() plt.show()
Step5:利用 決策樹模型 在二分類上 進行訓練和預測
## 為了正確評估模型性能,將數據划分為訓練集和測試集,並在訓練集上訓練模型,在測試集上驗證模型性能。 from sklearn.model_selection import train_test_split ## 選擇其類別為0和1的樣本 (不包括類別為2的樣本) data_target_part = data[data['Species'].isin([0,1])][['Species']] data_features_part = data[data['Species'].isin([0,1])][['Culmen Length (mm)','Culmen Depth (mm)', 'Flipper Length (mm)','Body Mass (g)']] ## 測試集大小為20%, 80%/20%分 x_train, x_test, y_train, y_test = train_test_split(data_features_part, data_target_part, test_size = 0.2, random_state = 2020)
## 從sklearn中導入決策樹模型 from sklearn.tree import DecisionTreeClassifier from sklearn import tree ## 定義 決策樹模型 clf = DecisionTreeClassifier(criterion='entropy') ## 在訓練集上訓練決策樹模型 clf.fit(x_train, y_train) ## 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')
## 可視化 ## 本段代碼實際效果為本地生成PDF可視化文檔,在體驗過程中可以不運行,可能無法正常展示結果; ## 代碼生成的可視化結果會截圖展示實際效果 import graphviz dot_data = tree.export_graphviz(clf, out_file=None) graph = graphviz.Source(dot_data) graph.render("penguins") ## 'penguins.pdf'
## 在訓練集和測試集上分布利用訓練好的模型進行預測 train_predict = clf.predict(x_train) test_predict = clf.predict(x_test) from sklearn import metrics ## 利用accuracy(准確度)【預測正確的樣本數目占總預測樣本數目的比例】評估模型效果 print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict)) print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict)) ## 查看混淆矩陣 (預測值和真實值的各類情況統計矩陣) confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test) print('The confusion matrix result:\n',confusion_matrix_result) # 利用熱力圖對於結果進行可視化 plt.figure(figsize=(8, 6)) sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues') plt.xlabel('Predicted labels') plt.ylabel('True labels') plt.show() ## The accuracy of the Logistic Regression is: 0.9954545454545455 ## The accuracy of the Logistic Regression is: 1.0 ## The confusion matrix result: ## [[31 0] ## [ 0 25]]
我們可以發現其准確度為1,代表所有的樣本都預測正確了
Step6:利用 決策樹模型 在三分類(多分類)上 進行訓練和預測
## 測試集大小為20%, 80%/20%分 x_train, x_test, y_train, y_test = train_test_split(data[['Culmen Length (mm)','Culmen Depth (mm)', 'Flipper Length (mm)','Body Mass (g)']], data[['Species']], test_size = 0.2, random_state = 2020) ## 定義 決策樹模型 clf = DecisionTreeClassifier() # 在訓練集上訓練決策樹模型 clf.fit(x_train, y_train) ## DecisionTreeClassifier(class_weight=None, criterion='gini', 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')
## 在訓練集和測試集上分布利用訓練好的模型進行預測 train_predict = clf.predict(x_train) test_predict = clf.predict(x_test) ## 由於邏輯回歸模型是概率預測模型(前文介紹的 p = p(y=1|x,\theta)),所有我們可以利用 predict_proba 函數預測其概率 train_predict_proba = clf.predict_proba(x_train) test_predict_proba = clf.predict_proba(x_test) print('The test predict Probability of each class:\n',test_predict_proba) ## 其中第一列代表預測為0類的概率,第二列代表預測為1類的概率,第三列代表預測為2類的概率。 ## 利用accuracy(准確度)【預測正確的樣本數目占總預測樣本數目的比例】評估模型效果 print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict)) print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict)) # The test predict Probability of each class: # [[0. 0. 1.] # [0. 1. 0.] # [0. 1. 0.] # [1. 0. 0.] # ………… # [0. 1. 0.] # [0. 0. 1.] # [1. 0. 0.] # [1. 0. 0.]] # The accuracy of the Logistic Regression is: 0.996363636364 # The accuracy of the Logistic Regression is: 0.971014492754
## 查看混淆矩陣 confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test) print('The confusion matrix result:\n',confusion_matrix_result) # 利用熱力圖對於結果進行可視化 plt.figure(figsize=(8, 6)) sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues') plt.xlabel('Predicted labels') plt.ylabel('True labels') plt.show() # The confusion matrix result: # [[30 1 0] # [ 0 23 0] # [ 2 0 13]]