天池---智慧交通预测挑战赛总结(一)

2017/07 -- 2017/09 天池智慧交通预测赛思路及模型总结(一)


说在前面的话


ML的建模方法和数据处理方法看来是一个CS专业学生必备的技能了,但是课余时间单纯的学习一些基础的模型感觉并没有实质性的进展,因此,决定在暑期参加一次比赛来更好地学习这样一个领域。本篇博客就是为了自己整理一下暑期比赛的材料,思路简要概述一下,然后附上源码。有兴趣的同学希望我们一起探讨。
(ps:整体选用了三种模型,本篇博客先总结传统机器学习模型:xgb和LGBM,关于LSTM和static后续再上。)

比赛链接: https://tianchi.aliyun.com/competition/introduction.htmspm=5176.100066.0.0.7dc8b4bacGhJST&raceId=231598

关于数据,如果需要的同学可以私信我。

第一赛季排名:61
复 赛 排 名: 12
队员:moka,LRain,过把火

只可惜天池的比赛跟京东的不相同,只能前五名进决赛,区区千分位的差距,心里还是感觉有些不甘。


1 赛题介绍


移动互联网时代的开启使得每个出行者都成为了交通信息的贡献者,超大规模的位置数据在云端进行处理和融合生成城市全时段,无盲区的交通信息。本届算法挑战赛以“移动互联时代的智慧交通预测”为主题,邀请参赛者基于互联网交通信息建立算法模型,精准预测各关键路段在某个时段的通行时间,实现对交通状态波动起伏的预判,助力社会智慧出行和城市交通智能管控。组委会将通过计算参赛者提交预测值和记录真实值之间的误差确定预测准确率,评估所提交的预测算法。

1.1 数据源

移动APP数据实时匿名收集用户地理位置信息, 处理和融合生成城市全时段,无盲区的交通信息。本次大赛将提供城市关键路段(link)的属性信息,路段间网络拓扑结构以及每条路段在历史各时间段内的通行时间,供参赛者建立和测试算法模型。

1.2 数据介绍

a. 路段(link)属性表
每条道路的每个通行方向由多条路段(link)构成,数据集中会提供每条link的唯一标识,长度,宽度,以及道路类型,如表1所示;图1示例了地面道路link1和link2的属性信息。

b. link上下游关系表
link之间按照车辆允许通行的方向存在上下游关系,数据集中提供每条link的直接上游link和直接下游link,如表2所示;图2示例了link2的in_links和out_links。

c. link历史通行时间表
数据集中记录了历史每天不同时间段内(2min为一个时间段)每条link上的平均旅行时间,每个时间段的平均旅行时间是基于在该时间段内进入link的车辆在该link上的旅行时间产出。字段解释如表3所示:

1.3 目标说明

其实初赛跟复赛的要求是一样的,都是基于已给数据来预测未来一段时间内的交通流量的情况。
初赛是预测2016年6月份[8:00-9:00)每条link上每两分钟时间片的平均旅行时间。
复赛:
复赛第一阶段
预测2017年7月1日至7月15早高峰、日平峰和晚高峰三个时段中各一个小时的数据,预测时段为:

  1. 早高峰: [8:00 - 9:00)
  2. 日平峰: [15:00 - 16:00)
  3. 晚高峰: [18:00 - 19:00)

复赛第二阶段
预测2017年7月1日至7月31早高峰、日平峰和晚高峰三个时段中各一个小时的数据,预测时段为:

  1. 早高峰:[8:00 - 9:00)
  2. 日平峰:[15:00 - 16:00)
  3. 晚高峰:[18:00 - 19:00 )

1.4 评估指标

指标说明:
ttp : 参赛者提交的预测通行时间
ttr: 真实通行时间
N: 预测link数量
T_i: 第i个link上的预测时间片数量
MAPE值越低说明模型准确度越高。

1.5 模型架构:

我们的模型分为三个:
LightGBM
LSTM
Static(线性规则)


2 赛题分析

1、首先我们根据题目要求可以基本判断这是一道回归预测问题。
2、其次我们还可以很容易看出来赛题数据与时间序列相关,结合数据量还算较大,因此可以考虑使用LSTM。
3、原始数据的维数并不是很大,因此特征的挖掘局限但也较为容易,对于传统的机器学习模型,xgboost和LightGBM都可以考虑拿来做baseline。
4、预测难点:
可能我们第一想法就是进行单点预测,也就是前一个来预测后一个,但是问题要求我们一次性预测出连续时间段的结果,即使这样,可能我们也会尝试去一个个预测,再将前一个预测值拿来预测后一个,但是这样的误差堆积会导致结果越来越差。经实验表明,单点预测到第四个的时候,误差就已经超出可接受范围了。
因此我们考虑利用前一段时间的数据来将目标连续结果一起给出。这样我们的数据贡献来自于全部的前一段时间的数据,这样的构造要求我们必须足够好地去构造历史数据以及前一段时间的数据。

