基于:大航杯“智造扬中”电力AI大赛参赛经验
赛题背景
主办方为大航集团提供21个月江苏省杨中市1454家企业日用电量,来估计下一个月日总用电量
从给的数据分析,这次给的数据只有历史企业日用电量,用来估计日总用电量,是一个典型的时域分析问题
但是这同我们以往的时序问题不一样,向往常时序问题预测的是每个企业的未来每日的用电量,而这个比赛却是求全部企业的总数.
由于我报名比赛时候比较晚,比赛已经接近尾声,比赛5月18号开始,6月8号中午切换数据,13号截止,我6月8号晚上下载数据,由于我以前已经做了几个类似的比赛,但是一直没有系统的做一个,抱着锻炼的自己的态度,决定系统做一次,权当练手.
首先分析一下提交的结果,预测一个月的日总用电量,总共为31个数据,给的历史数据只有21个月的,按月的比例来看,只有21个值去训练值去预测一个值,根据往常的比赛经验来看,这种比赛适合使用规则方法来做,然而我剩下的验证机会不多了,只能用模型,但是过拟合的危险非常大,如果不能找到一个好的方法克服过拟合,复赛都进不去.
当然最后还是没有找到一个很好的办法,止步于复赛,不过这次比赛让我学到很多,主要通过这次比赛自己琢磨出来自己如何搭建基于IPython Notebook
的管道结构,这个管道帮我自动生成上万特征.
管道 #
什么是管道,在数据挖掘比赛中很多大神都着重讲了一定要搭建一个自动化的架构,我们暂且称他为"管道",这个"管道"我们要能够把数据倒进去,结果倒出来.
这个管道用专业的术语来看要有以下几个功能
- 能够自由添加
Feture
- 能够自动评判得到添加的
Feture
的效果 - 管道能够自己选择合适的参数训练模型
- 能够输出结果
其实简单来说,我们要做的是一个能够非常方便的扩展的脚手架,我们不可以第一次就把所以的特征全部找出来,所以我们要搭建一个能够实时添加Feture
的框架.
其实很早以前就看过类似文章,也有很多人推荐大神开源的一个脚手架,然而找到的大多是用python
实现
我因为一开始就是使用Notebook
进行数据挖掘,主要Notebook
能够提供一个实时的反馈,而纯python
,对于复杂多变的数据来说,显得非常笨重,你经常有个好想法想验证一下,又得重新跑一遍,尤其是对于我的机器配置来说,重新跑一边的时间都够我喝杯茶了.而且notebook
有个特点,可视化特别方便,有时候从数据上看不到,可以画个图表
好了,夸了这么久,现在就来仔细讲讲脚手架如何搭建.
我们先回到赛题,第一步审题,当时我看到日平均两个字,直接把日字省略,看成平均用电量,结果白白浪费了两个验证机会…..
审完了题我们来看我们要提交的数据,换数据后要预测十月日用电总量.我们来看看给我们数据,只有一份数据,表头如下
record_date,user_id,power_consumption
2015/1/1,1,1135
2015/1/2,1,570
2015/1/3,1,3418
2015/1/4,1,3968
2015/1/5,1,3986
解释一下字段,record_date
–日期,user_id
–企业id, power_consumption
–日用电量
非常简单,就这么简单单单的数据,我现在要教大家怎么从这么简单的数据上抽取6000维度的
我把代码已经推到Github
上了(由于数据比较少,我把数据也推上去了,方便大家本地跑跑,看完如果对你有帮助的话,请不要吝啬你的star哦),我就对照我的代码解释如何搭建一个可以跑出上万维度的脚手架
数据划分(split_samples.ipynb
)
#
首先要搭建本地预测集,也就是线下样本(这个很重要,有时候线下的结果很大程度对应你线上的结果)
给的数据要我们从前面21个月预测下一个月的日总用电量,我们很容易就能想到,那我们用前面20个月预测第21个月来做线下测试,但是这样我们就只有30个训练样本,要来预测30个,99.999%过拟合啊,首先我们要扩大样本,我们采用滑动移窗的方法把预测的样本按照月份推移,也就是分别预测9月8月7月等等
这种方法在实现Notebook
有几个难点,首先你划分了预测集,那么就也要划分训练集,就相当于把一份数据切分成好几份,切分完之后有个问题,你必须要隔离每个部分
举个例子,我们把训练集划分成为2份,1月到7月预测8月,2月到8月预测9月,训练1-7月数据集的时候,我们不能让这个训练集接触到2月到8月的数据,因为8月对于前一个训练集来说是未知的,
如果我们让第一个训练集接触倒第二个训练集我们称为信息泄露,很影响线上的结果
我们知道这个问题之后,我们就要用巧妙的方法来解决,首先我们要考虑我们代码的复杂度,以前我的解决训练集隔离的方法采用的是循环法,使用一个列表存贮所以训练集,然后使用for
循环分别传参到函数里面,这个方法能解决隔离训练集,但是有几个问题
在单个ipy
文件中训练所以的样本,在测试的时候跑起来太慢,而且要把数据全部加载在内存里面,这次数据量还算小,但是对于某些小内存的电脑来说,这种方法时不时就得报Memory Error
,而且感觉调试起来特别麻烦,所以一直在寻找更好的解决方案.
这次想到了一种巧妙的方法,虽然有点取巧但是效果我很满意.
我们先看到split_samples.ipynb
文件,首先我把数据划分为9个样本,一个预测样本.分别放入不同文件夹进行物理隔离.但是名字相同.
再其次我让ipy
能够获取参数,这样我通过外部参数就能更换数据集,平常添加Feture
的时候默认选取一个训练集,这样我开发的时候调试就非常方便,而且可以丢掉for
循环,还我一个清新脱俗的ipy
.
这里说一个小细节,因为我传参必须要外部调用这种,对于运行ipy
我使用了runipy
这个工具,然后我死活没有找到,如何使用runipy
把参数传倒ipy
里面去的方法(如果找到了请告诉我),我一拍脑袋那就转换成py
文件传过去,通过sys.argv
很轻松就能获取到,所以我又用jupyter nbconvert
的工具把ipy
转换成py
文件
所以绕了一圈最后又回到了py
上(手动滑稽).不过我们工作还是在ipy
上进行,生成的py
文件我好像没打开过….
特征提取(extract_fetures.ipynb
)
#
聊完如何划分数据集,现在我们进入如何特征提取,我们可以看到这次数据其实就三个特征:时间-企业-用电量.由于企业的信息只有一个id
,所以我首先提取的是时序的特征,首先把时间分解为八个维度
- dayofweek
- dayofyear
- days_in_month
- quarter
- week
- weekofyear
- month
- year
我们可以通过pandas
轻松提取出来
然后我们再从两个方向来看,第一个就是我们日总用电量特征,从全部企业日总用电量
第二个就是日用电量特征,从每个企业日用电量来看,这些特征我们使用简单统计又可以得到10个维度数据(mean,std,等等)
看完这些之后我们又可以从多个时间维度来看这些特征,比如30天前,90天前等等(我划分了30,60, 90,180,360五个),
这样我们就有了 8 * 2 * 5 * 10
个特征,但是这远远达不到我们说的上万维度,
现在我们从业务逻辑上来思考,因为我们知道,其实我们中国节假日和周末,天气这些对用电量影响非常大(我们老家打雷就停电…..)
所以我们要引入外部数据集,我采用两个爬虫分别是weather_crawl,holiday_crawl
爬取了天气和节假日的数据
我们按照前面的思路,从天气节假日的角度又可以划分出n多特征(这时候我的特征已经达到3000了)
完了这些基础特征后,我发现有些特征重要性特别大(使用Randomforest
得到),这时候我们又要请出我们第二大神器,交叉特征,比如月和假期的特征融合,这一波操作直接让我的特征到了6000+维度(如果将窗口扩大轻轻松松上万)
在这里要介绍一个特征生成的方法,有时候我们特征少,我们会采用自己命名的,自己生成,然后这个由于规律性比较大,
如果我们自己手动一个一个写的话,这上万Fetures
够你写的,所以要让他自己生成特征,我们只要建好模子就行,由于这次
时间仓促,基本上我没有自己手动命名feture
,全部都由程序生成,省掉很多代码量,具体可以看看代码实现,原理很简单.
训练模型(train_model.ipynb
)
#
训练模型的话,一般比赛都推荐先使用树模型,一方面速度快,第二个可以看到feture
的重要性,这对于你挑选交叉特征非常有用,模型调参的我这里就不讲,一方面我自己也不是很懂,第二个方面也网上教程也多,我讲的不一定比他好
这里要推荐一个发现有趣的包,mlxtend
,我用他来进行stacking
特别方便,有意思的时,我用他融合了四个模型,最后我的训练结果竟然为1,完全拟合了……
这个包可以很简单的进行模型的stacking
,然而这个比赛我没有把他用好(手动滑稽)
通过训练模型后我们把模型存到pkl
文件中,然后在用他来预测数据,这样在文件夹里转一圈的原因,因为原来打过部分比赛数据量太大,训练模型后内存不足,只能先del
,清空内存,再预测,存到文件夹后,结束进程,清空内存,这样就能省下空间来读取下一步数据.
总结 #
其实在这个脚手架上可以扩展很多东西,比如最后搏一搏单车变摩托的时候,我就在分割数据和训练数据之间加了一个过滤清洗数据层,在训练模型和融合特征之间加了一个降维的中间层.
建立一个好的脚手架只是能让你在增添特征,选择特征时更加轻松,其实比赛看的还是你对数据的一种掌控力,建立这个脚手架主要是为了节省更多时间给提取特征、选择特征上.特征决定你的上限.
这次比赛比较特殊,模型在这个比赛效果可能没有规则好,因为数据量太小,我stacking
一下直接完全拟合了.可惜验证的次数还是
太少,除去前面两次错误的提交,我只有三次验证机会,如果次数多一点的话,选择特征降维或者模型调参一下遏制拟合结果可能会好很多吧.
但是这次比赛自己学到了如何搭一个ipy
的管道和增加了一些特征调参、特征降维的经验。因为以前看到的搭建管道资料都是基于py
,很少基于ipy
的,所以把自己搭建ipy
管道经验分享出来,也希望自己写的这篇博文能够抛砖引玉,帮助大家搭建自己的完美管道.
附上我的开源示例: https://github.com/mrzhangboss/electricAI
大家觉得有帮助就给我点个star吧