参考:相关学习资料
参考2:相关博文
模型融合一般用于A榜比赛的尾声和B榜比赛的全程
主要包括以下基础方法:
以上的方法从模型的结果, 样本集的集成和模型自身融合三个方面去记忆。
模型的结果方面:
这种加权融合的技术是从模型结果的层面来说的, 就是让每个模型跑一遍结果,用加权平均的方式将结果融合起来。
投票法(Voting)是集成学习里面针对分类问题的一种结果结合策略。投票法的输出有两种类型:一种是直接输出类标签,另外一种是输出类概率,使用前者进行投票叫做硬投票(Majority/Hard voting),使用后者进行分类叫做软投票(Soft voting)。
硬投票:少数服从多数。
软投票:在使用soft voting时,把概率当做权值,加权计算。
#硬投票
from xgboost import XGBClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
clf1 = LogisticRegression(random_state=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = XGBClassifier(learning_rate=0.1, n_estimators=150, max_depth=4, min_child_weight=2, subsample=0.7,objective='binary:logistic')
vclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('xgb', clf3)])
vclf = vclf .fit(x_train,y_train)
print(vclf .predict(x_test))
#软投票
#在VotingClassifier中加入参数 voting='soft', weights=[2, 1, 1],weights用于调节基模型的权重
from xgboost import XGBClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
clf1 = LogisticRegression(random_state=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = XGBClassifier(learning_rate=0.1, n_estimators=150, max_depth=4, min_child_weight=2, subsample=0.7,objective='binary:logistic')
vclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('xgb', clf3)], voting='soft', weights=[2, 1, 1])
vclf = vclf .fit(x_train,y_train)
print(vclf .predict(x_test))
将若干基学习器获得的预测结果,将预测结果作为新的训练集来训练一个次级分类器。
主要特点:
1)次级分类器一般比较简单:尽量选择线性模型
2)训练基分类器的时候的样本训练数据采用5折交叉验证进行,防止过拟合
预测阶段:把真正的测试集先用第一层的模型预测,把预测结过作为第二层测试集的特征进行第二层的预测。
只不过stacking那里是每个模型都会经历K折交叉验证,也就是有多少模型,就会有多少次K折交叉验证,而blending这里是所有模型合起来只经历了一次K折交叉验证
Blending的优势在于:
•Blending比较简单,而Stacking相对比较复杂;
•能够防止信息泄露:generalizers和stackers使用不同的数据;
而缺点在于:
•只用了整体数据的一部分;
•最终模型可能对留出集(holdout set)过拟合;
•Stacking多次交叉验证要更加稳健
stacking工具StackingCVRegressor:
from mxltend.regressor import StackingCVRegressor
StackingCVRegressorAPI及参数如下:
StackingCVRegressor(regressors,meta_regressor,cv = 5,shuffle = True,use_features_in_secondary = False)
•regressors: 基回归器,列表的形式,第一层的模型,可以这么写[xgb, lgb], 当然xgb,lgb是事先定义好的。
•meta_regressor: 元回归器, 这个可以理解为第二层的那个模型,即将前面回归器结果合起来的那个回归器,推荐使用lr,因为第二层的模型不要太复杂
•cv: 交叉验证策略, 默认是5折交叉验证。
•use_features_in_secondary: 默认是false, 意思是第二层的回归器只接收第一层回归器的结果进行训练和预测, 和我们上面介绍的原理样,如果设置为true,意思是第二层的回归器不仅接收第一层回归器的结果,还接收原始的数据集一块进行训练。
•shuffle: 如果设置为true, 则在交叉验证之前的训练数据将在拟合阶段打乱顺序。
方法:
•依然是.fit(x,y)进行训练, 但这里的x和y要求是数组了, 所以如果是DataFrame, 需要np.array()一下。并且X的shape[n_samples, n_features], y的shape, [n_samples]
•预测依然是.redict(x_test), 只不过这里的x_test依然是数组, 形状和上面的一样。
示例:
# 使用lgb和xgb那两个模型
def bulid_modl_xgb(x_train, y_train):
model = XGBRegressor(n_estimators=400, learning_rate=0.05, gamma=0, subsample=0.8, colsample_bytree=0.9, max_depth=7)
model.fit(x_train, y_train)
return model
def bulid_modl_lgb(x_train, y_train):
model = LGBMRegressor(n_estimators=1100, leaves=200, learning_rate=0.05, objective='regression_l1')
model.fit(x_train, y_train)
return model
def build_model_stackReg(x_train, y_train, xgb, lgb, lr):
model = StackingCVRegressor(regressors=(xgb, lgb), meta_regressor=lr)
model.fit(np.array(x_train), np.array(y_train))
return model
# Stacking
xgb = XGBRegressor(n_estimators=4000, learning_rate=0.05, gamma=0, subsample=0.8, colsample_bytree=0.9, max_depth=7)
lgb = LGBMRegressor(n_estimators=11000, leaves=200, learning_rate=0.05, objective='regression_l1')
lr = LinearRegression()
model_stack = build_model_stackReg(X, Y, xgb, lgb, lr)
val_stack = model_stack.predict(np.array(XTest))
MAE_stack = mean_absolute_error(Ytrue, np.expm1(val_stack))
print(MAE_stack)
StackingClassifierAPI及参数如下:
StackingClassifier(classifiers, meta_classifier, use_probas=False, average_probas=False, verbose=0, use_features_in_secondary=False), 这里的参数和上面的StackingCVRegressor基本上差不多
•classifiers: 基分类器, 数组形式[clf1, clf2, clf3], 每个基分类器的属性被存储在类属性 self.clfs_.
•meta_classifier: 目标分类器,即将前面分类器合起来的分类器
•use_probas : bool (default: False) ,如果设置为True, 那么目标分类器的输入就是前面分类输出的类别概率值而不是类别标签
•average_probas : bool (default: False),用来设置上一个参数当使用概率值输出的时候是否使用平均值。
•verbose : int, optional (default=0)。用来控制使用过程中的日志输出,当 verbose = 0时,什么也不输出, verbose = 1,输出回归器的序号和名字。verbose = 2,输出详细的参数信息。verbose > 2, 自动将verbose设置为小于2的,
•use_features_in_secondary : bool (default: False). 如果设置为True,那么最终的目标分类器就被基分类器产生的数据和最初的数据集同时训练。如果设置为False,最终的分类器只会使用基分类器产生的数据训练。
方法: .fit(), .predict()常用
使用示例:
from mlxtend.classifier import StackingCVClassifier
# 上面的这个操作,如果换成StackingClassifier, 是这样的形式:
clf1 = RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini')
clf2 = ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='gini')
clf3 = ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='entropy')
clf4 = GradientBoostingClassifier(learning_rate=0.05, subsample=0.5, max_depth=6, n_estimators=5)
clf5 = LogisticRegression(solver='lbfgs')
sclf = StackingCVClassifier(classifiers=[clf1, clf2, clf3, clf4], meta_classifier=clf5, cv=3)
sclf.fit(X, y)
# 5这交叉验证
#scores = cross_val_score(sclf, X, y, cv=3, scoring='accuracy')
y_submission = sclf.predict(X_predict)
print("Val auc Score of Stacking: %f" % (roc_auc_score(y_predict, y_submission)))
# 模型融合中用到的单个模型
clfs = [LogisticRegression(solver='lbfgs'),
RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'),
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.3, random_state=2020)
dataset_blend_train = np.zeros((int(X.shape[0]/n_splits), len(clfs))) # 每个模型的预测作为第二层的特征
dataset_blend_test = np.zeros((X_predict.shape[0], len(clfs)))
# 5折stacking
n_splits = 5
skf = StratifiedKFold(n_splits)
skf = skf.split(X, y)
fold = {}
for i, (train, test) in enumerate(skf):
fold[i] = (X[train], y[train], X[test], y[test])
Y_blend = []
for j, clf in enumerate(clfs):
# 依次训练各个单模型
dataset_blend_test_j = np.zeros((X_predict.shape[0], 5))
# 5——fold交叉训练,使用第i个部分作为预测, 剩余的部分来训练模型, 获得其预测的输出作为第i部分的新特征。
X_train, y_train, X_test, y_test = fold[j]
clf.fit(X_train, y_train)
dataset_blend_train[:, j] = clf.predict(X_test)
Y_blend.extend(y_test)
# 对于测试集,直接用这k个模型的预测值作为新的特征
dataset_blend_test[:, j] = clf.predict(X_predict)
print("val auc Score: %f" % roc_auc_score(y_predict, dataset_blend_test[:, j]))
dataset_blend_train = dataset_blend_train.T.reshape(70, -1)
dataset_blend_test = np.mean(dataset_blend_test, axis=1).reshape(-1, 1)
Y_blend = np.array(Y_blend).reshape(-1, 1)
clf = LogisticRegression(solver='lbfgs')
clf.fit(dataset_blend_train, Y_blend)
y_submission = clf.predict(dataset_blend_test)
print("Val auc Score of Stacking: %f" % (roc_auc_score(y_predict, y_submission)))
## 结果:
Val auc Score of Stacking: 1.000000
# 以python自带的鸢尾花数据集为例
data_0 = iris.data
data = data_0[:100,:]
target_0 = iris.target
target = target_0[:100]
#模型融合中基学习器
clfs = [LogisticRegression(),
RandomForestClassifier(),
ExtraTreesClassifier(),
GradientBoostingClassifier()]
#切分一部分数据作为测试集
X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.3, random_state=914)
#切分训练数据集为d1,d2两部分
X_d1, X_d2, y_d1, y_d2 = train_test_split(X, y, test_size=0.5, random_state=914)
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()
clf.fit(dataset_d1, y_d2)
y_submission = clf.predict_proba(dataset_d2)[:, 1]
print("Val auc Score of Blending: %f" % (roc_auc_score(y_predict, y_submission)))
import pickle
"""第一种, pickle的序列化和反序列化"""
#模型的保存
pickle.dump(model, open('./model/xgb1.pkl', 'wb'))
#模型的载入
model1 = pickle.load(open('./model/xgb1.pkl', 'rb'))
#模型的预测
model1.predict(dtest)
"""第二种模型的存储与导入方式 - sklearn的joblib"""
from sklearn.externals import joblib
#模型的保存
joblib.dump(model, './model/xgb.pkl')
#模型的载入
model2 = joblib.load('./model/xgb.pkl')
#模型的预测
model2.predict(dtest)