文本分類模型第三彈:BoW(Bag of Words) + TF-IDF + LightGBM

1、前言

本文是文本分類模型的第三彈,利用詞袋模型(BoW),詞頻逆文檔頻率(TF-IDF)與 LightGBM 模型進行文本分類。html

本來計劃的第三彈內容爲 TextCNN 網絡,介於最近剛剛利用 LightGBM 完成了一個簡單的文本分類的任務,就趁熱記錄一下,做爲第三彈的內容。python

這裏是文本分類系列:算法

文本分類模型第一彈:關於Fasttext,看這一篇就夠了網絡

文本分類模型第二彈:HAN(Hierarchy Attention Network)app

文本分類模型第三彈:BoW(Bag of Words) + TF-IDF + LightGBM機器學習


2、相關論文及理論

1.LightGBM

這裏是 LightGBM 提出的論文《LightGBM: A Highly Efficient Gradient Boosting Decision Tree》,LightGBM 本質上也是 梯度提高樹(GBDT)的優化模型,GBDT 的本質是迴歸樹模型,在作分類任務時,經過「迴歸相應類別」的機率值,來曲線完成分類任務。LightGBM 與上一代 kaggle 神器 Xgboost 相比,因爲採用了直方圖算法(用於特徵處理),和 Leaf-wise 的樹分裂方法(用於模型構建),模型準確度更高,訓練耗時更低。其不只應用於傳統的機器學習迴歸及二分類,多分類任務,在 CTR 預估,推薦系統中也有着普遍的應用。性能

2.詞袋模型(BoW)

再囉嗦一句詞袋模型,Bag of Words,這是我學習的第一個 NLP 語言模型。Bag of Words 會將詞典裏面的每個單詞編一個序號,這個序號從 0 開始累加,這樣當構造一個長度等於詞典的 list 時,它其中的每一維就對應了詞典中的每個字。學習

當須要表示某一個詞時,這個向量對應這個單詞的那一維的值爲1,其他爲0,這就是詞的 one-hot 表示方法。優化

當須要表示一篇文章時,文章中的每個詞對應的那一維的值爲單詞出現的次數,也叫作詞頻(TF),這就是最簡單的文本表示方法。url

3.TF-IDF

理論上來講,當咱們構造出了基於 BoW 的文檔向量後,只要對向量稍加處理(歸一化),就可使用這個文檔進行文本分類了,但這樣的效果並非很好,由於 BoW + TF 構造的向量只是對單個文檔進行了信息統計,並無考慮到全部文檔的統計信息,以及文檔之間究竟以什麼來區分。因此須要對文檔中出現的詞的 TF 值稍加處理,那就是計算TF-IDF。

網上搜一下 TF-IDF 的原理,大概能夠搜到上萬篇博客文章,因此這裏就再也不進行贅述。只用一句話來解釋它的做用就是:找出本身有什麼,而別人沒有。


3、代碼

代碼分爲兩部分來介紹,分別是向量構建及模型構建部分。

文本特徵向量構建其實就是機器學習過程當中構造特徵工程的過程。這裏使用了 gensim 和 LightGBM 包進行構建,sklearn 中也集成有調用 BoW, TF-IDF 和 LightGBM 的方法,你也能夠經過 sklearn 一站式搞定它們。

1.詞袋模型及文本特徵向量構建

from gensim import corpora, models

# bulid dictionay and tfidf model
all_corporas = []

for data in raw_data:
    text = clean_data(data)
    all_corporas.append(text)
    
    
dictionary = corpora.Dictionary(all_corporas)
corpus = [dictionary.doc2bow(text) for text in all_corporas]
tfidf = models.TfidfModel(corpus, id2word = dictionary)


# bulid one hot doc vector
def bulid_onehot_vector(data):
    tfidf_vec = tfidf[dictionary.doc2bow(clean_data(data))]
    one_hot = [0] * len(dictionary)
    for x in tfidf_vec:
        one_hot[x[0]] = x[1]
    return one_hot

