智慧海洋建设-Task5 模型融合

5.1 学习目标

学习融合策略

完成相应学习打卡任务

5.2 内容介绍

https://mlwave.com/kaggle-ensembling-guide/
https://github.com/MLWave/Kaggle-Ensemble-Guide

模型融合是比赛后期一个重要的环节,大体来说有如下的类型方式。

  1. 简单加权融合:

    • 回归(分类概率):算术平均融合(Arithmetic mean),几何平均融合(Geometric mean);
    • 分类:投票(Voting)
  2. boosting/bagging(在xgboost,Adaboost,GBDT中已经用到):

    • 多树的提升方法
  3. stacking/blending:

    • 构建多层模型,并利用预测结果再拟合预测。

5.3 相关理论介绍

5.3.1 简单加权融合

平均法-Averaging

  1. 对于回归问题,一个简单直接的思路是取平均。将多个模型的回归结果取平均值作为最终预测结果,进而把多个弱分类器荣和城强分类器。

  2. 稍稍改进的方法是进行加权平均,权值可以用排序的方法确定,举个例子,比如A、B、C三种基本模型,模型效果进行排名,假设排名分别是1,2,3,那么给这三个模型赋予的权值分别是3/6、2/6、1/6。

  3. 平均法或加权平均法看似简单,其实后面的高级算法也可以说是基于此而产生的,Bagging或者Boosting都是一种把许多弱分类器这样融合成强分类器的思想。

  4. Averaging也可以用于对分类问题的概率进行平均。

投票法-voting

  1. 对于一个二分类问题,有3个基础模型,现在我们可以在这些基学习器的基础上得到一个投票的分类器,把票数最多的类作为我们要预测的类别。

  2. 投票法有硬投票(hard voting)和软投票(soft voting)

  3. 硬投票: 对多个模型直接进行投票,不区分模型结果的相对重要度,最终投票数最多的类为最终被预测的类。

  4. 软投票:增加了设置权重的功能,可以为不同模型设置不同权重,进而区别模型不同的重要度。

5.3.2 stacking/blending

堆叠法-stacking

基本思想:用初始训练数据学习出若干个基学习器后,将这几个学习器的预测结果作为新的训练集(第一层),来学习一个新的学习器(第二层)。

背景: 为了帮助大家理解模型的原理,我们先假定一下数据背景。

  1. 训练集数据大小为10000*100,测试集大小为3000*100。即训练集有10000条数据、100个特征;测试集有3000条数据、100个特征。该数据对应回归问题

  2. 第一层使用三种算法-XGB、LGB、NN。第二层使用GBDT。

算法解读

  1. stacking 第一层

  2. XGB算法 - 对应图中model 1部分

- 输入:使用训练集进行5-fold处理
- 处理:具体处理细节如下- 使用1、2、3、4折作为训练集,训练一个XGB模型并预测第5折和测试集,将预测结果分别称为**XGB-pred-tran5**(shape `2000*1`)和**XGB-pred-test1**(shape `3000*1`).- 使用1、2、3、5折作为训练集,训练一个XGB模型并预测第4折和测试集,将预测结果分别称为**XGB-pred-tran4**(shape `2000*1`)和**XGB-pred-test2**(shape `3000*1`).- 使用1、2、4、5折作为训练集,训练一个XGB模型并预测第3折和测试集,将预测结果分别称为**XGB-pred-tran3**(shape `2000*1`)和**XGB-pred-test3**(shape `3000*1`).- 使用1、3、4、5折作为训练集,训练一个XGB模型并预测第2折和测试集,将预测结果分别称为**XGB-pred-tran2**(shape `2000*1`)和**XGB-pred-test4**(shape `3000*1`).- 使用2、3、4、5折作为训练集,训练一个XGB模型并预测第1折和测试集,将预测结果分别称为**XGB-pred-tran1**(shape `2000*1`)和**XGB-pred-test5**(shape `3000*1`).
- 输出:- 将XGB分别对1、2、3、4、5折进行预测的结果合并,得到**XGB-pred-tran**(shape `10000*1`)。并且根据5-fold的原理可以知道,与原数据可以形成对应关系。因此在图中称为NEW FEATURE。- 将XGB-pred-test1 - 5 的结果使用Averaging的方法求平均值,最终得到**XGB-pred-test**(shape `3000*1`)。
  1. LGB算法 - 同样对应图中model 1部分
