零基礎入門NLP - 基於機器學習的文本分類

任何分類問題, 都須要從數據中挖掘有用的特徵, 文本分類也不例外. 這裏會介紹幾種從文本中提取特徵的方式. 也是處理文本最基礎的方法.python

文本表示方法

在機器學習算法的訓練過程當中,假設給定$N$個樣本,每一個樣本有$M$個特徵,這樣組成了$N×M$的樣本矩陣,而後完成算法的訓練和預測。一樣的在計算機視覺中能夠將圖片的像素看做特徵,每張圖片看做hight×width×3的特徵圖,一個三維的矩陣來進入計算機進行計算。算法

可是在天然語言領域,上述方法卻不可行:文本是不定長度的。文本表示成計算機可以運算的數字或向量的方法通常稱爲詞嵌入(Word Embedding)方法。詞嵌入將不定長的文本轉換到定長的空間內,是文本分類的第一步。dom

One-hot獨熱標籤

one-hot一般被用來編碼不一樣類別, 一個編碼的每一位對應一個類別, 且只有其中一位是1, 其他均爲0. 按照相同的思想, 咱們也能夠用one-hot編碼來表示每個單詞. 好比下面兩句話機器學習

句子1:我 愛 北 京 天 安 門
句子2:我 喜 歡 上 海

首先會統計兩句話中的全部字的類別, 並將每一個類別編號函數

{
'我': 1, '愛': 2, '北': 3, '京': 4, '天': 5,
'安': 6, '門': 7, '喜': 8, '歡': 9, '上': 10, '海': 11
}

在這裏共包括11個字,所以每一個字能夠轉換爲一個11維度稀疏向量:工具

