TF-IDF算法(2)—python實現


  參加完數模之后休息了幾天,今天繼續看TF-IDF算法。上篇中對TF-IDF算法已經做了詳細的介紹,在此不再贅述。今天主要是通過python,結合sklearn庫實現該算法,並通過k-means算法實現簡單的文檔聚類。

一 結巴分詞                                                                                     

1.簡述

  中文分詞是中文文本處理的一個基礎性工作,長久以來,在Python編程領域,一直缺少高准確率、高效率的分詞組建,結巴分詞正是為了滿足這一需求而提出。

2.安裝

(1)全自動安裝

在安裝了easy—stall的情況之下可以全自動安裝:easy_install jieba

(2)半自動安裝

  •下載地址:https://pypi.python.org/pypi/jieba/

  •在cmd下找到具體的目錄python setup.py安裝

3.功能

(1)全模式:將句子中所有的可以成詞的詞語都掃描出來,速度非常快,但是不能解決歧義問題;

  jieba.cut方法接收兩個參數:第一個參數為需要分詞的字符串,第二個cut_all參數用來控制是否采用全模式進行分詞。

>>> #coding:utf-8
>>> import jieba >>> seg_list = jieba.cut("我愛西郵西郵愛我",cut_all = True) >>> print "Full Mode:","/".join(seg_list)

  Full Mode: 我/愛/西/郵/西/郵/愛/我

(2)精確模式:將句子最精確分開,適合文本分析: 

>>> seg_list = jieba.cut("喜歡玩游戲,可以把編程當成玩游戲,還挺好玩的,哈哈哈哈") >>> print "Default Mode:", "/ ".join(seg_list)

   Default Mode: 喜歡/ 玩游戲/ ,/ 可以/ 把/ 編程/ 當成/ 玩游戲/ ,/ 還/ 挺好玩/ 的/ ,/ 哈哈哈哈

  除此之外,默認表示的也是精確模式: 

>>> seg_list = jieba.cut("喜歡玩游戲,可以把編程當成玩游戲,還挺好玩的,哈哈哈哈") >>> print ",".join(seg_list)

 (3)搜索引擎模式:在精確模式的基礎上,對長詞再次切分 ,提高召回率。

  jieba.cut_for_search方法只接收需要分詞的字符串,這種方法分詞分的比較細: 

>>> seg_list = jieba.cut_for_search("西郵就是西安郵電大學的簡稱") >>> print ",".join(seg_list)

結果:西郵,就是,西安,郵電,電大,大學,郵電大學,的,簡稱

  當然結巴分詞還有很多功能,比如添加字典啊什么的,在此不再詳細說明。

二  scikit-learn                                                         

  scikit-learn含有完善的文檔和豐富的機器學習算法,已經實現了所有基本的機器學習算法,並且其本身就帶有一些標准的數據集。比如用來分類的iris數據集、digits數據集;用來回歸的boston house price 數據集。

  更多內容見http://dataunion.org/20071.html。

三 python實現TF-IDF算法                                                                                             

  之前用的是python3.4,但由於不可抗的原因,又投入了2.7的懷抱,在這里編寫一段代碼,簡單的實現TF-IDF算法。大致的實現過程是讀入一個測試文檔,計算出文檔中出現的詞的tfidf值,並保存在另一個文檔中。

