參加完數(shù)模之后休息了幾天,今天繼續(xù)看TF-IDF算法。上篇中對(duì)TF-IDF算法已經(jīng)做了詳細(xì)的介紹,在此不再贅述。今天主要是通過(guò)python,結(jié)合sklearn庫(kù)實(shí)現(xiàn)該算法,并通過(guò)k-means算法實(shí)現(xiàn)簡(jiǎn)單的文檔聚類(lèi)。
一 結(jié)巴分詞
1.簡(jiǎn)述
中文分詞是中文文本處理的一個(gè)基礎(chǔ)性工作,長(zhǎng)久以來(lái),在Python編程領(lǐng)域,一直缺少高準(zhǔn)確率、高效率的分詞組建,結(jié)巴分詞正是為了滿(mǎn)足這一需求而提出。
2.安裝
(1)全自動(dòng)安裝
在安裝了easy—stall的情況之下可以全自動(dòng)安裝:easy_install jieba
(2)半自動(dòng)安裝
·下載地址:https://pypi.python.org/pypi/jieba/
·在cmd下找到具體的目錄python setup.py安裝
3.功能
(1)全模式:將句子中所有的可以成詞的詞語(yǔ)都掃描出來(lái),速度非??欤遣荒芙鉀Q歧義問(wèn)題;
jieba.cut方法接收兩個(gè)參數(shù):第一個(gè)參數(shù)為需要分詞的字符串,第二個(gè)cut_all參數(shù)用來(lái)控制是否采用全模式進(jìn)行分詞。
>>> #coding:utf-8>>> import jieba>>> seg_list = jieba.cut("我愛(ài)西郵西郵愛(ài)我",cut_all = True)>>> print "Full Mode:","/".join(seg_list)
Full Mode: 我/愛(ài)/西/郵/西/郵/愛(ài)/我
(2)精確模式:將句子最精確分開(kāi),適合文本分析:
>>> seg_list = jieba.cut("喜歡玩游戲,可以把編程當(dāng)成玩游戲,還挺好玩的,哈哈哈哈")>>> print "Default Mode:", "/ ".join(seg_list)
Default Mode: 喜歡/ 玩游戲/ ,/ 可以/ 把/ 編程/ 當(dāng)成/ 玩游戲/ ,/ 還/ 挺好玩/ 的/ ,/ 哈哈哈哈
除此之外,默認(rèn)表示的也是精確模式:
>>> seg_list = jieba.cut("喜歡玩游戲,可以把編程當(dāng)成玩游戲,還挺好玩的,哈哈哈哈")>>> print ",".join(seg_list)
(3)搜索引擎模式:在精確模式的基礎(chǔ)上,對(duì)長(zhǎng)詞再次切分 ,提高召回率。
jieba.cut_for_search方法只接收需要分詞的字符串,這種方法分詞分的比較細(xì):
>>> seg_list = jieba.cut_for_search("西郵就是西安郵電大學(xué)的簡(jiǎn)稱(chēng)")>>> print ",".join(seg_list)
結(jié)果:西郵,就是,西安,郵電,電大,大學(xué),郵電大學(xué),的,簡(jiǎn)稱(chēng)
當(dāng)然結(jié)巴分詞還有很多功能,比如添加字典啊什么的,在此不再詳細(xì)說(shuō)明。
二 scikit-learn
scikit-learn含有完善的文檔和豐富的機(jī)器學(xué)習(xí)算法,已經(jīng)實(shí)現(xiàn)了所有基本的機(jī)器學(xué)習(xí)算法,并且其本身就帶有一些標(biāo)準(zhǔn)的數(shù)據(jù)集。比如用來(lái)分類(lèi)的iris數(shù)據(jù)集、digits數(shù)據(jù)集;用來(lái)回歸的boston house price 數(shù)據(jù)集。
更多內(nèi)容見(jiàn)http://dataunion.org/20071.html。
三 python實(shí)現(xiàn)TF-IDF算法
之前用的是python3.4,但由于不可抗的原因,又投入了2.7的懷抱,在這里編寫(xiě)一段代碼,簡(jiǎn)單的實(shí)現(xiàn)TF-IDF算法。大致的實(shí)現(xiàn)過(guò)程是讀入一個(gè)測(cè)試文檔,計(jì)算出文檔中出現(xiàn)的詞的tfidf值,并保存在另一個(gè)文檔中。
# -*- coding: cp936 -*-import jiebaimport jieba.posseg as psegimport osimport sysfrom sklearn import feature_extractionfrom sklearn.feature_extraction.text import TfidfTransformerfrom sklearn.feature_extraction.text import CountVectorizerimport sysreload(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))) #將得到的詞語(yǔ)轉(zhuǎn)換為詞頻矩陣freWord = CountVectorizer()#統(tǒng)計(jì)每個(gè)詞語(yǔ)的tf-idf權(quán)值transformer = TfidfTransformer()#計(jì)算出tf-idf(第一個(gè)fit_transform),并將其轉(zhuǎn)換為tf-idf矩陣(第二個(gè)fit_transformer)tfidf = transformer.fit_transform(freWord.fit_transform(data))#獲取詞袋模型中的所有詞語(yǔ)word = freWord.get_feature_names()#得到權(quán)重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')
至此,對(duì)算法已經(jīng)有了一個(gè)簡(jiǎn)單的實(shí)現(xiàn),接下來(lái)需要做的是將其應(yīng)用到文檔聚類(lèi)中加以運(yùn)用。
四 實(shí)現(xiàn)簡(jiǎn)單的文本聚類(lèi)
要聚類(lèi),聚什么是重點(diǎn)!結(jié)合上述分析,我們可以將一篇文章中的關(guān)鍵詞和對(duì)應(yīng)的tf-idf值一一對(duì)應(yīng)起來(lái),顯然想到的是dict,那么聚類(lèi)是聚的當(dāng)然不止一篇文章,那么我們就可以分別將每篇文章的關(guān)鍵詞和對(duì)應(yīng)的tf-idf值對(duì)應(yīng)起來(lái),最后整合起來(lái)進(jìn)行聚類(lèi),當(dāng)然還是得用到dict。
結(jié)合上述tf-idf的實(shí)現(xiàn),可以將得到的結(jié)果分別存在同一個(gè)目錄下的.txt中,導(dǎo)入目錄讀取并整合,直接上代碼:
# -*- coding: cp936 -*-#-*- coding:utf-8 -*-from PIL import Image,ImageDrawimport os, codecs, randomfrom math import sqrt#將得到的結(jié)果按照字典存放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
至此,相當(dāng)于得到了數(shù)據(jù),接下來(lái)就是k-means算法的實(shí)現(xiàn)了,之前的文章中都有詳細(xì)說(shuō)明,在此不再贅述,所不同的是在此采用了余弦距離計(jì)算相似度:
#得到余弦距離,其中v1就是row,v2是聚類(lèi)中心點(diǎn)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)
主程序段如下:
#算法的實(shí)現(xiàn)def kcluster(rows,distance=cosine,k=3): ranges=rows_range(rows) #初始化聚類(lèi)中心 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 #開(kāi)始迭代 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#testif __name__ == '__main__': corpus_dir='D:/python2.7/exercise/clusting/data/' rows=readfile(corpus_dir) print 'create vectorspace' n=3 clust=kcluster(rows,k=n)
簡(jiǎn)單測(cè)試,結(jié)果還是挺理想的,但還是可以結(jié)合之前對(duì)k-means算法的優(yōu)化,實(shí)現(xiàn)更好的聚類(lèi)。
聯(lián)系客服