機器學習——決策樹模型:Python實現

揚帆起航追太陽發表於2020-11-09

1 決策樹模型的程式碼實現

決策樹模型既可以做分類分析(即預測分類變數值),也可以做迴歸分析(即預測連續變數值),分別對應的模型為分類決策樹模型(DecisionTreeClassifier)及迴歸決策樹模型(DecisionTreeRegressor)。

1.1 分類決策樹模型(DecisionTreeClassifier)

from sklearn.tree import DecisionTreeClassifier
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [1, 0, 0, 1, 1]

model = DecisionTreeClassifier(random_state=0)
model.fit(X, y)

print(model.predict([[5, 5]]))

1.2 迴歸決策樹模型(DecisionTreeRegressor)

from sklearn.tree import DecisionTreeRegressor
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [1, 2, 3, 4, 5]

model = DecisionTreeRegressor(max_depth=2, random_state=0)
model.fit(X, y)

print(model.predict([[9, 9]]))

2 案例實戰:員工離職預測模型搭建

2.1 模型搭建

# 1.讀取資料與簡單預處理
import pandas as pd
df = pd.read_excel('員工離職預測模型.xlsx')
df = df.replace({'工資': {'低': 0, '中': 1, '高': 2}})

# 2.提取特徵變數和目標變數
X = df.drop(columns='離職') 
y = df['離職']   

# 3.劃分訓練集和測試集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123)

# 4.模型訓練及搭建
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(max_depth=3, random_state=123)
model.fit(X_train, y_train) 

2.2 模型預測及評估

2.2.1 直接預測是否離職

y_pred = model.predict(X_test)
print(y_pred[0:100])

# 通過構造DataFrame進行對比
a = pd.DataFrame()  # 建立一個空DataFrame 
a['預測值'] = list(y_pred)
a['實際值'] = list(y_test)
a.head()

# 如果要檢視整體的預測準確度,可以採用如下程式碼:
from sklearn.metrics import accuracy_score
score = accuracy_score(y_pred, y_test)
print(score)

# 或者用模型自帶的score函式檢視預測準確度
model.score(X_test, y_test)

2.2.2 預測不離職&離職概率

其實分類決策樹模型本質預測的並不是準確的0或1的分類,而是預測其屬於某一分類的概率,可以通過如下程式碼檢視預測屬於各個分類的概率:

y_pred_proba = model.predict_proba(X_test)
print(y_pred_proba[0:5])

b = pd.DataFrame(y_pred_proba, columns=['不離職概率', '離職概率']) 
b.head()

如果想檢視離職概率,即檢視y_pred_proba的第二列,可以採用如下程式碼,這個是二維陣列選取列的方法,其中逗號前的“:”表示所有行,逗號後面的數字1則表示第二列,如果把數字1改成數字0,則提取第一列不離職概率。

y_pred_proba[:,1]

2.2.3 模型預測及評估

在Python實現上,可以求出在不同閾值下的命中率(TPR)以及假警報率(FPR)的值,從而可以繪製ROC曲線。

from sklearn.metrics import roc_curve
fpr, tpr, thres = roc_curve(y_test, y_pred_proba[:,1])

已知了不同閾值下的假警報率和命中率,可通過matplotlib庫可繪製ROC曲線,程式碼如下:

import matplotlib.pyplot as plt
plt.plot(fpr, tpr)
plt.show()

結果如圖:
在這裡插入圖片描述
通過如下程式碼則可以快速求出模型的AUC值:

from sklearn.metrics import roc_auc_score
score = roc_auc_score(y_test, y_pred_proba[:,1])
print(score)

2.2.4 特徵重要性評估

model.feature_importances_

# 通過DataFrame進行展示,並根據重要性進行倒序排列
features = X.columns  # 獲取特徵名稱
importances = model.feature_importances_  # 獲取特徵重要性