# -*- coding: cp936 -*-
import jieba import jieba.posseg as pseg import os import sys from sklearn import feature_extraction from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import CountVectorizer import sys reload(sys) sys.setdefaultencoding( "utf-8" ) sys.path.append("C:\Users\Administrator\Desktop\9.17") from numpy import * fr = open('exercise.txt') fr_list = fr.read() dataList = fr_list.split('\n') data = [] for oneline in dataList: data.append(" ".join(jieba.cut(oneline))) #將得到的詞語轉換為詞頻矩陣
freWord = CountVectorizer() #統計每個詞語的tf-idf權值
transformer = TfidfTransformer() #計算出tf-idf(第一個fit_transform),並將其轉換為tf-idf矩陣(第二個fit_transformer)
tfidf = transformer.fit_transform(freWord.fit_transform(data)) #獲取詞袋模型中的所有詞語
word = freWord.get_feature_names() #得到權重
weight = tfidf.toarray() tfidfDict = {} for i in range(len(weight)): for j in range(len(word)): getWord = word[j] getValue = weight[i][j] if getValue != 0: if tfidfDict.has_key(getWord): tfidfDict[getword] += string.atof(getValue) else: tfidfDict.update({getWord:getValue}) sorted_tfidf = sorted(tfidfDict.iteritems(), key = lambda d:d[1],reverse = True) fw = open('result.txt','w') for i in sorted_tfidf: fw.write(i[0] + '\t' + str(i[1]) +'\n')

至此,對算法已經有了一個簡單的實現,接下來需要做的是將其應用到文檔聚類中加以運用。 

四 實現簡單的文本聚類                                                                

  要聚類,聚什么是重點!結合上述分析,我們可以將一篇文章中的關鍵詞和對應的tf-idf值一一對應起來,顯然想到的是dict,那么聚類是聚的當然不止一篇文章,那么我們就可以分別將每篇文章的關鍵詞和對應的tf-idf值對應起來,最后整合起來進行聚類,當然還是得用到dict。

  結合上述tf-idf的實現,可以將得到的結果分別存在同一個目錄下的.txt中,導入目錄讀取並整合,直接上代碼: 

# -*- coding: cp936 -*- #-*- coding:utf-8 -*-
from PIL import Image,ImageDraw import os, codecs, random from math import sqrt #將得到的結果按照字典存放
rows_norms = {} def readfile(dirname): rows = {} for f in os.listdir(dirname):#目錄
        fr = codecs.open(dirname + f,'r',encoding = 'utf-8') tw_dict = {} norm = 0 for line in fr: items = line.split('\t') token = items[0].strip() if len(token)<2: continue w = float(items[1].strip()) norm = w**2 tw_dict[token] = w rows[str(f[:-4])] = tw_dict rows_norms[str(f[:-4])] = sqrt(float(norm)) #print len(rows)
    return rows

   至此,相當於得到了數據,接下來就是k-means算法的實現了,之前的文章中都有詳細說明,在此不再贅述,所不同的是在此采用了余弦距離計算相似度:

#得到余弦距離,其中v1就是row,v2是聚類中心點
def cosine(v1,norm_v1,v2,norm_v2): if norm_v1 == 0 or norm_v2 == 0: return 1.0 dividend = 0 for k,v in v1.items(): for k in v2: dividend += v*v2[k] return 1.0-dividend/(norm_v1*norm_v2)

主程序段如下:

#算法的實現
def kcluster(rows,distance=cosine,k=3): ranges=rows_range(rows) #初始化聚類中心
    clusters=[] for i in range(k): clusters.append(random_vec(ranges)) clusteres_norm=[] for i in range(k): clusteres_norm.append(norm(clusters[i])) lastmatches=None #開始迭代
    for t in range(300): print '第%d次迭代' % t bestmatches=[[] for i in range(k)] for j in rows.keys(): row=rows[j] row_norm=rows_norms[j] bestmatch=0 min_dis=10000000
            for i in range(k): d=distance(row, row_norm, clusters[i],clusteres_norm[i]) if d<min_dis: bestmatch=i min_dis=d bestmatches[bestmatch].append(j) if bestmatches==lastmatches: break lastmatches=bestmatches for i in range(k): clusters[i]=center(bestmatches[i], rows) print bestmatches return bestmatches #test
if __name__ == '__main__': corpus_dir='D:/python2.7/exercise/clusting/data/' rows=readfile(corpus_dir) print 'create vectorspace' n=3 clust=kcluster(rows,k=n)

  簡單測試,結果還是挺理想的,但還是可以結合之前對k-means算法的優化,實現更好的聚類。

 


免責聲明!

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



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