模型融合
介紹:模型融合通常可以在各種不同的機器學習任務中使結果獲得提升。顧名思義,模型融合就是綜合考慮不同模型的情況,並將它們的結果融合到一起。具體內容會從以下幾個方面來講:
1、Voting
2、Averaging
3、Ranking
4、Bagging
5、Boosting
6、Stacking
7、Blending
一、Voting
Voting即投票機制,分為軟投票和硬投票兩種,其原理采用少數服從多數的思想。
硬投票:對多個模型直接進行投票,最終投票數最多的類為最終被預測的類。
軟投票:和硬投票原理相同,增加了設置權重的功能,可以為不同模型設置不同權重,進而區別模型不同的重要度。
備注:此方法用於解決分類問題。
代碼實例如下:
硬投票:
iris = datasets.load_iris() x=iris.data y=iris.target x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3) clf1 = XGBClassifier(learning_rate=0.1, n_estimators=140, max_depth=1, min_child_weight=2, gamma=0, subsample=0.7, colsample_bytree=0.6, objective='binary:logistic', nthread=4, scale_pos_weight=1) clf2 = RandomForestClassifier(n_estimators=50, max_depth=1, min_samples_split=4, min_samples_leaf=54,oob_score=True) clf3 = SVC(C=0.1, probability=True)# 硬投票eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)], voting='hard')for clf, label in zip([clf1, clf2, clf3, eclf], ['XGBBoosting', 'Random Forest', 'SVM', 'Ensemble']): scores = cross_val_score(clf, x, y, cv=5, scoring='accuracy') print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
軟投票:
x=iris.data y=iris.target x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3) clf1 = XGBClassifier(learning_rate=0.1, n_estimators=140, max_depth=1, min_child_weight=2, gamma=0, subsample=0.7, colsample_bytree=0.6, objective='binary:logistic', nthread=4, scale_pos_weight=1) clf2 = RandomForestClassifier(n_estimators=50, max_depth=1, min_samples_split=4, min_samples_leaf=54,oob_score=True) clf3 = SVC(C=0.1, probability=True)# 軟投票eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)], voting='soft', weights=[2, 1, 1]) clf1.fit(x_train, y_train)
二、Averaging
Averaging,其原理是對模型結果取平均。
處理回歸問題,直接取平均值作為最終的預測值。(也可以使用加權平均)
平均法存在問題就是如果不同回歸方法的預測結果波動幅度相差比較大,那么波動小的回歸結果在融合時候起的作用就比較小。
三、Ranking
Ranking的思想和Averaging一致,但是因為上述平均法存在一定的問題。
所以這里采用了把排名做平均,如果有權重,則求n個模型權重比排名之和,即為最后的結果。
四、Bagging
Bagging方法的出現,可以完美地解決了決策樹過擬合的問題,同時bagging的使用也會使分類器分類效果得到了顯著的提高。
應用場景:對不穩定的分類器做Bagging是一個好主意。在機器學習中,如果訓練數據的一個小變化導致學習中的分類器的大變化,則該算法(或學習算法)被認為是不穩定的。
Bagging就是采用有放回的方式進行抽樣,用抽樣的樣本建立子模型,對子模型進行訓練,這個過程重復多次,最后進行融合。大概分為兩步:
1.重復K次
有放回地重復抽樣建模
訓練子模型
2.模型融合
模型融合,如果是分類問題用voting解決 。如果是回歸問題用average解決。
注意:在bagging集成中,各個模型的預測不會彼此依賴。Bagging算法不用我們自己實現,隨機森林就是基於Bagging算法的一個典型例子,采用的基分類器是決策樹。可以直接調用。
五、Boosting
Boosting的思想是一種迭代的方法,它每次訓練使用的都是同一個訓練集。但是每次它會給這些分類錯誤的樣例增加更大的權重,下一次迭代的目標就是能夠更容易辨別出上一輪分類錯誤的樣例。最終將這些弱分類器進行加權相加。
注意:Boosting下一次的迭代必須在上一次的基礎上。
同樣地,基於Boosting思想的有AdaBoost、GBDT等,也可以直接調用。
六、Stacking
stacking是一種分層模型集成框架。以兩層為例,第一層由多個基學習器組成,其輸入為原始訓練集,第二層的模型則是以第一層基學習器的輸出作為訓練集進行再訓練,從而得到完整的stacking模型。
stacking兩層模型都使用了全部的訓練數據。
第一層模型:
首先數據有訓練集和測試集兩部分
1.對訓練集進行五折交叉驗證,把訓練集划分為A,B兩部分
2.對A部分進行訓練,對B部分進行預測,得到a1,五折后則為a1,a2,a3,a4,a5,對他們合並,形成n行一列的數據
3.對測試集進行預測,會得到b1,b2,b3,b4,b5,將各部分相加取平均得到m行一列的數據
4,。以上是一個模型,如果有三個模型,則可以得到A1,A2,A3,B1,B2,B3
5.在此之后,我們把A1,A2,A3並列合並得到一個n行三列的矩陣作為training data,B1,B2,B3並列合並得到一個m行三列的矩陣作為testing data。讓下一層的模型,基於他們進一步訓練。
代碼實例:
#創建訓練的數據集data, target = make_blobs(n_samples=50000, centers=2, random_state=0, cluster_std=0.60)#模型融合中使用到的各個單模型clfs = [RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), GradientBoostingClassifier(learning_rate=0.05, subsample=0.5, max_depth=6, n_estimators=5)]#切分一部分數據作為測試集X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.33, random_state=2017) dataset_blend_train = np.zeros((X.shape[0], len(clfs))) dataset_blend_test = np.zeros((X_predict.shape[0], len(clfs)))#5折stackingn_folds = 5skf = list(StratifiedKFold(y, n_folds))for j, clf in enumerate(clfs): #依次訓練各個單模型 dataset_blend_test_j = np.zeros((X_predict.shape[0], len(skf))) for i, (train, test) in enumerate(skf): #使用第i個部分作為預測,剩余的部分來訓練模型,獲得其預測的輸出作為第i部分的新特征。 X_train, y_train, X_test, y_test = X[train], y[train], X[test], y[test] clf.fit(X_train, y_train) y_submission = clf.predict_proba(X_test)[:, 1] dataset_blend_train[test, j] = y_submission dataset_blend_test_j[:, i] = clf.predict_proba(X_predict)[:, 1] #對於測試集,直接用這k個模型的預測值均值作為新的特征。 dataset_blend_test[:, j] = dataset_blend_test_j.mean(1) print("val auc Score: %f" % roc_auc_score(y_predict, dataset_blend_test[:, j]))# clf = LogisticRegression()clf = GradientBoostingClassifier(learning_rate=0.02, subsample=0.5, max_depth=6, n_estimators=30) clf.fit(dataset_blend_train, y) y_submission = clf.predict_proba(dataset_blend_test)[:, 1]print("Linear stretch of predictions to [0,1]") y_submission = (y_submission - y_submission.min()) / (y_submission.max() - y_submission.min())print("val auc Score: %f" % (roc_auc_score(y_predict, y_submission)))
備注:此處只是一部分代碼
七、Blending
Bending是一種模型融合方法,對於一般的Blending,主要思路是把原始的訓練集先分成兩部分,比如70%的數據作為新的訓練集,剩下30%的數據作為測試集。第一層我們在這70%的數據上訓練多個模型,然后去預測那30%數據的label。在第二層里,我們就直接用這30%數據在第一層預測的結果做為新特征繼續訓練即可。
Blending的優點在於:
1.比stacking簡單(因為不用進行k次的交叉驗證來獲得stacker feature)
2.避開了一個信息泄露問題:generlizers和stacker使用了不一樣的數據集
而缺點在於:
1.使用了很少的數據(第二階段的blender只使用training set10%的量)
2.blender可能會過擬合
3.stacking使用多次的交叉驗證會比較穩健
對於實踐中的結果而言,stacking和blending的效果是差不多的,所以使用哪種方法都沒什么所謂,完全取決於個人愛好。
代碼實例:
#創建訓練的數據集data, target = make_blobs(n_samples=50000, centers=2, random_state=0, cluster_std=0.60)#模型融合中使用到的各個單模型clfs = [RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), GradientBoostingClassifier(learning_rate=0.05, subsample=0.5, max_depth=6, n_estimators=5)]#切分一部分數據作為測試集X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.33, random_state=2017)#5折stackingn_folds = 5skf = list(StratifiedKFold(y, n_folds))#切分訓練數據集為d1,d2兩部分X_d1, X_d2, y_d1, y_d2 = train_test_split(X, y, test_size=0.5, random_state=2017) dataset_d1 = np.zeros((X_d2.shape[0], len(clfs))) dataset_d2 = np.zeros((X_predict.shape[0], len(clfs)))for j, clf in enumerate(clfs): #依次訓練各個單模型 clf.fit(X_d1, y_d1) y_submission = clf.predict_proba(X_d2)[:, 1] dataset_d1[:, j] = y_submission #對於測試集,直接用這k個模型的預測值作為新的特征。 dataset_d2[:, j] = clf.predict_proba(X_predict)[:, 1] print("val auc Score: %f" % roc_auc_score(y_predict, dataset_d2[:, j]))#融合使用的模型clf = GradientBoostingClassifier(learning_rate=0.02, subsample=0.5, max_depth=6, n_estimators=30) clf.fit(dataset_d1, y_d2) y_submission = clf.predict_proba(dataset_d2)[:, 1]print("Linear stretch of predictions to [0,1]") y_submission = (y_submission - y_submission.min()) / (y_submission.max() - y_submission.min())print("val auc Score: %f" % (roc_auc_score(y_predict, y_submission)))
總結:
以上的七種模型融合方法,在一定情況下可以提高模型的准確率,方法沒有好壞之分,各有自己的優缺點,具體實施可針對具體場景。