統計學習方法-AdaBoost筆記
AdaBoost演算法和SVM演算法曾被當做兩大最好的監督學習分類演算法,現在可能要再加上神經網路了(以上均為聽說。。。)
AdaBoost是adaptive boosting的縮寫(自適應增強學習),是基於Boosting思想的機器學習演算法,是整合學習中的一種,其基本原理就是將多個弱分類器(弱分類器一般選用單層決策樹,也叫決策樹樁)進行線性組合,使其成為一個強分類器,從而提高分類效能
說到Boost方法,則需要先理解下整合方法(參照文章:整合學習原理小結 ):
- 整合方法本身不是單個機器學習演算法,而是通過構造並結合多個學習機來學習;可以用於分類問題整合,迴歸問題整合,特徵選取整合,異常點檢測整合等等
- 整合方法的個體學習機有兩種選擇:1. 個體學習機是同質的,即都為同一種學習機,比如都是決策樹或者都是神經網路;2. 個體學習機是異質的,即是由不同學習機組成的,比如由SVM/LR/NB等學習機共同來學習
-
目前來說同質學習機使用最為廣泛,其主要可以分為兩大類:Bagging和Boosting(其實還有stacking,這裡不做介紹了)
- Bagging方法,主要通過對訓練資料集進行隨機取樣,以重新組合成不同的資料集,利用弱學習演算法對不同的新資料集進行學習,得到一系列的預測結果;對這些預測結果做平均或者投票做出最終的預測,因此這多個學習機是並行 的,如隨機森林演算法
- Boosting方法,主要通過對樣本設定權值(錯誤學習的樣本給予較大的權值),最終得到一系列的預測結果,並用加權多數表決方法,使預測效果較好的個體學習機獲得較大的權值,因此這多個學習機是序列的 ,比如AdaBoost和GBDT(Gradient Boost Decision Tree,梯度提升決策樹)演算法
此外再補充一句(機器學習-周志華):Boosting主要關注降低偏差,因此Boosting能基於泛化效能相當弱的學習器構建出很強的整合;Bagging主要關注降低方差,因此它在不剪枝的決策樹、神經網路等學習器上效用更為明顯
從AdaBoost演算法中可看出,其主要兩個權值:
- 第一個是樣本權值,每個樣本都一個初始化權值,然後不斷迭代,提高前一輪被錯誤分類樣本的權值,並且在Z歸一化後,使得每次總權值不變,因此正確分類的樣本權值會不斷減少,而錯誤分類樣本權值則會不斷增加(相當於中加權誤差 )
- 第二個是弱分類器(一般指那些誤差率略低於50% 的演算法,比如單層決策樹?)權值,由於每個弱分類器一般側重於前一輪錯誤分類的樣本(因為錯誤分類樣本權值高),但其不能保證將之前都正確分類的樣本也再次分對,因此需要通過分類錯誤率來計算每個弱分類器的權值;由於AdaBoost演算法最終是多個弱分類器線性組合的結果,再加上加權多數表決 的方法,因此權值越大的弱分類器,其對於最終分類效果其的作用就越大
此外對於弱分類器而言,不僅僅侷限於單層決策樹,其他分類器都是可以的,但是簡單的弱分類器效果更好
從上也能大致看出AdaBoost演算法的基本思路(分而治之),如果以二分類問題演算法為例(弱分類器選擇決策樹樁),演算法流程如下(參照《統計學習方法》):
- 初始化樣本權值
- 迴圈選擇每個特徵值的切點(閾值),找出加權誤差率最小的切點
- 根據公式8.2計算弱分類器的權值alpha
- 根據公式8.4更新每個樣本的權值D
- 迭代多次(或者直至誤差樣本為0),根據公式8.7構建線性組合分類器
- 以該分類器對測試集做預測
從上述可看出,AdaBoost的公式理解比較簡單,因此用Python實現也不復雜,如下所示:
class Adaboost: def calc_e(self, X, y, i, threshold, orientation, D): # 計算錯誤率和G(x)分類結果 e = np.ones((X.shape[0],1)) Gx = np.zeros((X.shape[0],1)) if orientation == "left": Gx[X[:,i] <= threshold] = 1 Gx[X[:,i] > threshold] = -1 else: Gx[X[:,i] > threshold] = 1 Gx[X[:,i] <= threshold] = -1 e[Gx == y] = 0 # 加權誤差weight_e weight_e = D * e return weight_e, Gx def build_stump(self, X, y, D): # 設定步長,對於非二值化的資料而言 numSteps = 4 # 用於儲存決策樹樁的一些資料,比如切點、分類方向、加權誤差等 best_stump = {} weight_e_min = 1 for i in range(X.shape[1]): X_min = X[:,i].min() X_max = X[:,i].max() step_size = (X_max-X_min) / numSteps for j in range(-1, int(numSteps) + 1): for ori in ["left", "right"]: thr = X_min + j * step_size weight_e, Gx = self.calc_e(X, y, i, thr, ori, D) if weight_e < weight_e_min: weight_e_min = weight_e best_stump["e"] = weight_e_min best_stump["threshold"] = thr best_stump["orientation"] = ori best_stump["Gx"] = Gx best_stump["feature"] = i return best_stump def adaboost_classfier(self, X, y, max_iter = 200): m, n = np.shape(X) # 初始化樣本權值 D = np.mat([1 / m] * m) # 儲存每個弱分類器 weak_classfier = [] fx = np.mat(np.zeros((m,1))) for i in range(max_iter): stump = self.build_stump(X, y, D) Gx = stump["Gx"] # 公式8.2,計算alpha alpha = 1/2 * np.log((1 - stump["e"]) / stump["e"]) # 公式8.4,更新樣本權值 D = np.multiply(D, np.exp(-1 * alpha * np.multiply(y, stump["Gx"]).T)) D = D / np.sum(D) stump["alpha"] = alpha weak_classfier.append(stump) # 構建線性組合分類器 fx += np.multiply(alpha, Gx) # 計算測試誤差,為0則結束迭代 error = np.sum(np.sign(fx) != y) if error == 0: break return weak_classfier def predict(self, X_test, classfier): for stump in classfier: threshold = stump["threshold"] orientation = stump["orientation"] feature = stump["feature"] if orientation == "left": if X_test[:,feature] <= threshold: return 1 else: return -1 else: if X_test[:,feature] > threshold: return 1 else: return -1
取《統計學習方法習題8.1》為例,用AdaBoost演算法學習一個強分類器(從結果中可看出,迭代6次就可以結束了):
train_X = np.mat([[0.,1.,3.], [0.,3.,1.], [1.,2.,2.], [1.,1.,3.], [1.,2.,3.], [0.,1.,2.], [1.,1.,2.], [1.,1.,1.], [1.,3.,1.], [0.,2.,1.]]) train_y = np.mat([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0]).T adaboost = Adaboost() tree = adaboost.adaboost_classfier(X=train_X, y=train_y, max_iter = 50) len(tree) >>6
此外還有些內容,如Adaboost演算法可以利用加性模型的損失函式最小化來推匯出來,,有確切的誤差界,模型是加法模型,損失函式是指數損失,演算法是前向分佈演算法
為了防止Adaboost過擬合,通常會正則化,在Adaboost中就相當於對每個迭代器加上一個正則化項(步長或者叫學習率Learning rat),為了避免過多的迭代器所造成的過擬合(其實在Adaboost使用中,也可以通過設定弱分類器迭代次數來避免過擬合,這兩種方法需要綜合權衡考慮),學習率一般設定範圍在0-1之間(1就相當於不正則化。。。那麼較小的學習率就會使得更多的弱分類器迭代次數)
對於多分類的情況,Adaboost也是可以處理的,只需要將多分類轉化為多個二分類問題即可
Adaboost演算法優點:分類時精確度很好;可以將不同的分類演算法作為弱分類器;相比bagging,其考慮了每個分類器的權重;結果可讀可解釋;無需調參;不易發生過擬合
缺點:對異常樣本非常敏感,因為異常樣本會在迭代中獲得相對較高的權值;資料不平衡會導致精度下降;因為要迴圈選擇最佳切點,有時會非常耗時