機器學習算法往往無法直接處理文本數據,需要把文本數據轉換為數值型數據,One-Hot表示把文本轉換為數值的一種方法。
一,One-Hot表示
One-Hot表示是把語料庫中的所有文本進行分詞,把所有單詞(詞匯)收集起來,並對單詞進行編號,構建一個詞匯表(vocabulary),詞匯表是一個字典結構,key是單詞,value是單詞的索引
vocabulary = { 'one':0,'hot':1, ...'term':n-1}
如果詞匯表有n個單詞構成,那么單詞的索引從0開始,到n-1結束。
有了詞匯表之后,就可以使用向量來表示單個詞匯。每一個詞匯都表示為一個由n列構成的向量,稱作詞向量,詞向量的第0列對應詞匯表(vocabulary)中的第0號索引,詞向量的第1列對應詞匯表(vocabulary)中的第1號索引,依次類推。
詞匯向量有n列,但是只有一列的值為1,把值為1的列的索引帶入到詞匯表(vocabulary)中,就可以查找到該詞向量表示的詞匯,也就是說,對於某個單詞 term,如果它出現在詞匯序列中的位置為 k,那么它的向量表示就是“第 k 位為1,其他位置都為0 ”,這就是One-Hot(獨熱)名稱的由來。
1,用One-Hot表示單詞
例如,有語料庫(corpus)如下:
John likes to watch movies. Mary likes movies too.
John also likes to watch football games.
把上述語料中的詞匯整理出來並進行排序(具體的排序原則可以有很多,例如可以根據字母表順序,也可以根據出現在語料庫中的先后順序),假設我們的詞匯表排序結果如下:
{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies": 5, "also":6, "football": 7, "games": 8, "Mary": 9, "too": 10}
那么,得出如下詞向量表示:
John: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
likes: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
……
2,文檔向量
文檔向量的表示方法是直接把各詞的詞向量表示加和,那么原來的兩句話的向量表示如下:
[1, 2, 1, 1, 2, 0, 0, 0, 1, 1]
[1, 1, 1, 1, 0, 1, 1, 1, 0, 0]
文檔向量中,列的值表示詞在文檔中出現的次數。
3,One-Hot表示的缺點
One-Hot方法很簡單,但是它的問題也很明顯:
- 沒有考慮單詞之間的相對位置,任意兩個詞之間都是孤立的;
- 如果文檔中有很多詞,詞向量會有很多列,但是只有一個列的值是1;
4,One-Hot表示的應用
sklearn使用詞袋(Bag of Words)和TF-IDF模型來表示文本數據,這兩個模型都是One-Hot表示的應用,其中,詞袋模型對應的就是文檔向量。
二,詞袋模型
詞袋模型(BoW)是用於文本表示的最簡單的方法, BoW把文本轉換為文檔中單詞出現次數的矩陣,該模型只關注文檔中是否出現給定的單詞和單詞出現頻率,而舍棄文本的結構、單詞出現的順序和位置。
1,構建詞袋模型的步驟
對於一個文本語料庫,構建詞袋模型有三個步驟:
- 文本分詞:把每個文檔中的文本進行分詞
- 構建詞匯表:把文本分詞得到的單詞構建為一個詞匯表,包含文本語料庫中的所有單詞,並對單詞進行編號,假設詞匯表有n個單詞,單詞編號從0開始,到n-1結束,可以把單詞編號看作是單詞的索引,通過單詞編號可以唯一定位到該單詞。
- 詞向量表示:每個單詞都表示為一個n列的向量,在單詞編號(詞匯索引)位置上的列值為1,其他列的值為0
- 統計頻次:統計每個文檔中每個單詞出現的頻次。
舉個例子,有如下包含三個文檔(doc)的語料庫,每個文檔是一行文本:
Doc 1: I love dogs.
Doc 2: I hate dogs and knitting.
Doc 3: Knitting is my hobby and passion.
根據語料庫,對文本進行分詞,創建詞匯表。根據詞匯表計算每個文檔中的單詞出現的次數,這個矩陣叫做文檔-詞矩陣(DTM,Document-Term Matrix)。

這個矩陣使用的是單個詞,也可以使用兩個或多個詞的組合,叫做bi-gram模型或tri-gram模型,統稱n-gram模型。
使用sklearn構建詞袋模型:
CountVectorizer(input=’content’, encoding=’utf-8’, decode_error=’strict’, strip_accents=None, lowercase=True, preprocessor=None, tokenizer=None, stop_words=None, token_pattern=’(?u)\b\w\w+\b’, ngram_range=(1, 1), analyzer=’word’, max_df=1.0, min_df=1, max_features=None, vocabulary=None, binary=False, dtype=<class ‘numpy.int64’>)
常用參數注釋:
- input:默認值是content,表示輸入的是順序的字符文本
- decode_error:默認為strict,遇到不能解碼的字符將報UnicodeDecodeError錯誤,設為ignore將會忽略解碼錯誤
- lowercase:默認值是True,在分詞(Tokenize)之前把文本中的所有字符轉換為小寫。
- preprocessor:預處理器,在分詞之前對文本進行預處理,默認值是None
- tokenizer:分詞器,把文本字符串拆分成各個單詞(token),默認值是None
- analyzer:用於預處理和分詞,可設置為string類型,如’word’, ‘char’, ‘char_wb’,默認值是word
- stop_words:停用詞表,如果值是english,使用內置的英語停用詞列表;如果是一個列表,那么使用該列表作為停用詞,設為None且max_df∈[0.7, 1.0)將自動根據當前的語料庫建立停用詞表
- ngram_range:tuple(min_n,max_n),表示ngram模型的范圍
- max_df:可以設置為范圍在[0.0 1.0]的浮點數,也可以設置為沒有范圍限制的整數,默認為1.0。這個參數的作用是作為一個閾值,當構造語料庫的詞匯表時,如果某個詞的document frequence大於max_df,這個詞不會被當作關鍵詞。如果這個參數是float,則表示詞出現的次數與語料庫文檔數的百分比,如果是int,則表示詞出現的次數。如果參數中已經給定了vocabulary,則這個參數無效
- min_df:類似於max_df,不同之處在於如果某個詞的document frequence小於min_df,則這個詞不會被當作關鍵詞
- max_features:對所有關鍵詞的term frequency進行降序排序,只取前max_features個作為關鍵詞集
- vocabulary:默認為None,自動從輸入文檔中構建關鍵詞集,也可以是一個字典或可迭代對象。
- binary:默認為False,一個關鍵詞在一篇文檔中可能出現n次;如果binary=True,非零的n將全部置為1,這對需要布爾值輸入的離散概率模型的有用的
- dtype :用於設置fit_transform() 或 transform()函數返回的矩陣元素的數據類型
模型的屬性和方法:
- vocabulary_:詞匯表,字典類型
- get_feature_names():所有文本的詞匯,列表型
- stop_words_:停用詞列表
模型的主要方法:
- fit(raw_document):擬合模型,對文本分詞,並構建詞匯表等
- transform(raw_documents):把文檔轉換為文檔-詞矩陣
- fit_transform(raw_documents):擬合文檔,並返回該文檔的文檔-詞矩陣
2,單個詞的詞袋模型
使用CounterVectorizer()函數構建單個詞的詞袋模型:
>>> 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?', ... ] >>> vectorizer = CountVectorizer() >>> dt = vectorizer.fit_transform(corpus) >>> print(vectorizer.get_feature_names()) ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this'] >>> print(dt.toarray()) [[0 1 1 1 0 0 1 0 1] [0 2 0 1 0 1 1 0 1] [1 0 0 1 1 0 1 1 1] [0 1 1 1 0 0 1 0 1]]
三,TF-IDF模型
TF-IDF模型用於對特征信息量進行縮放,當一個詞在特定的文檔中經常出現,而在其他文檔中出現的頻次很低,那么給予該詞較高的權重;當一次詞在多個文檔中出現的頻次都很高,那么給予該詞較低的權重。如果一次單詞在特定的文檔中出現的頻次很高,而在其他文檔中出現的頻次很低,那么這個單詞很可能是該文檔獨有的詞,能夠很好地描述該文檔。
1,TF-IDF模型計算原理
TF( Term Frequency)是詞頻,表示每個單詞在文檔中的數量(頻數),TF依賴於BoW模型的輸出。
IDF(Inverse Document Frequency)是逆文檔頻率,代表一個單詞的普遍成都,當一個詞越普遍(即有大量文檔包含這個詞)時,其IDF值越低;反之,則IDF值越高。IDF是包含該單詞的文檔數量和文檔總數的對數縮放比例