- 输入:与XGB算法一致
- 处理:与XGB算法一致。只需更改预测结果的命名即可,如**LGB-pred-tran5**和**LGB-pred-test1**
- 输出:- 将LGB分别对1、2、3、4、5折进行预测的结果合并,得到**LGB-pred-tran**(shape `10000*1`)。- 将LGB-pred-test1 - 5 的结果使用Averaging的方法求平均值,最终得到**LGB-pred-test**(shape `3000*1`)。
  1. NN算法 - 同样对应图中model 1部分
- 输入:与XGB算法一致
- 处理:与XGB算法一致。只需更改预测结果的命名即可,如**NN-pred-tran5**和**NN-pred-test1**
- 输出:- 将NN分别对1、2、3、4、5折进行预测的结果合并,得到**NN-pred-tran**(shape `10000*1`)。- 将NN-pred-test1 - 5 的结果使用Averaging的方法求平均值,最终得到**NN-pred-test**(shape `3000*1`)。
  1. stacking 第二层
  • 训练集:将三个新特征 XGB-pred-tranLGB-pred-tranNN-pred-tran合并得到新的训练集(shape 10000*3)
  • 测试集:将三个新测试集XGB-pred-testLGB-pred-testNN-pred-test合并得到新的测试集(shape 30000*3)
  • 用新训练集和测试集构造第二层的预测器,即GBDT模型

混合法 - blending

Blending与Stacking大致相同,只是Blending的主要区别在于训练集不是通过K-Fold的CV策略来获得预测值从而生成第二阶段模型的特征,而是建立一个Holdout集。简单来说,Blending直接用不相交的数据集用于不同层的训练。

同样以上述数据集为例,构造一个两层的Blending模型。

首先将训练集划分为两部分(d1,d2),例如d1为4000条数据用于blending的第一层,d2是6000条数据用于blending的第二层。

第一层:用d1训练多个模型,将其对d2和test的预测结果作为第二层的New Features。例如同样适用上述三个模型,对d2生成6000*3的新特征数据;对test生成3000*3的新特征矩阵。

第二层:用d2的New Features和标签训练新的分类器,然后把test的New Features输入作为最终的测试集,对test预测出的结果就是最终的模型融合的值。

优缺点对比

Blending的优点在于:

  1. 比stacking简单(因为不用进行k次的交叉验证来获得stacker feature)

  2. 避开了一个信息泄露问题:generlizers和stacker使用了不一样的数据集

  3. 在团队建模过程中,不需要给队友分享自己的随机种子

而缺点在于:

  1. 使用了很少的数据(是划分hold-out作为测试集,并非cv)

  2. blender可能会过拟合(其实大概率是第一点导致的)

  3. stacking使用多次的CV会比较稳健

5.4 代码实现

import pandas as pd
import numpy as np
import warnings
import matplotlib
import matplotlib.pyplot as plt
import seaborn as snswarnings.filterwarnings('ignore')
%matplotlib inlineimport 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,RandomForestRegressor
from sklearn.linear_model import LogisticRegression
# from mlxtend.classifier import StackingClassifier
from sklearn.model_selection import cross_val_score, train_test_split
# from mlxtend.plotting import plot_learning_curves
# from mlxtend.plotting import plot_decision_regionsfrom sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import train_test_split
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import VotingClassifier
import lightgbm as lgb
from sklearn.neural_network import MLPClassifier,MLPRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error

5.4.1 load data

