機器學習集成學習 Ensemble Learning(常用集成算法彙總)

集成方法是將幾種機器學習技術組合成一個預測模型的元算法,以達到減小方差(bagging)、偏差(boosting)或改進預測(stacking)的效果。集成學習潛在的思想是即便某一個弱分類器得到了錯誤的預測,其他的弱分類器也可以將錯誤糾正回來。

目前主要的集成學習算法類型有Voting, Bagging, Boost ,  Stacking。

目錄

一、Voting 投票

二、Bagging

三、Boosting

五、stacking


一、Voting 投票

1、voting原理

假設有1000種分類器,每個分類器預測的正確率只有50.5%,如果以預測類別最多的作爲預測結果,則準確率可達到60%,如果有10000種分類器,則準確率可達到84%左右。該結果的前提是分類器彼此獨立,但是現實中它們都在同一個數據集上進行訓練,可能會犯同樣的錯誤,所以準確率會有降低。

2、Voting可以分爲硬投票法(Harding Voting)和軟投票法(Soft Voting)

-- 硬投票法

根據分類器預測的結果出現最多的類別作爲預測值。

-- 軟投票法

如果所有分類器都能夠估算出類別的概率,那麼對所有分類器的類別概率求平均,然後給出平均概率最高的類別作爲預測。

通常來說,它比硬投票法的表現更優,因爲它給予那些高度自信的投票更高的權重。

from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC

lr = LogisticRegression()
dt = DecisionTreeClassifier()
svm = SVC() # 若是soft voting,則probability=True
voting = VotingClassifier(
    estimators=[('lr',lr),('rf',dt),('svc',svm)],
    voting='hard' # 軟投票法,voting='soft'
)

二、Bagging

1、原理

bagging中每個基學習器採用的是相同的算法,分別在各自隨機抽取(有放回的採樣)的子數據集上進行訓練,預測的結果出現最多的類別作爲預測值。

#  bootstrap = True 爲bagging,bootstrap=False爲pasting(無放回採樣)
# max_samples設置爲整數表示的就是採樣的樣本數,設置爲浮點數表示的是max_samples*x.shape[0]
bag_clf = BaggingClassifier(
    SVC(),
    n_estimators=500, max_samples=1.0, bootstrap=True, n_jobs=-1
    # ,oob_score=True
)

2、隨機森林 RandomFroest

隨機森林是決策樹的集成,通常用bagging方法進行訓練。

# 如果基分類器是決策樹,那麼該bagging算法就是隨機森林
bag_clf = BaggingClassifier(
    DecisionTreeClassifier(splitter="random", max_leaf_nodes=16),
    n_estimators=500, max_samples=1.0, bootstrap=True, n_jobs=-1
)
# 上面等同於sklearn提供的RF的API
rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rnd_clf.fit(X, y)
print(rnd_clf.__class__.__name__, '=', accuracy_score(y, y_hat))

三、Boosting

Boosting算法要涉及到兩個部分,加法模型和前向分步算法。加法模型就是說強分類器由一系列弱分類器線性相加而成;前向分步就是說在訓練過程中,下一輪迭代產生的分類器是在上一輪的基礎上訓練得來的。

1、AdaBoost

每一輪如何改變訓練數據的權值:AdaBoost改變了訓練數據的權值,也就是樣本的概率分佈,其思想是將關注點放在被錯誤分類的樣本上,減小上一輪被正確分類的樣本權值,提高那些被錯誤分類的樣本權值。然後,再根據所採用的一些基本機器學習算法進行學習,比如邏輯迴歸。

如何將弱分類器組合成一個強分類器:AdaBoost採用加權多數表決的方法,加大分類誤差率小的弱分類器的權重,減小分類誤差率大的弱分類器的權重。這個很好理解,正確率高分得好的弱分類器在強分類器中當然應該有較大的發言權。

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
rf = DecisionTreeClassifier()
model = AdaBoostClassifier(base_estimator=rf,n_estimators=50,algorithm="SAMME.R", learning_rate=0.5)
model.fit(X_train,y_train)
y_train_hat = model.predict(X_train)

2、GBDT

GBDT模型是一個集成模型,基分類器採用CART,集成方式爲Gradient Boosting。GBDT基於boosting增強策略的加法模型,訓練的時候採用前向分佈算法進行貪婪的學習,每次迭代都學習一棵CART樹來擬合之前 t-1 棵樹的預測結果與訓練樣本真實值的殘差。它不像AdaBoost那樣在每個迭代中調整實例權重,而是讓新的預測器針對前一個預測器的殘差進行擬合。

from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import GradientBoostingRegressor
gbdt = GradientBoostingRegressor(max_depth=5, n_estimators=3, learning_rate=1.0)

3、XGBoost

XGBoost的核心思想是不斷地添加樹,不斷地進行特徵分裂來生長一棵樹,每次添加一個樹,其實是學習一個新函數f(x),去擬合上次預測的殘差。當我們訓練完成得到k棵樹,我們要預測一個樣本的分數,其實就是根據這個樣本的特徵,在每棵樹中會落到對應的一個葉子節點,每個葉子節點就對應一個分數。最後只需要將每棵樹對應的分數加起來就是該樣本的預測值。

XGBoost對GBDT進行了一系列優化,比如損失函數進行了二階泰勒展開、目標函數加入正則項、支持並行和默認缺失值處理等,在可擴展性和訓練速度上有了巨大的提升,但其核心思想沒有大的變化。

