Python TF-IDF計算100份文檔關鍵詞權重

一,TF-IDF介紹

  TF-IDF(Term Frequency–Inverse Document Frequency)是一種用於資訊檢索與文本挖掘的常用加權技術。TF-IDF是一種統計方法,用以評估一個字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨着它在文件中出現的次數成正比增加,但同時會隨着它在語料庫中出現的頻率成反比下降。TF-IDF加權的各種形式常被搜索引擎應用,作爲文件與用戶查詢之間相關程度的度量或評級。

  TF-IDF的主要思想是:如果某個詞或短語在一篇文章中出現的頻率TF高,並且在其他文章中很少出現,則認爲此詞或者短語具有很好的類別區分能力,適合用來分類。TF-IDF實際上是:TF * IDF。

  (1)詞頻(Term Frequency,TF)指的是某一個給定的詞語在該文件中出現的頻率。即詞w在文檔d中出現的次數count(w, d)和文檔d中總詞數size(d)的比值。

tf(w,d) = count(w, d) / size(d)

  這個數字是對詞數(term count)的歸一化,以防止它偏向長的文件。(同一個詞語在長文件裏可能會比短文件有更高的詞數,而不管該詞語重要與否。)

  (2)逆向文件頻率(Inverse Document Frequency,IDF)是一個詞語普遍重要性的度量。某一特定詞語的IDF,可以由總文件數目除以包含該詞語之文件的數目,再將得到的商取對數得到。即文檔總數n與詞w所出現文件數docs(w, D)比值的對數。  

idf = log(n / docs(w, D))

  TF-IDF根據 tf 和 idf 爲每一個文檔d和由關鍵詞w[1]...w[k]組成的查詢串q計算一個權值,用於表示查詢串q與文檔d的匹配度:

tf-idf(q, d)
= sum { i = 1..k | tf-idf(w[i], d) }
= sum { i = 1..k | tf(w[i], d) * idf(w[i]) }

  某一特定文件內的高詞語頻率,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的TF-IDF。因此,TF-IDF傾向於過濾掉常見的詞語,保留重要的詞語

  關於TF-IDF的詳細介紹和例子,有興趣的同學可以看這一篇博客。  下面主要分享TF-IDF在Python的如何使用。

二,Python中計算TF-IDF

  在Python中,scikit-learn包下有計算TF-IDF的api,其效果也很不錯。首先得安裝Scikit-clearn。不同系統安裝請看:http://scikit-learn.org/stable/install.html。

  本機環境:linux(ubuntu) 64位,python2.7.6

  1. 安裝scikit-learn包(先安裝依賴包,再安裝sklearn)

sudo apt-get install build-essential python-dev python-setuptools \
                     python-numpy python-scipy \
                     libatlas-dev libatlas3gf-base
sudo apt-get install python-sklearn

  或者通過pip進行安裝,pip是一個給python用的挺不錯的安裝工具。 

sudo apt-get install python-pip 
sudo pip install -U scikit-learn

  檢驗是否安裝成功,在terminal裏面輸入

pip list

  會列出pip安裝的所有東西,如果裏面有sklearn這一項,則安裝成功。

  2. 安裝jieba分詞包

  由於計算TF-IDF是對分詞結果進行計算,所以這裏需要使用jieba中文分詞。有關結巴分詞的使用,可以看上一篇博文:Python 結巴分詞

sudo pip install jieba 

  3. 計算TF-IDF

  scikit-learn包進行TF-IDF分詞權重計算主要用到了兩個類:CountVectorizer和TfidfTransformer。其中

  CountVectorizer是通過fit_transform函數將文本中的詞語轉換爲詞頻矩陣,矩陣元素a[i][j] 表示j詞在第i個文本下的詞頻。即各個詞語出現的次數,通過get_feature_names()可看到所有文本的關鍵字,通過toarray()可看到詞頻矩陣的結果。簡例如下:

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> vectorizer = CountVectorizer()
>>> corpus = [
...     'This is the first document.',
...     'This is the second second document.',
...     'And the third one.',
...     'Is this the first document?',
... ]
>>> X = vectorizer.fit_transform(corpus)
>>> X.toarray()           
array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
       [0, 1, 0, 1, 0, 2, 1, 0, 1],
       [1, 0, 0, 0, 1, 0, 1, 1, 0],
       [0, 1, 1, 1, 0, 0, 1, 0, 1]]...)