import pandas as pd
import numpy as np
from sklearn.metrics import classification_report, f1_score
from sklearn.model_selection import StratifiedKFold, KFold,train_test_split
def reduce_mem_usage(df):start_mem = df.memory_usage().sum() / 1024**2 print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))for col in df.columns:col_type = df[col].dtypeif col_type != object:c_min = df[col].min()c_max = df[col].max()if str(col_type)[:3] == 'int':if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:df[col] = df[col].astype(np.int8)elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:df[col] = df[col].astype(np.int16)elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:df[col] = df[col].astype(np.int32)elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:df[col] = df[col].astype(np.int64)  else:if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:df[col] = df[col].astype(np.float16)elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:df[col] = df[col].astype(np.float32)else:df[col] = df[col].astype(np.float64)else:df[col] = df[col].astype('category')end_mem = df.memory_usage().sum() / 1024**2 print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))return df
all_df = pd.read_csv('data/group_df.csv',index_col=0)
all_df = reduce_mem_usage(all_df)
all_df = all_df.fillna(99)
Memory usage of dataframe is 30.28 MB
Memory usage after optimization is: 7.59 MB
Decreased by 74.9%
all_df.shape
(9000, 440)
all_df['label'].value_counts()
 2    4361
-1    20000    16211    1018
Name: label, dtype: int64

all_df中label为0/1/2的为训练集,一共有7000条;label为-1的为测试集,一共有2000条。

  1. label为-1的测试集没有label,这部分数据用于模拟真实比赛提交数据。

  2. train数据均有标签,我们将从中分出30%作为验证集,其余作为训练集。在验证集上比较模型性能优劣,模型性能均使用f1作为评分。

train = all_df[all_df['label'] != -1]
test =  all_df[all_df['label'] == -1]
feats = [c for c in train.columns if c not in ['ID', 'label']]# 根据7:3划分训练集和测试集
X_train,X_val,y_train,y_val= train_test_split(train[feats],train['label'],test_size=0.3,random_state=0)

5.4.2 单模及加权融合

这里训练三个单模,分别是用了一个三种不同的RF/LGB/LGB模型。事实上模型融合需要基础分类器之间存在差异,一般不会选用相同的分类器模型。这里只是作为展示。

# 单模函数
def build_model_rf(X_train,y_train):model = RandomForestClassifier(n_estimators = 100)model.fit(X_train, y_train)return modeldef build_model_lgb(X_train,y_train):model = lgb.LGBMClassifier(num_leaves=127,learning_rate = 0.1,n_estimators = 200)model.fit(X_train, y_train)return modeldef build_model_lgb2(X_train,y_train):model = lgb.LGBMClassifier(num_leaves=63,learning_rate = 0.05,n_estimators = 400)model.fit(X_train, y_train)return model
# 这里针对三个单模进行训练,其中subA_rf/lgb/nn都是可以提交的模型
# 单模没有进行调参,因此是弱分类器,效果可能不是很好。print('predict rf ...')
model_rf = build_model_rf(X_train,y_train)
val_rf = model_rf.predict(X_val)
subA_rf = model_rf.predict(test[feats])
rf_f1_score = f1_score(y_val,val_rf,average='macro')
print(rf_f1_score)print('predict lgb...')
model_lgb = build_model_lgb(X_train,y_train)
val_lgb = model_lgb.predict(X_val)
subA_lgb = model_lgb.predict(test[feats])
lgb_f1_score = f1_score(y_val,val_lgb,average='macro')
print(lgb_f1_score)print('predict lgb 2...')
model_lgb2 = build_model_lgb2(X_train,y_train)
val_lgb2 = model_lgb2.predict(X_val)
subA_lgb2 = model_lgb2.predict(test[feats])
lgb2_f1_score = f1_score(y_val,val_lgb2,average='macro')
print(lgb2_f1_score)
predict rf ...
0.8987051046527208
predict lgb...
0.9144414270113281
predict lgb 2...
0.9183965870229657
voting_clf = VotingClassifier(estimators=[('rf',model_rf ),('lgb',model_lgb),('lgb2',model_lgb2 )],voting='hard')voting_clf.fit(X_train,y_train)
val_voting = voting_clf.predict(X_val)
subA_voting = voting_clf.predict(test[feats])
voting_f1_score = f1_score(y_val,val_voting,average='macro')
print(voting_f1_score)
0.9142736444973326