clean_data() 中完成了對原始語料的分詞以及去停用詞操做,去停用詞的操做。特別要說明的是,因爲是基於文本中詞的統計信息來分類,因此去停用詞很重要,能夠去掉一些不重要詞的干擾。

接下來就是構造詞典,詞典中能夠去除一些詞頻太低的詞語,這裏能夠本身查閱 gensim 官方文檔對一些參數進行設置。最後創建 TF-IDF 模型,對特徵向量進行構造。

2.LightGBM

import lightgbm as lgb

lgb_train = lgb.Dataset(np.array(train_data), np.array(train_label))
lgb_val = lgb.Dataset(np.array(test_data), np.array(test_label))

params = {'max_depth': 15, 'min_data_in_leaf': 55, 'num_leaves': 80, 'learning_rate': 0.1, 'lambda_l1': 0.1,
          'lambda_l2': 0.2, 'objective': 'multiclass', 'num_class': 3, 'verbose': -1}

num_boost_round = 200

gbm = lgb.train(params, lgb_train, num_boost_round, verbose_eval=50, valid_sets=lgb_val)
result = gbm.predict(np.array(test_data), num_iteration=gbm.best_iteration)

LightGBM 的構建就更加簡單了,首先將訓練數據封裝成 Dataset 格式,設置好參數,直接 train 就ok,這裏主要說一下參數的設置吧。

LightGBM 調參中,最重要的三個參數分別是 max_depth, min_data_in_leaf, num_leaves。

LightGBM 採用的分裂方式是 Leaf-wise,這樣每一棵 LightGBM 可以更好的對上一棵樹預測殘差的負梯度進行擬合,這使得 LightGBM 的精度更高,但也更容易過擬合,這三個參數是控制 LightGBM 模型擬合程度的關鍵所在。

首先,max_depth 表明樹的深度,樹越深越容易過擬合。

min_data_in_leaf 表明每一個葉子節點上的最小樣本數量。樣本過少容易過擬合。樣本過多容易欠擬合,何以理解爲預剪枝的操做。

num_leaves 表明樹的葉子節點個數。節點數過多容易過擬合,節點數過少容易欠擬合。

也是因爲 LightGBM 採用的分裂方式是 Leaf-wise,所以 max_depth 與 num_leaves 並不存在任何關聯,須要在 num_leaves 小於最大葉子節點數的前提下分別獨立調參。


4、結論

因爲數據來源於公司,因此這裏訓練過程和分類結果就只有跳票,直接來下結論吧。

BoW + TF-IDF + LightGBM 的文本分類原理,表面來講,是基於關鍵詞。但實際上則是基於文檔中詞的統計信息,這種分類方法徹底不會對文章的語義進行理解和分析,因此只適用於一些類別之間特徵明顯的簡單文本分類任務,當遇到未登陸詞或須要依靠複雜語義分析和語義特徵提取的任務時,就沒法正確的進行分類判斷。固然也可經過分析 bad case,針對性的增長相應語料來提高分類性能。

當文本各個類別的樣本數量不均衡時,能夠考慮使用 focal loss 來做爲 loss function,具體的方法後面單獨再寫一篇來記錄。

另外,當詞典過長時,構造的文本向量長度也就較長,這樣會形成 LightGBM 推理時間過長。因此須要對詞典中的一些詞頻較低的詞進行捨棄,但這樣也會形成必定的分類精度下降。

最後的一個 trick 是,在用這種方法分類中文文本時,分類的準確程度就變得更爲重要,所以能夠在分詞的基礎上,在詞典和文本向量中加入單個漢字,對分類的性能也會有必定的提高。

 

 

若有錯誤遺漏歡迎交流指正,轉載請註明出處。

發佈了69 篇原創文章 · 獲贊 95 · 訪問量 13萬+
相關文章
相關標籤/搜索