1 前言
TF-IDF稱為“詞頻-逆向文件頻率”荠诬,是英文“term frequency–inverse document frequency”的縮寫柑贞,它是NLP領(lǐng)域在做文本處理,信息檢索等任務(wù)時(shí)常用到的一種經(jīng)典算法棠众,該算法的目的是為了衡量一個(gè)詞的重要性有决。今天從算法的原理和實(shí)踐進(jìn)行介紹书幕。
2 原理
在闡述原理前,可以先想想一個(gè)任務(wù):給你幾篇經(jīng)濟(jì)領(lǐng)域文章苛骨,讓你找出文章中一些關(guān)鍵詞苟呐。從統(tǒng)計(jì)學(xué)的角度考慮:你會(huì)覺(jué)得出現(xiàn)頻率高的詞更可能是關(guān)鍵詞掠抬,這個(gè)統(tǒng)計(jì)詞頻的想法就是TF的思想;然而在統(tǒng)計(jì)詞頻后排序輸出時(shí)瞳步,你可能發(fā)現(xiàn)有“的”单起、“一直”等這樣跟經(jīng)濟(jì)沒(méi)多大關(guān)聯(lián)的詞劣坊;在解決這個(gè)問(wèn)題時(shí),你可能想如果一個(gè)詞在每篇文章都出現(xiàn)测蘑,就可以視該詞像“的”這類助詞一樣康二,沒(méi)什么代表性沫勿,不重要味混,而這個(gè)想法就是IDF的思想翁锡。
總的來(lái)說(shuō),TF-IDF的主要思想是:如果某個(gè)單詞在一篇文章中出現(xiàn)的頻率(TF值)很高馆衔,而在其他文章中很少出現(xiàn)(IDF值很大)哈踱,就認(rèn)為該詞具有很高的代表性梨熙,對(duì)該篇文章更重要咽扇。
下面來(lái)介紹TF-IDF的數(shù)學(xué)表達(dá)公式:
(1) TF詞頻(Term Frequency)
其中质欲,表示詞w出現(xiàn)的頻率(次數(shù))嘶伟,
表示整個(gè)語(yǔ)料庫(kù)中所有詞出現(xiàn)的次數(shù)九昧,也可認(rèn)為是語(yǔ)料庫(kù)文本的長(zhǎng)度毕匀。TF用來(lái)統(tǒng)計(jì)一個(gè)詞出現(xiàn)的頻率,出現(xiàn)的頻率越高蹋笼,一定程度上可認(rèn)為越重要剖毯。
(2) IDF逆向文件頻率(Inverse Document Frequency)
其中逊谋,表示文檔的總數(shù)量活玲,
表示詞出現(xiàn)的文檔數(shù)量,加1是為了防止分母為0穗熬,一種平滑處理丁溅。簡(jiǎn)單來(lái)理解就是:總文件數(shù)目除以包含該詞的文件的數(shù)目,再取對(duì)數(shù)即為該詞的idf值妓柜。若包含詞w的文檔越少, IDF越大棍掐,則說(shuō)明該詞更具有代表性拷况。
(3) TF-IDF
將詞w計(jì)算出的tf值和idf值相乘赚瘦,即為tf_idf值。在NLP任務(wù)中鹰服,可用tf_idf值將詞向量化悲酷,也可用tf_idf值作為一個(gè)權(quán)重參與計(jì)算舔涎。TF-IDF用一句話來(lái)概括就是:過(guò)濾掉常見(jiàn)的詞語(yǔ),保留重要的詞語(yǔ)亡嫌。
但TF-IDF也存在缺陷:當(dāng)一個(gè)關(guān)鍵詞每篇文章都出現(xiàn)挟冠,那TF-IDF會(huì)把它當(dāng)著不重要的詞來(lái)處理知染。它是基于統(tǒng)計(jì)學(xué)的思想控淡,是具備一定說(shuō)服力和意義的,但不能解決所有問(wèn)題辫诅,所以在使用時(shí)炕矮,還的結(jié)合具體任務(wù)來(lái)進(jìn)行調(diào)整者冤。
3 實(shí)踐
3.1 任務(wù)說(shuō)明
利用TF-IDF方法邢滑,找出醫(yī)療領(lǐng)域文本中tf_idf最大的top詞。
file_corpus是我從網(wǎng)上收集的醫(yī)療領(lǐng)域語(yǔ)料庫(kù)殊鞭,比較小,約50M泵督。
在統(tǒng)計(jì)詞過(guò)程中庶喜,先過(guò)濾掉標(biāo)點(diǎn)符號(hào)小腊,長(zhǎng)度為1的詞,這樣可以提高一下要找詞的質(zhì)量久窟。在分詞中秩冈,使用的是開源分詞器jieba。
3.2 代碼
import codecs
import jieba
import re
import math
def compute_tf_idf(file_dir,tf_idf_file):
D=0 #文檔的數(shù)量
N=0 #詞出現(xiàn)的總頻率斥扛,也是文檔的長(zhǎng)度累積
re_han = re.compile(u"([\u4E00-\u9FD5a-zA-Z0-9]+)") #過(guò)濾掉標(biāo)點(diǎn)符號(hào)之類的符號(hào)
with codecs.open(file_dir ,'r' ,encoding='utf-8') as f:
#統(tǒng)計(jì)每個(gè)詞的tf,idf值入问,以字典的形式存儲(chǔ)
dataset=dict()
for line in f:
N+=len(line)
D+=1
tmp = [] #統(tǒng)計(jì)idf時(shí),一條文本中詞只統(tǒng)計(jì)一次稀颁,為了出重設(shè)置的變量
blocks = re_han.split(line)
for blk in blocks:
if re_han.match(blk):
for w in jieba.cut(blk):
if len(w)>= 2: #過(guò)濾掉長(zhǎng)度為1的詞
if w in dataset:
dataset[w]['tf'] += 1
if w not in tmp:
dataset[w]['idf'] += 1
tmp.append(w)
else:
dataset.setdefault(w, {})
dataset[w]['tf'] = 1
dataset[w]['idf'] = 1
tmp.append(w)
# print(D,N)
#計(jì)算tf-idf值
res=[]
for key in dataset:
tf=dataset[key]['tf']/N
idf=math.log(D/(dataset[key]['idf']+1))
tf_idf=tf*idf
res.append([key,tf_idf])
#排序輸出
res=sorted(res,key=lambda x:x[1],reverse=True)
with codecs.open(tf_idf_file, 'w', encoding='utf-8') as f:
for item in res:
f.write(item[0]+'\t'+str(item[1])+'\n')
if __name__=="__main__":
corpus_dir=r'F:\open_data\file_corpus.txt'
tf_idf_dir=r'F:\tf_idf.txt'
compute_tf_idf(corpus_dir,tf_idf_dir)
3.3 結(jié)果分析
運(yùn)行上述的代碼芬失,輸出的文件就是按tf_idf大小降序排列的詞,下面是前20詞的截圖:
通過(guò)上面的顯示匾灶,我們可以看出都是跟醫(yī)療相關(guān)的,其中“腫瘤”的tf-idf值最大颊糜。這前20一個(gè)詞基本都是醫(yī)學(xué)領(lǐng)域?qū)S性~业筏,整體來(lái)說(shuō)惯疙,tf-idf找領(lǐng)域關(guān)鍵詞是有效果的对碌,但也存在缺陷:因?yàn)樗淖罱K結(jié)果是由tf與idf共同決定的,當(dāng)tf特別大,idf即使很小叁丧,可能最終的結(jié)果也是靠前的。這就能解釋為何“出現(xiàn)”、“發(fā)生”這類詞的tf-idf值很高(排在20~40范圍內(nèi))的原因,而這些可能并不是我們想要的凄硼。所以,面對(duì)具體任務(wù)下骏全,我們可以在tf-idf的基礎(chǔ)上,再加一些限定條件,比如該詞是不是領(lǐng)域?qū)S性~,或者其他統(tǒng)計(jì)指標(biāo)苹熏,這樣得到的效果會(huì)更好。