视频点击比赛总结
0. 赛题目的
以用户的视频行为数据为基础,构建推荐模型,预测待测试数据中用户在对应的视频上是否会产生点击行为。
1. 数据分析
1.1 原始工作
- 训练数据包括2019年11月7, 8, 9,10四天的数据。但是7号的数据比较少(大概有几十条),合并后每天的数据量约为360万。预测集为11号的数据。
- 计算每天新老用户分布,下表列出了9、10和11三天昨日老用户占比。可以看出前一天老用户占比60%多 ,所以在后面的特征工程做了大量针对用户前一天行为的特征。
history_9 = data[data['day'] == '9'] print(len(set(history_9['deviceid'])&set(history_10['deviceid'])))
- 数据集中代表用户的字段有两个,分别是代表设备的deviceid和用户注册的guid,通过分析可以发现数据中每个deviceid和每个guid几乎是一一对应的,deviceid与guid的皮尔森相关系数在0.9以上,且deviceid缺失值更少,因此删除guid而使用deviceid代表用户ID;
- 代表视频的字段为newsid,本次提供的数据集有一个明显的缺陷便是与视频相关的字段只有newsid,其余诸如视频类型、时长、内容等属性都没有,因此很难对视频进行刻画,相当于在推荐场景下却无法刻画item,这无疑显著增加了任务的难度。
- pos:部分视频都被推荐到了一种固定的pos,而从各个pos的点击率分布可以看出pos与点击率息息相关,因此这也是值得挖掘的地方。
- lng_lat:从点击率分布,可以看出点击行为在地理位置上也有一定的聚集性,因此无论是视频推荐位置,还是地理位置,都是很重要的特征。
1.2 app表:每个用户使用的app
1.3 user表:用户画像,标签+评分
2 构造特征
2.1 历史信息特征
对user或item的历史数据进行统计分析是推荐场景下的常用手段之一
针对deviceid统计前一天的点击次数、浏览量、点击率。deviceid就相当于user
以及deviceid和pos的联合点击次数...
count 特征主要反应偏好属性,具有一定曝光度的作用,比如今天哪个视频曝光量大,用户倾向于在哪个时间,哪个网络环境下使用 APP。
为什么没有进行更细粒度的统计?比如前1小时、前6小时?
更细粒度的统计在该数据集上效果不佳,因为该数据集在时间上的分布并不均匀,粒度太细会造成大量样本的特征缺失,反而影响最终的效果.没有考虑的地方:newsid就相当于item,既然对user的历史信息进行了统计,自然也可以对item的历史信息进行统计。
2.2 曝光时间差特征
2.2.1 正常时间统计
- 时间差即时间间隔,比如user前一次点击与当前点击的时间间隔、前一次浏览与当前浏览的时间间隔等,其实也属于对历史数据进行统计。
- 直观上分析,一般一个用户看完当前视频之后,很可能还会紧接着再看另外一个视频,那么统计这二者的时间差或许会有所帮助
- 本方案对devceid、newsid、经纬度、pos等特征和相互之间的组合进行了前1次、前2次、前3次、前5次、前10次的曝光时间差统计。
为什么没有对点击时间差进行统计?
还是由于数据本身的原因,点击时间差会造成严重过拟合。
2.2.2 穿越时间统计
- 时间穿越其实就是指在特征构造的时候用到了未来的信息。
- 正常历史统计是统计前n次与当前的时间差,而穿越统计则统计后n次与当前的时间差。加上这组穿越统计特征之后,分数可以暴涨十几个百分点,然而这都是没有意义的,因为在真实业务场景下是不可能获取到未来的信息的。
- 这么做的原因也很好理解,假如一个人点击了某个视频,那么必然会观看一段时间,那么距离下一次视频的曝光就会久一点,ts 差值也较大。相反,连续两次视频的曝光时间间隔应该很小。距离上次视频的曝光时间差也是有效的,根据 APP 的推荐规则,在点击视频后下次推荐的也是相关视频,从而再次点击的可能性较大。
2.3 交叉特征
特征之间相互交叉是数据挖掘中的常用手段。推荐场景下的原始特征大多都是稀疏特征,即离散特征,本次任务提供的数据集也不例外。本方案从中挑选了5个较为重要的特征进行两两交叉,这5个特征分别是deviceid、newsid、pos、netmodel、lng_lat。
选择这五个类别特征是根据树模型给出的特征重要性中选择的,这五个类别特征以及其相关的交叉特征的重要性比较高,效果比较好。
比如设备deviceid和视频newsid交叉,可以统计各个设备与各个视频的共现次数,为各个设备推荐的视频列表的熵(?)、不同视频的个数、每个视频在其中的次数占比等。
当然还可以进行更高阶的交叉,比如三个特征的交叉、四个特征的交叉等,考虑到运行时间和资源消耗等各方面因素,本方案只进行了二阶交叉。
2.4 embedding特征
- 本方案选取deviceid、newsid、lng_lat进行两两embedding,相互刻画。
- 比如将各个设备上的视频列表提取出来作为sentence,运用skip-gram生成各个视频对应的embedding向量,然后将各个设备上的视频列表中的每个视频对应的向量取平均得到各个设备对应的向量,以此做为特征来刻画各个设备;反过来也一样,提取出各个视频上的设备列表,以同样的方式得到最终各个视频对应的向量,以此作为特征来表征各个视频。
- 作为推荐中重要的一方,数据集中本身的视频信息十分少,只有一列简单的视频 id,并没有视频分类之类的对推荐重要的属性信息,但是可以从视频被推送的用户群除非。以视频为单位,找出被推荐的用户列表,每个列表作为句子喂到 Word2Vec 模型得到每个用户的 embedding 向量,用视频所有被推荐的用户的 embedding 向量平均值表示视频,从而刻画部分用户群特征。得到 embedding 之后,就可以度量两个视频之间的相似度,所以也就产生了另外一种思路,当一个新视频被推荐给用户后,计算新视频与之前用户被推荐过(或者看过)的视频的平均相似度,平均相似度越大,相似用户群点击的可能性越大。
- word2vec方法中,由于id数据经过脱敏,不像user-tag的svd方法中,通过tag的embedding相似度可以直观地评估embedding训练效果,未来可以通过相似度测量、聚类、可视化等方法,定量分析embedding训练质量。
3 从别的团队借鉴到的地方
3.1 位置信息处理
- 原始训练文件中提供了lng和lat经纬度信息,为了更具体的表征用户的位置,我们做了以下三步操作:
- 首先对经度取前7位,纬度取前6位,这样可以避免用户位置的细微变动带来的噪声影响,相当于做一个简单的平滑;
- 另外我们将经纬度字符串进行拼接来表征用户的具***置;
- 最后我们根据用户的经纬度来对用户位置做一个区域性的划分,Geohash是一个Python模块,它提供了在纬度和经度坐标之间解码和编码的Geohashes函数,经过测试,对经纬度分别进行3、4、5位编码可以大致认为划分的区域大小为省、市、区的大小。
3.2 app表
- 通过app.csv获取用户下载app情况,之后统计所有用户中各类app出现的次数,通过统计的次数过滤掉出现次数很多或者很少的app种类。最后构建字典。
- 对于app类数据,通过构建的字典将每个用户的数据编码成如下形式: (长度为字典长度),如:[0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0]
3.3 user表
- 通过app.csv中的tag字段和outertag字段获取用户画像特征,之后统计所有用户中各词出现的次数,通过统计的次数过滤掉出现次数很多或者很少的词汇。最后构建字典。将数据进行编码:(bow/tf-idf,选用的是bow的方案)
- 对于tag类数据可以有以下两种处理方式:
[0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0] 和
[0,0,2.7,0,3.2,0,0,0,0,0,0,0.2,0.5,0,0,0,0,0,0,0] - app.csv表和user.csv表 的数据提取后作为用户画像操作,在不加穿越特征时有0.003的提升
3.3.1 user-tag特征
- 其基本步骤为首先遍历user表获得每个用户对其tag的评分值,并按照userID,、itemsID、rating的方式形成评分表,对其进行异常值平滑之后构建userID和itemsID的评分矩阵。评分矩阵中行代表用户userID,列代表兴趣tag,其中的值代表用户对tag的打分。基于SVD的优势在于用户的评分数据是稀疏矩阵,可以用SVD将原始数据映射到低维空间中,可以节省计算资源。我们采用线下三折交叉验证的方式来对评分矩阵进行训练,之后使用训练得到的20维的隐向量来表征用户的兴趣。我们使用svd算法进行矩阵分解,训练得到deviceid和tag的20维分解矩阵,根据余弦相似度,计算每个tag与其相似的tag,比如“恋爱”和“结婚”两个词的余弦相似度比较大,两个词比较相似,说明模型已经从数据中学到了隐藏的关系。
- 受限于 APP 的用户体验,单纯的用户属性对预测作用不大,这也是为什么 app 表和 user 无法正确打开的原因。所以需要从用户的行为数据(也就是 train 表)构造特征,但行为数据中也有大量不可信操作。有些用户为了完成 APP 的任务拿奖励,会随意点击观看视频,这部分行为完全随机,无法从中正确提炼出用户的兴趣所在,也就很难去预测未来的点击行为。
3.4 Embedding特征
- 第一种构建序列的方法是以用户的曝光时间序列作为训练数据进行建模,把用户的曝光日志中newsid按照时间排序,也就形成了曝光序列。将曝光序列视为文档,就可以计算文档中item(也就是newsid)的Embedding。这里不仅可以构造deviceid到newsid的嵌入向量,还可以是视频newsid到用户deviceid,newsid到位置lng_lat等。
- 第二种构建序列的方式就是Deepwalk方法,在推荐场景下,数据对象之间更多呈现的是图结构。这个时候word2vec就不能很好的展现这层关系,所以我们选择了Graph Embeding的方式,具体的使用了DeepWalk,可以将用户的曝光记录转化为关系图。基于这些曝光视频序列构建视频关系图,采用随机游走的方式随机选择起始点,重新产生用户和视频曝光的随机游走序列。最后再将这些曝光序列输入Word2vec模型,生成最终的newsid的Embedding向量。
4. 验证集划分
本赛题是一个时序预测问题,所以如果使用交叉验证会出现线下分数很好但线上测试分数却不理想的情况,原因就是忽视了时间序列的影响,导致了用未来的数据去预测过去的数据。因此在切分验证集的时候,我们的做法是用前面8、9号的数据作为训练集,10号的数据作为线下验证集,线下验证没有花精力在调整模型参数上,主要是为了通过线下验证集获取模型的最优迭代次数和概率阈值(当模型预测的点击概率大于阈值时,则认为用户会有点击行为)。
做预测时,使用8、9、10号全量数据集来训练模型。这样相比使用全量数据集进行五折交叉验证分数要更高且更稳定。
5. 模型
- LightGBM:速度快,效果好,不过有些情况下对GPU支持不太友好
- 由于F1 Score阈值敏感,所以我们在根据预测结果得到最终是否点击时需要对阈值做一个简单的迭代搜索,即指定一个阈值初始值和迭代步长,通过在验证集上不断增加阈值来确定F1 Score分数最优时的阈值,进而应用到测试集的预测结果中。
- 比赛采用精确度(precision)、召回率(recall)和F1值作为评估指标
- 这一题数据量比较大,模型训练起来也比较慢,所以针对LightGBM 模型准备了两套参数,一套学习率比较大用于快速迭代验证特征效果,训练一次大概在半小时左右,线上分数0.825。另外一套学习率为0.01的参数用于正式提交,运行一次大概需要15小时,线上分数0.8377。
5.1 别的团队:多模型融合
- 寻找阈值:在多模型融合时,可以通过验证集上线性回归模型输出的概率结果,来寻找最优阈值,并将其用于测试集上(我们主要使用的是这种方式)。另一种方式是,记录每个模型在验证集上的最佳阈值,在得到最后是否点击的结果时,同样地也需要对各个模型的阈值进行同样地加权处理。还有一种单模型、多模型通用的确定阈值的方法,即我们通过统计8、9、10号三天的点击数据,得到正负样本的比例大致为0.11,因此,我们也可以对融合后的概率预测结果进行排序,取概率最大的前11%的数据label置为1,即预测会做出点击行为。这种方式比较简单,省去了搜索确定最优阈值的步骤。
- 特征筛选:对于LightGBM等拟合能力超强的模型来说,很多和标签完全无关的特征甚至是随机加入的噪声,都能通过海量的子树建立密切的联系,如果我们单纯根据特征重要性来删除则会删除掉很多潜在的有用的信息。我们使用了两种特征筛选的方法以供参考。
- 第一种是称为Null Importance的方法,其基本思路就是将真实特征训练得到的分数与随机假特征训练得到的分数进行对比,假如某特征的分数并不能明显超过随机假特征,那么证明这个特征是一个无用的特征。首先计算原始特征的特征重要性,然后shuffle 标签y指定次数n,每shuffle一次重新训练一个模型然后记录特征重要性,直到全部训练完毕,将得到的n个特征重要性矩阵合并之后,就可以开始进行比较了。比如对于特征A,我们用没有shuffle的特征A的特征重要性除以多次shuffle之后所有的A的特征重要性的75%分位数,然后结果取对数,如果结果小于0则说明特征A不如随机特征。对于每次构造的新的特征群,都会结合原始特征群后使用Null Importance的方法来进行特征筛选,有用的特征加入最终的特征群,明显无用的噪声特征则进行删除,以此来保证输入每个模型的最后的特征数量在300-400之间。
- 第二种方法,是通过shuffle数据中某特征列的值,使用之前训练好的模型进行预测,观察f1和auc下降的程度进行筛选。shuffle后对预测值的影响就越小,指标下降越小(甚至指标还会有提升),说明特征的重要程度越低,该特征可以考虑删除。具体做法如下。一、将提取好的所有特征,划分出训练集、验证集。二、使用训练集数据进行模型的训练,在验证集上进行预测得到基准的f1和auc指标。三、对每个特征,对验证集上该特征列的值进行shuffle,再使用模型对进行预测,得到新的f1和auc指标,与基准的f1和auc指标作对比。四、可以尝试筛除掉造成指标下降最少的一些特征。
- null importance方法缺点是每次迭代都需要重新训练模型,适合对构造的特征群进行初筛,速度较慢。第二种方法只需要训练一次,速度快,适合模型训练完成后再次对特征进行精筛;