赞
踩
拖了这么长时间,一方面是我在找实习面试准备、另一方面是在做第二问的过程中,我始终坚持要做出真实的、负责的、优秀的作品,为此我查阅了很多资料,做了很多实验我做了很多工作,尝试了很多模型,有LSTM、传统的Arima等等、写了很多代码,看到很多粉丝私信问我什么更新第二题我也很着急,还有粉丝给我展示了他买的其他博主的作品,真就两块儿代码,还不能运行,这不纯纯骗人嘛!!,所谓失败乃是成功它娘,经过无数次尝试失败,最后终于做出来了,选择了LGBM模型并且预测效果很好!
我将我所有写的代码分为了解题的代码文件夹和其他代码文件夹,这不仅仅只是为了解题,更是希望其他的代码能为大家带来一定的帮助,以后可能用的上代码,就大大减少了工作量了。我将会在明天录制第二问的讲解代码视频,以及配套解题工作流程的思维导图,我希望不单单是为了解题而解题,而是能真正帮助大家达到以赛促学的目的。
本题解仅我个人的解法!!!
根据第一问的简单分析,和衍生出了一些特征,例如年月日、价格标签、是否节假日、week等
读入第一问保存的文件csv,process1.csv,进行数据再探索,发现需要对价格进行更细致的分区间,我采用最优分箱操作,将每个产品的价格归为不同的价位区间,因为相同的产品,它在不同的地区,不同的时间,价格会有波动,所以使用分箱,可以大致归纳价格特征。
然后再在此基础上,衍生出其他特征,星期几、是否工作日等(因为跟据EDA数据探索和第一问可视化分析,发现周末、还有不是工作日时,需求量会有所上升。)
然后主线任务思想是,先将现有的各种产品(3931种产品)进行以地区、销售区域编码 产品编码 产品大类编码 产品细类编码组合,先设置其在2018-12-21到2019-1-31的需求量都为0。作为表sub1(先预测出19年的1月)
然后将sub1进行衍生特征,构造为与df相同的特征列,然后sub1和df进行拼接为一个大表
然后将大表经过特征工程处理后,划分天数大于等于1207(2018-12-21日)的数据为预测集、天数大于1176小于1207的数据作为验证集,天数小于1176的作为训练集。
分地区进行LGBM建模训练,并且预测未来大于1207的预测集,
然后将预测的数据,增加回原数据中作为训练集,再如上诉步骤构建19年2月,进行预测2月的,如此重复,又预测3月的。
由于样例数据,数据不完整,所以我暂时值预测了19年的1月,然后我们预测目标文件predict_sku0.csv中的产品在样例数据中没有,(数据不完整),所以预测1、2、3月就等完整数据出来再进行预测
以地区101为例:
sns.barplot(x='是否节假日', y='订单需求量', data=df_101)
sns.barplot(x='销售渠道名称', y='订单需求量', data=df_101)
可以看出是节假日和线上销售的需求量要高些,这将会在特征工程时进行需求量趋势构建时有一定的帮助
我们再看看101地区各个细类编码的产品需求量如何:
其总需求量和平均需求量:
x = df_101['产品细类编码']
y = df_101['订单需求量']
plt.figure(figsize=(15,5))
plt.title('订单需求量 by 产品细类编码')
plt.xlabel('产品细类编码')
plt.ylabel('订单需求量')
plt.scatter(x,y)
plt.show()
plt.figure(figsize=(20,6))
fig = sns.barplot(x='产品细类编码', y='订单需求量', data=df_101)
可以发现细类编码为407的需求量总的最高,可是平均需求量却是402的最高,说明101地区的407可能存在某一时间段销量暴增的情况。这在建模的特征工程处理时,可以以平均值进行拉平处理。
我们再看看时间对需求量的影响
可以发现101地区在10月和2017年的需求量最高,以及平均下来的每个月需求量,可以发现其在4月和10月,12月的需求量居多,这可能是促销日、节假日等影响,所以后续我们需要衍生这些特征。
再看看week周对销售量分布
可以看出week其实与month的特征没太大差别,所以week列衍生可能用不上
数据处理部分主要是做了个价格分箱处理,像上面说过的,因为相同的产品,它在不同的地区,不同的时间,价格会有波动,所以使用分箱,可以大致归纳价格特征。
from scipy.stats import stats
def optimal_bins(Y,X,n):
"""
:Y 目标变量
:X 待分箱特征
:n 分箱数初始值
return : 统计值,分箱边界值列表、woe值、iv值
"""
r = 0 #xia相关系数的初始值
total_bad = Y.sum() #总的坏样本数
total_good = Y.count() - total_bad #总的好样本数
#分箱过程
while np.abs(r) <1: #相关系数的绝对值等于1结束循环,循环目的找寻最好正反相关性
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX
qua = X.quantile(i/(n+1)) #quantile把给定的乱序的数值有小到大并列分成n等份,参数表述取出第百分之多少大小的数值
#i的取值范围是1->n 1/n.2/n 3/n...n/n
cut.append(round(qua,6))
return cut
#对RevolvingRatio列进行分箱操作:
cut_bins = optimal_bins(df.订单需求量,df.产品价格,n=10)
cut_bins
df['价格区间'] = pd.cut(df['产品价格'],cut_bins,labels=[x for x in range(len(cut_bins)-1)])
df
分箱后生成6个区间,价格由高到低。这将有利于我们对预测数据时,不同区域、不同产品的价格进行区间编码匹配。
通过数据再探索和第一问的分析,我们需要构造一些特征,最后主要准备的数据格式为:
以增加2019年1月数据为例:
先构造各产品的的2019年一月数据:
我们需要借助销售区域编码+大类编码+细类编码+产品编码为zuhe列:
df['zuhe'] = df['销售区域编码'].astype(str)+'_'+df['产品大类编码'].astype(str)+'_'+df['产品细类编码'].astype(str)+'_'+df['产品编码'].astype(str)
df
然后构建一月的数据:
现阶段给出的数据,有3931种,我们将先构造一下这3931种产品,每天的需求量为0,加入到原数据中
先预测一个月的,再将一个月的数据加入到原始作为训练集,再去预测第二个月的,
意思是先预测出3931种产品2019-1月的需求量,再去预测2019-2,最后时2019-3月。
#从2018-12-21到2019-1-31日的数据
dt1 = pd.date_range(start="20181221", end="20190131", freq="D")
dt1
len(dt1)
dates=[]
need=[]
ids =[]
for d in dt1:
date = str(d).split(' ')[0] #得到日期xx-xx-xx
dates=dates+[date]*len(set(df['zuhe']))
need = need+[0]*len(set(df['zuhe']))
ids=ids+list(set(df['zuhe']))
xxxxx
然后对temp表格进行处理和构造特征,得到与df相同的数据格式,以及数据类型:
可以看出,我们先设置出各种产品每天的需求量为0,165102行是因为有3931产品,从2018-20-21到2019-1-31有42天,所有3931*42=165102。
拼接temp和df为整个数据集:
这样就看的懂了构建的什么数据集了。
滞后特征是将时间序列预测问题转化为监督学习问题的经典方法。对销售的目标变量引入滞后。我使用的最大延迟是60天。这完全取决于你想引入多少滞后。
df['产品编码_avg'] = df.groupby('产品编码')['订单需求量'].transform('mean').astype(np.float16)
df['销售区域编码_need_avg'] = df.groupby('销售区域编码')['订单需求量'].transform('mean').astype(np.float16)
df['产品大类编码_need_avg'] = df.groupby('产品大类编码')['订单需求量'].transform('mean').astype(np.float16)
df['产品细类编码_need_avg'] = df.groupby('产品细类编码')['订单需求量'].transform('mean').astype(np.float16)
df['销售渠道名称_need_avg'] = df.groupby('销售渠道名称')['订单需求量'].transform('mean').astype(np.float16)
xxxxxxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
我将计算每周销售的滚动平均数。更多的特征,如滚动最小值,最大值或总和也可以计算。同样,同样的功能也可以用于计算需求量
df['rolling_need_mean'] = df.groupby(['销售区域编码','产品编码','产品大类编码','产品细类编码'])['订单需求量']xxxxx
这是滚动窗口技术的高级版本。在滚动窗口的情况下,当窗口随着时间向前移动而滑动时,窗口的大小是恒定的。因此,我们只考虑最近的值,而忽略过去的值。 我将计算需求量的扩大平均值。还可以计算更多的特征,如扩展最小值、最大值或总和。同样,同样的功能也可以用于计算需求量。
我将创建一个需求量趋势特征,如果每日需求量大于整个持续时间的平均值(d_1 - d_1248),则为负值。可以添加更多的趋势特性,但我只添加这一个以保持简单。
data = pd.read_pickle('data4_5.pkl')
valid = data[(data['D']>=1176) & (data
for store in states:
df = data[data['销售区域编码']==store]
#Split the data
xxxxx
#Train and validate
model = LGBMRegressor(
n_estimators=1000,
learning_rate=0.3,
subsample=0.8,
XXXXX
)
print('*****Prediction for 销售区域: {}*****'.format(store))
model.fit(X_train, y_train, eval_set=[(X_train,y_train),(X_valid,y_valid)],
eval_metric='rmse', verbose=20, early_stopping_rounds=20)
valid_preds[X_valid.index] = model.predict(X_valid)
eval_preds[X_test.index] = model.predict(X_test)
filename = 'model'+str(store)+'.pkl'
# save model
joblib.dump(model, filename)
del model, X_train, y_train, X_valid, y_valid
RMSE值很小,模型效果很不错。
model = joblib.load("models\model_101.pkl")
model
df = data[data['销
y_valid
x_axis=np.linspace(1,len(y_valid),len(y_valid))
font1 = {'family' : 'SimSun','weight' : 'normal','size' : 20,}
colors =['black','green','yellow','blue','cyan','red','orange','pink']
plt.figure(dpi=300,figsize=(28,12))
plt.plot(x_axis[:200],y_valid[:200])
plt.plot(x_axis[:200],s[:200])
plt.legend(['true','prediction'],prop = {'size':20})
# plt.scatter(x_data,y_data_yuemo,color='blue')
plt.tick_params(labelsize=20) #修改刻度显示大小
可以看出,模型预测的结果拟合的很好,需求量走势和峰值等都相差不多。相信完整数据出来后,模型效果会更好。
可以看出我们前期的特征工程处理的很好。
我们现在将19年1月的预测结果进行汇总处理,然后再去predict_sku0.csv进行匹配,得到每个产品的1月需求量:
读取待预测的predict_sku0.csv:
#制作透视表得到所有产品19年1月的需求量
result_df = pd.pivot_table(result_df, index=['销售区域编码','产品大类编码','产品细类编码','产品编码'], columns='订单日期',
values='订单需求量', aggfunc=np.sum,fill_value=0).reset_index()
result_df
xxxxx
你会发现进行匹配后,结果变少了,这是因为predict_df中有的产品,在result_df中没有,这是因为目前只有样例数据,没有完整的数据导致的。 等完整的数据出来后,匹配将会很完美。所以现在暂时不去做预测2、3月无意义的事了。等完整数据发布了,再运行代码。
压缩包内容为:
会更新代码讲解视频和B题论文给大家借鉴。
如需获取代码详情请看。社区
应粉丝建议,我创建了一个交流群,欢迎各位小伙伴入群交流问题:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。