>>> vectorizer.get_feature_names()
(['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this'])

 

  TfidfTransformer是統計vectorizer中每個詞語的tf-idf權值,用法如下:

 

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> transformer = TfidfTransformer()
>>> counts = [[3, 0, 1],
...           [2, 0, 0],
...           [3, 0, 0],
...           [4, 0, 0],
...           [3, 2, 0],
...           [3, 0, 2]]

>>> tfidf = transformer.fit_transform(counts)
>>> tfidf.toarray()                        
array([[ 0.85...,  0.  ...,  0.52...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.55...,  0.83...,  0.  ...],
       [ 0.63...,  0.  ...,  0.77...]])

 

  關於函數的具體說明,請看官方說明文檔:scikit-learn common-vectorizer-usage

  這裏我處理的是對100份文檔進行分詞,然後進行TF-IDF的計算,其效果相當好。

import os
import jieba
import jieba.posseg as pseg
import sys
import string
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
reload(sys)
sys.setdefaultencoding('utf8')
#獲取文件列表(該目錄下放着100份文檔)
def getFilelist(argv) :
    path = argv[1]
    filelist = []
    files = os.listdir(path)
    for f in files :
        if(f[0] == '.') :
            pass
        else :
            filelist.append(f)
    return filelist,path
#對文檔進行分詞處理
def fenci(argv,path) :
    #保存分詞結果的目錄
    sFilePath = './segfile'
    if not os.path.exists(sFilePath) : 
        os.mkdir(sFilePath)
    #讀取文檔
    filename = argv
    f = open(path+filename,'r+')
    file_list = f.read()
    f.close()
    
    #對文檔進行分詞處理,採用默認模式
    seg_list = jieba.cut(file_list,cut_all=True)

    #對空格,換行符進行處理
    result = []
    for seg in seg_list :
     seg = ''.join(seg.split())
        if (seg != '' and seg != "\n" and seg != "\n\n") :
            result.append(seg)

    #將分詞後的結果用空格隔開,保存至本地。比如"我來到北京清華大學",分詞結果寫入爲:"我 來到 北京 清華大學"
    f = open(sFilePath+"/"+filename+"-seg.txt","w+")
    f.write(' '.join(result))
    f.close()

#讀取100份已分詞好的文檔,進行TF-IDF計算
def Tfidf(filelist) :
  path = './segfile/'
    corpus = []  #存取100份文檔的分詞結果
    for ff in filelist :
        fname = path + ff
        f = open(fname,'r+')
        content = f.read()
        f.close()
        corpus.append(content)    

    vectorizer = CountVectorizer()    
    transformer = TfidfTransformer()
    tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
    
    word = vectorizer.get_feature_names() #所有文本的關鍵字
    weight = tfidf.toarray()              #對應的tfidf矩陣
    
    sFilePath = './tfidffile'
    if not os.path.exists(sFilePath) : 
        os.mkdir(sFilePath)

    # 這裏將每份文檔詞語的TF-IDF寫入tfidffile文件夾中保存
    for i in range(len(weight)) :
     print u"--------Writing all the tf-idf in the",i,u" file into ",sFilePath+'/'+string.zfill(i,5)+'.txt',"--------"
        f = open(sFilePath+'/'+string.zfill(i,5)+'.txt','w+')
        for j in range(len(word)) :
            f.write(word[j]+"    "+str(weight[i][j])+"\n")
        f.close()
            
if __name__ == "__main__" : 
    (allfile,path) = getFilelist(sys.argv)
  for ff in allfile :
        print "Using jieba on "+ff
        fenci(ff,path)

    Tfidf(allfile)

 

參考資料:

  1.維基百科:http://zh.wikipedia.org/wiki/TF-IDF

  2.TF-IDF模型的概率解釋:http://www.cnblogs.com/weidagang2046/archive/2012/10/22/tf-idf-from-probabilistic-view.html#top

  3.liuxuejiang158的專欄:http://blog.csdn.net/liuxuejiang158blog/article/details/31360765

  4.Scikit-learn:http://scikit-learn.org/stable/modules/feature_extraction.html#common-vectorizer-usage

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章