【第十一届泰迪杯B题产品订单的数据分析与需求预测产品订单的数据分析与需求预测 】第二大问代码分享+解题思路(EDA数据再探索+LightGBM模型)

【第十一届泰迪杯B题产品订单的数据分析与需求预测】第二大问代码分享+解题思路(EDA数据再探索+LightGBM模型)

写在前面:

​ 拖了这么长时间,一方面是我在找实习面试准备、另一方面是在做第二问的过程中,我始终坚持要做出真实的、负责的、优秀的作品,为此我查阅了很多资料,做了很多实验我做了很多工作,尝试了很多模型,有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月就等完整数据出来再进行预测

题解主要部分目录内容:

在这里插入图片描述

EDA数据再探索:

以地区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个区间,价格由高到低。这将有利于我们对预测数据时,不同区域、不同产品的价格进行区间编码匹配。

特征工程+LGBM建模预测

通过数据再探索和第一问的分析,我们需要构造一些特征,最后主要准备的数据格式为:

在这里插入图片描述

增加待预测的三个月数据(2019年1,2,3,月)

以增加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值很小,模型效果很不错。

挑选出101区域的模型进行模型验证:

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题论文给大家借鉴。

如需获取代码详情请看。社区
应粉丝建议,我创建了一个交流群,欢迎各位小伙伴入群交流问题:
在这里插入图片描述

  • 22
    点赞
  • 234
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葡萄成熟时_

谢谢您,祝您生活愉快,所想及得

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值