TF-IDF(術語頻率 - 逆文檔頻率)模型是TF和IDF相乘的結果:TF-IDF=TF*IDF。
在文檔中具有高tf-idf的單詞,大多數情況下,只發生在給定的文檔中,並且在其他文檔中不存在,所以這些詞是該文檔的特征詞匯。

2,構建TF-IDF模型
使用TfidfVectorizer()函數構建TF-IDF模型
TfidfVectorizer(input=’content’, encoding=’utf-8’, decode_error=’strict’, strip_accents=None, lowercase=True, preprocessor=None, tokenizer=None, stop_words=None, token_pattern=’(?u)\b\w\w+\b’, ngram_range=(1, 1), analyzer=’word’, max_df=1.0, min_df=1, max_features=None, vocabulary=None, binary=False, dtype=dtype=<class ‘numpy.float64’>, norm=’l2’, use_idf=True, smooth_idf=True, sublinear_tf=False)
大部分參數和CountVectorizer相同,TfidfVectorizer獨有的參數注釋:
- norm=’l2’:每個輸出行具備單位規范,當引用'l2'范式時,所有向量元素的平方和為1;當應用l2范數時,兩個向量之間的余弦相似度是它們的點積。 *'l1':向量元素的絕對值之和為1。
- use_idf=True:啟用IDF來重新加權
- smooth_idf=True:平滑idf權重,向文檔-詞頻矩陣的所有位置加1,就像存在一個額外的文檔,只包含詞匯表中的每個術語一次,目的是為了防止零分裂。
- sublinear_tf=False:應用次線性tf縮放,默認值是False。
舉個例子,使用TfidfVectorizer()函數構建以下四個句子的TF-IDF模型:
>>> from sklearn.feature_extraction.text import TfidfVectorizer >>> corpus = [ ... 'This is the first document.', ... 'This document is the second document.', ... 'And this is the third one.', ... 'Is this the first document?', ... ] >>> vectorizer = TfidfVectorizer() >>> X = vectorizer.fit_transform(corpus) >>> print(vectorizer.get_feature_names()) ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this'] >>> print(X.toarray()) [[0. 0.46979139 0.58028582 0.38408524 0. 0. 0.38408524 0. 0.38408524] [0. 0.6876236 0. 0.28108867 0. 0.53864762 0.28108867 0. 0.28108867] [0.51184851 0. 0. 0.26710379 0.51184851 0. 0.26710379 0.51184851 0.26710379] [0. 0.46979139 0.58028582 0.38408524 0. 0. 0.38408524 0. 0.38408524]]
四,查看文檔的特征
對Bow和TF-IDF算法生成的模型進行操作
1,查看文本特征
從原始文檔列表(語料)中獲取特征列表:
>>> print(vectorizer.get_feature_names()) ['adr', 'authorized', 'contact', 'device', 'distributor', 'hub', 'information', 'installer', 'interested', 'microsoft', 'partner', 'program', 'receive', 'reseller', 'sign', 'surface', 'updates', 'website']
2,查看詞匯表
查看詞匯表中的詞匯和其對應的索引:
>>> items=vectorizer.vocabulary_.items() >>> print(items) dict_items([('information', 6), ('surface', 15), ('hub', 5), ('microsoft', 9), ('authorized', 1), ('device', 3), ('reseller', 13), ('adr', 0), ('interested', 8), ('contact', 2), ('distributor', 4), ('sign', 14), ('receive', 12), ('updates', 16), ('program', 11), ('partner', 10), ('website', 17), ('installer', 7)])
把dict_items結構轉換為Python的字典結構,key是索引,value是詞匯:
>>> feature_dict = {v: k for k, v in vectorizer.vocabulary_.items()}
3,查看詞-文檔矩陣
模型的fit_transform()或tranform()函數返回的是詞-文檔矩陣,在詞-文檔矩陣中列代表的是特征,行代表的原始文檔的數量,列代表該文檔包含的特征(即詞匯),列值是特征的TD-IDF值,范圍從0-1。
>>> print(X.toarray()) [[0. 0.46979139 0.58028582 0.38408524 0. 0. 0.38408524 0. 0.38408524] [0. 0.6876236 0. 0.28108867 0. 0.53864762 0.28108867 0. 0.28108867] [0.51184851 0. 0. 0.26710379 0.51184851 0. 0.26710379 0.51184851 0.26710379] [0. 0.46979139 0.58028582 0.38408524 0. 0. 0.38408524 0. 0.38408524]]
參考文檔:
sklearn.feature_extraction.text.TfidfVectorizer
