Datawhale组队学习 Task5-模型融合

1. 集成学习Ensemble Learning

(1)下文总结于周志华老师的西瓜书
(2)强烈推荐周老师的Boosting 25年分享报告
(3)笔记链接:Boosting 25年分享报告笔记
(4)视频链接:Boosting 25年(2014周志华老师)

在这里插入图片描述

1.1 Boosting

序列化的方法:个体学习器间存在强依赖关系,必须串行生成

知识点1:Boosting工作机制

  • s t e p 1 step1 step1 先从初试训练集训练出基学习器1
  • s t e p 2 step2 step2 根据基学习器的表现,调整训练样本分布(调整方法见参考链接2),使得基学习器1做错的训练样本在后续得到更多关注
  • s t e p 3 step3 step3 根据调整后的样本分布训练基学习器2
  • s t e p 4 step4 step4 重复进行,得到 T T T 个基学习器
  • s t e p 5 step5 step5 T T T 个基学习器加权结合

1.2 Bagging和随机森林

并行化的方法:个体学习器间不存在强依赖关系,可同时生成

知识点2:为保证基学习器尽可能独立,其中一种可行方法

  • s t e p 1 step1 step1 将训练集采样,产生若干不同子集
  • s t e p 2 step2 step2 通过不同子集分别训练出不同基学习器。注,因为每个基学习器只用到了一小部分训练数据,甚至不足以进行有效学习,该处我们可考虑使用相互有交叠的采样子集
  • s t e p 3 step3 step3 T T T 个基学习器加权结合

1.2.1 Bagging(全称 Bootstrap AGGregatING)

知识点3:Bagging工作机制

  • s t e p 1 step1 step1 基于自助采样法进行采样,可以采样出 T T T 个样本集,每个样本集包含 m m m 个样本点
  • s t e p 2 step2 step2 基于 T T T 个样本集训练得到 T T T 个基学习器
  • s t e p 3 step3 step3 T T T 个基学习器结合,分类任务常用简单投票法,回归任务常用简单平均法

【自助采样法 Bootstrap sampling】

  1. 给定包含 m m m 个样本的数据集
  2. 随机抽取一个样本放入采样集,再把该样本放回初始数据集(使该样本下次抽取仍有机会被选中)
  3. 经过 m m m 次随机采样,得到包含 m m m 个样本的采样集
  4. 观察可知:在新得到的采样集中,针对初试训练集的某个样本,可能该样本出现多次,也可能从未出现

如图是上学期学结构方程时,教材中的一幅图,没想到这里再次遇到它hh
在这里插入图片描述

1.2.2 随机森林(Random Forest)

RF是Bagging的一个扩展变体,在以决策树为基学习器构建Bagging集成基础上,进一步在决策树的训练过程中引入了随机属性选择(具体不展开,详情见西瓜书)

1.3 结合策略

在这里插入图片描述

1.3.1 Stacking

这里主要说明“学习法”中的Stacking

  • 学习法:通过另一个学习器来进行结合
  • 初级学习器:待结合的个体学习器
  • 次级学习器/元学习器:用于结合的学习器

知识点4:Stacking工作机制

  • s t e p 1 step1 step1 先从包含 m m m 个样本点的初始数据集,训练出 T T T 个初级学习器
  • s t e p 2 step2 step2 根据“生成”(交叉验证法/留一法等)的新数据集训练次级学习器

