sklearn: TfidfVectorizer 中文處理及一些使用參數
常規使用
TfidfVectorizer可以把原始文本轉化為tf-idf的特征矩陣,從而為后續的文本相似度計算,主題模型(如LSI),文本搜索排序等一系列應用奠定基礎。基本應用如:
from sklearn.feature_extraction.text import TfidfVectorizer
document = ["I have a pen.",
"I have an apple."]
tfidf_model = TfidfVectorizer().fit(document)
# 得到tf-idf矩陣,稀疏矩陣表示法
sparse_result = tfidf_model.transform(document)
print(sparse_result)
# 第0個字符串,對應詞典序號為3的詞的TFIDF為0.8148
# (0, 3) 0.814802474667
# (0, 2) 0.579738671538
# (1, 2) 0.449436416524
# (1, 1) 0.631667201738
# (1, 0) 0.631667201738
print(sparse_result.todense())
# 轉化為更直觀的一般矩陣
# [[ 0. 0. 0.57973867 0.81480247]
# [ 0.6316672 0.6316672 0.44943642 0. ]]
print(tfidf_model.vocabulary_)
# 詞語與列的對應關系
# {'have': 2, 'pen': 3, 'an': 0, 'apple': 1}
注意:在上述計算tfidf過程中,有的詞因為過於簡短,會被自動丟棄,比如 I a 這兩個詞會被自動丟掉,這和
參數有關系,token_pattern。它默認只匹配長度>=2的單詞。
中文使用:
分詞
使用中文預料來統計tfidf
中文不比英文,詞語之間有着空格的自然分割,所以我們首先要進行分詞處理,再把它轉化為與上面的document類似的格式。用著名的中文分詞庫jieba進行分詞:
import jieba
text = """我是一條天狗呀!
我把月來吞了,
我把日來吞了,
我把一切的星球來吞了,
我把全宇宙來吞了。
我便是我了!"""
sentences = text.split()
sent_words = [list(jieba.cut(sent0)) for sent0 in sentences]
document = [" ".join(sent0) for sent0 in sent_words]
print(document)
# ['我 是 一條 天狗 呀 !', '我 把 月 來 吞 了 ,', '我 把 日來 吞 了 ,', '我 把 一切 的 星球 來 吞 了 ,', '我 把 全宇宙 來 吞 了 。', '我 便是 我 了 !']
建模
理論上,現在得到的document的格式已經可以直接拿來訓練了。讓我們跑一下模型試試。
tfidf_model = TfidfVectorizer().fit(document)
print(tfidf_model.vocabulary_)
# {'一條': 1, '天狗': 4, '日來': 5, '一切': 0, '星球': 6, '全宇宙': 3, '便是': 2}
sparse_result = tfidf_model.transform(document)
print(sparse_result)
# (0, 4) 0.707106781187
# (0, 1) 0.707106781187
# (2, 5) 1.0
# (3, 6) 0.707106781187
# (3, 0) 0.707106781187
# (4, 3) 1.0
# (5, 2) 1.0
注意:這里沒有出現報錯,但是我們發現,這里丟掉了一些詞,是參數搞的怪,會自動丟掉過短的詞。
參數
單字的問題是token_pattern這個參數搞的鬼。它的默認值只匹配長度≥2的單詞,就像其實開頭的例子中的'I'也被忽略了一樣,一般來說,長度為1的單詞在英文中一般是無足輕重的,但在中文里,就可能有一些很重要的單字詞,所以修改如下:
tfidf_model2 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b").fit(document)
print(tfidf_model2.vocabulary_)
# {'我': 8, '是': 12, '一條': 1, '天狗': 7, '呀': 6, '把': 9, '月': 13, '來': 14, '吞': 5, '了': 2, '日來': 10, '一切': 0, '的': 15, '星球': 11, '全宇宙': 4, '便是': 3}
token_pattern這個參數使用正則表達式來分詞,其默認參數為r"(?u)\b\w\w+\b"
,其中的兩個\w決定了其匹配長度至少為2的單詞,所以這邊減到1個。對這個參數進行更多修改,可以滿足其他要求,比如這里依然沒有得到標點符號,在此不詳解了。
過濾單詞
-
max_df/min_df: *[0.0, 1.0]內浮點數或正整數, 默認值=1.0* 當設置為浮點數時,過濾出現在超過max_df/低於min_df比例的句子中的詞語;正整數時,則是超過max_df句句子。
這樣就可以幫助我們過濾掉出現太多的無意義詞語,如下面的"我"就被過濾(雖然這里“我”的排比在文學上是很重要的)。
# 過濾出現在超過60%的句子中的詞語
tfidf_model3 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_df=0.6).fit(document)
print(tfidf_model3.vocabulary_)
# {'是': 8, '一條': 1, '天狗': 5, '呀': 4, '月': 9, '來': 10, '日來': 6, '一切': 0, '的': 11, '星球': 7, '全宇宙': 3, '便是': 2}
- stop_words: *list類型* 直接過濾指定的停用詞。
tfidf_model4 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_df=0.6, stop_words=["是", "的"]).fit(document)
print(tfidf_model4.vocabulary_)
# {'一條': 1, '天狗': 5, '呀': 4, '月': 8, '來': 9, '日來': 6, '一切': 0, '星球': 7, '全宇宙': 3, '便是': 2}
- vocabulary: dict*類型*
只使用特定的詞匯,其形式與上面看到的tfidf_model4.vocabulary_相同,也是指定對應關系。
這一參數的使用有時能幫助我們專注於一些詞語,比如我對本詩中表達感情的一些特定詞語(甚至標點符號)感興趣,就可以設定這一參數,只考慮他們:
tfidf_model5 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b",vocabulary={"我":0, "呀":1,"!":2}).fit(document)
print(tfidf_model5.vocabulary_)
# {'我': 0, '呀': 1, '!': 2}
print(tfidf_model5.transform(document).todense())
# [[ 0.40572238 0.91399636 0. ]
# [ 1. 0. 0. ]
# [ 1. 0. 0. ]
# [ 1. 0. 0. ]
# [ 1. 0. 0. ]
- ngram_range: tuple
有時候我們覺得單個的詞語作為特征還不足夠,能夠加入一些詞組更好,就可以設置這個參數,如下面允許詞表使用1個詞語,或者2個詞語的組合:
這里順便使用了一個方便的方法 get_feature_names() ,可以以列表的形式得到所有的詞語
tfidf_model5 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", ngram_range=(1,2), stop_words=["是", "的"]).fit(document)
print(tfidf_model5.get_feature_names())
"""
['一切', '一切 星球', '一條', '一條 天狗', '了', '便是', '便是 我', '全宇宙', '全宇宙 來', '吞', '吞 了', '呀', '天狗', '天狗 呀', '我', '我 一條', '我 了', '我 便是', '我 把', '把', '把 一切', '把 全宇宙', '把 日來', '把 月', '日來', '日來 吞', '星球', '星球 來', '月', '月 來', '來', '來 吞']
"""
-
max_feature: int
在大規模語料上訓練TFIDF會得到非常多的詞語,如果再使用了上一個設置加入了詞組,那么我們詞表的大小就會爆炸。出於時間和空間效率的考慮,可以限制最多使用多少個詞語,模型會優先選取詞頻高的詞語留下。下面限制最多使用10個詞語:
tfidf_model6 = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b", max_features=10, ngram_range=(1,2), stop_words=["是", "的"]).fit(document)
print(tfidf_model6.vocabulary_)
"""
{'我': 3, '把': 5, '來': 8, '吞': 1, '了': 0, '我 把': 4, '來 吞': 9, '吞 了': 2, '日來 吞': 6, '星球': 7}
"""
比如這里大部分的詞組都被過濾了,但是“我 把”因為多次出現而保留了。
參考博客:
https://blog.csdn.net/blmoistawinde/article/details/80816179