有以上基本认识后,这个比赛的大致方向其实就差不多了,事实证明赛后top同学的思路也是这样的,只是差别在于特征册处理以及模型的调参。


3 数据分析

首先对数据进行一个大致的查阅。

3.1 数据可视化

借助Tableau,对数据进行了较为直观的查阅。尤其是对于这些时序性数据,可视化的方法能够给我们一个较为全面的参考和对比。
针对道路数据的特性,我们着重在Tableau上对同期数据进行对比,尤其是不同月的相同小时及分钟的数据,一是为了验证同期车流量整体趋势是否上升或下降的猜想,而是为了选取合适的粗细粒度来设计统计特征。如下图所示

上图着重选取了几条具有不同时序特征的道路进行分析,从图中可以明显看出大多数路段同期单位小时内的趋势基本相似,但仍存在类似于浅蓝色道路这种每个月趋势性信息不明显的道路。考虑到车流量受星期因素影响较大,因此我们又在工作日、周末维度对数据进行分析。如下图所示:

在对数据细分到每周的星期之后,发现相同的道路受星期的因素较大,可以猜想,某些位于工业园区的道路周末由于休假的缘故,因此车流量在低位平缓,但在工作日会在早晚高峰呈现拥堵的情况;相反,对于某些靠近商业区或是休闲区的道路,工作日游客较少,因此相对较为平缓,但在周末甚至周五晚上,这些道路会出现较大的起伏。这样的特点也在一定程度上帮助我们在设计线性加权模型时,将星期的因素进行单独考虑。

3.2 离群点

监测数据的准确性以及个别抽样算法所导致的数据误差是不可避免的,我们在观测了全部数据后的确发现有这样数据的存在,因此,我们采用outliers的方式,剔除了首尾95%分位点的数据。

3.3 缺失值

时序数据的缺失很常见,目前也有很多研究是针对这一方面进行研究,例如我们实验室的郑宇老师(目前是微软亚研院的主要负责人之一),他所做的城市计算方向中包含了城市时空数据缺失值的填补方向,具体可参阅郑宇老师的主页。

对于这一赛题的数据来说,由于只有单维数据(时域数据),而没有空间或是其他相关数据,因此我们选择填充的空间就比较有限。最终我们选用了前后均值来替代中间的缺失值。对于某些有头无尾或是有尾无头的数据,我们就选用最近邻的数据来替代。

4 特征工程

特征工程可参考如下流程图


image.png

4.1 尝试

数据为时间序列数据,起初尝试LGBM + 原始数据的前30个点来预测后30个点,但是效果很差(除了第一个点),打印出前30个点的特征重要性发现,只有最后2个点的重要性最高,前面的28个点都几乎很小,因此放弃使用纯原始数据来做时间序列预测。
(ps:因为不懂时间序列预测,所以后来发现在做时间序列预测的时候,不能直接使用纯原始值,需要加上额外的统计特征)

4.2 时间特征

由于是是时序数据,因此我们首先要对时间进行挖掘。因为只有时间给好了相关的数据处理才好进行,例如一些groupby等聚合操作。这里要感谢河北工大-“麻婆豆腐”学长的支援。代码如下:

def AddBaseTimeFeature(df):
    df['time_interval_begin']=pd.to_datetime(df['time_interval'].map(lambdax:x[1:20]))
    df=df.drop(['date','time_interval'],axis=1)
    df['time_interval_month']=df['time_interval_begin'].map(lambdax:x.strftime('%m'))
    df['time_interval_day']=df['time_interval_begin'].map(lambdax:x.day)
    df['time_interval_begin_hour']=df['time_interval_begin'].map(lambdax:x.strftime('%H'))
    df['time_interval_minutes']=df['time_interval_begin'].map(lambdax:x.strftime('%M'))
    #Monday=1,Sunday=7
    df['time_interval_week']=df['time_interval_begin'].map(lambdax:x.weekday()+1)
    df['time_interval_point_num']=df['time_interval_minutes'].map(lambdax:str((int(x)+2)/2))
return df

