前言
本文試圖提綱挈領的對決策樹和隨機森林的原理及應用做以分析
決策樹
算法偽代碼
def 創建決策樹: if (數據集中所有樣本分類一致): #或者其他終止條件 創建攜帶類標簽的葉子節點 else: 尋找划分數據集的最好特征 根據最好特征划分數據集 for 每個划分的數據集: 創建決策子樹(遞歸)
注意算法要采用遞歸的方法
依據選取划分數據集特征的方法,有三種常用方法:
ID3:信息增益
C4.5:信息增益率
CART:基尼系數
對於連續特征:
比如m個樣本的連續特征A有m個,從小到大排列為a1,a2,...,am,則CART算法取相鄰兩樣本值的中位數,一共取得m-1個划分點,其中第i個划分點Ti表示Ti表示為:Ti=(ai+ai+1)/2。對於這m-1個點,分別計算以該點作為二元分類點時的基尼系數。選擇基尼系數最小的點作為該連續特征的二元離散分類點,這樣我們就做到了連續特征的離散化。要注意的是,與離散屬性不同的是,如果當前節點為連續屬性,則該屬性后面還可以參與子節點的產生選擇過程。
過擬合問題-——剪枝
過多的枝葉會導致算法的過擬合,所以常使用減枝的方法防止過擬合:常用的剪枝方法有前置法和后置法,前置法指的是在要構建決策樹時,依據終止條件確定是否提前終止;后置法指構建好決策樹后,再依據條件確定是否用單一節點代替子樹。
回歸問題
一般采用均方誤差作為評價特征的標准
隨機森林
bootstrap方法:從樣本集進行有放回的重采樣。
隨機森林步驟:
1. 樣本的隨機:從樣本集中用Bootstrap隨機選取n個樣本
2. 特征的隨機:從所有屬性中隨機選取K個屬性,選擇最佳分割屬性作為節點建立CART決策樹
3. 重復以上兩步m次,即建立了m棵CART決策樹
4. 這m個CART形成隨機森林,通過投票表決結果,決定數據屬於哪一類(投票機制有一票否決制、少數服從多數、加權多數)
參考:https://www.cnblogs.com/fionacai/p/5894142.html
sklearn.tree.DecisionTreeClassifier
class sklearn.tree.
DecisionTreeClassifier
(criterion=’gini’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort=False)
Parameters: criterion='gini' or 'entropy'
max_depth 設置樹的最大深度 默認為‘None’
min_sample_split 分割的最小樣本數 默認為2
詳細內容的中文說明可以參考 https://www.cnblogs.com/pinard/p/6056319.html
sklearn.tree.DecisionTreeRegressor
Parameters: criterion='mse' 還可以使用‘friedman_mse’或者'mae'
max_depth 設置樹的最大深度 默認為‘None’
sklearn.ensemble
.RandomForestClassifier
Parameters: n_estimator=10 生成決策樹的個數
criterion='gini' or 'entropy'
應用舉例
使用隨機森林進行回歸的例子
import numpy as np import matplotlib.pyplot as plt from sklearn.tree import DecisionTreeRegressor N=100 x = np.random.rand(N) * 6 - 3 x.sort() y=0.1*x**3+np.exp(-x*x/2)+ np.random.randn(N) * 0.2 #3次函數+高斯函數+噪聲 x = x.reshape(-1, 1) x_bar=np.linspace(-3,3,50).reshape(-1,1) y_bar=0.1*x_bar**3+np.exp(-x_bar*x_bar/2) plt.plot(x,y,'r.') plt.plot(x_bar,y_bar) plt.show() plt.plot(x,y,'r.') x_test=np.linspace(-3,3,50).reshape(-1,1) dt = DecisionTreeRegressor(criterion='mse') depth=[3,6,18] color='rgy' for d,c in zip(depth,color): dt.set_params(max_depth=d) dt.fit(x, y) y_test = dt.predict(x_test) plt.plot(x_test,y_test,'-',color=c, linewidth=2, label='Depth=%d' % d) plt.legend(loc='upper left') plt.xlabel(u'X') plt.ylabel(u'Y') plt.grid(b=True) plt.show()
圖1
圖2
對比圖1中的真實曲線和圖2中三條擬合折線可以發現,圖二中的折現較好的擬合了原始曲線,如果單純使用一次特征的線性回歸肯定是達不到這樣的效果的,其次,我們可以看到當樹最大深度為3時,折線段較少,細小的彎曲無法體現,而當深度達到18時,折線波折又過多,有過擬合的嫌疑,當深度為6時,相對較好,因此,我們推斷樹的深度在擬合過程中起到了重要作用。
數據集 Adult
字段名 |
含義 |
類型 |
age |
年齡 |
Double |
workclass |
工作類型 |
string |
fnlwgt |
序號 |
string |
education |
教育程度* |
string |
education_num |
受教育時間 |
double |
maritial_status |
婚姻狀況* |
string |
occupation |
職業* |
string |
relationship |
關系* |
string |
race |
種族* |
string |
sex |
性別* |
string |
capital_gain |
資本收益 |
string |
capital_loss |
資本損失 |
string |
hours_per_week |
每周工作小時數 |
double |
native_country |
國籍 |
string |
income |
收入 |
string |
表1
基於上面特征,預測收入是否大於50K,我們用決策樹和隨機森林來解決上述問題。
import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import LabelEncoder column_names = 'age', 'workclass', 'fnlwgt', 'education', 'education-num', 'marital-status', 'occupation', \ 'relationship', 'race', 'sex', 'capital-gain', 'capital-loss', 'hours-per-week',\ 'native-country', 'income' #不加括號為元組 data = pd.read_csv('adult.data', header=None, names=column_names) data.isnull().any().any() #是否存在null for name in column_names: data[name]=LabelEncoder().fit_transform(data[name]) #自動轉換非數字列為數字 x = data[data.columns[:-1]] y = data[data.columns[-1]] x_train, x_valid, y_train, y_valid = train_test_split(x, y, test_size=0.3, random_state=0) DT = DecisionTreeClassifier(criterion='gini',max_depth=10,min_samples_split=5) RF = RandomForestClassifier(criterion='gini', max_depth=10, min_samples_split=5,n_estimators=20) LR= LogisticRegression() models=[DT,RF,LR] for model in models: model.fit(x_train,y_train) y_pre=model.predict(x_valid) print('驗證集准確率:', accuracy_score(y_pre, y_valid))
運行結果為:
驗證集准確率: 0.852287849319
驗證集准確率: 0.858429726686
驗證集准確率: 0.805507216706
對比結果,在隨機森林與決策樹選取相似的參數時,隨機森林的結果略好於決策樹,logistic回歸結果最差,但注意這里logistic回歸沒有調參。
附:Adult數據集 https://pan.baidu.com/s/1vTMN9Yp6VPndezUR1UtYtw
致謝:本文基於小象學院鄒博老師機器學習課程,部分代碼參考該課程,特此感謝。