機器學習:AdaBoost演算法及其實現
阿新 • • 發佈:2019-01-01
文章目錄
楔子
前面提到boosting演算法為一類演算法,這一類演算法框架分為3步:1、訓練一個弱分類;2、根據分類結果調整樣本權重;3、最後決策時,根據弱模型的表現來決定其話語權。
那麼這裡面就有2個關鍵點:
1、如何調整樣本權重;
2、如何根據弱模型的表現來決定其話語權。
演算法描述:
adaboost裡的樣本權重和話語權
事實上,能夠將這兩個問題的解決方案有機地糅合在一起、正是 AdaBoost 的巧妙之處之一。
如何調整樣本權重,一個弱分類器得到一個錯誤分類率e > 0.5, 我們調整樣本權重是分類錯誤率等於0.5,用這個樣本權重用於下一個分類器,這個這兩個分類器就不會強相關,這個就是調整樣本權重的主要思想。
分類錯誤樣本權重乘以d倍,分類正確樣本權重處理d,得到e*d = (1-e)/d =====> d^2 = (1-e)/e
我們定義該分類器的話語權為:alpha = ln(d) = 0.5*ln (1-e)/e,話語權是隨著錯誤率的增大而減小的。
事實上,能夠將這兩個問題的解決方案有機地糅合在一起、正是 AdaBoost 的巧妙之處之一。
實際的樣本權重是歸一化處理過的:
演算法描述
AdaBoost的實現:
實現比較簡單,首先你的分類器需要支援樣本權重,然後按照序列呼叫你的分類器就行了,每次把計算好的樣本權重傳進去。
class AdaBoost:
# 弱分類器字典,如果想要測試新的弱分類器的話、只需將其加入該字典即可
_weak_clf = {
"SKMNB": SKMultinomialNB,
"SKGNB": SKGaussianNB,
"SKTree": SKTree,
"MNB": MultinomialNB,
"GNB": GaussianNB,
"ID3": ID3Tree,
"C45": C45Tree,
"Cart": CartTree
}
"""
AdaBoost框架的樸素實現
使用的弱分類器需要有如下兩個方法:
1) 'fit' 方法,它需要支援輸入樣本權重
2) 'predict' 方法, 它用於返回預測的類別向量
"""
def __init__(self):
# 初始化結構
# self._clf:記錄弱分類器名稱的變數
# self._clfs:記錄弱分類器的列表
# self._clfs_weights:記錄弱分類器“話語權”的列表
self._clf, self._clfs, self._clfs_weights = "", [], []
def fit(self, x, y, sample_weight=None, clf=None, epoch=10, eps=1e-12, **kwargs):
# 預設使用10個CART決策樹樁作為弱分類器
if clf is None or AdaBoost._weak_clf[clf] is None:
clf = "Cart"
kwargs = {"max_depth": 1}
# 當前使用的分類器
self._clf = clf
# 樣本權重,注意是歸一化後的樣本權重,預設樣本權重為[1/N,1/N,...]
if sample_weight is None:
sample_weight = np.ones(len(y)) / len(y)
else:
sample_weight = np.array(sample_weight)
# AdaBoost演算法的主迴圈,epoch為迭代次數
for _ in range(epoch):
# 根據樣本權重訓練弱分類器
tmp_clf = AdaBoost._weak_clf[clf](**kwargs)
tmp_clf.fit(x, y, sample_weight)
# 呼叫弱分類器的predict方法進行預測
y_pred = tmp_clf.predict(x)
# 計算加權錯誤率;考慮到數值穩定性,在邊值情況加了一個小的常數
# 點乘是行*列
em = min(max((y_pred != y).dot(self._sample_weight[:, None])[0], eps), 1 - eps)
# 計算該弱分類器的“話語權”,化簡了一下
am = 0.5 * log(1 / em - 1)
# 更新樣本權重並利用deepcopy將該弱分類器記錄在列表中
sample_weight *= np.exp(-am * y * y_pred)
sample_weight /= np.sum(sample_weight)
# 記錄分類器和話語權
self._clfs.append(deepcopy(tmp_clf))
self._clfs_weights.append(am)
def predict(self, x):
x = np.atleast_2d(x)
# 儲存結果
rs = np.zeros(len(x))
# 根據各個弱分類器的“話語權”進行決策
for clf, am in zip(self._clfs, self._clfs_weights):
rs += am * clf.predict(x)
# 將預測值大於0的判為類別1,小於0的判為類別-1
return np.sign(rs)
數學基礎(瞭解)
AdaBoost 演算法是前向分步演算法的特例,AdaBoost 模型等價於損失函式為指數函式的加法模型。
所謂的前向分步演算法,就是從前向後、一步一步地學習加法模型中的每一個基函式及其權重而非將f(x)作為一個整體來訓練,這也正是 AdaBoost 的思想。