一、赛题理解
- 时序预测、回归类问题
任务一:预测未来一个月,A/B两个岗位按天的业务量
任务二:预测未来一个月,A/B两个岗位每天48个时段的细分业务量(半小时一个时间段) - 数据:
date:日期
post_id:A、B两种业务类型
biz_type:业务类型细分,A有13种,B只有一种
period:时段(每天48个)
amount:业务量(label)
PS;我又截图截晚了,官网只剩下这点了。。
二、数据预处理
- 周期性
取2020年11月的数据观察,分A/B两种业务类型,可以发现具有明显的周期性。
- A类型:以一周为周期,工作日业务量大,周末骤减,且周六业务量总大于周日业务量。
- B类型:以一周为周期,工作日业务量大,周末基本为0。11月数据有上升趋势(这一点比赛时有些忽视)。
2. 对称性:
取任意一天数据,可以观察出明显的对称性。
- 工作时间有业务量,非工作时间业务量为0。中午时间会有短暂的业务量下降,以正午时刻为对称轴,业务量有对称趋势。
- 同时,周中也会有对称性:周一、周五业务量较大,周三业务量会下降。
- 异常数据
由于跨越了2020年初的这段时间(疫情影响),所以,业务量会有不规则突变,考虑将这部分数据剔除。
训练集数据仅选取2020年4月以后的数据 - 数据筛选
由于预测的11、12月均没有节日和调休情况出现,所以去掉’NH’,‘SS’,'WS’三种类型的数据。
三、特征工程
- 基础特征:年、月、日等时间特征
- 原始重要特征:periods(时段)、WKD_TYP_CD(指示是否是工作日)
- 周期性特征:
dayofweek(星期几):用于刻画周期性 - 对称性特征:
abs_period:与中间时段的绝对值差,能体现正午对称性。
abs_week:以周三为对称轴的绝对值差,周末置为0。 - 趋势性特征:年底业务量增大,刻画出向上递增的趋势。
week_num:一年内的周数(1-52)
day_num:一年内的天数(1-365) - 其他特征:
work_time:刻画工作时间的特征
q1:特征交叉,强特增益。(效果不明显,不过其他比赛可以用)
四、模型优化
比赛时囤积了不少模型,从最开始开源的lightgbm开始,后面又做了XGB、catboost、RandomForest等等(全部都是树模型)。
- 模型选择:XGB
无论是A榜还是B榜,XGB都表现出非常好的稳定性。
A榜任务一单模:0.0505
B榜任务二单模:0.1699 - 做法:由于A/B换榜时shake了一下。任务一换榜之后,单模0.1,但任务二XGB单模能到0.169,任务二预测较为稳定准确。最后通过分析数据走势,采取通过任务二按天汇总(求和)得到任务一按天的结果,此方式0.08255。
- 网格搜索调参:有一定的提升,但只在万分位上提升了一点点吧。
- 换评价函数MAPE:之前一直选取的是xgb自带的rmse评价指标,B榜突发奇想换了一下,对于B类型的业务有不小的提升。0.169—>0.164
五、规则与Trick
- 调整系数
由于年底业务量增加,特征和模型对于这部分识别不到位,需要人为的去调整一下。A/B类型业务分开乘以系数。
0.08225–>0.063左右 - 放缩操作
由于任务一调整系数之后预测的准确率较高,将任务二的每个时段占全天业务量的比例计算出来,乘以任务一中每天的业务量,对于任务二的数据按比例放缩。
0.163–>0.147左右
六、最终结果
任务一:0.062
任务二:0.147
总分:0.08752
七、总结与感悟
又到了矫情阶段,求轻喷555~~
- 数据为基、特征为王:
真的是数据竞赛永恒不变的真理。
(1)看榜一大佬,只多加了2018年10-12月的数据,多做了两个节假日前后标识特征,任务一能上到0.048+。数据筛选做的好,特征构造的巧,上分如喝水。
(2)我本人当时limzero大佬开源baseline之后,只加了一个貌似week_num特征就从0.11–>0.095,可见特征重要性。 - 多做图多观察:
在写这篇分享帖时,为了让周期性和对称性展示的更明显,特地去画了几张图,观察到了比赛时没有发现的规律:B业务每周整体有一个向上的递增,趋势性十分明显。如果早点观察到这一点,我可能会在乘系数阶段对B业务每周乘以不同的系数,呜呜呜,千金难买早知道啊,哎~ - 对规则部分可以刻画的更细致一些。
比如:上面说的每周递增
再比如:不光是用乘法,可以加一个值说不定有好的效果呢。 - 模型要多元化
该学学别的模型了,别总用那几个树模型(此处应该配一张锤自己脑壳儿的表情包hhh)。看大佬们分享的prophet、时间序列分解等等,应该勇于创新,不能总停留在一个“舒适区”。这样A/B换榜时,储存多个模型也不容易被shake下去。 - 不管怎么说,还是要感谢limzero大佬的开源分享,在基础上二次创新,让我A榜能很快上到一个非常高的分(A榜0.078,rank3)。
- 多总结多分享。
我是看别人baseline一点点学习数据竞赛的,不断成长。所以,也想把这份爱心传递下去吧,在总结分享的过程中,也是对自己的学习方法一种复习,如果能帮助到大家就更好了,嘻嘻~ - 最后,还是要感谢群里各位大佬们的思路分享,开阔视野,一起提升成长。感谢朋友“爱撒谎的小超”、“尼888888”、“不学无墅”的支持与帮助。
附上代码,供参考:
import pandas as pd
import numpy as np
import datetime
import math
import os
# import xgboost as xgb
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
pd.set_option('display.min_rows', 100)
#--------------------特征工程函数-------------------
def timer(x):
if x in range(18,25):
return 3
elif x in range(25,30):
return 2
elif x in range(30,37):
return 3
elif x in range(37,39):
return 1
else:
return 0
def date_feature(data):
data['type']=data['WKD_TYP_CD'].map({
'WN':0,'SN': 1, 'NH': 1, 'SS': 1, 'WS': 0})
data['date']=pd.to_datetime(data['date'])
data['dayofweek']=data['date'].dt.dayofweek+1
data['day']=data['date'].dt.day
data['month']=data['date'].dt.month
data['year']=data['date'].dt.year
data['week_num']=data['date'].dt.weekofyear
data['abs_period']=data['periods'].apply(lambda x:abs(x-24))
data['day_num']=data['date'].dt.dayofyear
data['abs_week']=data['dayofweek'].apply(lambda x:0 if x in [6,7] else abs(x-3)+1)
data['work_time1']=data['periods'].apply(timer)
data['sin_period']=data['periods'].apply(lambda x:math.sin(x*math.pi/48))
data['q1']=data['abs_period']**2+data['abs_week']**2
data[&#