举个例子:假设现有两个初级学习器 M o d e l 1 , 1 Model_{1,1} Model1,1 M o d e l 1 , 2 Model_{1,2} Model1,2和一个次级学习器 M o d e l 2 Model_2 Model2

  • s t e p 1 step1 step1 基于 M o d e l 1 , 1 Model_{1,1} Model1,1 ,预测 X t r a i n X_{train} Xtrain X t e s t X_{test} Xtest 的标签列,分别为 P 1 P_1 P1 T 1 T_1 T1
    ( . . X t r a i n . . ) → p r e d i c t i o n m o d e l 1 , 1 ( . . P 1 . . ) {\begin{pmatrix}.\\ .\\X_{train} \\ .\\ .\end{pmatrix}}\xrightarrow[ prediction]{model_{1,1}}{\begin{pmatrix}.\\ .\\P_{1} \\ .\\ .\end{pmatrix}} ..Xtrain..model1,1 prediction..P1..
    ( . . X t e s t . . ) → p r e d i c t i o n m o d e l 1 , 1 ( . . T 1 . . ) {\begin{pmatrix}.\\ .\\X_{test} \\ .\\ .\end{pmatrix}}\xrightarrow[ prediction]{model_{1,1}}{\begin{pmatrix}.\\ .\\T_{1} \\ .\\ .\end{pmatrix}} ..Xtest..model1,1 prediction..T1..
  • s t e p 2 step2 step2 基于 M o d e l 1 , 2 Model_{1,2} Model1,2 ,预测 X t r a i n X_{train} Xtrain X t e s t X_{test} Xtest 的标签列,分别为 P 2 P_2 P2 T 2 T_2 T2
    ( . . X t r a i n . . ) → p r e d i c t m o d e l 1 , 2 ( . . P 2 . . ) {\begin{pmatrix}.\\ .\\X_{train} \\ .\\ .\end{pmatrix}}\xrightarrow[ predict]{model_{1,2}}{\begin{pmatrix}.\\ .\\P_{2} \\ .\\ .\end{pmatrix}} ..Xtrain..model1,2 predict..P2..
    ( . . X t e s t . . ) → p r e d i c t m o d e l 1 , 2 ( . . T 2 . . ) {\begin{pmatrix}.\\ .\\X_{test} \\ .\\ .\end{pmatrix}}\xrightarrow[ predict]{model_{1,2}}{\begin{pmatrix}.\\ .\\T_{2} \\ .\\ .\end{pmatrix}} ..Xtest..model1,2 predict..T2..
  • s t e p 3 step3 step3 合并 P 1 P 2 P_1P2 P1P2以及 T 1 T 2 T_1T_2 T1T2,得到新训练集 T r a i n 2 Train_2 Train2 T e s t 2 Test_2 Test2
    { T r a i n 2 : ( . . . . P 1 P 2 . . . . ) T e s t 2 : ( . . . . T 1 T 2 . . . . ) \left\{\begin{matrix} Train_2: &{\begin{pmatrix}.&. \\ . & .\\ P_1&P_2\\ . &. \\ . &. \\\end{pmatrix}} \\ Test_2: & {\begin{pmatrix}.&. \\ . & .\\ T_1&T_2\\ . &. \\ . &. \\\end{pmatrix}} \end{matrix}\right. Train2:Test2:..P1....P2....T1....T2..
  • s t e p 4 step4 step4 T r a i n 2 Train_2 Train2和真实训练集标签训练次级学习器 M o d e l 2 Model_2 Model2
    ( . . . . P 1 P 2 . . . . ) → M o d e l 2 t r a i n ( . . Y t r u e . . ) {\begin{pmatrix}.&. \\ . & .\\ P_1&P_2\\ . &. \\ . &. \\\end{pmatrix}}\xrightarrow[Model_2]{train}{\begin{pmatrix}.\\ .\\ Y_{true}\\ .\\ .\end{pmatrix}} ..P1....P2..train Model2..Ytrue..
  • s t e p 5 step5 step5 T e s t 2 Test_2 Test2预测最终的标签列
    ( . . . . T 1 T 2 . . . . ) → M o d e l 2 p r e d i c t ( . . Y p r e . . ) {\begin{pmatrix}.&. \\ . & .\\ T_1&T_2\\ . &. \\ . &. \\\end{pmatrix}}\xrightarrow[Model_2]{predict}{\begin{pmatrix}.\\ .\\ Y_{pre}\\ .\\ .\end{pmatrix}} ..T1....T2..predict Model2..Ypre..

但是,Stacking会导致过拟合,= = 这个过拟合的原因我竟然想了半天,都怪上面我的矩阵表示华而不实,于是手写 再捋顺下过程就明白了。为自己智商捉急。
在这里插入图片描述

为了解决P生成的问题(换句话说,解决再训练过程的过拟合问题),一般采用两种方法:

  1. 次级学习器尽量选择简单的线性模型
  2. 利用K折交叉验证

1.3.2 K折交叉验证下的Stacking(以5折为例)

在这里插入图片描述

  • s t e p 1 step1 step1 将训练集分为5份,对于每个初级学习器,我们使用其中4份训练(蓝色),未被用于训练的训练集(左侧橘黄色)用于下一步预测 即产生 P P P
  • s t e p 2 step2 step2 对于5个初级学习器,分别进行步骤1,最终我们将获得5个训练好的初级学习器,以及通过交叉验证得到的训练集预测结果 P 1 , P 2 , P 3 , P 4 , P 5 P_1,P_2,P_3,P_4,P_5 P1,P2,P3,P4,P5(右侧橘黄色)
  • s t e p 3 step3 step3 P 1 , P 2 , P 3 , P 4 , P 5 P_1,P_2,P_3,P_4,P_5 P1,P2,P3,P4,P5(右侧橘黄色)和真实值,训练得到次级学习器(右侧模型6)
    在这里插入图片描述
  • s t e p 4 step4 step4 将测试集数据,放到5个训练好的初级学习器中预测,取平均,得到 T 1 , T 2 , T 3 , T 4 , T 5 T_1,T_2,T_3,T_4,T_5 T1,T2,T3,T4,T5
  • s t e p 5 step5 step5 T 1 , T 2 , T 3 , T 4 , T 5 T_1,T_2,T_3,T_4,T_5 T1,T2,T3,T4,T5(橘黄色),测试次级学习器(模型6)

1.3.2 Blending

  • 对于一般的blending,主要思路是把原始的训练集先分成两部分,比如70%的数据作为新的训练集,剩下30%的数据作为测试集。
  • 我们在这70%的数据上训练多个初级学习器,然后用余下的30%预测相应的 P P P
  • 我们直接用这30%数据在第一层预测的 P P P结合真实值,作为新特征继续训练次级学习器。

1.3.3 Stacking v.s Blending

二者比较:

  • Stacking,用了全部训练数据 ;Blending,只是用了部分训练数据
  • Stacking多次使用CV,结果会比较稳健;但是通过K折交叉验证获得新特征,较麻烦
  • Blending划分数据集后,能够避免数据泄露;但是,划分会使得数据量变小,过小的数据量可能导致过拟合
  • 据说在实践中结果差不多,所以使用哪种方法都没什么所谓,看心情吧…

2. 代码示例

2.1 平均法

2.1.1 简单加权平均

import numpy as np
import pandas as pd
from sklearn import metrics

## 生成一些简单的样本数据,test_prei 代表第i个模型的预测值
test_pre1 = [1.2, 3.2, 2.1, 6.2]
test_pre2 = [0.9, 3.1, 2.0, 5.9]
test_pre3 = [1.1, 2.9, 2.2, 6.0]

# y_test_true 代表第模型的真实值
y_test_true = [1, 3, 2, 6] 

## 定义结果的加权平均函数
def Weighted_method(test_pre1,test_pre2,test_pre3,w=[1/3,1/3,1/3]):
    Weighted_result = w[0]*pd.Series(test_pre1)+w[1]*pd.Series(test_pre2)+w[2]*pd.Series(test_pre3)
    return Weighted_result

# 各模型的预测结果计算MAE
print('Pred1 MAE:',metrics.mean_absolute_error(y_test_true, test_pre1))
print('Pred2 MAE:',metrics.mean_absolute_error(y_test_true, test_pre2))
print('Pred3 MAE:',metrics.mean_absolute_error(y_test_true, test_pre3))

## 根据加权计算MAE
w = [0.3,0.4,0.3] # 定义比重权值
Weighted_pre = Weighted_method(test_pre1,test_pre2,test_pre3,w)
print('Weighted_pre MAE:',metrics.mean_absolute_error(y_test_true, Weighted_pre))

2.1.2 其他形式加权平均

# mean平均
def Mean_method(test_pre1,test_pre2,test_pre3):
    Mean_result = pd.concat([pd.Series(test_pre1),pd.Series(test_pre2),pd.Series(test_pre3)],axis=1).mean(axis=1)
    return Mean_result

# median平均
def Median_method(test_pre1,test_pre2,test_pre3):
    Median_result = pd.concat([pd.Series(test_pre1),pd.Series(test_pre2),pd.Series(test_pre3)],axis=1).median(axis=1)
    return Median_result
    
Mean_pre = Mean_method(test_pre1,test_pre2,test_pre3)
print('Mean_pre MAE:',metrics.mean_absolute_error(y_test_true, Mean_pre))
Median_pre = Median_method(test_pre1,test_pre2,test_pre3)
print('Median_pre MAE:',metrics.mean_absolute_error(y_test_true, Median_pre))

2.2 投票法

'''
硬投票:对多个模型直接进行投票,不区分模型结果的相对重要度,最终投票数最多的类为最终被预测的类。
'''
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')
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=150, max_depth=3, min_child_weight=2, subsample=0.8,
                     colsample_bytree=0.8, 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, probability=True)

# 软投票
eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)], voting='soft', weights=[2, 1, 1])
clf1.fit(x_train, y_train)

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))

