JDD专栏-2017JDD_销量预测&2018JDD人口预测

       俗话说的话,没有正确的模型,只是恰好模型对这个问题的解答很好。JDD销量预测的概述是对未来3个月的销售额(卖出去多少钱)进行预测。

一:简单的规则预测

       首先,题目提供给我们5张表,分别是ads,comment,product,order,sales_sum(前缀是t_)的数据。我们先来确定一下label是什么,label就是sales_sum表里面的sale_amt_3m。既然label是和sale_amt_3m有关的数值数据,那么通过观察,在oeder表中,存在sale_amt即当月当天的销售额度信息。这个时候大家会绘制一些曲线,最容易想到的就是绘制sale_amt_3m以及sale_amt随时间变化的情况。其中,绘制曲线的目的可以帮助我们看到数据中的一些异常波动点和趋势。异常波动点的处理需要凭借对数据的观察以及尝试线下去发现,最后得到y± σ 的值作为最终的label,详情可以参考kaggle的房价预测,对数据中的y进行清洗得到清洗后数据,可以提高不少成绩。对数据进行清洗后,就要首先考虑,什么和sale_amt_3m有关,最容易的想法就是

sale_amt_3m = sale_amt_m_1 + sale_amt_m_2 + sale_amt_m_3

那么,后面的sale_amt_m_i 要从哪里得到呢,这里面,可以有两个简单的思路,第一个思路就是sale_amt_m_i都是同一个月的数据,用i月的数据乘3得到sale_amt_3m的值。第二个思路就是sale_amt_m_i为三个不同的月份的数据。当然距离目标越近的影响越大,那么就来实现第一种思路,以一种最简单的思路去实现。

      123

 

#coding:utf-8

# 主要思路 寻找当月销量和未来90天的一个系数 一个简单的规则 A榜 0.415的线上分数
# 改善思路,数据去掉一些异常值
# 主观相反,推测未来销量不低于当月销量的一个倍数

import pandas as pd
import math
# 读取原始数据 订单数据
dir = '../data/'
t_order = pd.read_csv(dir + 't_order.csv')
t_order['year_month'] = t_order['ord_dt'].map(lambda x:str(x)[:7])
# 统计历史的sum根据年月统计
t_order_sum = t_order[t_order.columns.drop(['ord_dt','pid'])].groupby(['shop_id','year_month'],as_index=False).sum()

# 此处可以手动查看 11 12 1 月份每个shop当月销量的的sum 
# 2016-11 2016-12 2017-01
month_4_sale = t_order_sum[t_order_sum['year_month']=='2016-11'][['sale_amt','shop_id','offer_amt','rtn_amt']]
month_4_sale['sale_amt'] = month_4_sale['sale_amt']
# 读取未来90天的数据
true_12_sale = pd.read_csv(dir + 't_sales_sum.csv')
true_12_sale['year_month'] = true_12_sale['dt'].map(lambda x:str(x)[:7])
# 2016-11 2016-12 2017-01
true_12_sale = true_12_sale[true_12_sale['year_month']=='2016-11']
# 计算比值
all_ = pd.merge(month_4_sale,true_12_sale,on='shop_id').drop_duplicates('shop_id')

print sum(all_['sale_amt_3m'] / all_['sale_amt']) 


# 以下是预测过程
# month_4_sale = month_4_sale.groupby(['shop_id'],as_index=False).sale_amt.sum()
# month_4_sale['sale'] = month_4_sale['sale_amt'] * (8025.17717344 / 3000)
# month_4_sale[['shop_id','sale']].to_csv('./1203_e_sale_ruler.csv',index=False,header=False)

 

以上代码的解释,主要是寻找当月的销售与未来三个月的关系,那么具体的关系量,要通过之前的数据去确定,确定的过程就是用已知当月数据去寻找与未来三月的关系。这里面,经过一些简单的寻找,发现在当月销量* 0.26左右是找到的一个比较好的值。线上A榜的验证得分在0.415左右。对于第二种思路,由于懒得验证所以没有测试,就是sale_amt_m_i 分别属于不同的月份,拟合一个比较好的不同系数。思路扩展一下,我们可以对历史的i天数据(i的取值是之前可用的所有数据,去找一个系数相关的表达式)表示为y=a1*x1 + a2*x2 + a3*x*3 + ... 这些过程都是自己线下去拟合,推进大家可以看一下 段子的规则直播 ,他讲了蚂蚁商铺的一个规则,方法可以学习一下,同时他也降了UAI的相关内容。

 

