文本類似性計算(一) 文本類似性計算(二) 前面說了兩篇了,分別介紹了TFIDF
和向量空間的相關東西,而後介紹了主題模型
,這一篇咱們就來試試這兩個東西。詞向量就不在這篇試了,詞向量和這兩個關係不大,很差對比,不過我最後也給出了代碼。html
工欲善其事,必先利其器
,那麼咱們先來利其器,這裏咱們使用的是python的gensim
工具包,地址是:radimrehurek.com/gensim/inde…,這個工具包很強大,我就不一一介紹了,反正咱們須要的功能都有,並且咱們用得很簡單,它還能夠分佈式部署,感興趣能夠去官網看具體介紹。html5
爲何不本身寫?這個問題....呵呵.....呵呵....我寫不出來.....
java
至於安裝,須要先安裝python 2.6以上
(廢話),NumPy 1.3
以上,SciPy 0.7
以上,後兩個是python的科學計算的包。python
easy_install
很容易搞定,這裏就不廢話了,windows上安裝可能有點困難,但我好久沒用過windows了,我電腦上安裝很輕鬆,三四個命令搞定,能夠去看gensim的官方文檔,上面也有怎麼安裝,若是你裝都裝不上,那就google,百度,總有解決辦法。git
除了gensim,還有個分詞的包須要裝一下,就是jieba分詞
,這個也很容易裝。github
數據準備但是個技術活,個人職業操守很高,沒有用公司的數據,那隻能本身找數據了,若是直接找網上的語料,顯得太Low了。因而我本身爬了一些數據。golang
首先,我瞄準了目前全國最火的全棧技術網站(就是SegmentFault啦),而後瞄準了一個汽車網站,因而開始爬數據,本身寫了個爬蟲開始爬數據,恩,個人爬蟲我以爲還能夠,調度器+爬取器組成,爬取器插件化了,可使用任意語言作編寫,甚至能夠直接對接chrome
爬取純JS單頁面網站爬取,也支持代理池,若是你們感興趣我也能夠說說爬蟲相關的東西,分佈式的哦,能夠隨便加機器增長爬取能力。算法
好了,八卦完了,爬了兩個網站,能夠開始幹活了,爬兩個類型的網站是爲了說明後面LDA主題模型,你們就有個認識了。spring
數據爬下來後,要作的就是數據清洗工做了,我以前有一篇搞機器學習的技能說了,數據的清理是一個算法工程師的必備技能,若是沒有好的數據,算法怎麼好都沒用。chrome
拿到數據之後,寫個腳本
中的內容幹掉了,一堆代碼對我來講沒什麼用。
ID(其實是url)
[TAB]TITLE(標題)
[TAB]CONTENT(文章詳情)
一共有11628
篇文章,其中汽車類大約6000,技術類(SF站)大約6000,好了,數據也基本上清洗好了。
都以爲這一節纔是重點,其實有jieba
分詞和gensim
之後,代碼很是簡單,不超過50行,咱們來一步一步玩。
分詞是基礎,首先進行分詞
from gensim import corpora,models,similarities,utils
import jieba
import jieba.posseg as pseg
jieba.load_userdict( "user_dic.txt" ) #載入自定義的詞典,主要有一些計算機詞彙和汽車型號的詞彙
#定義原始語料集合
train_set=[]
f=open("./data/all.txt")
lines=f.readlines()
for line in lines:
content = (line.lower()).split("\t")[2] + (line.lower()).split("\t")[1]
#切詞,etl函數用於去掉無用的符號,cut_all表示非全切分
word_list = filter(lambda x: len(x)>0,map(etl,jieba.cut(content,cut_all=False)))
train_set.append(word_list)
f.close()複製代碼
獲得的tain_set就是原始語料
了,而後對這些語料導入到詞典中,創建一個詞典。
#生成字典
dictionary = corpora.Dictionary(train_set)
#去除極低頻的雜質詞
dictionary.filter_extremes(no_below=1,no_above=1,keep_n=None)
#將詞典保存下來,方便後續使用
dictionary.save(output + "all.dic")複製代碼
將語料導入詞典後,每一個詞實際上就已經被編號成1,2,3....這種編號了,這是向量化的第一步,而後把詞典保存下來。 而後生成數字語料
corpus = [dictionary.doc2bow(text) for text in train_set]複製代碼
這一句表示把每一條原始數據向量化成編號,這樣之後,corpus這個變量是個二維數據,每一行表示一個文檔的每一個詞的編號和詞頻,每一行像這樣
[(1,2),(2,4),(5,2)....] 表示編號爲1的詞出現了2次,編號爲2的詞出現了4次....
OK,前期準備OK了,原始文章經過切詞
-->創建詞典
-->生成語料
後已經被咱們數字化了,後面就簡單了。
有了數字語料之後,咱們能夠生成一個TFIDF模型
#使用數字語料生成TFIDF模型
tfidfModel = models.TfidfModel(corpus)
#存儲tfidfModel
tfidfModel.save(output + "allTFIDF.mdl")複製代碼
這一句是關鍵,咱們用了原始的數字語料,生成了一個TFIDF模型,這個模型能幹什麼呢?gensim
重載了[]操做符
,咱們能夠用相似[(1,2),(2,4),(5,2)....]
的原始向量傳進去,變成一個tfidf的向量,像這樣[(1,0.98),(2,0.23),(5,0.56)....]
,這樣就說明編號1的詞的重要性比後面兩個詞都要大,這個向量能夠做爲後面LDA的原始向量輸入。
而後咱們把全部的語料都TFIDF向量化,並做爲一個索引數據存起來方便之後查找的時候使用
#把所有語料向量化成TFIDF模式,這個tfidfModel能夠傳入二維數組
tfidfVectors = tfidfModel[corpus]
#創建索引並保存
indexTfidf = similarities.MatrixSimilarity(tfidfVectors)
indexTfidf.save(output + "allTFIDF.idx")複製代碼
好了,TFIDF部分完了,先記下來,咱們生成了一個模型數據(allTFIDF.mdl)
,生成了一份所有語料的TFIDF向量的索引數據(allTFIDF.idx)
,加上上面的詞典數據(all.dic)
,咱們如今有三份數據了,後面再說怎麼用,如今先繼續LDA部分。
LDA上一篇講了那麼多,在gensim
看來就是下面幾行代碼,並且使用了傳說中的機器學習
哦。只能說gensim的代碼封裝得太簡潔了。
#經過TFIDF向量生成LDA模型,id2word表示編號的對應詞典,num_topics表示主題數,咱們這裏設定的50,主題太多時間受不了。
lda = models.LdaModel(tfidfVectors, id2word=dictionary, num_topics=50)
#把模型保存下來
lda.save(output + "allLDA50Topic.mdl")
#把全部TFIDF向量變成LDA的向量
corpus_lda = lda[tfidfVectors]
#創建索引,把LDA數據保存下來
indexLDA = similarities.MatrixSimilarity(corpus_lda)
indexLDA.save(output + "allLDA50Topic.idx")複製代碼
雖然只有這三步,可是仍是挺耗時的,在log打開的狀況下能夠看處處理過程,我隨便截取了幾個,像下面同樣,很明顯,前面幾個主題都和汽車相關,後面幾個主題都和技術相關,看樣子還算比較靠譜的。
#38 (0.020): 0.003*新奇 + 0.003*駿 + 0.002*途安 + 0.002*配備 + 0.002*都市 + 0.001*除 + 0.001*昂科威
#27 (0.020): 0.003*配置 + 0.003*內飾 + 0.003*車型 + 0.002*氣囊 + 0.002*瑞風 + 0.002*萬元 + 0.002*逸緻 +
#0 (0.020): 0.004*奔騰 + 0.003*加速 + 0.003*嘉年華 + 0.002*油門 + 0.002*愛麗舍 + 0.002*秒
#49 (0.020): 0.004*瑞虎 + 0.004*紳寶 + 0.004*歐諾 + 0.002*雷克薩斯 + 0.002*車型 + 0.002*樂途
#26 (0.020): 0.011*列表 + 0.009*流 + 0.007*快捷鍵 + 0.006*崩潰 + 0.002*大神 + 0.002*混淆 + 0.002*郵箱
#21 (0.020): 0.035*命令 + 0.018*瀏覽器 + 0.007*第三方 + 0.007*安裝 + 0.006*控制檯
topic #25 (0.020): 0.064*文件 + 0.004*約束 + 0.004*練習 + 0.003*複製到 + 0.003*就好了 + 0.003*反編譯複製代碼
好了,LDA部分也完了,又多了兩個文件allLDA50Topic.mdl
和allLDA50Topic.idx
,加上前面的3個,一共5個文件了,OK,休息一下,喝杯可樂,繼續下一步。
好了,第四部分中不知不覺咱們已經使用機器學習
這麼高端的東西了,那如今要驗證一下這麼高端的東西到底效果如何了。
前面的TFIDF和LDA咱們都保存了模型和向量數據,那麼咱們就用兩篇新的文章,來看看和這篇文章最類似的文章都有哪些來驗證這兩個模型靠譜不靠譜吧。
我隨便打開一個汽車網站,選了一篇汽車的文章(寶馬的評測),再找了我以前的一篇技術的文章(講搜索引擎的),而且只隨機截取了文章的一段進行測試。
看開頭這應該是一篇爲全新寶馬X1 Li(下文簡稱新X1)洗地的文章,我想不少寶馬死忠、車神也已經準備移步評論........
通常狀況下,搜索引擎默認會認爲索引是不會有太大的變化的,因此把索引分爲全量索引和增量索引兩部分,全量索引通常是以天.......
好,文章選好了,先載入以前保存的數據文件
#載入字典
dictionary = corpora.Dictionary.load(output + "all.dic")
#載入TFIDF模型和索引
tfidfModel = models.TfidfModel.load(output+"allTFIDF.mdl")
indexTfidf = similarities.MatrixSimilarity.load(output + "allTFIDF.idx")
#載入LDA模型和索引
ldaModel = models.LdaModel.load(output + "allLDA50Topic.mdl")
indexLDA = similarities.MatrixSimilarity.load(output + "allLDA50Topic.idx")複製代碼
而後把測試數據進行切詞
,TFIDF向量化
,找類似
,LDA向量化
,找類似
#query就是測試數據,先切詞
query_bow = dictionary.doc2bow(filter(lambda x: len(x)>0,map(etl,jieba.cut(query,cut_all=False))))
#使用TFIDF模型向量化
tfidfvect = tfidfModel[query_bow]
#而後LDA向量化,由於咱們訓練時的LDA是在TFIDF基礎上作的,因此用itidfvect再向量化一次
ldavec = ldaModel[tfidfvect]
#TFIDF類似性
simstfidf = indexTfidf[tfidfvect]
#LDA類似性
simlda = indexLDA[ldavec]複製代碼
好了,結束,全部代碼就這麼些了。太簡單了。。。。咱們來看看效果。
咱們先看TFIDF的結果
汽車的測試文章TFIDF結果(前10結果中隨機選3個)
優惠購車推薦寶馬x3優惠3.5-7萬元 保時捷macan競爭力分析寶馬x3
寶馬2014年新車展望多達十餘款新車
技術的測試文章TFIDF結果(前10結果中隨機選3個)
用golang寫一個搜索引擎(0x06) 索引那點事 [搜索引擎] sphinx 的介紹和原理探索
很明顯,結果基本都比較靠譜,第一個基本是說寶馬車的,第二個基本都在說搜索引擎和索引。 咱們再看看LDA的結果,LDA的主要功能是文本分類而不是關鍵詞的匹配,就是看測試文章分類分得對不對,咱們這裏基本上是兩類文章,一類技術文章,一類汽車文章,因此咱們經過找和測試文章最類似的文章,而後看看找出來最類似的文章是否是正好都是技術類的或者汽車類的,若是是,表示模型比較好。
汽車的測試文章LDA結果(前10結果中隨機選3個)
編輯心中最美中級車一汽-大衆新cc 25萬時尚品質4款豪華緊湊車之奔馳a級
iphone手機html5上傳圖片方向問題解決
技術的測試文章LDA結果(前10結果中隨機選3個)
java 多線程核心技術梳理(附源碼) springsession原理解析 併發中的鎖文件模式
從結果看,基本比較靠譜,但汽車那個出現了一個badcaseiphone手機html5上傳圖片方向問題解決
,這是篇技術文章,可是出如今了汽車類上面。
咱們來分析一下這個結果,對於TFIDF模型,在現有數據集(12000篇文章)的狀況下,推薦結果強相關,讓人以爲推薦結果很靠譜,這也是TFIDF這種算法簡單有效的地方,他把文章中的關鍵詞很好的提取出來了,因此推薦的結果讓人以爲強相關,可是他也有本身的問題。
文本類似性
最重要,但有可能按TFIDF算出來是模型
這個詞最重要。 對於純文本的推薦系統來講,這種文本相關性的推薦可能比較適合垂直類的網站,好比像SegmentFault這種,看某篇文章的人極可能但願看到相似的文章,更深刻的瞭解這個領域,這種算法比較靠譜,不過據我觀察,SegmentFault是使用的標籤推薦,這種推薦效果更好,但人爲因素更多點,要是我寫文章的時候隨便打標籤就比較麻煩了。再來看看LDA模型,LDA主要用在文本聚類上,並且他的基礎是主題,若是把他做爲推薦系統的算法來使用,要看具體場景,他的推薦結果在數據樣本不太夠的狀況下,可能看上去不太靠譜(即使樣本大可能也看上去不太好),顯得粒度很粗,但正由於很粗,因此比較適合作內容發現,好比我對數碼新聞感興趣,這種感興趣不只僅是隻對iphone
感興趣,只要是數碼這個主題的我都感興趣,因此用LDA能夠很好的給我推薦數碼
這個主題下的東西,這比正在看iphone
的文章,下面全是iphone
的文章要靠譜多了。
LDA出現上一節的哪一種badcase的時候怎麼辦呢?由於基本不太可能改模型,那麼只能從幾個方面入手。
算法工程師
的價值所在啊)算法工程師
必備技能耐心和細心
) 因此,不一樣的模型對於不一樣的場景是很重要的,根據你的場景選擇合適的模型才能達到合適的效果。機器學習
技術哦。其實,像LDA,以及word2vec這種模型,已是被數學抽象得很強的模型了,和實際場景基本上已經脫離了,已經徹底數學化了
,因此其實不必定要用在文本處理上,在流量分析,用戶行爲分析上同樣有用,這就是算法工程師
要想的事情,一個好的算法如何用在現有的場景中。
試想一下,若是咱們想給咱們的用戶分個類,看看哪些用戶興趣比較類似。咱們其實能夠這麼來作:
用戶A :[瀏覽了a頁面,點擊了b按鈕,瀏覽了c頁面....]
算法工程師
的必備技能之一----想象力
,那麼咱們把每一個用戶的行爲當成一篇文章,每一個行爲數據當成一個詞語,而後使用LDA
.....呵呵 這樣算出來的主題,是否是就是用戶的類別呢?有類似行爲數據的用戶會出如今相同的主題下,那麼這樣就把這些用戶分類了,那麼是否是能夠理解爲一樣類別的下的用戶有着類似的愛好呢?若是你以爲可行,能夠拿你公司的用戶數據試試,看看效果好很差:)最後,全部代碼在github上,點擊這裏能夠看獲得,代碼至關簡單,整個不超過200行,核心的就是我上面列的那些,代碼中也有word2vec的代碼和使用,這篇文章就沒提了,另外,爬取的文章就不放上來了,太大了。
若是你們想要語料本身玩,能夠上wiki百科,他們開放了他們的全部數據給全世界作語料分析,其中有中文的,地址是:dumps.wikimedia.org/zhwiki/late…,但維基上中文語料並很少,中文語料多的是百度百科,但看看百度百科,呵呵,不但不開放,防爬蟲跟防賊同樣,呵呵,不過我也給你們個地址,100G的百度百科原始頁面:pan.baidu.com/s/1i3wvfil ,接頭密碼:neqs,由亞洲第二爬蟲天王梁斌penny
友情提供。
好了,今天的文章有點長,就到這了,後面會把算法部分放一放,最近工做太忙,等這一段結束了,我會再說說算法部分,由於如今工做中會有一些比較好玩的算法要用,接下來的文章會主要寫寫系統架構方面的東西了,另外我本身的那個搜索引擎目前太忙沒時間整,也要等一小段時間了,很差意思:)但放心,不會有頭無尾啦。
歡迎關注個人公衆號,主要聊聊搜索,推薦,廣告技術,還有瞎扯。。文章會在這裏首先發出來:)掃描或者搜索微信號XJJ267或者搜索西加加語言就行