gaozhanfire / BDC2019-rank24th

**高校计算机大赛-大数据挑战赛,Rank24 解决方案

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BDC2019-rank24th

**高校计算机大赛-大数据挑战赛,Rank24 解决方案

赛题描述:

https://www.kesci.com/home/competition/5cc51043f71088002c5b8840/content/1
我对业务的简单理解:
实际上就是搜索引擎,你搜一个 “我是蔡”,即一个query
对应可能的搜索结果(即title):①我是蔡虚鲲 ②我是菜徐坤 ③我是共产党的接班人
这时候你很可能就会去点 我是蔡徐坤
这就是这个比赛的任务,给你一个query-title对,让你预测这个query-title对 被点击的概率,即可看做一个二分类问题,标签为0或1.


方案细节:

lgb两千万数据 分数 a榜 0.590
nn均为纯文本输入,6个nn进行stacking之后分数 a榜 接近0.58.
nn stacking+lgb a榜605 b榜618 。

方案耗时:

6个nn训练时间:共计24小时。
特征生成时间(在1亿数据上):普通特征1小时,w2v距离特征8小时,tsvd特征1小时。共计10小时。

赛题解决方案:

通过分析可知,
①query和title的相关度(也就是相似度)越高,这个query-title 被点击的概率也就越大,
②query-title的内容越吸引人,被点击的概率也就越大
③可以根据一个query或一个title曾被浏览过/点击过 的次数,来判断这个query/title 的点击概率是不是很高

于是可制定以下方案:
①手动/通过nn,来提取query和title相似度特征(诸如query和title公共词数量,非公共词数量等等)
②通过nn,来提取query-title的语义信息
③对query和title的历史点击率(即如 title出现过的次数 title被点击的次数 title出现过的次数/title被点击的次数)


所用特征:

所用的相似度特征与其他队无太大差别。
主要还是fuzzy和莱文斯顿这两个库里的相似度特征。

本队的trick特征:

  • ctr特征(三个特征即可达到0.578的baesline):

    • 拿复赛举例,复赛10亿训练数据,我们选取了最后5千万条数据进行训练。
      我们使用了没用来训练的那9.5亿条数据进行groupby('title')['label'].agg({'count':'title_count','sum','title_sum','mean','title_ctr'}) 来构造出了点击率特征,count的含义,就是该条title的出现量(投放量),而sum,就是title出现了这么多次,这其中有多少次用户点击了该条title。 我们对ctr特征进行了贝叶斯平滑*,以此取得了两个千分位的提升,具体代码已包含在文件中 *
    • 我们没有对query进行统计,这是因为query在测试集和训练集的重复率并不高,所以没法利用query的历史信息。
  • tsvd降维特征(3个千的提升):

    • 我们对query的tfidf矩阵进行tsvd降维。这个特征很多队伍没有用到,原因是tfidf维度过高。
      我们采用的方法是使用了gensim库里的lsi主题模型,lsi的本质即对矩阵进行tsvd降维。
      我们曾尝试降到50维 30维 20维,最终结果为20维效果最佳。

      需要注意的是,具体做法为:
      先把(训练集10亿数据+测试集1.3亿数据)所有的query和title装到一个set里(即去重操作),然后做tfidf出来(用gensim)。(因为tfidf是一个统计值,所以数据量越大越好)
      然后把每条(上面set里的)query的tfidf拿出来,组成一个shape为(query的数量 * tfidf维度)的一个矩阵。
      然后用gensim中的lsi模型进行分解,分解的时候注意设置chunksize,并且使用迭代器(具体的见代码,要不然内存会炸)。

  • 在使用fuzzy和莱文斯顿库的时候,首先要将加密的词映射为一个个汉字。(这个特征是后来修正的,有一到两个千的提升。) 原因,比如编辑距离,如果你按原来的文本,就是如 2125 到2134(两个词),按编辑距离,正常来讲应该是1,但是如果按他本身的文本,2需要变成3,5需要变成4.那么编辑距离就成2了。


一些提分的操作:
- 5折交叉验证:即5折训练5个模型,最后模型结果取平均,能有一个千分位提升。
- 模型blending/stacking:像这种数据用不完的大数据量比赛,可以使用stacking(因为你可以抽一部分来训练,抽另一部分来做stacking,避免信息泄露),我们在我们抽取的5000W训练集之外又抽取了1000W数据,用这1000W数据对模型结果进行了集合。
- 对投放量(title_count)、点击次数(title_sum)、title下query的种类数(title_nunique_prefix),在训练集和测试集上分别进行了归一化。* 该操作有5个万的提升。 使用的库为 from sklearn import preprocessing 中的QuantileTransformer这个函数。 我们不是用训练集的均值来对测试集归一的,而是fit_transform(train) fir_transform_test (用训练集的均值对测试集归一化,我们也尝试过,效果没有对训练集和测试集分别归一的好)


复赛的代码优化:

  • 特征生成时
    经过分析,我们发现我们的时间主要消耗在apply上。 apply本质上为一个for循环,
    所以apply(lambda x:x[0]+x[1]) 效率比 x[0]+x[1]直接做加法,时间上能差百倍。
    所以我们做了以下优化
    - 特征能在一个apply中做完的,尽量集中在一个apply中做完,不要分着好几个apply做。
    - 对于比如对几列数据取avg/max/sum之类的,都是可以直接x[0]+x[1]这种用python内置的函数 来完成的。

  • 多进程时: 最好不要把一个大变量直接通过形式参数传入到函数里,能把这个变量设置成全局变量,就最好按全局变量处理。
    比如 def test(temp): 其中temp是一个存了几百万数据的一个DataFrame,有的时候python的深拷贝机制就会让temp这个变量占用两倍的内存。 如果你只想取一个变量的一部分,比如索引为0:10000000的数据,你可以把索引范围传入到函数中。

  • 关于多进程并行: 把文件的索引分块,比如1亿数据,有16个cpu核心,即每块为100000000/16=6250000,运用skiprows和nrows这两个函数,把每一块的起始索引和终止索引传入读文件函数,使用多进程并行读取数据,最后合在一起进行concat。
    这样的文件读取方式可以实现在同等内存消耗量下1亿数据的秒级读取。
    同理,很多pandas函数都可以按如上方式实现并行化。
    关于上述多进程,需要注意的一点,是,不要每一个特征占一个进程,而是应该把一个大变量分成多个小变量,然后每个小变量安排一个进程。
    这样的原因:

- 1.如果每一个特征都占一个进程,那么每一个特征所用时间可能是不均等的,也就是说,你某一个特征做完了,可能另一个特征还没做完,那么此时你就只有一个进程在工作,而另一个进程空下来了。
- 2.如果每一个特征都占一个进程,那么你一个进程就必须操作一个大变量,多个进程就需要操作多个大变量。内存消耗大,效率和先分成多个小变量的效率相等

About

**高校计算机大赛-大数据挑战赛,Rank24 解决方案


Languages

Language:Jupyter Notebook 100.0%