sklearn: TfidfVectorizer 中文處理及一些使用參數

  • 2019 年 10 月 30 日
  • 筆記

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/blmoistawinde/article/details/80816179

TfidfVectorizer可以把原始文本轉化為tf-idf的特徵矩陣,從而為後續的文本相似度計算,主題模型(如LSI),文本搜索排序等一系列應用奠定基礎。基本應用如:

#coding=utf-8  from sklearn.feature_extraction.text import TfidfVectorizer  document = ["I have a pen.",              "I have an apple."]  tfidf_model = TfidfVectorizer().fit(document)  sparse_result = tfidf_model.transform(document)     # 得到tf-idf矩陣,稀疏矩陣表示法  print(sparse_result)  # (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}

但是要把它運用到中文上還需要一些特別的處理,故寫此文分享我的經驗。

第一步:分詞

中文不比英文,詞語之間有著空格的自然分割,所以我們首先要進行分詞處理,再把它轉化為與上面的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)      # ['我 是 一條 天狗 呀 !', '我 把 月 來 吞 了 ,', '我 把 日來 吞 了 ,', '我 把 一切 的 星球 來 吞 了 ,', '我 把 全宇宙 來 吞 了 。', '我 便是 我 了 !']

PS:語料來自郭沫若《天狗》。另外,由於分詞工具的不完善,也會有一些錯誤,比如這邊錯誤地把"日來"分到了一起。

第二步:建模

理論上,現在得到的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)bw+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)bww+b",其中的兩個w決定了其匹配長度至少為2的單詞,所以這邊減到1個。對這個參數進行更多修改,可以滿足其他要求,比如這裡依然沒有得到標點符號,在此不詳解了。

當然有些時候我們還是要過濾掉一些無意義的詞,下面有些別的參數也可以幫助我們實現這一目的:

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)bw+b", max_df=0.6).fit(document)      print(tfidf_model3.vocabulary_)      # {'是': 8, '一條': 1, '天狗': 5, '呀': 4, '月': 9, '來': 10, '日來': 6, '一切': 0, '的': 11, '星球': 7, '全宇宙': 3, '便是': 2}

2.stop_words: list類型

直接過濾指定的停用詞。

    tfidf_model4 = TfidfVectorizer(token_pattern=r"(?u)bw+b", max_df=0.6, stop_words=["是", "的"]).fit(document)      print(tfidf_model4.vocabulary_)      # {'一條': 1, '天狗': 5, '呀': 4, '月': 8, '來': 9, '日來': 6, '一切': 0, '星球': 7, '全宇宙': 3, '便是': 2}

3.vocabulary: dict類型

只使用特定的辭彙,其形式與上面看到的tfidf_model4.vocabulary_相同,也是指定對應關係。

這一參數的使用有時能幫助我們專註於一些詞語,比如我對本詩中表達感情的一些特定詞語(甚至標點符號)感興趣,就可以設定這一參數,只考慮他們:

    tfidf_model5 = TfidfVectorizer(token_pattern=r"(?u)bw+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.        ]