我:[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
愛:[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
...
海:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

這種思路看似是合理的, 但存在明顯的2個問題學習

  1. 對於一個稍複雜的語料數據, 就已經包含龐大數量的詞, 而且一個詞還會有多種形式, 若是每一個詞都用一個one-hot編碼向量表示, 會致使維度爆炸.
  2. one-hot向量沒法建模單詞之間(one-hot向量相互正交)的關係, 然而這種信息是文本中重要的特徵.

Bag of Words

bag of words(BoW)也叫詞袋模型, 是一種從文本中提取特徵用於建模的方法.this

詞袋模型是一種描述一個文檔中的單詞出現的文本表示,它主要包括編碼

  • 一個已有單詞的詞典.
  • 已有單詞表示的度量.

之因此被稱爲詞袋, 由於BoW只關心已知單詞在文檔中是否出現, 並不關心它在文檔中出現的順序和結構信息.它將每一個詞在文檔中的計數做爲特徵.設計

構建一個BoW模型包括如下幾個步驟

  1. 收集數據
    好比

    It was the best of times,
    it was the worst of times,
    it was the age of wisdom,
    it was the age of foolishness,
  2. 設計詞典
    能夠將文檔庫(收集的數據)中本身認爲重要的單詞加入到詞典中, 詞典的形式以下

    「it」
    「was」
    「the」
    「best」
    「of」
    「times」
    「worst」
    「age」
    「wisdom」
    「foolishness」
  3. 建立文檔向量
    這一步的目的是將每一個文檔(能夠理解成包含不定長度單詞的句子)轉換爲一個固定長度的向量, 向量的長度爲詞典中單詞的個數.
    那麼如何將文檔轉換爲單個向量呢, 最簡單的方式就是, 使用一個布爾值來表示詞典中每一個詞是否在文檔中是否出現, 出現了即爲1, 不然爲0
    好比上面的一個文檔獲得的向量爲

    「it」 = 1
    「was」 = 1
    「the」 = 1
    「best」 = 1
    「of」 = 1
    「times」 = 1
    「worst」 = 0
    「age」 = 0
    「wisdom」 = 0
    「foolishness」 = 0

    對應向量爲:

    [1, 1, 1, 1, 1, 1, 0, 0, 0, 0]

在sklearn中, 咱們能夠利用自帶的工具快速的實現BoW的功能

from sklearn.feature_extraction.text import CountVectorizer
corpus = [
        'This is the first document.',
        'This document is the second document.',
        'And this is the third one.',
        'Is this the first document?',
]
# 將每一個單詞在詞典中出現的次數做爲特徵
counter = CountVectorizer()
vectors = counter.fit_transform(corpus)

N-gram

簡單來講, N-gram模型根據前N-1個已有的單詞來預測一個單詞出現的機率, 但N=2(N-1=1)時, 即一個單詞出現的機率僅由它的前一個單詞決定.
那麼如何根據N-1個已出現的單詞來預測一個單詞的出現呢?
首先, 咱們須要一個語料庫(corpus), 包含了大量的句子. 假設如今語料庫包含了以下的句子

1.He said thank you.
2.He said bye as he walked through the door.
3.He went to San Diego.
4.San Diego has nice weather.
5.It is raining in San Francisco.

假設咱們設置N爲2, 即只根據它前一個詞來進行預測單詞出現的機率.一般而言, 機率的計算方式以下
$\frac{count(wp wn)}{count(wp)}$, wp表示上一個單詞, wn表示當前單詞, count爲計數函數.

好比咱們要獲得you 出如今thank以後的機率P(you|thank),它等同於

occurence times of "thank you" / occurence times of "thank"
= 1 / 1
= 1

咱們能夠說, 不管何時出現了thank, you都會出如今它後面.

TF-IDF

TF-IDF(term frequency-inverse document frequency), 它是一種統計度量的方法, 用來評估一個單詞對於文檔庫中的一個文檔的相關程度. 它在信息檢索和文本挖掘常常被使用.
對於一個文檔中的一個單詞, 它的TF-IDF能夠經過乘以兩個不一樣的指標來獲得

  • term-frequency(TF): $TF(t) = \frac{count(t)}{ total \quad terms} =\frac{單詞t在當前文檔出現的次數}{當前文檔中總的單詞數}$
  • inverse document frequency(IDF): $IDF(t)=In(\frac{count(document)}{count(document\quad which\quad contain\quad term\quad t)})=In(\frac{總的文檔數目}{包含單詞t的文檔數目})$

好比一個文檔中包含100個詞, 單詞cat出現了3次, 則TF(cat)=3/100=0.03, 假設咱們有1e7個文檔, cat在其中的1e3箇中出現了, 則IDF(cat)=log(1e7/1e3)=4, 所以TF_IDF權重爲: 0.03 * 4 = 0.12.

如今回到競賽的數據中去, 嘗試使用TF-IDF來構建特徵進行分類

import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.metrics import  f1_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import RidgeClassifier

root_dir = '/content/drive/My Drive/competitions/NLPNews'

# 內存有限, 這裏只讀取10000行
train_df = pd.read_csv(root_dir+'/train.csv', sep='\t', nrows=10000)

# max_features表示詞典的大小, 包含詞頻最高的max_features個詞
tfidf = TfidfVectorizer(ngram_range=(1, 3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])

# 構建分類器
clf = RidgeClassifier()

# 切分數據集
x_train, x_test, y_train, y_test = train_test_split(train_test, train_df['label'], test_size=0.1, random_state=0)

# 訓練模型
clf.fit(x_train, y_train)

# 執行預測
y_pred = clf.predict(x_test)

# 輸出宏平均f1-score
print(f1_score(y_test, y_pred, average='macro'))
0.8802400152512864

總結

經過本次的學習, 對於文本的表示方法以及文本數據集的特徵構建有了一個基本的瞭解.

Reference

[1] Datawhale零基礎入門NLP賽事 - Task3 基於機器學習的文本分類)
[2] A Gentle Introduction to the Bag-of-Words Model
[3] An Introduction to N-grams: What Are They and Why Do We Need Them?
[4] what does tf-idf mean?

相關文章
相關標籤/搜索