简单加权融合
回归:
-
算术平均融合(Arithmetic mean)
-
加权算术平均法
-
几何平均融合(Geometric mean)
分类: 投票(Voting) -
绝对多数投票法:最终结果必须在投票中占一半以上。
-
相对多数投票法:最终结果在投票中票数最多。
-
硬投票:对多个模型直接进行投票,不区分模型结果的相对重要度,最终投票数最多的类为最终被预测的类。
-
软投票:增加了设置权重的功能,可以为不同模型设置不同权重,进而区别模型不同的重要度。
综合:
- 排序融合(Rank averaging)
- log融合
from sklearn import datasets
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.model_selection import train_test_split
from xgboost.sklearn import XGBClassifier
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=150, max_depth=3, min_child_weight=2, subsample=0.7,
colsample_bytree=0.6, objective='binary:logistic')
clf2 = RandomForestClassifier(n_estimators=50, max_depth=1, min_samples_split=4,
min_samples_leaf=63, oob_score=True)
clf3 = SVC(C=0.1)
# 硬投票
eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)],
voting='hard', n_jobs=-1)
# 软
# eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)], voting='soft', weights=[2, 1, 1])
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))
boosting/bagging
(在xgboost,Adaboost,GBDT中已经用到)
多树的提升方法
Bagging基于bootstrap(自采样),也就是有放回的采样。训练子集的大小和原始数据集的大小相同。Bagging的技术使用子集来了解整个样本集的分布,通过bagging采样的子集的大小要小于原始集合。
采用bootstrap的方法基于原始数据集产生大量的子集
基于这些子集训练弱模型base model
模型是并行训练并且相互独立的
最终的预测结果取决于多个模型的预测结果
Boosting是一种串行的工作机制,即个体学习器的训练存在依赖关系,必须一步一步序列化进行。Boosting是一个序列化的过程,后续模型会矫正之前模型的预测结果。也就是说,之后的模型依赖于之前的模型。
其基本思想是:增加前一个基学习器在训练训练过程中预测错误样本的权重,使得后续基学习器更加关注这些打标错误的训练样本,尽可能纠正这些错误,一直向下串行直至产生需要的T个基学习器,Boosting最终对这T个学习器进行加权结合,产生学习器委员会。
stacking/blending
构建多层模型,并利用预测结果再拟合预测
第一层原始训练集训练多个基学习器,预测训练集、测试集
第二层的模型以第一层基学习器的训练集预测结果作为训练集进行再训练,
用第一层测试集预测结果作为测试集
Stacking本质上就是这么直接的思路,但是直接这样有时对于如果训练集和测试集分布不那么一致的情况下是有一点问题的,其问题在于用初始模型训练的标签再利用真实标签进行再训练,毫无疑问会导致一定的模型过拟合训练集,这样或许模型在测试集上的泛化能力或者说效果会有一定的下降,因此现在的问题变成了如何降低再训练的过拟合性,这里我们一般有两种方法。
- 次级模型尽量选择简单的线性模型
- 利用K折交叉验证
# ---------------------------------------Stacking
# ___________________________train,val(作为test)
base_models_stacking = [LinearRegression(**parm_lr),
SVR(),
DecisionTreeRegressor(),
RandomForestRegressor(),
GradientBoostingRegressor(),
BaggingRegressor()]
train_pre_stacking = np.zeros((len(x_train_tree), len(base_models_stacking)))
val_pre_stacking = np.zeros((len(x_val_tree), len(base_models_stacking)))
# 5折stacking
n_splits = 5
skf = KFold(n_splits=n_splits).split(x_train_tree, y_train_tree)
for i, model in enumerate(base_models_stacking):
#依次训练各个单模型
val_pre_skf = np.zeros((len(x_val_tree), n_splits))
for j, (train_train_index, train_val_index) in enumerate(skf):
#5-Fold交叉训练,使用第i个部分作为预测,剩余的部分来训练模型,获得其预测的输出作为第i部分的新特征。
x_train, y_train = x_train_tree[train_train_index], y_train_tree[train_train_index]
x_val, y_val = x_train_tree[train_val_index], y_train_tree[train_val_index]
model.fit(x_train, y_train)
print(x_train.shape)
train_pre_stacking[train_val_index, i] = model.predict(x_val) # 训练集预测结果
val_pre_skf[:, j] = model.predict(x_val_tree) # 验证集预测结果i
val_pre_stacking[:, i] = val_pre_skf.mean() # 验证集预测结果
print("{} MAE Score: {}".format(str(model).split('(')[0],
mean_absolute_error(y_val_tree, val_pre_stacking[:, i])))
stack_model = LinearRegression(**parm_lr)
stack_model.fit(train_pre_stacking, y_train_tree) # (len_train, num_models), len_train
print('Stacking Model MAE Score: {} '.format(mean_absolute_error(y_val_tree,
stack_model.predict(val_pre_stacking))))
import warnings
warnings.filterwarnings('ignore')
import itertools
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from sklearn import datasets
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.model_selection import cross_val_score
from mlxtend.plotting import plot_learning_curves
from mlxtend.plotting import plot_decision_regions
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
meta_classifier=lr)
label = ['KNN', 'Random Forest', 'Naive Bayes', 'Stacking Classifier']
clf_list = [clf1, clf2, clf3, sclf]
fig, ax = plt.subplots(2, 2, figsize=(20, 20), dpi=100)
clf_cv_mean = []
clf_cv_std = []
for i in range(len(clf_list)):
clf = clf_list[i]
label = labels[i]
scores = cross_val_score(clf, X, y, cv=3, scoring='accuracy')
print("Accuracy: %.2f (+/- %.2f) [%s]" %(scores.mean(), scores.std(), label))
clf_cv_mean.append(scores.mean())
clf_cv_std.append(scores.std())
clf.fit(X, y)
fig = plot_decision_regions(X=X, y=y, clf=clf, ax=ax[i//2, i%2])
plt.title(label)
plt.show()
Blending采用了和stacking同样的方法,不过只从训练集中选择一个fold的结果,再和原始特征进行concat作为元学习器meta learner的特征,测试集上进行同样的操作。
在第一层,70%的数据上训练多个模型,预测30%数据、测试集。
在第二层,用第一层30%数据预测的结果作为训练集继续训练,用第一层预测的测试集结果作为测试集
其优点在于:
1.比stacking简单(因为不用进行k次的交叉验证来获得stacker feature)
2.避开了一个信息泄露问题:generlizers和stacker使用了不一样的数据集
缺点在于:
1.使用了很少的数据(第二阶段的blender只使用training set10%的量)
2.blender可能会过拟合
3.stacking使用多次的交叉验证会比较稳健
#------------------------------------blending
# ___________________________train, val(作为test)
base_models_blending = [LinearRegression(**parm_lr),
SVR(),
DecisionTreeRegressor(),
RandomForestRegressor(),
GradientBoostingRegressor(),
BaggingRegressor()]
x_train_70, x_train_30, y_train_70, y_train_30 = train_test_split(x_train_tree, y_train_tree, test_size=0.3, random_state=2020)
train_30_pre_blending = np.zeros((len(x_train_30), len(base_models_blending)))
val_pre_blending = np.zeros((len(x_val_tree), len(base_models_blending)))
for i, model in enumerate(base_models_blending):
#依次训练各个单模型
model.fit(x_train_70, y_train_70)
train_30_pre_blending[:, i] = model.predict(x_train_30)
# 对于测试集,直接用这k个模型的预测值作为新的特征。
val_pre_blending[:, i] = model.predict(x_val_tree)
print('{} MAE Score: {}'.format(str(model).split('(')[0],
mean_absolute_error(y_val_tree, val_pre_blending[:, i])))
blend_model = GradientBoostingClassifier(learning_rate=0.02, subsample=0.5, max_depth=6, n_estimators=30)
blend_model.fit(train_30_pre_blending, y_train_30)
print('Blending Model MAE Score: {} '.format(mean_absolute_error(y_val_tree,
blend_model.predict(val_pre_blending))))
网友评论