2.3 Stacking融合(回归)

2.3.1 原始Stacking

# 原始stacking融合
def Stacking_method(train_reg1,train_reg2,train_reg3,y_train_true,test_pre1,test_pre2,test_pre3,model_L2= linear_model.LinearRegression()):
    model_L2.fit(pd.concat([pd.Series(train_reg1),pd.Series(train_reg2),pd.Series(train_reg3)],axis=1).values, y_train_true)
    Stacking_result = model_L2.predict(pd.concat([pd.Series(test_pre1),pd.Series(test_pre2),pd.Series(test_pre3)],axis=1).values)
    return Stacking_result


train_reg1 = [3.2, 8.2, 9.1, 5.2]
train_reg2 = [2.9, 8.1, 9.0, 4.9]
train_reg3 = [3.1, 7.9, 9.2, 5.0]
y_train_true = [3, 8, 9, 5]
test_pre1 = [1.2, 3.2, 2.1, 6.2]
test_pre2 = [0.9, 3.1, 2.0, 5.9]
test_pre3 = [1.1, 2.9, 2.2, 6.0]
y_test_true = [1, 3, 2, 6]

model_L2 = linear_model.LinearRegression()
Stacking_pre = Stacking_method(train_reg1,train_reg2,train_reg3,y_train_true,test_pre1,test_pre2,test_pre3,model_L2)
print('Stacking_pre MAE:', metrics.mean_absolute_error(y_test_true, Stacking_pre))

