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句),把它們合在一起,就構成了這篇文章的自動摘要
文章來自於:
謝謝作者!!!