一直想总结一下这次的比赛,拖啊拖。。。一直等到现在,趁着现在要找实习,好好总结一下。
比赛题目
比赛的官方网站在这,。
这次比赛的题目是给定 2015 年 7 ~ 11 月份的用户在不同地点口碑购买记录,以及 2015 年 7 ~ 11 月淘宝上用户的购物行为数据,来预测 12 月这一整月用户来到一个地点之后会光顾哪些口碑商铺。这个比赛有一个很有意思的地方,就是它关注的是一个用户来到一个他之前没有去过的新地点之后,他会去哪些店铺消费,有一点像推荐系统中经典的冷启动问题。比赛提供的数据也有这个特点:
在测试集中,只有 10 % 的用户用之前使用口碑的记录;
有 5 % 的用户虽然有之前使用口碑的记录,但是在测试集中,这些用户来到了新的地点;
所有用户都有他们淘宝购物的行为数据。
如果题目只是这样的,其实还不算奇怪,奇怪的是题目的评价标准上加上了 budget 这个神奇的东西,先来看看评价指标:
$$P = \frac{\sum_i min(|S_i \cap S_i^*, b_i|)}{\sum_i| S_i^* |}$$
$$R = \frac{\sum_i min(|S_i \cap S_i^*, b_i|)}{\sum_i min(|S_i, b_i|)}$$
$$F_1 = \frac{2 \ast P \ast R}{P + R}$$
最后考核的目标是 F1 值。简单来说一下这个 budget:
我们的目标是在用户来到一个地点之后,给他推荐他可能会去的店铺。这里,把问题转换一下,我们要给很多店铺来推荐可能会来这里购物的人。这里推荐的人数要受到 budget 的限制,即不能超过店铺的最大承载量以及口碑提供给这家店铺的优惠券的个数。
先详细介绍一下比赛提供的数据格式:
Online user behavior before Dec. 2015. (ijcai2016 taobao.csv)
2015 年 7 ~ 11 月淘宝上用户的购物行为数据,包括用户的点击、购买,购买物品种类等属性。
Users shopping records at brick-and-mortar stores before Dec. 2015. (ijcai2016 Koubei train.csv)
2015 年 7 ~ 11 月份的用户在不同地点口碑购买记录,数据格式:(user_id, loc_id, merchant_id, time_stamp)
Merchant information (ijcai2016 merchant info.csv)
不同口碑商铺的位置分布情况,有的商铺有连锁店,数据格式:(merchan_id, loc_id1:loc_id2:...)
Prediction result. (ijcai2016 Koubei test.csv)
最后要提交的数据格式
user_id, loc_id, merchant_id1:merchant_id2...
对于这个问题,我们的想法是,要充分利用每一个用户和每一个口碑商铺的历史数据。更准确的说,我们要从训练集中提取足够的可训练的特征,然后利用一些经典的模型,比如 Xgboost 来构建分类模型。同时最需要注意的是,我们要时刻考虑 budget 的影响。
如何来利用历史数据 ?
我们分析了题目所给的训练集,然后将数据切分为两部分,第一部分是 2015 年 11 月 23 号之前的数据,我们把这当做本地训练集;另一部分是 2015 年 11 月 23 号之后的数据,我们把这当做本地测试集。通过对这些数据的整理和分析,我发现几条条重大的规律:
如果地点确定的话,对于一个用户,他最有可能去的是他曾经光顾过的店。
从口碑店铺的角度来讲,如果这家店铺曾经的销量很好,那么它也将在未来吸引更多的顾客去消费。
从这两条观察出来的规律来看,我们将探索数据的方向划分为两条道路:一条是从用户的角度出发;另外则是从口碑商店的角度出发。
从用户的历史信息来看
基于我们的观察,当一个人来到一个他之前去过的地点,他们更倾向于去之前购物过的商店消费。因此,一个在过去的一段时间内在一家商铺的消费次数能够在很大程度上影响我们的推荐质量。频率越高,越能代表这个人在未来会再次来到这家店消费。
我们做了一个统计,如果一个用户在过去曾经关顾过一家口碑店铺超过 6 次的话,当我们在之后再向这位用户推荐这家店的话,我们会得到超过 90 % 的准确率。
不过从另一方面说,每一家口碑店铺都有 budget 限制,这意味着,如果按照用户之前光顾过哪家店铺来推荐的话,肯定会有部分店铺的 budget 超标。
我们在用户的数据中找寻这样一个键值对 (user, location, merchant),通过计算这样一个键值对出现的频率,我们可以统计出 (user, location, merchant, frequency) 的键值对,将这个键值对按照 frequency 来从高到低排序,然后按照这个顺序,从高到低来给 (user, query) 这样一个查询来推荐店铺,直到这家店铺的 budget 耗尽为止。
经过统计发现,平均每一个用户在一个地点只会关顾 1.3 个商家,所以在这里我们限制最大的推荐个数为 4。
从商家的历史信息来看
经过之前的分析,我们发现不同的店铺有着不同的“受欢迎度”。举个例子,“820”这个商家在整个训练集中几乎出现 1/4。问题是我们怎么定义这个“受欢迎度”呢?
为了解决这个问题,我们首先定义,在不同地点的同一家口碑商铺是不一样。因为在题目给定的数据中,存在大量的连锁商铺,但是这些连锁店铺在不同地点的“受欢迎度”是完全不同的。
接下来我们设想这样一种情况,90 % 来到地点 A 的人都会去 商铺 B 消费,在这种情况下,如果我们给所有的来地点 A 的人都推荐 B 商铺的话,我们就能得到 90 % 的准确率。所以,在一个地点某家店铺消费的总人数占该地点所有人数的比例,我们称之为该店铺的 “受欢迎度” (Popularity)。
因此我们将所有店铺按照 Popularity 从大到小来进行排序,依次推荐来到该地点的所有用户,直到超过 budget。经过一些线下的实验,我们取这个 Popularity 的值的阈值为 0.25。
引入淘宝数据来提升推荐质量
我们之前的推荐完全没有用到每个人的特征,相当于无法做到“千人千面”。于是接下来我们就想办法,如何利用淘宝的数据来提升推荐质量。
从直观上而且,淘宝的数据应该很有帮助,比如,在淘宝上经常浏览或者购买电子产品的人往往不太会去关顾口碑商铺里面那些卖女式服装的。受到这个的启发,我们就建立了一个这样的表:如果存在这样一条记录,一个用户在淘宝上浏览或者购买的商铺 A;同时也在线下口碑上的商铺 B 消费,我们就把 (A, B) 这个关系链表放入表中。基于这样的表,我们对那些之前没有口碑消费记录的新用户,如果他们曾在淘宝上购买或浏览了商铺 A, 那么我们就只给他推荐在关系链表中与 A 相连的口碑商铺。线上的结果证明,我们的预测质量提升了。
引入机器学习模型
目前为止我们都没有怎么用机器学习模型,用普通的规则就可以在天池上面排一个不错的名次。但是为了取得更好的成绩,我们尝试着去探寻每一个用户、地点和商铺的各种各样可能的特征。下面我将详细介绍这些我们的做法。
我们将这个问题看成是一个二分类问题。我们的方法是对每一个店铺建模,比如说,在数据集中,用户 u 在地点 l 的店铺 m 消费了。我们可以产生一个三元组 (u, l, m)。对应于这个三元组,我们可以产生一些训练数据,首先,对于我们而言,正样本即是那些消费过的用户,即 (u, l, m) 是 True;第二,我们的负例是那些同样是这个地点的其他商铺,比如说 m‘,我们将 (u, l, m') 定义为 False。按照这个方法,我们可以产生供二分类的训练集。根据这个道理,对于赛题要我们预测的用户来到一个地点之后会去哪些店铺的情况,我们也可以根据这个三元组,产生一个每一个店铺的预测概率。
这么做其实负样本是很多的。。。为了避免正负样本不平衡的问题,我们采取采样的方法去提取负样本。
特征工程
特征工程对应机器学习来说十分重要,俗话说,特征是模型的上限。我们观察到,有些用户喜欢关顾那些他们之前去过的店,有些喜欢光顾该地点上最热门的店铺,有些则喜欢去那些刚开张的店铺。
所以,针对 (u, l, m) 这样一个三元组,我们试图找寻关于他们其中任意一个的特征。
我们找寻的特征如下:
键值对 (u, l, m) 出现的次数,即 frequence,用户关顾这家店的频率。
键值对 (u, l, m) 是否出现过,True or False。
user_id 的 onehot 编码。
merchant_id 编码。
(l, m) 出现次数,即这个地点这个商店的总销量。
open_interval:店铺的开业时间。
用户 u 在淘宝上购物的次数
用户 u 在淘宝上浏览的次数
用户 u 在淘宝上购买过的商品的种类的 onehot 编码
用户 u 在淘宝上购买过的商铺的 id 的 onehot 编码
用户 u 在淘宝上购买的比例 (购买数 / (购买 + 点击)
用户 u 在淘宝上购买的次数
用户 u 在淘宝上点击的次数
通过 SVD 算出来的用户 u 的潜在矩阵
通过 SVD 算出来的商店 m 的潜在矩阵
模型融合
之前的规则可以得出一个结果,之后的模型也可以得出一个结果,在比赛的最后阶段,我们对模型进行融合,尝试各种不同的参数,达到了这个名次。