2.3.2 K折Stacking

知识点5:StratifiedKFold()

  • StratifiedKFold用法和Kfold类似,但是他是分层采样,确保训练集、测试集中各样本的比例与原始数据集相同
  • 返回的是index值,比如原始8个样本数据,4折处理,即每折2个。6个训练,2个测试

知识点6:roc_auc_score() (详情见参考链接6)

  • AUC的全称是Area under the Curve of ROC,也就是ROC曲线下方的面积
  • AUC值就是一个用来评价二分类模型优劣的常用指标,AUC值越高通常表明模型的效果越好
iris = datasets.load_iris()
data_0 = iris.data
data = data_0[:100,:]  # 取前100行
target_0 = iris.target
target = target_0[:100]

# 初级学习器设定
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(70,4) y(70,) X_predict(30,4) y_predict(30,)
X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.3, random_state=2020)  # random_state固定随机种子
dataset_blend_train = np.zeros((X.shape[0], 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)

for j,clf in enumerate(clfs):
    # 依次训练单个模型
    dataset_blend_test_j = np.zeros((X_predict.shape[0],5))
    for i,(train,test) in enumerate(skf):
        # 5折交叉训练,第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]  #predict_proba返回的是一个n行k列的数组,(i,j)数值是模型预测第i个预测样本为某个标签的概率,并且每一行的概率和为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(solver='lbfgs')  # lbfgs:quasi-Newton方法的优化器,适合小数据集
clf.fit(dataset_blend_train, y)  # 要注意对应关系,容易写错
y_submission = clf.predict_proba(dataset_blend_test)[:,1]
print("Val auc Score of Stacking: %f" % (roc_auc_score(y_predict, y_submission)))

在这里插入图片描述

2.3.3 利用mlxtend实现Stacking

# 利用mlxtend进行Stacking融合
# 分类的Stacking融合(利用mlxtend)
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 = plt.figure(figsize=(10,8))
gs = gridspec.GridSpec(2,2)  # 画布分为两行两列
grid = itertools.product([0, 1], repeat=2)

clf_cv_mean = []
clf_cv_std = []
for clf, label, grd in zip(clf_list, label, grid):
    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)
    ax = plt.subplot(gs[grd[0], grd[1]])
    fig = plot_decision_regions(X=X, y=y, clf=clf)  # 画出决策边界
    plt.title(label)

plt.show()

在这里插入图片描述

2.4 Blending

# Blending
iris = datasets.load_iris()
data_0 = iris.data
data = data_0[:100, :]

target_0 = iris.target
target = target_0[:100]