5.4.3 Stacking融合

_N_FOLDS = 5  # 采用5折交叉验证
kf = KFold(n_splits=_N_FOLDS, random_state=42)  # sklearn的交叉验证模块,用于划分数据def get_oof(clf, X_train, y_train, X_test):oof_train = np.zeros((X_train.shape[0], 1)) oof_test_skf = np.empty((_N_FOLDS, X_test.shape[0], 1))  for i, (train_index, test_index) in enumerate(kf.split(X_train)): # 交叉验证划分此时的训练集和验证集kf_X_train = X_train.iloc[train_index,]kf_y_train = y_train.iloc[train_index,]kf_X_val = X_train.iloc[test_index,]clf.fit(kf_X_train, kf_y_train)oof_train[test_index] = clf.predict(kf_X_val).reshape(-1, 1) oof_test_skf[i, :] = clf.predict(X_test).reshape(-1, 1)  oof_test = oof_test_skf.mean(axis=0)  # 对每一则交叉验证的结果取平均return oof_train, oof_test  # 返回当前分类器对训练集和测试集的预测结果
# 将你的每个分类器都调用get_oof函数,并把它们的结果合并,就得到了新的训练和测试数据new_train,new_test
new_train, new_test = [], []model1 = RandomForestClassifier(n_estimators = 100)
model2 = lgb.LGBMClassifier(num_leaves=127,learning_rate = 0.1,n_estimators = 200)
model3 = lgb.LGBMClassifier(num_leaves=63,learning_rate = 0.05,n_estimators = 400)for clf in [model1, model2, model3]:oof_train, oof_test = get_oof(clf, X_train, y_train, X_val)new_train.append(oof_train)new_test.append(oof_test)new_train = np.concatenate(new_train, axis=1)
new_test = np.concatenate(new_test, axis=1)
# 用新的训练数据new_train作为新的模型的输入,stacking第二层
# 使用LogisticRegression作为第二层是为了防止模型过拟合
# 这里使用的模型还有待优化,因此模型融合效果并不是很好
clf = LogisticRegression()
clf.fit(new_train, y_train)
result = clf.predict(new_test)stacking_f1_score = f1_score(y_val,result,average='macro')
print(stacking_f1_score)
0.8816601744239989

5.5 思考题

  1. 如何基于stacking改进出blending - stacking使用了foldCV,blending使用了holdout.

  2. stacking还可以进行哪些优化提升F1-score - 从第一层模型数量?模型差异性?角度出发

参考内容

https://blog.csdn.net/weixin_44585839/article/details/110148396

https://blog.csdn.net/weixin_39962758/article/details/111101263