二:模型预测

通过使用销量数据我们就可以得到0.415的成绩,那么,增加一些其他数据,按照道理来说应该可以提高不少。通过数据的简单了解,发现其中含有6月和11月数据的小波动。按照正常的过程,应该对这部分数据进行一些平滑处理,也就是让整体数据更加适合模型去拟合,机器本来不会超过人类的智慧,对数据的预先处理可以更好的帮助机器去理解数据。

那么,首先确定一下我们要做的主体思路,就是根据历史去统计,最后以未来3月作为标签。那么,提供的月份有很多,选择那些月份,选择那些星期,对网购节假日如何标记,都是要思考的问题。这里,我选择以月份为周期,就分别统计1,2,3,4,5... ... 当月的数据,作为统计的到的特征x,这样就可以放入模型中去拟合,其中因为t月对t+1月的影响大于t-1月对t+1月的影响。所以如果直接以t对t+1进行预测,那么线下的结果太好,但是题目中却没有给预测目标4月之前的2,3月数据,所以这种方式不能实际实现我们想要的目标。所以,这里采用选择n个月分的数据,例如选择1,2,3,....的数据分别预测模型,最后得到的预测值加权得到结果。

 

这里面的特征建立过程不详细描述,只是介绍一下最终建模的过程。

 

# 标签特征 之前的部分为制作特征,这个制作特征的过程每个人有不同的思路,这里我就不写我的具体特征流程
datas = []
y_train_1 = X_train_1.pop('sale_amt_3m')
y_train_2 = X_train_2.pop('sale_amt_3m')
y_train_3 = X_train_3.pop('sale_amt_3m')

datas.append([X_train_1,y_train_1])
datas.append([X_train_2,y_train_2])
datas.append([X_train_3,y_train_3])

# 多组模型融合
import xgboost as xgb

print('bulid _3_ model')
# 这里是建立3个相同的模型,放入一个list中
bsts = []
bst1 = model1()
bsts.append(bst1)
bst2 = model2()
bsts.append(bst2)
bst3 = model2()
bsts.append(bst3)
# 定义评测函数
import numpy as np
def score_function(ytrue, ypre):
    ypre = np.asmatrix(ypre)
    ytrue = np.asmatrix(ytrue)
    a = ypre - ytrue
    b = abs(a).sum()
    c = ytrue.sum()
    return b / c
# 把轮回预测,其实这个部分来自于CS231N的第一课的内容,详情可以看看 FEI FEI LI的CS231N
for i in range(len(bsts)):
    bsts[i].fit(datas[i][0].as_matrix(),datas[i][1].as_matrix())
for i,bst in enumerate(bsts):
    for j,data in enumerate(datas):
        if i!=j:
            res = bst.predict(data[0].as_matrix())
            print('data:%s,bst:%s'%(j,i))
            print(score_function(data[1],res))
            print('------------')

gc.collect()

res = []
for i in bsts:
    res.append(i.predict(x_train_5.as_matrix()))
print('generate result')
# 这里需要去找一些权重系数
res = pd.DataFrame(res).T
res.columns=['pre0','pre1','pre2']
# 0.7 0.4 0.5
res = pd.DataFrame(((res.pre0*0.9 + res.pre1*1.2 + res.pre2*0.9 )/3)).reset_index()

res['index'] = res['index'] + 1

ResFileName = './result.csv'
res.to_csv(ResFileName,header = False,encoding='utf-8',index=False)

 

 

 

最后把模型的结果+规则得到的结果简单0.5权重加权,最终可以得到A榜的0.394的成绩,之后我没有继续做,因为个人实在能力有限,并且由于最近心浮气躁,导致不能更好的去实现一些东西,比如天模型,自己统计90天的数据再统计后90天的数据,之后以90-t的移动预测90-t的目标,保证90-t的尺度和90天大小一致。

