如何使用Scikit-learn實現(xiàn)用于機器學(xué)習(xí)的文本數(shù)據(jù)準(zhǔn)備
在使用文本數(shù)據(jù)來搭建預(yù)測模型前,都需要特殊的準(zhǔn)備工作。
文本首先要通過解析來提取單詞,這一過程稱為詞條化。然后單詞需要編碼為整數(shù)或浮點值,作為機器學(xué)習(xí)算法的輸入,稱為特征提取(或量化)。
scikit-learn提供了簡單的工具幫助我們對你的文本數(shù)據(jù)進行詞條化和特征提取。
在這篇文章中,你會學(xué)到在Python中如何使用scikit-learn實現(xiàn)用于機器學(xué)習(xí)的文本數(shù)據(jù)準(zhǔn)備。
在讀完這篇文章后,你會了解到:
- 如何使用CountVectorizer將文本的轉(zhuǎn)化成單詞頻數(shù)向量。
- 如何使用TfidfVectorizer提取文本的單詞權(quán)重向量。
- 如何使用HashingVectorizer將文本映射到特征索引。
讓我們開始吧。
“詞袋(Bag-of-words)”模型
在使用機器學(xué)習(xí)算法時,我們不能直接用文本進行運算。相反,我們需要將文本轉(zhuǎn)換成數(shù)字。
我們想對文檔進行分類時,每個文檔作為“輸入”,文檔的類別標(biāo)簽是我們預(yù)測算法的“輸出”。算法只能接受數(shù)字向量作為輸入,所以需要將文檔轉(zhuǎn)換成固定長度的數(shù)字向量。
機器學(xué)習(xí)領(lǐng)域有一個簡單且有效的模型,適用于文本文檔,叫做“詞袋”(Bag-of-Words)模型,簡稱為BOW。
該模型的簡單之處在于,它舍棄了單詞中的所有順序信息,并主要關(guān)注文檔中單詞的出現(xiàn)頻率。
這一點可以通過分配給每個單詞一個唯一的數(shù)字來實現(xiàn)。這樣一來,我們看到的任何文檔都可以編碼成一個固定長度的向量,長度為已知單詞所構(gòu)成的詞匯表的長度。該向量中每個位置的值是編碼文檔中的每個單詞出現(xiàn)的次數(shù)或頻率。
這就是“詞袋”模型,我們只關(guān)心編碼方法,能表示哪些詞語在文檔中出現(xiàn)了,或者他們在編碼文檔中出現(xiàn)的頻率,而不考慮任何關(guān)于順序的信息。
這個簡單的方法有很多種擴展,既可以更好地解釋“單詞”的含義,也可以定義向量中每個單詞的編碼方式。
scikit-learn提供了3種可供我們使用的不同方法,我們將簡要地看一下每種方法。
CountVectorizer——量化單詞數(shù)量
CountVectorizer提供了一種簡單的方法,不僅可以將文本文檔的數(shù)據(jù)集轉(zhuǎn)化成詞條并建立一個已知單詞的詞匯表,而且還可以用該詞匯表對新文本進行編碼。
使用方法如下:
- 創(chuàng)建CountVectorizer類的一個實例。
- 調(diào)用fit()函數(shù),通過學(xué)習(xí)從一個或多個文檔中得出一個詞匯表。
- 對一或多個文檔應(yīng)用transform()函數(shù),將每個文檔編碼成一個向量。
編碼得到的向量能夠返回整個詞匯表的長度,以及每個單詞在該文檔中出現(xiàn)的次數(shù)。
由于這些向量含有許多零值,所以我們稱之為稀疏的。Python在scipy.sparse庫中提供了一種處理這類稀疏向量的有效方法。
調(diào)用transform()所返回的向量是稀疏向量,你可以將它們轉(zhuǎn)換為numpy數(shù)組,看起來更直觀也更好理解,這一步可以通過調(diào)用toarray()函數(shù)完成。
下面是一個使用CountVectorizer來詞條化、構(gòu)造詞匯表,以及編碼文檔的示例。
- from sklearn.feature_extraction.text import CountVectorizer
- # 文本文檔列表
- text = ["The quick brown fox jumped over the lazy dog."]
- # 構(gòu)造變換函數(shù)
- vectorizer = CountVectorizer()
- # 詞條化以及建立詞匯表
- vectorizer.fit(text)
- # 總結(jié)
- print(vectorizer.vocabulary_)
- # 編碼文檔
- vector = vectorizer.transform(text)
- # 總結(jié)編碼文檔
- print(vector.shape)
- print(type(vector))
- print(vector.toarray())
從上例中可以看到,我們通過詞匯表來查看到底是什么被詞條化了:
- print(vectorizer.vocabulary_)
可以看到,所有單詞默認(rèn)情況下是小寫,并且忽略掉標(biāo)點符號。詞條化的這些參數(shù)以及其他方面是可配置的,我建議你在API文檔中查看所有選項。
運行這個示例,首先會顯示出詞匯表,然后顯示出編碼文檔的形狀。我們可以看到,詞匯表中有8個單詞,于是編碼向量的長度為8。
可以看出,編碼向量是一個稀疏矩陣。***,我們可以看到以數(shù)組形式出現(xiàn)的編碼向量,顯示出每個單詞的出現(xiàn)次數(shù)為1,除了索引號為7的單詞出現(xiàn)次數(shù)為2。
- {'dog': 1, 'fox': 2, 'over': 5, 'brown': 0, 'quick': 6, 'the': 7, 'lazy': 4, 'jumped': 3}
- (1, 8)
- <class 'scipy.sparse.csr.csr_matrix'>
- [[1 1 1 1 1 1 1 2]]
重要的是,該量化方法可以用于含有詞匯表中沒有出現(xiàn)的單詞的文檔。這些單詞會被忽略掉,然后在得到的向量結(jié)果中不會給出出現(xiàn)次數(shù)。
下面是一個使用上述的詞條化工具對文檔進行編碼的示例,該文檔中含有一個詞匯表中的詞,以及一個不在詞匯表中的詞。
- # 編碼其他文檔
- text2 = ["the puppy"]
- vector = vectorizer.transform(text2)
- print(vector.toarray())
運行示例,顯示出編碼稀疏向量的矩陣形式,可以看出詞匯表中的單詞出現(xiàn)了1次,而沒在詞匯表中的單詞完全被忽略了。
- [[0 0 0 0 0 0 0 1]]
編碼的向量可以直接用于機器學(xué)習(xí)算法。
TfidfVectorizer——計算單詞權(quán)重
統(tǒng)計單詞出現(xiàn)次數(shù)是一個很好的切入點,但也是很基礎(chǔ)的特征。
簡單的次數(shù)統(tǒng)計的一個問題在于,有些單詞,例如“the”會出現(xiàn)很多次,它們的統(tǒng)計數(shù)量對于編碼向量沒有太大意義。
一個替代方法是統(tǒng)計單詞權(quán)重,目前***的方法是TF-IDF。這是一個縮寫詞,代表“詞頻-逆文檔頻率”(Term Frequency–Inverse Document Frequency),代表一個詞對于一個文檔的重要程度。
詞頻(Term Frequency):指的是某一個給定的詞語在一篇文檔中出現(xiàn)的次數(shù)。
逆文檔頻率(Inverse Document Frequency):單詞在文檔中出現(xiàn)的頻率越高,IDF值越低。
撇開數(shù)學(xué)不說,TF-IDF給出的是單詞權(quán)重,會把更有意思的單詞標(biāo)注出來,例如僅在某篇文檔中頻率很高但不會在所有文檔中都頻繁出現(xiàn)的詞。
TfidfVectorizer可以詞條化文檔,學(xué)習(xí)詞匯表以及逆文檔頻率權(quán)重,并且可以編碼新文檔。或者,如果你已經(jīng)用CountVectorizer學(xué)習(xí)得到了向量,你可以對它使用Tfidftransformer函數(shù),計算逆文檔頻率并且開始編碼文件。
同樣的,創(chuàng)建(create)、擬合(fit)以及變換(transform)函數(shù)的調(diào)用都與CountVectorizer相同。
下面是一個使用TfidfVectorizer來學(xué)習(xí)詞匯表和3篇小文檔的逆文檔頻率的示例,并對其中一篇文檔進行編碼。
- from sklearn.feature_extraction.text import TfidfVectorizer
- # 文本文檔列表
- text = ["The quick brown fox jumped over the lazy dog.",
- "The dog.",
- "The fox"]
- # 創(chuàng)建變換函數(shù)
- vectorizer = TfidfVectorizer()
- # 詞條化以及創(chuàng)建詞匯表
- vectorizer.fit(text)
- # 總結(jié)
- print(vectorizer.vocabulary_)
- print(vectorizer.idf_)
- # 編碼文檔
- vector = vectorizer.transform([text[0]])
- # 總結(jié)編碼文檔
- print(vector.shape)
- print(vector.toarray())
上例中,我們從文檔中學(xué)到了含有8個單詞的詞匯表,在輸出向量中,每個單詞都分配了一個唯一的整數(shù)索引。
我們計算了詞匯表中每個單詞的逆文檔頻率,給觀測到的最常出現(xiàn)的單詞“the”(索引號為7)分配了***的分?jǐn)?shù)1.0。
最終,***個文檔被編碼成一個8個元素的稀疏矩陣,我們可以查看每個單詞的最終權(quán)重分?jǐn)?shù),可以看到“the”、“fox”,以及“dog”的值與詞匯表中其他單詞的值不同。
- {'fox': 2, 'lazy': 4, 'dog': 1, 'quick': 6, 'the': 7, 'over': 5, 'brown': 0, 'jumped': 3}
- [ 1.69314718 1.28768207 1.28768207 1.69314718 1.69314718 1.69314718
- 1.69314718 1. ]
- (1, 8)
- [[ 0.36388646 0.27674503 0.27674503 0.36388646 0.36388646 0.36388646
- 0.36388646 0.42983441]]
這些分?jǐn)?shù)被歸一化為0到1之間的值,編碼的文檔向量可以直接用于大多數(shù)機器學(xué)習(xí)算法。
HashingVectorizer——哈希量化文本
單詞頻率和權(quán)重是很有用的,但是當(dāng)詞匯表變得很大時,以上兩種方法就會出現(xiàn)局限性。
反過來,這將需要巨大的向量來編碼文檔,并對內(nèi)存要求很高,而且會減慢算法的速度。
一種很好的方法是使用單向哈希方法來將單詞轉(zhuǎn)化成整數(shù)。好處是該方法不需要詞匯表,可以選擇任意長的固定長度向量。缺點是哈希量化是單向的,因此無法將編碼轉(zhuǎn)換回單詞(對與許多有監(jiān)督的學(xué)習(xí)任務(wù)來說或許并不重要)。
HashingVectorizer類實現(xiàn)了這一方法,所以可以使用它對單詞進行連續(xù)哈希量化,然后按需求詞條化和編碼文檔。
下面是對單一文檔使用HashingVectorizer進行編碼的示例。
我們選擇了一個固定長度為20的任意向量。這個值對應(yīng)哈希函數(shù)的范圍,小的值(例如20)可能會導(dǎo)致哈希碰撞。在之前的計算機科學(xué)課程中,我們介紹過一些啟發(fā)式算法,可以根據(jù)估計的詞匯量來選擇哈希長度和碰撞概率。
要注意這種量化方法不要求調(diào)用函數(shù)來對訓(xùn)練數(shù)據(jù)文件進行擬合。相反,在實例化之后,它可以直接用于編碼文檔。
- from sklearn.feature_extraction.text import HashingVectorizer
- # 文本文檔列表
- text = ["The quick brown fox jumped over the lazy dog."]
- # 創(chuàng)建變換函數(shù)
- vectorizer = HashingVectorizer(n_features=20)
- # 編碼文檔
- vector = vectorizer.transform(text)
- # 總結(jié)編碼文檔
- print(vector.shape)
- print(vector.toarray())
運行該示例代碼可以把樣例文檔編碼成一個含有20個元素的稀疏矩陣。
編碼文檔的值對應(yīng)于正則化的單詞計數(shù),默認(rèn)值在-1到1之間,但是可以修改默認(rèn)設(shè)置,然后設(shè)置成整數(shù)計數(shù)值。
- (1, 20)
- [[ 0. 0. 0. 0. 0. 0.33333333
- 0. -0.33333333 0.33333333 0. 0. 0.33333333
- 0. 0. 0. -0.33333333 0. 0.
- -0.66666667 0. ]]
深度閱讀
這一節(jié)我們?yōu)榇蠹姨峁┝艘恍╆P(guān)于這篇文章的深度閱讀材料。
自然語言處理
scikit-learn
- scikit-learn使用手冊4.2節(jié),特征提取。
- sckit-learn特征提取API。
- scikit-learn教程:文本數(shù)據(jù)處理。
類API
- CountVectorizer scikit-learn API
- TfidfVectorizer scikit-learn API
- TfidfTransformer scikit-learn API
- HashingVectorizer scikit-learn API
總結(jié)
在這篇教程中,你會學(xué)習(xí)到如何用scikit-learn來準(zhǔn)備用于機器學(xué)習(xí)的文本數(shù)據(jù)。
我們只是在這些例子中接觸了皮毛,我想強調(diào)的是這些類有許多設(shè)置細(xì)節(jié)會影響文檔詞條化的結(jié)果,值得我們繼續(xù)探究。