import xgboost as xgb
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
model =xgb.XGBClassifier(max_depth=3,learning_rate=0.3,n_estimators=6,silent=True,objective='binary:logistic')
model.fit(X_train,y_train)
# 訓練集上準確率
train_preds = model.predict(X_train)
train_accuracy = accuracy_score(y_train, train_preds)
# 測試集上準確率
preds = model.predict(X_test)
test_accuracy = accuracy_score(y_test, preds)
print("Test Accuracy: %.2f%%" % (test_accuracy * 100.0))

 -- 使用GridSearchCV(網格搜索交叉驗證)搜索最優參數

from sklearn.model_selection import GridSearchCV
model = xgb.XGBClassifier(learning_rate=0.1, silent=True, objective='binary:logistic')
param_grid = {
 'n_estimators': range(1, 51, 1),
 'max_depth':range(1,10,1)
}
clf = GridSearchCV(model, param_grid, "accuracy",cv=5)
clf.fit(X_train, y_train)
print(clf.best_params_, clf.best_score_)

-- 我們設置驗證valid集,當我們迭代過程中發現在驗證集上錯誤率增加,則提前停止迭代

from sklearn.model_selection import train_test_split
X_train_part, X_validate, y_train_part, y_validate = train_test_split(X_train, y_train, test_size=0.3,random_state=0)
# 設置boosting迭代計算次數
num_round = 100
bst =xgb.XGBClassifier(max_depth=2, learning_rate=0.1, n_estimators=num_round, silent=True, objective='binary:logistic')
eval_set =[(X_validate, y_validate)]
bst.fit(X_train_part, y_train_part, early_stopping_rounds=10, eval_metric="error",
    eval_set=eval_set, verbose=True)
    
results = bst.evals_result()

--  錯誤率可視化

results = bst.evals_result()
#print(results)

epochs = len(results['validation_0']['error'])
x_axis = range(0, epochs)

# plot log loss

plt.plot(x_axis, results['validation_0']['error'], label='Test')

plt.ylabel('Error')
plt.xlabel('Round')
plt.title('XGBoost Early Stop')
plt.show()

-- 學習曲線

# 設置boosting迭代計算次數
num_round = 100

# 沒有 eraly_stop
bst =xgb.XGBClassifier(max_depth=2, learning_rate=0.1, n_estimators=num_round, silent=True, objective='binary:logistic')
 
eval_set = [(X_train_part, y_train_part), (X_validate, y_validate)]
bst.fit(X_train_part, y_train_part, eval_metric=["error", "logloss"], eval_set=eval_set, verbose=True)
# retrieve performance metrics
results = bst.evals_result()
#print(results)


epochs = len(results['validation_0']['error'])
x_axis = range(0, epochs)

# plot log loss
fig, ax = plt.subplots()
ax.plot(x_axis, results['validation_0']['logloss'], label='Train')
ax.plot(x_axis, results['validation_1']['logloss'], label='Test')
ax.legend()
plt.ylabel('Log Loss')
plt.title('XGBoost Log Loss')
plt.show()

# plot classification error
fig, ax = plt.subplots()
ax.plot(x_axis, results['validation_0']['error'], label='Train')
ax.plot(x_axis, results['validation_1']['error'], label='Test')
ax.legend()
plt.ylabel('Classification Error')
plt.title('XGBoost Classification Error')
plt.show()

 

注:xgboost詳細參數講解及代碼實現,傳送門在此。

五、stacking

stacking 就是當用初始訓練數據學習出若干個基學習器後,將這幾個學習器的預測結果作爲新的訓練集,來學習一個新的學習器。

如圖所示,我們現在用5折交叉驗證來訓練數據,model1要做滿5次訓練和預測。

第一次,M1,拿traindata的800行做訓練集,200行做驗證集,然後預測出200行的數據a1。

第二次,M1,拿traindata的800行做訓練集,200行做驗證集,然後預測出200行的數據a2。

第三次,M1,拿traindata的800行做訓練集,200行做驗證集,然後預測出200行的數據a3。

第四次,M1,拿traindata的800行做訓練集,200行做驗證集,然後預測出200行的數據a4。

第五次,M1,拿traindata的800行做訓練集,200行做驗證集,然後預測出200行的數據a5。

然後將a1到a5拼接起來,得到一列,共1000行的數據。

針對測試集testdata有兩種方法,一種是全部訓練完成後,一次性預測輸出200行數據;另一種是M1每次做完訓練就那testdata中的數據做預測,一種得到5次200行的數據,然後做平均,得到一列200行的數據。

如果有10個基模型,那麼根據traindata會得到10列數據,作爲x,原來traindata中的label作爲y(很多文章都沒說這點,導致初學者有很多誤解),然後再放到一個模型中做訓練。而根據testdata會得到10列200行的數據,作爲測試數據。

最後,將訓練好的模型預測10列200行的數據,得到的最終結果就是最後需要的數據。

# sklearn並沒有集成stacking,使用前需用如下命令安裝 pip install mlxtend
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from mlxtend.classifier import StackingClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y.ravel(), train_size=0.8, random_state=0)
# 定義基分類器
clf1 = KNeighborsClassifier(n_neighbors=5)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
# 定義最後輸出的分類器
lr = LogisticRegression()
# 定義堆疊後的模型
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
                          meta_classifier=lr,use_probas=True)
# 對每一個類分類器進行打分
for model in [clf1,clf2,clf3,lr,sclf]:
    model.fit(X_train,y_train)
    y_test_hat = model.predict(X_test)
    print(model.__class__.__name__,',test accuarcy:',accuracy_score(y_test,y_test_hat))
                 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章