# 通過二維表格形式顯示
importances_df = pd.DataFrame()
importances_df['特徵名稱'] = features
importances_df['特徵重要性'] = importances
importances_df.sort_values('特徵重要性', ascending=False)

3 引數調優 - K折交叉驗證 & GridSearch網格搜尋

3.1 K折交叉驗證

from sklearn.model_selection import cross_val_score
acc = cross_val_score(model, X, y, scoring='roc_auc', cv=5)
acc

acc.mean()

3.2 GridSearch網格搜尋

3.2.1 單引數調優

from sklearn.model_selection import GridSearchCV  # 網格搜尋合適的超引數

# 指定引數k的範圍
parameters = {'max_depth': [3, 5, 7, 9, 11]}
# 構建決策樹分類器
model = DecisionTreeClassifier()  # 這裡因為要進行引數調優,所以不需要傳入固定的引數了

# 網格搜尋
grid_search = GridSearchCV(model, parameters, scoring='roc_auc', cv=5)   # cv=5表示交叉驗證5次,預設值為3;scoring='roc_auc'表示通過ROC曲線的AUC值來進行評分,預設通過準確度評分
grid_search.fit(X_train, y_train)

# 輸出引數的最優值
grid_search.best_params_

3.2.2 多引數調優

from sklearn.model_selection import GridSearchCV

# 指定決策樹分類器中各個引數的範圍
parameters = {'max_depth': [5, 7, 9, 11, 13], 'criterion':['gini', 'entropy'], 'min_samples_split':[5, 7, 9, 11, 13, 15]}
# 構建決策樹分類器
model = DecisionTreeClassifier()  # 這裡因為要進行引數調優,所以不需要傳入固定的引數了

# 網格搜尋
grid_search = GridSearchCV(model, parameters, scoring='roc_auc', cv=5)
grid_search.fit(X_train, y_train)

# 獲得引數的最優值
grid_search.best_params_

# 根據多引數調優的結果來重新搭建模型
model = DecisionTreeClassifier(criterion='entropy', max_depth=11, min_samples_split=13)
model.fit(X_train, y_train) 

# 檢視整體預測準確度
y_pred = model.predict(X_test)
from sklearn.metrics import accuracy_score
score = accuracy_score(y_pred, y_test)
print(score)

# 檢視新的AUC值
# 預測不違約&違約概率
y_pred_proba = model.predict_proba(X_test)
y_pred_proba[:,1]  # 如果想單純的檢視違約概率,即檢視y_pred_proba的第二列

score = roc_auc_score(y_test, y_pred_proba[:,1])
print(score)

注意點1:多引數調優和分別單引數調優的區別

多引數調優和單引數分別調優是有區別的,比如有的讀者為了省事,對上面的3個引數進行3次單獨的單引數調優,然後將結果彙總,這樣的做法其實是不嚴謹的。因為在進行單引數調優的時候,是預設其他引數取預設值的,那麼該引數和其他引數都不取預設值的情況就沒有考慮進來,也即忽略了多個引數對模型的組合影響。以上面的程式碼示例來說,使用多引數調優時,它是526=60種組合可能,而如果是進行3次單引數調優,則只是5+2+6=13種組合可能。 因此,如果只需要調節一個引數,那麼可以使用單引數調優,如果需要調節多個引數,則推薦使用多引數調優。

注意點2:引數取值是給定範圍的邊界

另外一點需要需要注意的是,如果使用GridSearchCV()方法所得到的引數取值是給定範圍的邊界,那麼有可能存在範圍以外的取值使得模型效果更好,因此需要我們額外增加範圍,繼續調參。舉例來說,倘若上述程式碼中獲得的最佳max_depth值為設定的最大值13,那麼實際真正合適的max_depth可能更大,此時便需要將搜尋網格重新調整,如將max_depth的搜尋範圍變成[9, 11, 13, 15, 17],再重新引數調優。

參考文獻:王宇韜, 錢妍竹. Python大資料分析與機器學習商業案例實戰[M]. 機械工業出版社, 2020.

相關文章