# 模型融合中使用到的各个单模型
clfs = [LogisticRegression(solver='lbfgs'),
        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.3, random_state=2020)
# 将训练集切分为d1,d2两部分
X_d1,X_d2,y_d1,y_d2 = train_test_split(X,y,test_size=0.5,random_state=2020)
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
    # 将原始数据集的测试集,放入初试学习器中,评价初试学习器好坏
    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(print("Val auc Score of Blending: %f" % (roc_auc_score(y_predict, y_submission))))

在这里插入图片描述
在学习代码时,发现各个数据集得仔细捋顺来源,要不然容易训练/测试时弄混。因为不是很熟练,所以画了个简图帮助理解~
在这里插入图片描述

3. 本赛题示例

注:在看教程时,有一个地方没太想清楚。教程中在模型融合部分,采用的是原始训练集中前70%数据的预测值(已经用来训练初级学习器的数据)训练次级学习器,我觉得这样会过拟合吗?如上图所示,个人认为应该用原始训练集中后30%的预测值作为新特征吧,于是我的代码改了一下,而且因为提供的测试集是没label的,故也不能如上图评价集成模型的好坏…

不知道我有没有想错,我凌乱了,明天再重新思考下。

# 教程的代码
model_lr_Stacking = build_model_lr(stacking_X_train,y_train)

# 改的,而且也只能用stacking_X_train评估下模型,结果显示确实MAE要高于教程的结果
model_lr_Stacking = build_model_lr(stacking_X_val,y_val) 
print('训练集-初级学习器MAE:', mean_absolute_error(model_lr_Stacking.predict(stacking_X_train),y_train))

>>> MAE:646.5239797688496

最后的预测结果大概是:
在这里插入图片描述

import pandas as pd
import numpy as np
import warnings
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
warnings.filterwarnings('ignore')
import itertools
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 sklearn.model_selection import cross_val_score, train_test_split
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import train_test_split
from sklearn import linear_model
from sklearn import preprocessing
from sklearn.svm import SVR
from sklearn.decomposition import PCA,FastICA,FactorAnalysis,SparsePCA
import lightgbm as lgb
import xgboost as xgb
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error

# In[] 构造数据集
Train_data = pd.read_csv('data/used_car_train_20200313.csv', sep=' ')
TestA_data = pd.read_csv('data/used_car_testA_20200313.csv', sep=' ')
numerical_cols = Train_data.select_dtypes(exclude = 'object').columns
feature_cols = [col for col in numerical_cols if col not in ['SaleID','name','regDate','price']]
X_data = Train_data[feature_cols]
Y_data = Train_data['price']

X_test  = TestA_data[feature_cols]
# Y_test = TestA_data['price']

# 其他数值特征
def Sta_inf(data):
    print('_min',np.min(data))
    print('_max:',np.max(data))
    print('_mean',np.mean(data))
    print('_ptp',np.ptp(data))
    print('_std',np.std(data))
    print('_var',np.var(data))

print(Sta_inf(Y_data))  # 输出训练集y的数值特征
X_data = X_data.fillna(-1)
X_test = X_test.fillna(-1)

# In[] 构造模型
def build_model_lr(x_train,y_train):
    reg_model = linear_model.LinearRegression()
    reg_model.fit(x_train,y_train)
    return reg_model

def build_model_ridge(x_train,y_train):
    reg_model = linear_model.Ridge(alpha=0.8)#alphas=range(1,100,5)
    reg_model.fit(x_train,y_train)
    return reg_model

def build_model_lasso(x_train,y_train):
    reg_model = linear_model.LassoCV()
    reg_model.fit(x_train,y_train)
    return reg_model

def build_model_gbdt(x_train,y_train):
    estimator =GradientBoostingRegressor(loss='ls',subsample= 0.85,max_depth= 5,n_estimators = 100)
    param_grid = { 'learning_rate': [0.05,0.08,0.1,0.2]}
    gbdt = GridSearchCV(estimator, param_grid,cv=3)
    gbdt.fit(x_train,y_train)
    print(gbdt.best_params_)
    # print(gbdt.best_estimator_ )
    return gbdt

def build_model_xgb(x_train,y_train):
    model = xgb.XGBRegressor(n_estimators=120, learning_rate=0.08, gamma=0, subsample=0.8,\
        colsample_bytree=0.9, max_depth=5) #, objective ='reg:squarederror'
    model.fit(x_train, y_train)
    return model