【算法竞赛学习】数字中国创新大赛智慧海洋建设-Task5模型融合相关推荐

  1. 【算法竞赛学习】数字中国创新大赛智慧海洋建设-Task4模型建立

    智慧海洋建设-Task4模型建立 此部分为智慧海洋建设竞赛的模型建立模块.在该模块中主要介绍了如何进行模型建立并对模型调优. 学习目标 学习如何选择合适的模型以及如何通过模型来进行特征选择 掌握随机森 ...

  2. 【算法竞赛学习】数字中国创新大赛智慧海洋建设-Task2数据分析

    智慧海洋建设-Task2 数据分析 此部分为智慧海洋建设竞赛的数据分析模块,通过数据分析,可以熟悉数据,为后面的特征工程做准备,欢迎大家后续多多交流. 赛题:智慧海洋建设 数据分析的目的: EDA的主 ...

  3. 【算法实战篇】时序多分类赛题-2020数字中国创新大赛-智慧海洋建设top5方案(含源码)

        Hi,大家好!这里是AILIGHT!AI light the world!这次给大家带来的是2020数字中国创新大赛-数字政府赛道-智能算法赛:智慧海洋建设的算法赛复赛赛道B top5的方案以 ...

  4. 【时序多分类赛题】2020数字中国创新大赛-智慧海洋建设top5方案(含源码)

       这次给大家带来的是2020数字中国创新大赛-数字政府赛道-智能算法赛:智慧海洋建设的算法赛复赛赛道B top5的方案以及代码开源.比赛传送门:https://tianchi.aliyun.com ...

  5. 【算法竞赛学习】数字中国创新大赛智慧海洋建设-Task3特征工程

    智慧海洋建设-Task3 特征工程 此部分为智慧海洋建设竞赛的特征工程模块,通过特征工程,可以最大限度地从原始数据中提取特征以供算法和模型使用.通俗而言,就是通过X,创造新的X'以获得更好的训练.预测 ...

  6. 【算法竞赛学习】数字中国创新大赛智慧海洋建设-Task1地理数据分析常用工具

    智慧海洋建设-Task1 地理数据分析常用工具 在地理空间数据分析中,常会用到许多地理分析的工具,在本模块中主要是针对常用的shapely.geopandas.folium.kepler.gl.geo ...

  7. 天池算法赛:数据挖掘经典赛事!DCIC 2020 数字中国创新大赛启动!

    2020数字中国创新大赛(Digital China Innovation Contest, DCIC2020),以"培育数字经济新动能,助推数字中国新发展"为主题,采取多赛道并行 ...

  8. 2020数字中国创新大赛-智能算法赛-冠军方案

    写在前面的话 大家好,我是 Champion Chasing Boy 的 DOTA,在队友 鱼遇雨欲语与余. 尘沙杰少.林有夕.嗯哼哼唧 的Carry下,最终在本届智能算法赛拿到了复赛总榜单Top1的 ...

  9. 2020数字中国创新大赛-智能算法赛-冠军方案分享

    写在前面的话 大家好,我是 Champion Chasing Boy 的 DOTA,在队友 鱼遇雨欲语与余. 尘沙杰少.林有夕.嗯哼哼唧 的Carry下,最终在本届智能算法赛拿到了复赛总榜单Top1的 ...

最新文章

  1. python——元素列表基础
  2. 阿里某新员工感慨:入职阿里三个月生活一团糟,想辞职休息
  3. python 判断列表list是否为空
  4. operate XML file (Open,Insert)
  5. ARC下带CF前缀的类型与OC类型转换
  6. C#实现Windows后台服务实例浅析
  7. 【CodeForces - 245C 】Game with Coins (思维,贪心)
  8. python制作聊天机器人原理_用 Python 来做一个聊天机器人吧!(一)
  9. wex5部署教程到数据库
  10. IE9 新功能 五大新特点
  11. 你的第一个自动化测试:Selenium 自动化测试
  12. win10重新安装应用商店
  13. 【C++】归并排序-分治(图解+例题)
  14. Qt Design studio使用
  15. python控制电机_如何用Python控制LEGO Wedo 2.0的电机
  16. Python使用string.Formatter()制作打印模板
  17. qq 微信 服务器繁忙请稍后重试,微信支付提示 系统繁忙请稍后重试?
  18. Extention匿名类
  19. Spring Security oauth2.0微信小程序登录
  20. Latex从.dtx文件分解得到.sty文件

热门文章

  1. linux操作命令comm,Linux
  2. c# list 容量_C#中数组、ArrayList和List三者的区别 转
  3. Python模拟登陆 —— 征服验证码 7 京东
  4. 世界不是gameBoy
  5. 某公司故障分析案例(实战案例)
  6. SQL Server:Like 通配符特殊用法:Escape
  7. Vigenere加密法C++实现代码
  8. mysql逗号分隔函数_mysql split 函数(用逗号分隔)的实现
  9. 如何用php编写注册表格,发布PHP-MySQL注册表格
  10. mysql建表2个索引是啥意思_Mysql建表与索引使用规范详解