2018年到了,希望可以完成一次top20和top10的梦想,顺便脱单,哈哈哈,233,加油

 

又到了一年一度的JDD,今年是人口预测,经典的时间序列长期预测,由于最近要考六级,所以没怎么参加。

题目连接https://jdder.jd.com/index/jddDetail?matchId=3dca1a91ad2a4a6da201f125ede9601a

 赛题的数据包括人口流动、人口来源去向、移动设备用户占比三个样本,其中人口数目是经过预处理后的相对值,日期和地区代码均为模拟数据。

参赛者需要预测未来10天内各个区县每天的人口变动情况,同时也要填补出训练数据中缺失的5天各个区县每天的人口变动情况。。在https://zhuanlan.zhihu.com/p/50623176这个初赛开源的基础上,很容易可以改写一下,可以拆分为2个模型,一个预测训练数据中缺失的5天(8.19-8.23),另一个预测未来十天。在这里感谢xiejiajia大佬的开源了改写后的lgb代码(关键是把数据下载发我学习一波),赛后他自己写的所有方案也会在这边贴出来。使用时,可以将lgb模型与别的模型的结果log变换后做差,误差超过阈值的,然后将两者以一定比例融合。
随便给个xiejiajia在天池直播间的传送门,据说单身,里面有他联系方式,快找他去搞基:
https://tianchi.aliyun.com/forum/videoStream.html?spm=5176.11510306.4851108.14.61a44b260Gwi6P&postsId=5596&_lang=zh_CN

5天的预测

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Dec  2 09:50:26 2018

@author: xiejiayuan
"""

#import xgboost as xgb
import lightgbm as lgb
import pandas as pd
import numpy as np
from datetime import date
import datetime
import warnings
warnings.filterwarnings("ignore")

flow_train = pd.read_csv('./flow_train.csv')
tran_train = pd.read_csv('./transition_train.csv')

def year(date):
    date = str(date)
    return int(date[0:4])
def month(date):
    date = str(date)
    return int(date[4:6])
def day(date):
    date = str(date)
    return int(date[6:8])
flow_train['year'] = flow_train['date_dt'].apply(year)
flow_train['month'] = flow_train['date_dt'].apply(month)
flow_train['day'] = flow_train['date_dt'].apply(day)

flow_train['address'] = flow_train['city_code']+':'+flow_train['district_code']
address = list(set(flow_train['address']))

flow_train_1 = flow_train[flow_train['date_dt'] < 20170814]
flow_test_1 = flow_train[flow_train['date_dt'] >= 20170814]

label = ['dwell','flow_in','flow_out']
feature = ['year','month','day']

def rmsle(y_true, y_pred):
    return 'RMSLE', np.sqrt(np.mean(np.power(np.log1p(y_pred) - np.log1p(y_true), 2))), False

star = '20170818'#819-823
dates = []
for i in range(1,6):
    date_format = datetime.datetime.strptime(star,'%Y%m%d')
    fut_date = date_format + datetime.timedelta(days=i)
    dates.append(int(datetime.datetime.strftime(fut_date,'%Y%m%d')))
test_df = pd.DataFrame({'date_dt':dates})
test_df['year'] = test_df['date_dt'].apply(year)
test_df['month'] = test_df['date_dt'].apply(month)
test_df['day'] = test_df['date_dt'].apply(day)
test_df['date_dt'] = test_df['date_dt'].astype(str)

result = pd.DataFrame(columns=['date_dt', 'city_code', 'district_code', 'dwell', 'flow_in', 'flow_out'])

for ad in address:
    ad_split = ad.split(':')
    test_df['city_code'] = ad_split[0]
    test_df['district_code'] = ad_split[1]

    for y in label:
        train_x = flow_train[flow_train['address']==ad][feature]
        train_y = flow_train[flow_train['address']==ad][y]
        test_x = flow_test_1[flow_test_1['address']==ad][feature]
        test_y = flow_test_1[flow_test_1['address']==ad][y]


        gbm = lgb.LGBMRegressor(num_leaves=50,
                        learning_rate=0.05,
                        n_estimators=1000)
        gbm.fit(train_x, train_y, 
                eval_set=[(test_x, test_y)],
                eval_metric='l1',
                early_stopping_rounds=5)
        # predict
        y_pred = gbm.predict(test_x, num_iteration=gbm.best_iteration_)
        # eval
        print('The rmsle of prediction is:', rmsle(test_y, y_pred)[1])
        test_df[y] = gbm.predict(test_df[feature])
    result = pd.concat([result,test_df[result.columns]])

result['date_dt'] = result['date_dt'].astype(int)
result = result[['date_dt', 'city_code', 'district_code', 'dwell', 'flow_in', 'flow_out']]
result.to_csv('./prediction_5.csv', index=False, header=None)
 

 10天的预测

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Dec  2 09:50:26 2018

@author: xiejiayuan
"""