def build_model_lgb(x_train,y_train):
    estimator = lgb.LGBMRegressor(num_leaves=63,n_estimators = 100)
    param_grid = {'learning_rate': [0.01, 0.05, 0.1]}
    gbm = GridSearchCV(estimator, param_grid)
    gbm.fit(x_train, y_train)
    return gbm

# In[] XGBoost的五折交叉回归验证实现
xgr = xgb.XGBRegressor(n_estimators=120, learning_rate=0.1, subsample=0.8,colsample_bytree=0.9, max_depth=7)
scores_train = []
scores = []

## 5折交叉验证方式
sk=StratifiedKFold(n_splits=5,shuffle=True,random_state=0)
for train_ind,val_ind in sk.split(X_data,Y_data):
    train_x=X_data.iloc[train_ind].values
    train_y=Y_data.iloc[train_ind]
    val_x=X_data.iloc[val_ind].values
    val_y=Y_data.iloc[val_ind]
    
    xgr.fit(train_x,train_y)
    pred_train_xgb=xgr.predict(train_x)
    pred_xgb=xgr.predict(val_x)
    
    score_train = mean_absolute_error(train_y,pred_train_xgb)
    scores_train.append(score_train)
    score = mean_absolute_error(val_y,pred_xgb)
    scores.append(score)

print('Train mae:',np.mean(score_train))
print('Val mae',np.mean(scores))

# In[] 划分训练集数据,并用多种方法预测和训练
x_train,x_val,y_train,y_val = train_test_split(X_data,Y_data,test_size=0.3)

## Train and Predict
print('Predict LR...')
model_lr = build_model_lr(x_train,y_train)
val_lr = model_lr.predict(x_val)
subA_lr = model_lr.predict(X_test)

print('Predict Ridge...')
model_ridge = build_model_ridge(x_train,y_train)
val_ridge = model_ridge.predict(x_val)
subA_ridge = model_ridge.predict(X_test)

print('Predict Lasso...')
model_lasso = build_model_lasso(x_train,y_train)
val_lasso = model_lasso.predict(x_val)
subA_lasso = model_lasso.predict(X_test)

print('Predict GBDT...')
model_gbdt = build_model_gbdt(x_train,y_train)
val_gbdt = model_gbdt.predict(x_val)
subA_gbdt = model_gbdt.predict(X_test)

print('predict XGB...')
model_xgb = build_model_xgb(x_train,y_train)
val_xgb = model_xgb.predict(x_val)
subA_xgb = model_xgb.predict(X_test)

print('predict lgb...')
model_lgb = build_model_lgb(x_train,y_train)
val_lgb = model_lgb.predict(x_val)
subA_lgb = model_lgb.predict(X_test)

# In[] 模型融合_加权融合
def Weighted_method(test_pre1,test_pre2,test_pre3,w=[1/3,1/3,1/3]):
    Weighted_result = w[0]*pd.Series(test_pre1)+w[1]*pd.Series(test_pre2)+w[2]*pd.Series(test_pre3)
    return Weighted_result

## Init the Weight
w = [0.3,0.4,0.3]

## 测试验证集准确度
val_pre = Weighted_method(val_lgb,val_xgb,val_gbdt,w)
MAE_Weighted = mean_absolute_error(y_val,val_pre)
print('MAE of Weighted of val:',MAE_Weighted)

## 预测数据部分
subA = Weighted_method(subA_lgb,subA_xgb,subA_gbdt,w)
print('Sta inf:')
Sta_inf(subA)
## 生成提交文件
sub = pd.DataFrame()
sub['SaleID'] = X_test.index
sub['price'] = subA
sub.to_csv('./sub_Weighted.csv',index=False)

# In[] 模型融合_stacking融合
# 第一层.
# x_train为原始数据集的前70%的特征
train_lgb_pred = model_lgb.predict(x_train)
train_xgb_pred = model_xgb.predict(x_train)
train_gbdt_pred = model_gbdt.predict(x_train)

# stacking_X_train:x_train→初级学习器→预测值
stacking_X_train = pd.DataFrame()
stacking_X_train['Method_1'] = train_lgb_pred
stacking_X_train['Method_2'] = train_xgb_pred
stacking_X_train['Method_3'] = train_gbdt_pred

