2019中國高校計算機大賽-大數據挑戰賽-query-title-點擊率預估,Rank24 解決方案

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.如果每一個特徵都佔一個進程,那麼你一個進程就必須操作一個大變量,多個進程就需要操作多個大變量。內存消耗大,效率和先分成多個小變量的效率相等

代碼開源:
https://github.com/gaozhanfire/BDC2019-rank24th
歡迎star

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章