TFIDF之python實現


TFIDF介紹

現在有一篇長文《中國的蜜蜂養殖》,用計算機提取它的關鍵詞。

1、詞頻:如果某個詞很重要,它應該在這篇文章中多次出現。我們進行"詞頻"(Term Frequency,縮寫為TF)統計。

2、停用詞:結果你肯定猜到了,出現次數最多的詞是----"的"、"是"、"在"----這一類最常用的詞。它們叫做"停用詞"(stop words),表示對找到結果毫無幫助、必須過濾掉的詞。

3、IDF :最常見的詞("的"、"是"、"在")給予最小的權重,

    較常見的詞("中國")給予較小的權重,

    較少見的詞("蜜蜂"、"養殖")給予較大的權重。

    這個權重叫做"逆文檔頻率"(Inverse Document Frequency,縮寫為IDF),

    它的大小與一個詞的常見程度成反比。 

4、TF-IDF:"詞頻"(TF)和"逆文檔頻率"(IDF)以后,兩個值相乘,得到了一個詞的TF-IDF值。

    某個詞對文章的重要性越高,它的TF-IDF值就越大。

    所以,排在最前面的幾個詞,就是這篇文章的關鍵詞。

 

如果某個詞比較少見,但是它在這篇文章中多次出現,那么它很可能就反映了這篇文章的特性,正是我們所需要的關鍵詞。發現"中國"、"蜜蜂"、"養殖"這三個詞的出現次數一樣多,因為"中國"是很常見的詞,相對而言,"蜜蜂"和"養殖"不那么常見,"蜜蜂"和"養殖"的重要程度要大於"中國"。

 

具體實現:

1、計算詞頻

  詞頻(TF) = 某個詞在文章中的出現次數,文章有長短之分,為了便於不同文章的比較,做"詞頻"標准化。

  詞頻(TF) = 某個詞在文章中的出現次數 / 文章總詞數

或者 詞頻(TF) = 某個詞在文章中的出現次數 / 擁有最高詞頻的詞的次數

 

2、某個詞在文章中的出現次數

這時,需要一個語料庫(corpus),用來模擬語言的使用環境。

逆文檔頻率(IDF) = log(語料庫的文檔總數/包含該詞的文檔總數+1)

 

3、計算TF-IDF

  TF-IDF = 詞頻(TF) * 逆文檔頻率(IDF)

  可以看到,TF-IDF與一個詞在文檔中的出現次數成正比,與該詞在整個語言中的出現次數成反比。

  所以,自動提取關鍵詞的算法就是計算出文檔的每個詞的TF-IDF值,然后按降序排列,取排在最前面的幾個詞。

 

從上表可見,"蜜蜂"的TF-IDF值最高,"養殖"其次,"中國"最低。(如果還計算"的"字的TF-IDF,那將是一個極其接近0的值。)

所以,如果只選擇一個詞,"蜜蜂"就是這篇文章的關鍵詞。

 

  1 import os
  2 import codecs
  3 import math
  4 import operator
  5 
  6 
  7 def fun(filepath):  # 遍歷文件夾中的所有文件,返回文件list
  8     arr = []
  9     for root, dirs, files in os.walk(filepath):
 10         for fn in files:
 11             arr.append(root+"\\"+fn)
 12     return arr
 13 
 14 
 15 def wry(txt, path):  # 寫入txt文件
 16     f = codecs.open(path, 'a', 'utf8')
 17     f.write(txt)
 18     f.close()
 19     return path
 20 
 21 
 22 def read(path):  # 讀取txt文件,並返回list
 23     f = open(path, encoding="utf8")
 24     data = []
 25     for line in f.readlines():
 26         data.append(line)
 27     return data
 28 
 29 
 30 def toword(txtlis):  # 將一片文章按照‘/’切割成詞表,返回list
 31     wordlist = []
 32     alltxt = ''
 33     for i in txtlis:
 34         alltxt = alltxt+str(i)
 35     ridenter = alltxt.replace('\n', '')
 36     wordlist = ridenter.split('/')
 37     return wordlist
 38 
 39 
 40 def getstopword(path):  # 獲取停用詞表
 41     swlis = []
 42     for i in read(path):
 43         outsw = str(i).replace('\n', '')
 44         swlis.append(outsw)
 45     return swlis
 46 
 47 
 48 def getridofsw(lis, swlist):  # 去除文章中的停用詞
 49     afterswlis = []
 50     for i in lis:
 51         if str(i) in swlist:
 52             continue
 53         else:
 54             afterswlis.append(str(i))
 55     return afterswlis
 56 
 57 
 58 def freqword(wordlis):  # 統計詞頻,並返回字典
 59     freword = {}
 60     for i in wordlis:
 61         if str(i) in freword:
 62             count = freword[str(i)]
 63             freword[str(i)] = count+1
 64         else:
 65             freword[str(i)] = 1
 66     return freword
 67 
 68 
 69 def corpus(filelist, swlist):  # 建立語料庫
 70     alllist = []
 71     for i in filelist:
 72         afterswlis = getridofsw(toword(read(str(i))), swlist)
 73         alllist.append(afterswlis)
 74     return alllist
 75 
 76 
 77 def wordinfilecount(word, corpuslist):  # 查出包含該詞的文檔數
 78     count = 0  # 計數器
 79     for i in corpuslist:
 80         for j in i:
 81             if word in set(j):  # 只要文檔出現該詞,這計數器加1,所以這里用集合
 82                 count = count+1
 83             else:
 84                 continue
 85     return count
 86 
 87 
 88 def tf_idf(wordlis, filelist, corpuslist):  # 計算TF-IDF,並返回字典
 89     outdic = {}
 90     tf = 0
 91     idf = 0
 92     dic = freqword(wordlis)
 93     outlis = []
 94     for i in set(wordlis):
 95         tf = dic[str(i)]/len(wordlis)  # 計算TF:某個詞在文章中出現的次數/文章總詞數
 96         # 計算IDF:log(語料庫的文檔總數/(包含該詞的文檔數+1))
 97         idf = math.log(len(filelist)/(wordinfilecount(str(i), corpuslist)+1))
 98         tfidf = tf*idf  # 計算TF-IDF
 99         outdic[str(i)] = tfidf