# stacking_X_val:x_val(原始数据集的后30%的特征)→初级学习器→预测值
stacking_X_val = pd.DataFrame()
stacking_X_val['Method_1'] = val_lgb
stacking_X_val['Method_2'] = val_xgb
stacking_X_val['Method_3'] = val_gbdt

# stacking_X_test:原始测试集→初级学习器→预测值
stacking_X_test = pd.DataFrame()
stacking_X_test['Method_1'] = subA_lgb
stacking_X_test['Method_2'] = subA_xgb
stacking_X_test['Method_3'] = subA_gbdt

# 第二层.
"""
# 教程版
model_lr_Stacking = build_model_lr(stacking_X_train,y_train)
# 训练集
train_pre_stacking = model_lr_Stacking.predict(stacking_X_train)
print('MAE of train_pre_stacking:', mean_absolute_error(y_train,train_pre_stacking))

# 验证集
val_pre_stacking = model_lr_Stacking.predict(stacking_X_val)
print('MAE of val_pre_stacking:', mean_absolute_error(y_val,val_pre_stacking))

# 测试集
subA_Stacking = model_lr_Stacking.predict(stacking_X_test)
"""

# 自己写的
model_lr_Stacking = build_model_lr(stacking_X_val,y_val) # 未被用来训练初级学习器的训练集数据,训练次级学习器

# 评价初级学习器

print('训练集-初级学习器MAE:', mean_absolute_error(model_lr_Stacking.predict(stacking_X_train),y_train))

"""
print('测试集-初级学习器MAE:', mean_absolute_error(stacking_X_test,Y_test))
# 评价融合模型
print('融合模型MAE:', mean_absolute_error(model_lr_Stacking.predict(stacking_X_test),Y_test))
"""
# 预测
subA_Stacking = model_lr_Stacking.predict(stacking_X_test)
subA_Stacking[subA_Stacking<10]=10  ## 去除过小的预测值

sub = pd.DataFrame()
sub['SaleID'] = TestA_data.SaleID
sub['price'] = subA_Stacking
sub.to_csv('./sub_Stacking.csv',index=False)
print('Sta inf:')
print(Sta_inf(subA_Stacking))

4. 总结

十分庆幸当时我在犹豫要不要报名参加时 最后选择了参加,一是自己动手能力真的挺差的,越怕写代码就越不会,然后就越怕;二是自己也给自己找理由,觉得现在课题方向是神经网络,我耗费这么多时间去学这个,是否值得。事实证明 真的值得。回顾过去几天的学习,简单总结下吧:

  • 平时自己在闭门造车学习时,很容易产生自我感觉良好心理,但很缺乏 是骡子是马拉出来溜溜的机会。于是当看到Datawhale公众号推送中的学习路径图时,明确的意识到很多东西我是不会的,这就促使我报名一起学习。现在当我再翻出当时那张学习路径图,虽然不敢保证能一下子说清楚它的发展、原理等等,但是已经了解过它的背景,也小小试验过,这就为以后的学习打下了基础。
  • Datawhale每个任务教程的内容都特别丰富,也很成体系,这对我帮助很大,其实自己学习时总是会陷入类似一叶障目的状况,学了半天某某模型/知识点,与相关内容不太能串联起来,也不太会用,于是也就不知道现在学的这个东西到底学到什么程度会比较好,同时也没有反馈 更不利于之后的学习方向调整。所以每天参考着教程,就会有凭借去思考自己的路径,我觉得这个挺好的。
  • 虽然这几天学习的东西可能看上去对我的课题没有直接帮助,但是它的存在还是非常非常有意义的。一是这个过程让我明白以后的学习不能只是闷头学原理/看文字,更多是要实践/应用,这几天的任务也是个很强的正反馈,给了我继续学习的信心;二是有些知识点对我比较有启发,比如模型融合的方式,之后要继续学习一下。
  • 我也明白这几天学习的内容还是挺基础的,我的能力也是基础中的基础哈哈,路漫漫修远兮,一点点积累进步吧。这几天的学习内容只是入门,之后还要多参加这样的学习活动,自己也要逼着自己多尝试~

【参考文献/链接】

【1】周志华.机器学习[M].清华大学出版社:北京,2016:171-185.
【2】bagging和boosting 总结
【3】模型融合方法学习总结(很详细,推荐)
【4】小常识5-stacking和blending模型融合方法详解
【5】KFold,StratifiedKFold k折交叉切分
【6】机器学习备忘录 | AUC值的含义与计算方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值