link_info=pd.read_table(data_path+'/new_data'+'/gy_contest_link_info.txt',sep=';',dtype={'link_ID':'str'})
link_info=link_info.sort_values('link_ID')
training_data=pd.read_table(data_path+'/new_data'+'/gy_contest_traveltime_training_data_second.txt',sep=';',dtype={'link_ID':'str'})
feature_data=pd.merge(training_data,link_info,on='link_ID')
feature_data=feature_data.sort_values(['link_ID','time_interval'])
print('正在生成最终特征矩阵')
feature_data_date=AddBaseTimeFeature(feature_data)
print('正在写最终特征矩阵')
feature_data_date.to_csv(data_path+'/new_data'+'/feature_data_2017.csv',index=False)

print('正在读特征矩阵')
feature_data=pd.read_csv(data_path+'/data'+'/feature_data_2017_without_missdata.csv',dtype={"link_ID":str})##指定linkID为str(Object),方便对其进行oneHot
week=pd.get_dummies(feature_data['time_interval_week'],prefix='week')
delfeature_data['time_interval_week']
print('特征矩阵与week-oneHot拼接')
feature_data=pd.concat([feature_data,week],axis=1)

##加入每个点是第几个点的类别信息
print('特征矩阵与point_num拼接')
point_num=pd.get_dummies(feature_data['time_interval_point_num'],prefix='point_num')
delfeature_data['time_interval_point_num']
feature_data=pd.concat([feature_data,point_num],axis=1)

4.3 travel_time 统计特征的处理

尝试使用统计特征的时候,一股脑将常用的统计指标全部算出来,包括mean,mode,std,max,min等,同时外加前一个月此处需要感谢豆腐大佬(@麻婆豆腐)的代码共享(初赛还没结束,豆腐就把自己的源代码贡献在技术圈),Python代码部分没有很难懂的地方,但还是需要一点Dataframe的操作知识,其实多用几次基本就烂熟于心。在前期对原始数据进行了日期格式处理的基础上,我们开始进行统计值的特征处理部分。特征处理部分的代码如下:

需要注意的是,为了对特征进行归一化处理,我们将所有的数据在训练前都做了ln处理,使其更近似服从正态分布。然后在最后将其预测值做exp处理,使其返回原始值。

根据时间特征,为了极大化前段时间数据对后面一段时间连续数据的影响,采用了滑窗方法来对前一段时间的travel_time进行处理。

    '''
    train data 4月训练
    '''
    train = pd.DataFrame()
    train4 = pd.DataFrame()
    for curHour in [8,15,18]:
        print("train4 curHour", curHour)
        trainTmp = feature_data.loc[(feature_data.time_interval_month == 4)&
               (feature_data.time_interval_begin_hour==curHour)
              # &(feature_data.time_interval_day<=15)
               ,:]
    
        for i in [58,48,38,28,18,0]:
            tmp = feature_data.loc[(feature_data.time_interval_month == 4)&
                    (feature_data.time_interval_begin_hour==curHour-1)
                                            &(feature_data.time_interval_minutes >= i),:]
            tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                    'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                        ('mode_%d' % (i), mode_function)]).reset_index()
            #train = pd.merge(train,tmp,on=['link_ID','time_interval_day','time_interval_begin_hour'],how='left')
            trainTmp = pd.merge(trainTmp,tmp,on=['link_ID','time_interval_day'],how='left')
            
        train4 = pd.concat([train4,trainTmp], axis=0)
        print("     train4.shape", train4.shape)
    
    train4_history = feature_data.loc[(feature_data.time_interval_month == 3),: ]
    train4_history = train4_history.groupby(['link_ID', 'time_interval_minutes'])[
                'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                    ('mode_m', mode_function)]).reset_index()
    
    train4 = pd.merge(train4,train4_history,on=['link_ID','time_interval_minutes'],how='left')
    
    train_history2 = feature_data.loc[(feature_data.time_interval_month == 3),: ]
    train_history2 = train_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
                'travel_time'].agg([ ('median_h', np.median),
                                    ('mode_h', mode_function)]).reset_index()
                
    train4 = pd.merge(train4, train_history2,on=['link_ID','time_interval_begin_hour'],how='left')
    print("train4.shape", train4.shape)
    train = train4
    
    train_label = np.log1p(train.pop('travel_time'))
    train_time = train.pop('time_interval_begin')
    
    train.drop(['time_interval_month'],inplace=True,axis=1)
    train_link=train.pop('link_ID') #(253001, 35)
    print("train.shape", train.shape)
    
    '''
    test   评测6月整月    
    '''
    
    test = pd.DataFrame()
    for curHour in [8,15,18]:
        print("test curHour", curHour)
        testTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
               (feature_data.time_interval_begin_hour==curHour)
               ,:]
    
        for i in [58,48,38,28,18,0]:
            tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                    (feature_data.time_interval_begin_hour==curHour-1)
                                            &(feature_data.time_interval_minutes >= i),:]
            tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                    'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                        ('mode_%d' % (i), mode_function)]).reset_index()
            testTmp = pd.merge(testTmp,tmp,on=['link_ID','time_interval_day'],how='left')
        
        test = pd.concat([test,testTmp], axis=0)
        print("test.shape", test.shape)
    
    test_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
    test_history = test_history.groupby(['link_ID', 'time_interval_minutes'])[
                'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                    ('mode_m', mode_function)]).reset_index()
    
    test = pd.merge(test,test_history,on=['link_ID','time_interval_minutes'],how='left')
    
    test_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
    test_history2 = test_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
                'travel_time'].agg([ ('median_h', np.median),
                                    ('mode_h', mode_function)]).reset_index()
                
    test = pd.merge(test,test_history2,on=['link_ID','time_interval_begin_hour'],how='left')
    
    test_label = np.log1p(test.pop('travel_time'))
    test_time = test.pop('time_interval_begin')
    
    
    test.drop(['time_interval_month'],inplace=True,axis=1)
    
    #去掉link_ID
    test_link=test.pop('link_ID')


