天天看点

MDD Cup 2017 小记 (美团点评内部算法比赛)

gbdt版本

    MDD Cup 2017,是 美团点评内部首届算法大赛,主要是预测外卖的送达时间,是一个回归问题,简单说一说比赛过程自己的所思所想,记录一下。     拿到数据后,根据大赛的说明简单分析了一下,训练集给出的是一个月的部分数据,测试集是下一个月的数据,需要注意的是训练集给出的是每天24h的数据,而测试集只需要预测11点和17点高峰时期两个小时的数据,而且给出了10点和16点的数据用来辅助分析(测试集每天只有4个小时的数据)。因为测试只需要高峰期的数据,训练数据集需要和测试数据集分布一致,首先看一下训练数据集每天每个小时的订单分布(如下图),用来筛选数据,去除无效的数据。根据图中每个小时的订单数量分布,我们只留下了10点到20点的数据。我们希望尽量保留多的数据用来训练,模型的效果取决于数据、特征和参数,有效数据越多,泛化性就越好。

MDD Cup 2017 小记 (美团点评内部算法比赛)

    还有就是,验证集合的划分我们只保留了11点和17点的数据,保证验证集合和测试集合的数据分布一致,当然为了保证数据的一致性,还有很多更细致的工作需要做,这是一大块内容。 再看一下我们的label(每一个订单的配送时间),首先需要去除噪音,过滤掉配送时间太短和太长的数据。然后看分布,训练数据的label原始分布如下左图,做平滑后分布如右图,目的是希望label的分布尽量符合正态分布,这里用的是np.log1p(label),后面需要对应用np.expm1()做还原,同样这里可以进一步往下做,例如我们训练数据中30分钟左右的数据都可把label变成30分钟的来做。这里做到这一步已经差不多了,模型训练好以后,预测的lable也可以用同样方式做分析。

MDD Cup 2017 小记 (美团点评内部算法比赛)

    下面看一下特征,特征决定了模型的上限,在比赛宣讲中燕鹏大神就反复提醒大家,最后模型融合的效果取决于单模型的好坏,而单模型的好坏取决于特征的好坏,其实大部分人都会用到原始特征、统计特征、组合特征、复杂特征和未来的信息的特征,最后再模型融合应该是可以进入400的(这个比赛的评价指标是MAE,单位是秒),但以后更进一步,就需要在每一个环节做更多更细致的工作,下足功夫才行。     先说几个点, 因为往往其中任何一个出现问题,就会让人崩溃到放弃。一个是在类别特征的处理上,xgboost是不支持类别型特征的,如果要使用它需要进行one-hot编码,如果编码之后维度增加的很大,就会导致单机训练特别慢,有时可以慢到一天迭代不了几次,迭代的速度太慢是比赛的大忌,也很容易让人崩溃,这里给一个针对xgboost的解决方案,就是把类别型的特征变成数值型,再放到xgboost里面,其实我碰到的很多比赛,包括工作中,这种方式是和one-hot编码之后的效果差不太多的,但速度却可以提高很多。至于如何解释这种现象,就是当树很深的时候,其实就可以看成是一种one-hot的编码了,但实际中树完全不用很深就可以达到one-hot的效果,也可能这些个别的案例都让我碰到了。     lightGBM是支持类别特征处理的,就是不需要我们做one-hot编码,直接表识出类别型的特征,lightGBM就会自己处理。这里需要说的一点是,有几个版本中如果标识了类别特征,lightGBM就会挂掉,这其实是一个bug,最新版的lightGBM已经修复了。     还有就是比赛中,如果能用lightGBM就不要用xgboost,因为后期当特征提取到一定数量时候,xgboost就会慢到让人崩溃的地步,一天迭代不了几次,而lightGBM几分钟就可以迭代一次,真是让人爽爆。     因为每天的提交次数不超过5次,所以如何划分数据集,能够使得,离线的提升,提交后同样可以得到提升是至关重要的,这就相当于你可以无限提交,但是一般比赛中都是很难找到离线有提升,提交后就一定有提升的数据集划分方式,对于比赛中碰到离线有提升,而提交之后反而下降的情况是再正常不过的了,离线突然提升很多,提交后效果大幅下降,一般都是提取了过拟合的特征。     先说下第一名的方案,就是用的cv交叉验证方式,假设每天都是独立的,将数据按照天平均划分然后做交叉验证。第三名的做法是巧妙的利用了测试集前一个小时后十五分钟的数据作为离线的验证集,认为每天前一个小时和测试数据最相近。一种是离线用20天训练,5天测试,5天验证,还有很多其他方式这里不一一列举,当然还可以凭感觉,例如每次gbdt每次迭代的轮数。     模型训练完之后,我们就要分析下特征重要性,其实初次入手xgboost和lightGBM的一般都会只使用默认的F值特征重要性排序,而没有认识到gain排序的作用,要说明一点这些指标都是辅助我们分析模型的,排序靠前的特征并不一定说明这个特征很重要,就是说如果我们在模型中去掉这维特征,模型的效果不一定会下降,有可能还会提升,特别是当提取的特征重要性高,但是模型效果没有提升反而下降的时候,不要急于把这个特征丢掉,可以用来做其他模型,然后进行模型融合,这就是用多个gbdt融合的原因之一。     xgboost版本:model.get_score(importance_type='gain')     lightGBM版本:model.feature_importance(importance_type='gain')

    说到如何才能提取到有效的特征,除了盲目的按照套路来各种提取特征,各种尝试之外,最重要的就是要理解业务,首先要想明白到底哪些因素,决定了骑手的送餐时间,本次比赛官方给出的有

  • 订单:下单时刻、价格、菜品数
  • 用户:用户位置
  • 骑手:骑手负载
  • 商家:出餐能力、地理位置、积压的订单
  • 区域:骑手数、单量
  • 时间:午高峰期、晚高峰期、非高峰期
  • 天气数据:温度、风速、降水量

    我们提取特征的时候,应该围绕着这些因素,我私下和部分骑手聊过这个问题(从骑手的角度来看,每次送餐到底什么决定了送餐的时间),了解到的关键因素有商家的出餐能力和本区域的负载情况,还有最重要的是骑手每次送餐系统都会有一个预估时间,骑手如果超出这个时间,会有惩罚,这个预估时间对骑手至关重要,如果骑手有多单要送,会根据这个时间来调整配送的先后顺序,所以,我当时也在想是不是模型越接近系统给出预估时间的这个模型,预测的就越准确,搞来搞去不就是在拟合原来的模型么。总之一路做下来,感觉只有我们足够深入的了解接触这个业务,才能给提取出更多有效的特征,比赛是需要大量时间和精力的,每次想到这里我都要颤抖下,因为想到我的中间页排序还有好多好多的工作要做。 

美团 算法工程师 目前主要负责中间页排序

继续阅读