Sklearn--整合學習(2)
將多個決策樹,通過Bagging
的方法進行整合,便是常用的隨機森林了。
三、隨機森林
Bagging
和 RandomForest
from sklearn.ensemble import RandmForestClassifier
## 比較 BaggingClassifier + Decision 和 RandomForestClassifier
if __name__ == '__main__' :
x, y, x_t, y_t = get_moons_data()
## 隨機森林
rnd_clf = RandomForestClassifier(n_estimators= 500, # 500個樹
max_leaf_nodes=16,max_features = 1.0,
n_jobs=-1, random_state = 42
)
rnd_clf.fit(x, y)
y_prd_rf = rnd_clf.predict(x_t)
## Bagging + 決策樹
dec_clf = DecisionTreeClassifier(splitter='random', max_leaf_nodes= 16, random_state = 42)
bag_rf_clf = BaggingClassifier(dec_clf, n_estimators=500,max_features = 1.0,
bootstrap=True, n_jobs=-1,random_state = 42
)
bag_rf_clf.fit(x, y)
y_prd_bg = bag_rf_clf.predict(x_t)
print(sum((y_t-y_prd_rf)==0)/len(y_t))
print (sum((y_t-y_prd_bg)==0)/len(y_t))
""" 結果
0.88
0.89
可見兩者擬合效果基本是相同的
"""
四、極端樹
在隨機森林生長樹時,每個節點分裂時只考慮隨機特徵集上的特徵。相比於找到更好的特徵,可以通過使用對特徵使用隨機閾值使樹更加隨機。
這種極端隨機的樹被稱為Extremely Randomized Trees
,或者更簡單的稱為Extra-Tree
, 再一次用高偏差換低方差。它還使得Extra-Tree
比規則的隨機森林更快地訓練,因為在每個節點上,每個特徵的最佳閾值
使生長樹最耗時的任務之一
from sklearn.datasets import load_iris
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.metrics import accuracy_score
def get_importance(data, model):
for name, score in zip(data.feature_names, model.feature_importances_):
print(name, score)
if __name__ == '__main__' :
iris = load_iris()
rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rnd_clf.fit(iris['data'], iris['target'])
get_importance(iris, rnd_clf)
print(accuracy_score(iris['target'],rnd_clf.predict(iris['data'])))
et_clf = ExtraTreesClassifier(n_estimators = 500, n_jobs = -1)
et_clf.fit(iris['data'], iris['target'])
get_importance(iris, et_clf)
print(accuracy_score(iris['target'],et_clf.predict(iris['data'])))
"""
sepal length (cm) 0.09194217773494667
sepal width (cm) 0.022488796221977456
petal length (cm) 0.4367589103747967
petal width (cm) 0.44881011566827916
1.0
sepal length (cm) 0.09575810061808965
sepal width (cm) 0.05854316642710482
petal length (cm) 0.41837709271746937
petal width (cm) 0.4273216402373357
1.0
"""
極端樹的擬合速度更加快
五、Boosting
提升樹
一般常用的adaboost
簡單的做法就是:e
為錯誤率,alpha
為基分類器的權重
加大錯誤分類器的權重, np.exp(-1 * alpha * y[i] * h(x[i]))
加大優分類器的權重, alpha = 1/2 * np.log((1- e) / e)
sklearn
通常使用adaboost
的多分類版本 SAMME
這表明分段加建模使用多分類指數損失函式。如果是二分類, 那麼SAMME
是與 Adaboost
相同。要預測概率(即有predict_prob()
),需要用SAMME.R
,
依賴於概率的分類器通常比僅僅的分類更加好
from sklearn import AdaBoostClassifier
if __name__ == '__main__' :
x, y, x_t, y_t = get_moons_data()
dec_clf = DecisionTreeClassifier(max_depth=1)
ada_clf = AdaBoostClassifier(dec_clf, n_estimators=200, algorithm='SAMME.R', learning_rate=0.5)
ada_clf.fit(x, y)
accuracy_score(y_t, ada_clf.predict(x_t))
"""
0.86
"""
六、梯度提升
它不像Adaboost
那樣每次迭代都更改例項的權重,這個方法是去使用新的分類器去擬合前面分類器預測的殘差
from sklearn.tree import DecisionTreeRegressor
import numpy as np
def Get_poly_data():
np.random.seed(1212)
x = np.linspace(-2, 2, 60)
y_2 = 3 * x ** 2 + 2 * np.random.rand(len(x)) + 0.3
x_in_t1 = x.reshape((-1, 1))
return np.c_[np.ones((len(x), 1)), x_in_t1], y_2.reshape((-1, 1))
if __name__ == "__main__" :
x, y = Get_poly_data()
tree_reg = DecisionTreeRegressor(max_depth=2)
tree_reg.fit(x, y)
## 在一個分類器的殘差上訓練第二個分類器
y2 = y - tree_reg.predict(x)
tree_reg2 = DecisionTreeRegressor(max_depth=2)
tree_reg2.fit(x, y2)
## 在第二個分類器的殘差上訓練第三個分類器
y3 = y2 - tree_reg2.predict(x)
tree_reg3 = DecisionTreeRegressor(max_depth=2)
tree_reg3.fit(x, y3)
## 通過整合所有樹的預測來在一個新的例項上進行預測
y_prd = sum(reg.predict(x) for reg in (tree_reg, tree_reg2, tree_reg3))
print(np.var(y-y_prd))
"""
1.5815921095948544
"""
用GBRT
來訓練。與RandomForestClassifier
相似,它也有超引數去決定決策樹的生長,也有超引數去控制整合訓練
from sklearn.ensemble import GradientBoostingRegressor
if __name__ == '__main__' :
x, y = Get_poly_data()
gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=.1)
gbrt.fit(x, y)
print(np.var(y-gbrt.predict(x)))
"""
15.005525005176338
"""
為了找到樹的最優數量,可以使用早停技術。最簡單使用這個技術的方法就是使用 staged_predict()
:
它訓練的每個階段(用一棵樹,兩棵樹等)返回一個迭代器。
用120棵樹去訓練一個GBRT整合,然後在訓練的每個階段驗證錯誤以找到樹的最佳數量,最後
使用GBRT樹的最優數量訓練另一個整合
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
if __name__ == '__main__' :
x, y = Get_poly_data()
x_train, x_val, y_train, y_val = train_test_split(x, y)
gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120)
gbrt.fit(x_train, y_train)
print('梯度提升:',np.var(y_val - gbrt.predict(x_val)))
## 早停方法
errors = [mean_squared_error(y_val, y_prd) for y_prd in gbrt.staged_predict(x_val)]
bst_n_estimators = np.argmin(errors)
gbrt_best = GradientBoostingRegressor(max_depth=2, n_estimators=bst_n_estimators)
gbrt_best.fit(x_train, y_train)
print('梯度提升-早停:',np.var(y_val - gbrt_best.predict(x_val)))
"""
梯度提升: 18.56750851278303
梯度提升-早停: 14.492333262607817
"""
可以看出梯度提升早停的方法擬合的更加好