5 机器学习模型

我们首先使用了竞赛中的两大杀器:xbg和LGBM.
模型我就不介绍了毕竟真的太出名了。
具体的实现流程如下图:

训练集使用前面特征选取部分提到的3月和4月的数据,测试集分别有5月下半月和6月一整月。
在训练过程中的验证集test我们传入的是6月一整月,只不过在最后我们会预测出5月下半月和6月一整月的数据作为输出,以便手动在计算一次MAPE指标。
下面我只给出源码。

需要注意的是,我们需要自定义MAPE的损失函数,如下:

def mape_ln(y,d):
    c=d.get_label()
    result= -np.sum(np.abs(np.expm1(y)-np.abs(np.expm1(c)))/np.abs(np.expm1(c)))/len(c)
    return "mape",result
其中y为预测值,d为真实值

xgboost训练、验证及预测源码:

import xgboost as xgb
xlf = xgb.XGBRegressor(max_depth=8,
                       learning_rate=0.01,
                       n_estimators=1000,
                       silent=True,
                       objective=mape_object,
                       #objective='reg:linear',
                       nthread=-1,
                       gamma=0,
                       min_child_weight=6,
                       max_delta_step=0,
                       subsample=0.9,
                       colsample_bytree=0.8,
                       colsample_bylevel=1,
                       reg_alpha=1e0,
                       reg_lambda=0,
                       scale_pos_weight=1,
                       seed=9,
                       missing=None)

xlf.fit(train.values, train_label.values, eval_metric=mape_ln, 
        verbose=True, eval_set=[(test.values, test_label.values)],
        early_stopping_rounds=10)


'''
预测sub,并保存结果   5月下
'''
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 5)&
           (feature_data.time_interval_begin_hour==curHour)
           #&(feature_data.time_interval_day>15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 5)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#预测
sub_pred = xlf.predict(sub.values, ntree_limit=xlf.best_iteration)
mape_ln1(sub_pred, sub_label) #('mape', -0.27325180044232567)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['xgb_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/xgb_pred_m5.csv', index=False)

'''
预测sub,并保存结果   6月整月
'''
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
           (feature_data.time_interval_begin_hour==curHour)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#预测
sub_pred = xlf.predict(sub.values, ntree_limit=xlf.best_iteration)
mape_ln1(sub_pred, sub_label)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['xgb_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/xgb_pred_m6.csv', index=False)

'''
预测sub,并保存结果   7月上
'''
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 7)&
           (feature_data.time_interval_begin_hour==curHour)
          # &(feature_data.time_interval_day<=15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 7)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#预测
sub_pred = xlf.predict(sub.values, ntree_limit=xlf.best_iteration)
mape_ln1(sub_pred, sub_label)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['xgb_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/xgb_pred_m7.csv', index=False)

LGBM训练及预测:

# 中位数
def mode_function(df):
    counts = mode(df)
    return counts[0][0]

feature_data = pd.read_csv('E:/data/all_data_M34567.csv',dtype={'link_ID':str})

'''
train data 4月训练
'''