100     orderdic = sorted(outdic.items(), key=operator.itemgetter(
101         1), reverse=True)  # 給字典排序
102     return orderdic
103 
104 
105 def befwry(lis):  # 寫入預處理,將list轉為string
106     outall = ''
107     for i in lis:
108         ech = str(i).replace("('", '').replace("',", '\t').replace(')', '')
109         outall = outall+'\t'+ech+'\n'
110     return outall
111 
112 
113 def main():
114     swpath = r'哈工大停用詞表.txt'#停用詞表路徑
115     swlist = getstopword(swpath)  # 獲取停用詞表列表
116 
117     filepath = r'corpus'
118     filelist = fun(filepath)  # 獲取文件列表
119 
120     wrypath = r'TFIDF.txt'
121 
122     corpuslist = corpus(filelist, swlist)  # 建立語料庫
123 
124     outall = ''
125 
126     for i in filelist:
127         afterswlis = getridofsw(toword(read(str(i))), swlist)  # 獲取每一篇已經去除停用的詞表
128         tfidfdic = tf_idf(afterswlis, filelist, corpuslist)  # 計算TF-IDF
129 
130         titleary = str(i).split('\\')
131         title = str(titleary[-1]).replace('utf8.txt', '')
132         echout = title+'\n'+befwry(tfidfdic)
133         print(title+' is ok!')
134         outall = outall+echout
135     print(wry(outall, wrypath)+' is ok!')
136 
137 if __name__ == '__main__':
138     main()

 

 

總結:

TF-IDF算法的優點是簡單快速,結果比較符合實際情況。

缺點是,單純以"詞頻"衡量一個詞的重要性,不夠全面,有時重要的詞可能出現次數並不多。

而且,這種算法無法體現詞的位置信息,出現位置靠前的詞與出現位置靠后的詞,都被視為重要性相同,這是不正確的。(一種解決方法是,對全文的第一段和每一段的第一句話,給予較大的權重。)

 

 

TF-IDF與與余弦相似的應用:找相似文章

除了找到關鍵詞,還希望找到與原文章相似的其他文章

需要用到余弦相似性:

句子A:我喜歡看電視,不喜歡看電影

句子B:我不喜歡看電視,也不喜歡看電影

基本思路是:如果這兩句話的用詞越相似,它們的內容就應該越相似。因此,可以從詞頻入手,計算它們的相似程度。

 

1、分詞

  句子A:我/喜歡/看/電視,不/喜歡/看/電影。

  句子B:我/不/喜歡/看/電視,也/不/喜歡/看/電影。

2、列出所有值

  我,喜歡,看,電視,電影,不,也。

3、計算詞頻

  句子A:我 1,喜歡 2,看 2,電視 1,電影 1,不 1,也 0。

  句子B:我 1,喜歡 2,看 2,電視 1,電影 1,不 2,也 1

4、寫出詞頻向量。

  句子A:[1, 2, 2, 1, 1, 1, 0]

  句子B:[1, 2, 2, 1, 1, 2, 1]

我們可以通過夾角的大小,來判斷向量的相似程度。夾角越小,就代表越相似。假定a向量是[x1, y1],b向量是[x2, y2],那么可以將余弦定理改寫成下面的形式

 結論:

  我們就得到了"找出相似文章"的一種算法:

  • 使用TF-IDF算法,找出兩篇文章的關鍵詞
  • 每篇文章各取出若干個關鍵詞(比如20個),合並成一個集合,計算每篇文章對於這個集合中的詞的詞頻(為了避免文章長度的差異,可以使用相對詞頻);
  • 生成兩篇文章各自的詞頻向量
  • 計算兩個向量的余弦相似度,值越大就表示越相似

計算兩個向量的余弦相似度,值越大就表示越相似

 

 

如何通過詞頻,對文章進行自動摘要

信息都包含在句子中,有些句子包含的信息多,有些句子包含的信息少。"自動摘要"就是要找出那些包含信息最多的句子。

句子的信息量用"關鍵詞"來衡量。如果包含的關鍵詞越多,就說明這個句子越重要。

Luhn提出用"簇"(cluster)表示關鍵詞的聚集。所謂"簇"就是包含多個關鍵詞的句子片段。

 

只要關鍵詞之間的距離小於"門檻值",它們就被認為處於同一個簇之中。Luhn建議的門檻值是4或5。也就是說,如果兩個關鍵詞之間有5個以上的其他詞,就可以把這兩個關鍵詞分在兩個簇。

簇的重要性 = (包含的關鍵詞數量)^2 / 簇的長度。其中的簇一共有7個詞,其中4個是關鍵詞。因此,它的重要性分值等於 ( 4 x 4 ) / 7 = 2.3。

然后,找出包含分值最高的簇的句子(比如5句),把它們合在一起,就構成了這篇文章的自動摘要

 

 

文章來自於:

python實現TF-IDF算法

TFIDF介紹

謝謝作者!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM