向量化與HashTrick在文本挖掘中預(yù)處理中的體現(xiàn)
前言
在(文本挖掘的分詞原理)中,我們講到了文本挖掘的預(yù)處理的關(guān)鍵一步:“分詞”,而在做了分詞后,如果我們是做文本分類聚類,則后面關(guān)鍵的特征預(yù)處理步驟有向量化或向量化的特例Hash Trick,本文我們就對向量化和特例Hash Trick預(yù)處理方法做一個總結(jié)。
詞袋模型
在講向量化與Hash Trick之前,我們先說說詞袋模型(Bag of Words,簡稱BoW)。詞袋模型假設(shè)我們不考慮文本中詞與詞之間的上下文關(guān)系,僅僅只考慮所有詞的權(quán)重。而權(quán)重與詞在文本中出現(xiàn)的頻率有關(guān)。
詞袋模型首先會進行分詞,在分詞之后,通過統(tǒng)計每個詞在文本中出現(xiàn)的次數(shù),我們就可以得到該文本基于詞的特征,如果將各個文本樣本的這些詞與對應(yīng)的詞頻放在一起,就是我們常說的向量化。向量化完畢后一般也會使用TF-IDF進行特征的權(quán)重修正,再將特征進行標(biāo)準(zhǔn)化。 再進行一些其他的特征工程后,就可以將數(shù)據(jù)帶入機器學(xué)習(xí)算法進行分類聚類了。
詞袋模型的三部曲:
- 分詞(tokenizing);
- 統(tǒng)計修訂詞特征值(counting);
- 標(biāo)準(zhǔn)化(normalizing);
與詞袋模型非常類似的一個模型是詞集模型(Set of Words,簡稱SoW),和詞袋模型***的不同是它僅僅考慮詞是否在文本中出現(xiàn),而不考慮詞頻。也就是一個詞在文本在文本中出現(xiàn)1次和多次特征處理是一樣的。在大多數(shù)時候,我們使用詞袋模型,后面的討論也是以詞袋模型為主。
當(dāng)然,詞袋模型有很大的局限性,因為它僅僅考慮了詞頻,沒有考慮上下文的關(guān)系,因此會丟失一部分文本的語義。但是大多數(shù)時候,如果我們的目的是分類聚類,則詞袋模型表現(xiàn)的很好。
BoW之向量化
在詞袋模型的統(tǒng)計詞頻這一步,我們會得到該文本中所有詞的詞頻,有了詞頻,我們就可以用詞向量表示這個文本。這里我們舉一個例子,例子直接用scikit-learn的CountVectorizer類來完成,這個類可以幫我們完成文本的詞頻統(tǒng)計與向量化,代碼如下:
- from sklearn.feature_extraction.text import CountVectorizer
- corpus=["I come to China to travel",
- "This is a car polupar in China",
- "I love tea and Apple ",
- "The work is to write some papers in science"]
- print vectorizer.fit_transform(corpus)
我們看看對于上面4個文本的處理輸出如下:
- (0, 16)1
- (0, 3)1
- (0, 15)2
- (0, 4)1
- (1, 5)1
- (1, 9)1
- (1, 2)1
- (1, 6)1
- (1, 14)1
- (1, 3)1
- (2, 1)1
- (2, 0)1
- (2, 12)1
- (2, 7)1
- (3, 10)1
- (3, 8)1
- (3, 11)1
- (3, 18)1
- (3, 17)1
- (3, 13)1
- (3, 5)1
- (3, 6)1
- (3, 15)1
可以看出4個文本的詞頻已經(jīng)統(tǒng)計出,在輸出中,左邊的括號中的***個數(shù)字是文本的序號,第2個數(shù)字是詞的序號,注意詞的序號是基于所有的文檔的。第三個數(shù)字就是我們的詞頻。
我們可以進一步看看每個文本的詞向量特征和各個特征代表的詞,代碼如下:
- print vectorizer.fit_transform(corpus).toarray()
- print vectorizer.get_feature_names()
輸出如下:
- [[0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0]
- [0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0]
- [1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0]
- [0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1]]
- [u'and', u'apple', u'car', u'china', u'come', u'in', u'is', u'love', u'papers', u'polupar', u'science', u'some', u'tea', u'the', u'this', u'to', u'travel', u'work', u'write']
可以看到我們一共有19個詞,所以4個文本都是19維的特征向量。而每一維的向量依次對應(yīng)了下面的19個詞。另外由于詞”I”在英文中是停用詞,不參加詞頻的統(tǒng)計。
由于大部分的文本都只會使用詞匯表中的很少一部分的詞,因此我們的詞向量中會有大量的0。也就是說詞向量是稀疏的。在實際應(yīng)用中一般使用稀疏矩陣來存儲。將文本做了詞頻統(tǒng)計后,我們一般會通過TF-IDF進行詞特征值修訂。
向量化的方法很好用,也很直接,但是在有些場景下很難使用,比如分詞后的詞匯表非常大,達(dá)到100萬+,此時如果我們直接使用向量化的方法,將對應(yīng)的樣本對應(yīng)特征矩陣載入內(nèi)存,有可能將內(nèi)存撐爆,在這種情況下我們怎么辦呢?***反應(yīng)是我們要進行特征的降維,說的沒錯!而Hash Trick就是非常常用的文本特征降維方法。
Hash Trick
在大規(guī)模的文本處理中,由于特征的維度對應(yīng)分詞詞匯表的大小,所以維度可能非??植?,此時需要進行降維,不能直接用我們上一節(jié)的向量化方法。而最常用的文本降維方法是Hash Trick。說到Hash,一點也不神秘,學(xué)過數(shù)據(jù)結(jié)構(gòu)的同學(xué)都知道。這里的Hash意義也類似。
在Hash Trick里,我們會定義一個特征Hash后對應(yīng)的哈希表的大小,這個哈希表的維度會遠(yuǎn)遠(yuǎn)小于我們的詞匯表的特征維度,因此可以看成是降維。具體的方法是,對應(yīng)任意一個特征名,我們會用Hash函數(shù)找到對應(yīng)哈希表的位置,然后將該特征名對應(yīng)的詞頻統(tǒng)計值累加到該哈希表位置。如果用數(shù)學(xué)語言表示,假如哈希函數(shù)h使第i個特征哈希到位置j,即h(i)=j,則第i個原始特征的詞頻數(shù)值ϕ(i)將累加到哈希后的第j個特征的詞頻數(shù)值ϕ¯上,即:
但是上面的方法有一個問題,有可能兩個原始特征的哈希后位置在一起導(dǎo)致詞頻累加特征值突然變大,為了解決這個問題,出現(xiàn)了hash Trick的變種signed hash trick,此時除了哈希函數(shù)h,我們多了一個哈希函數(shù):
這樣做的好處是,哈希后的特征仍然是一個無偏的估計,不會導(dǎo)致某些哈希位置的值過大。
在scikit-learn的HashingVectorizer類中,實現(xiàn)了基于signed hash trick的算法,這里我們就用HashingVectorizer來實踐一下Hash Trick,為了簡單,我們使用上面的19維詞匯表,并哈希降維到6維。當(dāng)然在實際應(yīng)用中,19維的數(shù)據(jù)根本不需要Hash Trick,這里只是做一個演示,代碼如下:
- from sklearn.feature_extraction.text import HashingVectorizer
- vectorizer2=HashingVectorizer(n_features = 6,norm = None)print vectorizer2.fit_transform(corpus)
輸出如下:
- (0, 1)2.0
- (0, 2)-1.0
- (0, 4)1.0
- (0, 5)-1.0
- (1, 0)1.0
- (1, 1)1.0
- (1, 2)-1.0
- (1, 5)-1.0
- (2, 0)2.0
- (2, 5)-2.0
- (3, 0)0.0
- (3, 1)4.0
- (3, 2)-1.0
- (3, 3)1.0
- (3, 5)-1.0
和PCA類似,Hash Trick降維后的特征我們已經(jīng)不知道它代表的特征名字和意義。此時我們不能像上一節(jié)向量化時候可以知道每一列的意義,所以Hash Trick的解釋性不強。
小結(jié)
在特征預(yù)處理的時候,我們什么時候用一般意義的向量化,什么時候用Hash Trick呢?標(biāo)準(zhǔn)也很簡單。
一般來說,只要詞匯表的特征不至于太大,大到內(nèi)存不夠用,肯定是使用一般意義的向量化比較好。因為向量化的方法解釋性很強,我們知道每一維特征對應(yīng)哪一個詞,進而我們還可以使用TF-IDF對各個詞特征的權(quán)重修改,進一步完善特征的表示。
而Hash Trick用大規(guī)模機器學(xué)習(xí)上,此時我們的詞匯量極大,使用向量化方法內(nèi)存不夠用,而使用Hash Trick降維速度很快,降維后的特征仍然可以幫我們完成后續(xù)的分類和聚類工作。當(dāng)然由于分布式計算框架的存在,其實一般我們不會出現(xiàn)內(nèi)存不夠的情況。因此,實際工作中我使用的都是特征向量化。