train = pd.DataFrame()
train4 = pd.DataFrame()
for curHour in [8,15,18]:
    print("train4 curHour", curHour)
    trainTmp = feature_data.loc[(feature_data.time_interval_month == 4)&
           (feature_data.time_interval_begin_hour==curHour)
          # &(feature_data.time_interval_day<=15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 4)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        
        trainTmp = pd.merge(trainTmp,tmp,on=['link_ID','time_interval_day'],how='left')
        
    train4 = pd.concat([train4,trainTmp], axis=0)
    print("     train4.shape", train4.shape)

train4_history = feature_data.loc[(feature_data.time_interval_month == 3),: ]
train4_history = train4_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

train4 = pd.merge(train4,train4_history,on=['link_ID','time_interval_minutes'],how='left')

train_history2 = feature_data.loc[(feature_data.time_interval_month == 3),: ]
train_history2 = train_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([ ('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
train4 = pd.merge(train4, train_history2,on=['link_ID','time_interval_begin_hour'],how='left')
print("train4.shape", train4.shape)
train = train4

train_label = np.log1p(train.pop('travel_time'))
train_time = train.pop('time_interval_begin')

train.drop(['time_interval_month'],inplace=True,axis=1)
train_link=train.pop('link_ID') #(253001, 35)
print("train.shape", train.shape)

'''
test   评测6月整月    [374]   valid_0's mape: 0.284432
'''

test = pd.DataFrame()
for curHour in [8,15,18]:
    print("test curHour", curHour)
    testTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
           (feature_data.time_interval_begin_hour==curHour)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        testTmp = pd.merge(testTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    test = pd.concat([test,testTmp], axis=0)
    print("test.shape", test.shape)

test_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
test_history = test_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

test = pd.merge(test,test_history,on=['link_ID','time_interval_minutes'],how='left')

test_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
test_history2 = test_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([ ('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
test = pd.merge(test,test_history2,on=['link_ID','time_interval_begin_hour'],how='left')

test_label = np.log1p(test.pop('travel_time'))
test_time = test.pop('time_interval_begin')


test.drop(['time_interval_month'],inplace=True,axis=1)

#去掉link_ID
test_link=test.pop('link_ID')


def mape_ln1(y,d):
    #c=d.get_label()
    c=d
    result= -np.sum(np.abs(np.expm1(y)-np.abs(np.expm1(c)))/np.abs(np.expm1(c)))/len(c)
    return "mape",result


def mape_object(d,y):
    # print(d)
    # print(y)
    grad=1.0*(y-d)/d
    hess=1.0/d
    return grad,hess


def mape_ln_gbm(d,y):
    # c=d.get_label()
    result=np.sum(np.abs(np.expm1(y)-np.abs(np.expm1(d)))/np.abs(np.expm1(d)))/len(d)
    return "mape",result,False


import lightgbm as lgb
lgbmodel = lgb.LGBMRegressor(num_leaves=32,
                             # max_depth=9,
                             max_bin=511,
                       learning_rate=0.01,
                       n_estimators=2000,
                       silent=True,
                       objective=mape_object,
                       min_child_weight=6,
                       colsample_bytree=0.8,
                       reg_alpha=1e0,
                       reg_lambda=0)
lgbmodel.fit(train.values, train_label.values, eval_metric=mape_ln_gbm,
        verbose=True, eval_set=[(test.values, test_label.values)],
        early_stopping_rounds=100)
pred = lgbmodel.predict(test.values, num_iteration= lgbmodel.best_iteration)


'''
预测sub,并保存结果   5月下
'''

test
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 5)&
           (feature_data.time_interval_begin_hour==curHour)
        #   &(feature_data.time_interval_day>15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 5)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#预测
sub_pred = lgbmodel.predict(sub.values, num_iteration= lgbmodel.best_iteration)
#mape_ln1(sub_pred, sub_label)   ('mape', -0.27112186522435494)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['gbm_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/gbm_pred_m5.csv', index=False)


'''
预测sub,并保存结果   6月整月
'''

sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
           (feature_data.time_interval_begin_hour==curHour)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#预测
sub_pred = lgbmodel.predict(sub.values, num_iteration= lgbmodel.best_iteration)
#mape_ln1(sub_pred, sub_label)  

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['gbm_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/gbm_pred_m6.csv', index=False)


'''
预测sub,并保存结果   7月上
'''

sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 7)&
           (feature_data.time_interval_begin_hour==curHour)
         #  &(feature_data.time_interval_day<=15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 7)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#预测
sub_pred = lgbmodel.predict(sub.values, num_iteration= lgbmodel.best_iteration)
#mape_ln1(sub_pred, sub_label)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['gbm_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/gbm_pred_m7.csv', index=False)

总结

本次就先总结基本用到的特征处理和机器学习模型,重点还是看代码吧,因为个人时间问题,没能一气呵成把所有模型写完,后面会陆续完善。如有错误请大家交流指正。

我的博客 : https://NingSM.github.io

转载请注明原址,谢谢

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容