FaceBook: Text Tag Recommendation

Text Tag Recommendation 

--------2013/12/20

一: 背景

Kaggle上 facebook招聘比賽III。任務要求是給定文本中抽取關鍵詞,這裏稱作tag吧。

訓練集是Stack Exchange sites上面的大量問答文本,每個post上面有網頁的title ,body, 用戶打的tags

示例如下:



 

測試集是也是同樣的文本信息,但是沒有tags,這次比賽的任務就是讓參賽者從文本中預測出文本的tags,比如上面的javaunit-testing....

 

二: 評估指標

F1-score= 2*precision *recall/(precision+ recall)

這裏的問題是 任務是沒有告訴你文本的tags數量。如果你預測tags數量過多,precision就會很低,但是,recall相對高點。這裏的任務,預測tags數量也是很重要的一方面。

 

三:訓練集和測試集數據分佈

訓練集有600w+的文本,tags數量1-5,訓練集合中tags數量是4w+

測試集合大約200w+


 

 

 

 

 

 

四: tag 預測推薦算法

1: 數據預處理

最開始時候我從文本中剔除掉停用詞和對詞進行詞幹提取,但是效果沒有提升。後來,我放棄停止詞和詞幹的處理。在progamming中有一些停止詞還是有價值的。

同時我把類似這樣的詞: opt/lib/unix 分開成optlib, unix等等。

Title全部信息,body是抽取其中text信息。

 

2: cross-validation

600w+訓練樣本中抽取前100w樣本做cv訓練集,接着從取10w樣本作爲cv 測試集(其實從取1w cv測試集和10w測試集評估結果差別不大)。

 

3:訓練模型

 

3.1  文本語料

從訓練樣本中計算詞term的詞頻字典,term-tag共同出現頻率詞典。

訓練樣本的文本信息只包括title信息,沒有body信息,一方面大量訓練樣本已包含足夠

多的文本語料,而body含有很多噪音數據,加入訓練樣本中,會造成預測F1值降低。

文本語料中採用2-grams1-grams,相對只用1-gramsF1在測試集上表現能提高0.02的精度。

 

去除掉一些低頻詞,低頻tag,高頻詞。低頻的,我們認爲不可靠。

 

def is_pass_record(prob_term_1,prob_target_1,prob_term_1_target_1,):

    

    if  prob_term_1_target_1 <1e-5:            

        return 1

        

    if prob_term_1 < 0.00001 or prob_target_1< 0.00001 or prob_term_1 > 0.1 :

        return 1 

    

return 0   

 

 

3.2 計算單詞和tag的相關性得分

 

(1)互信息相關得分

 

Mutual_Score(term,.tag)  =  P(tag| term) -P(tag)

 

(2) z-score相關得分:

Z_Score(term, tag) = 

 

 

 

(3) Ensemble 相關得分


先對Mutual_Score Z_Score進行歸一化:

Ensemble過程中mutual score 的權重分配是0.7 和 z-score的權重是0.3

 

4)詞的權重

根據訓練樣本,計算詞的權重。不同單詞,它關聯的tags是否是最終預測的tag的重要程度不一樣。

 

方法有兩種: 

方法1tf-idf值作爲單詞的重要性值。

方法2: entropy值作爲詞重要性

根據上面得到詞頻和詞-tag頻值,可以計算Wj

同時歸一化中分母換成norm-2 


 

 

最終採用了entropy值作爲詞的權重。

 

 

4: 預測模型

4.1 預測樣本文本信息

預測文本信息主要是通過get_ensemble_title_and_body(title, body)函數得到的,綜合利用titlebody文本信息。

 

def extract_body(body):

    body_term = body.split()

    body_li = []

    body_li.extend(body_term[:20])

    body_li.extend(body_term[-20:-1])

    

    text = ' '.join(body_li)   

    

    return text

 

def get_ensemble_title_and_body(title, body):

    

    title_w = 5

    doc = (title + ' ') * title_w + body

return doc

 

 

4.2 預測

(1)通過4.1獲得每一個post的文本信息,根本文本中單詞的權重和單詞-tag關聯性預測tags:


 

 

(2)獲取得分最高的前5tags

pred_tags = [[tag ,w] for tag, w in pred_tags_dict.iteritems()]        

pred_tags = heapq.nlargest(5, pred_tags, key=lambda x: x[1])

 

(3)預測最終tag數目

 根據pred_tagstag得分,把低得分的tag去掉。

Threshold設定爲0.7

 

def get_estimate_tags_num_by_association_prob(pred_tags):

    

    threshold = 0.7

    

    i = 0

    sum_w = 0

    total = np.sum([item[1for item in pred_tags])

    for item in pred_tags:

        sum_w += item[1]

        i +=1

        if sum_w > threshold * total:

            break

    

    return i

這一步提升很明顯,提升0.03左右。

 

(4)cv結果

cv 10w結果大約在0.508

precision:  0.505054166667

recall:  0.511442333333

F1-Score:  0.508228176801

 

 

(5)最後提交

這次比賽的的測試集中大約有119w的測試樣本在訓練集合中出現。約佔總體樣本的60%

所以,第一步從測試集中把這119w樣本找出來,用訓練集中對應的tag預測。剩下40%的樣本用上面的說的關聯預測算法來做。

找相同文檔的算法:

給每個訓練集單詞建立倒排索引(這次把訓練樣本中去除停用詞和詞幹處理,且是binary索引,不考慮tf-idf)。

 

Kaggle leaderboard上,我是最後2周才加入的(2013/12/08提交第一次結果,2013/12/20 比賽結束),提交了7個結果,結果爲0.72,(最高是0.81

排名是 93, 總的隊伍數目是367. 大約25% 左右。這裏說明下,0.72對應的的cv結果只有0.39左右。


 

 

所以,我在比賽結束後的優化結果是cv0.50,相信leaderboard上的結果會有相對較高的提升,後續加上結果, 結果是

 

 

 

 

 

五:總結

這次kaggle比賽,對text挖掘有了比較不錯的提高,在實驗中,試驗了很多方案,比如KNNtopic model。 KNN的速度太慢,即使在建立tf-idf倒排索引的情況下,依然滿足不了需求,同時在這次比賽中knn精度也沒什麼好的表現,值得提到的是,對於相似文本的尋找算法,可以借鑑Wand算法來提升速度,這也是這個數據集後續可以再做的地方,text去重性能計算。Topic model是一個組粒度的預測方法,對於本次樣本中基本上都是program 文本,所以這種粗粒度的預測方法效果很差。

可以總結一句話:通過實驗,我們才能知道什麼方法纔是可行的,什麼是不可行的。

 

 

 

六 : 參考文獻:

[1]  http://www.kaggle.com/c/facebook-recruiting-iii-keyword-extraction

[2]  Stanley C, Byrne M D. Predicting Tags for StackOverflow Posts[J].

[3]  司憲策基於內容的社會標籤推薦與分析研究 [D][D]. 北京清華大學計算機科學與技術系, 2010.

[4]  Eisterlehner F, Hotho A, Jäschke R. ECML PKDD Discovery Challenge 2009 (DC09)[J]. CEUR-WS. org, 2009, 497.

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