#import xgboost as xgb
import lightgbm as lgb
import pandas as pd
import numpy as np
from datetime import date
import datetime
import warnings
warnings.filterwarnings("ignore")

flow_train = pd.read_csv('./flow_train.csv')
tran_train = pd.read_csv('./transition_train.csv')

def year(date):
    date = str(date)
    return int(date[0:4])
def month(date):
    date = str(date)
    return int(date[4:6])
def day(date):
    date = str(date)
    return int(date[6:8])
flow_train['year'] = flow_train['date_dt'].apply(year)
flow_train['month'] = flow_train['date_dt'].apply(month)
flow_train['day'] = flow_train['date_dt'].apply(day)

flow_train['address'] = flow_train['city_code']+':'+flow_train['district_code']
address = list(set(flow_train['address']))

flow_train_1 = flow_train[flow_train['date_dt'] < 20171026]
flow_test_1 = flow_train[flow_train['date_dt'] >= 20171026]

label = ['dwell','flow_in','flow_out']
feature = ['year','month','day']

def rmsle(y_true, y_pred):
    return 'RMSLE', np.sqrt(np.mean(np.power(np.log1p(y_pred) - np.log1p(y_true), 2))), False

star = '20171104'
dates = []
for i in range(1,11):
    date_format = datetime.datetime.strptime(star,'%Y%m%d')
    fut_date = date_format + datetime.timedelta(days=i)
    dates.append(int(datetime.datetime.strftime(fut_date,'%Y%m%d')))
test_df = pd.DataFrame({'date_dt':dates})
test_df['year'] = test_df['date_dt'].apply(year)
test_df['month'] = test_df['date_dt'].apply(month)
test_df['day'] = test_df['date_dt'].apply(day)
test_df['date_dt'] = test_df['date_dt'].astype(str)

result = pd.DataFrame(columns=['date_dt', 'city_code', 'district_code', 'dwell', 'flow_in', 'flow_out'])

for ad in address:
    ad_split = ad.split(':')
    test_df['city_code'] = ad_split[0]
    test_df['district_code'] = ad_split[1]

    for y in label:
        train_x = flow_train[flow_train['address']==ad][feature]
        train_y = flow_train[flow_train['address']==ad][y]
        test_x = flow_test_1[flow_test_1['address']==ad][feature]
        test_y = flow_test_1[flow_test_1['address']==ad][y]


        gbm = lgb.LGBMRegressor(num_leaves=50,
                        learning_rate=0.05,
                        n_estimators=1000,verbose_eval=False)
        gbm.fit(train_x, train_y, 
                eval_set=[(test_x, test_y)],
                eval_metric='l1',
                early_stopping_rounds=5)
        # predict
        y_pred = gbm.predict(test_x, num_iteration=gbm.best_iteration_)
        # eval
        print('The rmsle of prediction is:', rmsle(test_y, y_pred)[1])
        test_df[y] = gbm.predict(test_df[feature])
    result = pd.concat([result,test_df[result.columns]])

result['date_dt'] = result['date_dt'].astype(int)
result = result[['date_dt', 'city_code', 'district_code', 'dwell', 'flow_in', 'flow_out']]
result.to_csv('./prediction_10.csv', index=False, header=None)
 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值