机器学习中很多训练模型通过融合方式都有可能使得准确率等评估指标有所提高,这一块有很多问题想学习,于是写篇博客来介绍,主要想解决:
构建并结合多个学习器来完成学习任务,我们把它称为模型融合或者集成学习。不同的模型有各自的长处,具有差异性,而模型融合可以使得发挥出各个模型的优势,让这些相对较弱的模型(学习器)通过某种策略结合起来,达到比较强的模型(学习器)。基本的融合方式有:
选择融合模型的模型有两点要求:
主要思想是多个学习器投票、加权等方式来获得一个新的预测值,在分类问题中就是多数投票,回归问题就是加权,对学习器结果进行加权求和,权重值和为1。那么一些基本的融合方式就是:
少数服从多数思想,投票模型,直接可以根据多个模型结果做判断。
G ( x ) = s i g n ( ∑ t = 1 T 1 ∗ g t ( x ) ) G(x) = sign(\sum^{T}_{t=1}1*g_t(x)) \\ G(x)=sign(t=1∑T1∗gt(x))
在这里给每个学习器的权重都是1,每一个权重都是一样的,通过投票的方式来确定选择哪个。
G ( x ) = s i g n ( ∑ t = 1 T a t g t ( x ) ) a t ≥ 0 G(x) = sign(\sum^{T}_{t=1}a_tg_t(x)) \\ a_t \ge 0 G(x)=sign(t=1∑Tatgt(x))at≥0
在这里给每个学习器都指定了一个权重 a t a_t at。 a t a_t at通过之前的线性回归,逻辑回归等方法得到投票权重;最后便得到了最终模型。意思应该是每个权重也可以被训练得出。
例如可以采用简单的lgb和xgb的bagging融合,粗暴的bagging融合就是对lgb和xgb预测值之和取平均,稍微调整一下,通过遍历两个模型权重来选择最优的融合比例。
best_p = 0
best_score = 0
for p in range(0,1,0.05):
b_score = model(lgbmodel,xgbmodel,p)
if b_score > best_score :
best_score = b_score
best_p = p
lgb和xgb均用了3个不同种子的5折融合,相当于最后一共融合了30个模型的预测结果,这样的操作使最终线上得分突破了0.5。
Blending方式各个分类器直接相对都是独立的,Stacking则有点像组合方式,每一个层都是一个模型,下一层模型利用上一层模型的输出来得到结果作为下一层输入,但Stacking算法分为2层,第一层是用不同的算法形成T个弱分类器,同时产生一个与原数据集大小相同的新数据集,利用这个新数据集和一个新算法构成第二层的分类器。
上述都是单个模型,如果有m个模型,每次也是上述过程,那么输出就变成了:
说实话很多人对这个可能还是有点蒙,那个例子来做分析:
上面是第一层的训练结果,我们现在来看下第二层的训练过程:
一些问题思考:
stacking融合,加入NN和逻辑回归增强泛化能力。
我们在模型融合的时候,肯定会比较各个模型的使用场景等特点,所以需要知道各个模型的特性、优点、缺点等,但似乎现在网上并没有这方面的资料,这个地方不太好写,也似乎没有一个业内比较常用的模型组合。不过大家可以参考统计学习方法书中总结的内容,如下图所示:
XGBClassifier、RFClassifier 作为基模型,采用 LogisticRegressionCV 作为次模型。
from sklearn import datasets
from sklearn import model_selection
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 StackingCVClassifier
import numpy as np
import warnings
warnings.simplefilter('ignore')
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
RANDOM_SEED = 42
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=RANDOM_SEED)
clf3 = GaussianNB()
lr = LogisticRegression()
# Starting from v0.16.0, StackingCVRegressor supports
# `random_state` to get deterministic result.
sclf = StackingCVClassifier(classifiers=[clf1, clf2, clf3],meta_classifier=lr,use_probas=True, cv=5)
print('3-fold cross validation:\n')
for clf, label in zip([clf1, clf2, clf3, sclf],
['KNN',
'Random Forest',
'Naive Bayes',
'StackingClassifier']):
scores = model_selection.cross_val_score(clf, X, y,cv=3, scoring='accuracy')
print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
运行结果如下所示:
3-fold cross validation:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.90 (+/- 0.03) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.95 (+/- 0.03) [StackingClassifier]
具体的代码可以看到这篇github链接:StackingCVClassifier
。大家就算是来尝试一下这个模型融合的流程。
from mlxtend.regressor import StackingCVRegressor
from mlxtend.data import boston_housing_data
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.svm import SVR
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.metrics import mean_squared_error
import numpy as np
import matplotlib.pyplot as plt
x, y = boston_housing_data()
x = x[:100]
y = y[:100]
# 划分数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
# 初始化基模型
lr = LinearRegression()
svr_lin = SVR(kernel='linear', gamma='auto')
ridge = Ridge(random_state=2019,)
lasso =Lasso()
models = [lr, svr_lin, ridge, lasso]
params = {'lasso__alpha': [0.1, 1.0, 10.0],
'ridge__alpha': [0.1, 1.0, 10.0]}
sclf = StackingCVRegressor(regressors=models, meta_regressor=ridge)
grid = GridSearchCV(estimator=sclf, param_grid=params, cv=5, refit=True)
grid.fit(x_train, y_train)
print(grid.best_score_, grid.best_params_)
这里加了网格搜索,可以对参数进行调试,链接如下:
StackingCVRegressor
Stacking demo
Blending 主要在优化variance(即模型的鲁棒性),Stacking主要在优化bias(即模型的精确性)。这是从另一个角度来看这个问题。
模型融合 Blending 和 Stacking
机器学习比赛大杀器----模型融合(stacking & blending)
使用sklearn进行集成学习——理论