最近在做一個小APP,一直沒有來的及更新這個系列的文章争舞,是為抱歉。按照上文講到澈灼,我們已經(jīng)將數(shù)據(jù)重復(fù)的內(nèi)容用pandas庫去掉了竞川,接下來將干一件難度很大的事情,那就是對人名進(jìn)行提取叁熔。
我們當(dāng)前進(jìn)度:3
- 爬蟲程序——抓取全百度百科與“伯明翰大學(xué)”相關(guān)的數(shù)據(jù)
- 數(shù)據(jù)去重——用pandas去掉抓取相同的URL或相同的名稱
- 提取人名——利用HMM-Viterbi進(jìn)行人名篩選與提取
- 下載器——下載所有數(shù)據(jù)庫中數(shù)據(jù)清洗過的URL委乌,并存入數(shù)據(jù)庫
- 人物Ranking——按照一定的排名方式,對人物進(jìn)行知名度排名
- 人物梗概——利用NLP相關(guān)庫者疤,對提取的人物進(jìn)行自動化梗概
關(guān)于人名提取福澡,說白了,就是每一個字段(標(biāo)題)就是一句話驹马,我們對這句話進(jìn)行語法詞性分析革砸,提出其主語部分,其實(shí)質(zhì)是一個NLP的應(yīng)用問題糯累。
關(guān)于HMM-Viterbi算法算利,這里有一篇論文介紹。下面本文引用一篇講的很好很透徹的文章節(jié)選(引用自一文搞懂HMM(隱馬爾可夫模型))泳姐,里面的文字講的很清晰很透徹了效拭。本來想自己總結(jié)一下,但是感覺有些班門弄斧,索性直接引用缎患。
HMM(隱馬爾可夫模型)
隱馬爾可夫模型(Hidden Markov Model慕的,HMM)是統(tǒng)計模型,它用來描述一個含有隱含未知參數(shù)的馬爾可夫過程挤渔。其難點(diǎn)是從可觀察的參數(shù)中確定該過程的隱含參數(shù)肮街。然后利用這些參數(shù)來作進(jìn)一步的分析,例如模式識別判导。
是在被建模的系統(tǒng)被認(rèn)為是一個馬爾可夫過程與未觀測到的(隱藏的)的狀態(tài)的統(tǒng)計馬爾可夫模型嫉父。
下面用一個簡單的例子來闡述:
假設(shè)我手里有三個不同的骰子。第一個骰子是我們平常見的骰子(稱這個骰子為D6)眼刃,6個面绕辖,每個面(1,2擂红,3仪际,4,5篮条,6)出現(xiàn)的概率是1/6弟头。第二個骰子是個四面體(稱這個骰子為D4),每個面(1涉茧,2,3疹娶,4)出現(xiàn)的概率是1/4伴栓。第三個骰子有八個面(稱這個骰子為D8),每個面(1雨饺,2钳垮,3,4额港,5饺窿,6,7移斩,8)出現(xiàn)的概率是1/8肚医。
假設(shè)我們開始擲骰子,我們先從三個骰子里挑一個向瓷,挑到每一個骰子的概率都是1/3肠套。然后我們擲骰子,得到一個數(shù)字猖任,1你稚,2,3,4刁赖,5搁痛,6,7宇弛,8中的一個落追。不停的重復(fù)上述過程,我們會得到一串?dāng)?shù)字涯肩,每個數(shù)字都是1轿钠,2,3病苗,4疗垛,5,6硫朦,7贷腕,8中的一個。例如我們可能得到這么一串?dāng)?shù)字(擲骰子10次):1 6 3 5 2 7 3 5 2 4
這串?dāng)?shù)字叫做可見狀態(tài)鏈咬展。但是在隱馬爾可夫模型中泽裳,我們不僅僅有這么一串可見狀態(tài)鏈,還有一串隱含狀態(tài)鏈破婆。在這個例子里涮总,這串隱含狀態(tài)鏈就是你用的骰子的序列。比如祷舀,隱含狀態(tài)鏈有可能是:D6 D8 D8 D6 D4 D8 D6 D6 D4 D8
一般來說瀑梗,HMM中說到的馬爾可夫鏈其實(shí)是指隱含狀態(tài)鏈,因?yàn)殡[含狀態(tài)(骰子)之間存在轉(zhuǎn)換概率(transition probability)裳扯。在我們這個例子里抛丽,D6的下一個狀態(tài)是D4,D6饰豺,D8的概率都是1/3亿鲜。D4,D8的下一個狀態(tài)是D4冤吨,D6蒿柳,D8的轉(zhuǎn)換概率也都一樣是1/3。這樣設(shè)定是為了最開始容易說清楚锅很,但是我們其實(shí)是可以隨意設(shè)定轉(zhuǎn)換概率的其馏。比如,我們可以這樣定義爆安,D6后面不能接D4叛复,D6后面是D6的概率是0.9,是D8的概率是0.1。這樣就是一個新的HMM褐奥。
同樣的咖耘,盡管可見狀態(tài)之間沒有轉(zhuǎn)換概率,但是隱含狀態(tài)和可見狀態(tài)之間有一個概率叫做輸出概率(emission probability)撬码。就我們的例子來說儿倒,六面骰(D6)產(chǎn)生1的輸出概率是1/6。產(chǎn)生2呜笑,3夫否,4,5叫胁,6的概率也都是1/6凰慈。我們同樣可以對輸出概率進(jìn)行其他定義。比如驼鹅,我有一個被賭場動過手腳的六面骰子微谓,擲出來是1的概率更大,是1/2输钩,擲出來是2豺型,3,4买乃,5姻氨,6的概率是1/10。
其實(shí)對于HMM來說为牍,如果提前知道所有隱含狀態(tài)之間的轉(zhuǎn)換概率和所有隱含狀態(tài)到所有可見狀態(tài)之間的輸出概率哼绑,做模擬是相當(dāng)容易的。但是應(yīng)用HMM模型時候呢碉咆,往往是缺失了一部分信息的,有時候你知道骰子有幾種蛀恩,每種骰子是什么疫铜,但是不知道擲出來的骰子序列;有時候你只是看到了很多次擲骰子的結(jié)果双谆,剩下的什么都不知道壳咕。如果應(yīng)用算法去估計這些缺失的信息,就成了一個很重要的問題顽馋。這些算法我會在下面詳細(xì)講谓厘。
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
? 如果你只想看一個簡單易懂的例子,就不需要往下看了寸谜。
? ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
? 說兩句廢話竟稳,答主認(rèn)為呢,要了解一個算法,要做到以下兩點(diǎn):會其意他爸,知其形聂宾。答主回答的,其實(shí)主要是第一點(diǎn)诊笤。但是這一點(diǎn)呢系谐,恰恰是最重要,而且很多書上不會講的讨跟。正如你在追一個姑娘纪他,姑娘對你說“你什么都沒做錯!”你要是只看姑娘的表達(dá)形式呢晾匠,認(rèn)為自己什么都沒做錯茶袒,顯然就理解錯了。你要理會姑娘的意思混聊,“你趕緊給我道歉弹谁!”這樣當(dāng)你看到對應(yīng)的表達(dá)形式呢,趕緊認(rèn)錯句喜,跪地求饒就對了预愤。數(shù)學(xué)也是一樣,你要是不理解意思咳胃,光看公式植康,往往一頭霧水。不過呢展懈,數(shù)學(xué)的表達(dá)頂多也就是晦澀了點(diǎn)销睁,姑娘的表達(dá)呢,有的時候就完全和本意相反存崖。所以答主一直認(rèn)為理解姑娘比理解數(shù)學(xué)難多了冻记。
回到正題,和HMM模型相關(guān)的算法主要分為三類来惧,分別解決三種問題:
** 1)知道骰子有幾種(隱含狀態(tài)數(shù)量)冗栗,每種骰子是什么(轉(zhuǎn)換概率),根據(jù)擲骰子擲出的結(jié)果(可見狀態(tài)鏈)供搀,我想知道每次擲出來的都是哪種骰子(隱含狀態(tài)鏈)隅居。**
? 這個問題呢,在語音識別領(lǐng)域呢葛虐,叫做解碼問題胎源。這個問題其實(shí)有兩種解法,會給出兩個不同的答案屿脐。每個答案都對涕蚤,只不過這些答案的意義不一樣宪卿。第一種解法求最大似然狀態(tài)路徑,說通俗點(diǎn)呢赞季,就是我求一串骰子序列愧捕,這串骰子序列產(chǎn)生觀測結(jié)果的概率最大。第二種解法呢申钩,就不是求一組骰子序列了次绘,而是求每次擲出的骰子分別是某種骰子的概率。比如說我看到結(jié)果后撒遣,我可以求得第一次擲骰子是D4的概率是0.5邮偎,D6的概率是0.3,D8的概率是0.2.第一種解法我會在下面說到义黎,但是第二種解法我就不寫在這里了禾进,如果大家有興趣,我們另開一個問題繼續(xù)寫吧廉涕。
2)還是知道骰子有幾種****(隱含狀態(tài)數(shù)量)****泻云,每種骰子是什么****(轉(zhuǎn)換概率)****,根據(jù)擲骰子擲出的結(jié)果****(可見狀態(tài)鏈)****狐蜕,我想知道擲出這個結(jié)果的概率宠纯。
? 看似這個問題意義不大,因?yàn)槟銛S出來的結(jié)果很多時候都對應(yīng)了一個比較大的概率层释。問這個問題的目的呢婆瓜,其實(shí)是檢測觀察到的結(jié)果和已知的模型是否吻合。如果很多次結(jié)果都對應(yīng)了比較小的概率贡羔,那么就說明我們已知的模型很有可能是錯的廉白,有人偷偷把我們的骰子給換了。
3)知道骰子有幾種****(隱含狀態(tài)數(shù)量)****乖寒,不知道每種骰子是什么****(轉(zhuǎn)換概率)****猴蹂,觀測到很多次擲骰子的結(jié)果****(可見狀態(tài)鏈)****,我想反推出每種骰子是什么****(轉(zhuǎn)換概率)****楣嘁。
? 這個問題很重要晕讲,因?yàn)檫@是最常見的情況。很多時候我們只有可見結(jié)果马澈,不知道HMM模型里的參數(shù),我們需要從可見結(jié)果估計出這些參數(shù)弄息,這是建模的一個必要步驟痊班。
問題闡述完了,下面就開始說解法摹量。(0號問題在上面沒有提涤伐,只是作為解決上述問題的一個輔助)
? 0.一個簡單問題
其實(shí)這個問題實(shí)用價值不高馒胆。由于對下面較難的問題有幫助,所以先在這里提一下凝果。
知道骰子有幾種祝迂,每種骰子是什么,每次擲的都是什么骰子器净,根據(jù)擲骰子擲出的結(jié)果型雳,求產(chǎn)生這個結(jié)果的概率。
解法無非就是概率相乘:
[圖片上傳失敗...(image-b82e48-1510809177209)]
[圖片上傳失敗...(image-9c40d0-1510809177209)]
1.看見不可見的山害,破解骰子序列
? 這里我說的是第一種解法纠俭,解最大似然路徑問題。
? 舉例來說浪慌,我知道我有三個骰子冤荆,六面骰,四面骰权纤,八面骰钓简。我也知道我擲了十次的結(jié)果(1 6 3 5 2 7 3 5 2 4),我不知道每次用了那種骰子汹想,我想知道最有可能的骰子序列外邓。
其實(shí)最簡單而暴力的方法就是窮舉所有可能的骰子序列,然后依照第零個問題的解法把每個序列對應(yīng)的概率算出來欧宜。然后我們從里面把對應(yīng)最大概率的序列挑出來就行了坐榆。如果馬爾可夫鏈不長,當(dāng)然可行冗茸。如果長的話席镀,窮舉的數(shù)量太大,就很難完成了夏漱。
? 另外一種很有名的算法叫做Viterbi algorithm. 要理解這個算法豪诲,我們先看幾個簡單的列子。
? 首先挂绰,如果我們只擲一次骰子:
看到結(jié)果為1.對應(yīng)的最大概率骰子序列就是D4屎篱,因?yàn)镈4產(chǎn)生1的概率是1/4,高于1/6和1/8.
? 把這個情況拓展葵蒂,我們擲兩次骰子:
結(jié)果為1交播,6.這時問題變得復(fù)雜起來,我們要計算三個值践付,分別是第二個骰子是D6秦士,D4,D8的最大概率永高。顯然隧土,要取到最大概率提针,第一個骰子必須為D4。這時曹傀,第二個骰子取到D6的最大概率是
[圖片上傳失敗...(image-d6055d-1510809177209)]
[圖片上傳失敗...(image-c6ed01-1510809177209)]
? 同樣的辐脖,我們可以計算第二個骰子是D4或D8時的最大概率。我們發(fā)現(xiàn)皆愉,第二個骰子取到D6的概率最大嗜价。而使這個概率最大時,第一個骰子為D4亥啦。所以最大概率骰子序列就是D4 D6炭剪。
繼續(xù)拓展,我們擲三次骰子:
同樣翔脱,我們計算第三個骰子分別是D6奴拦,D4,D8的最大概率届吁。我們再次發(fā)現(xiàn)错妖,要取到最大概率,第二個骰子必須為D6疚沐。這時暂氯,第三個骰子取到D4的最大概率是[圖片上傳失敗...(image-fd4ab7-1510809177209)]
[圖片上傳失敗...(image-621be5-1510809177209)]
? 同上,我們可以計算第三個骰子是D6或D8時的最大概率亮蛔。我們發(fā)現(xiàn)痴施,第三個骰子取到D4的概率最大。而使這個概率最大時究流,第二個骰子為D6辣吃,第一個骰子為D4。所以最大概率骰子序列就是D4 D6 D4芬探。
寫到這里神得,大家應(yīng)該看出點(diǎn)規(guī)律了。既然擲骰子一二三次可以算偷仿,擲多少次都可以以此類推哩簿。我們發(fā)現(xiàn),我們要求最大概率骰子序列時要做這么幾件事情酝静。首先节榜,不管序列多長,要從序列長度為1算起别智,算序列長度為1時取到每個骰子的最大概率全跨。然后,逐漸增加長度亿遂,每增加一次長度浓若,重新算一遍在這個長度下最后一個位置取到每個骰子的最大概率。因?yàn)樯弦粋€長度下的取到每個骰子的最大概率都算過了蛇数,重新計算的話其實(shí)不難挪钓。當(dāng)我們算到最后一位時,就知道最后一位是哪個骰子的概率最大了耳舅。然后碌上,我們要把對應(yīng)這個最大概率的序列從后往前推出來。
2.誰動了我的骰子浦徊?
? 比如說你懷疑自己的六面骰被賭場動過手腳了馏予,有可能被換成另一種六面骰,這種六面骰擲出來是1的概率更大盔性,是1/2霞丧,擲出來是2,3冕香,4蛹尝,5,6的概率是1/10悉尾。你怎么辦么突那?答案很簡單,算一算正常的三個骰子擲出一段序列的概率构眯,再算一算不正常的六面骰和另外兩個正常骰子擲出這段序列的概率愕难。如果前者比后者小,你就要小心了惫霸。
? 比如說擲骰子的結(jié)果是:
要算用正常的三個骰子擲出這個結(jié)果的概率猫缭,其實(shí)就是將所有可能情況的概率進(jìn)行加和計算。同樣它褪,簡單而暴力的方法就是把窮舉所有的骰子序列饵骨,還是計算每個骰子序列對應(yīng)的概率,但是這回茫打,我們不挑最大值了蛉鹿,而是把所有算出來的概率相加肚吏,得到的總概率就是我們要求的結(jié)果。這個方法依然不能應(yīng)用于太長的骰子序列(馬爾可夫鏈)。
? 我們會應(yīng)用一個和前一個問題類似的解法效览,只不過前一個問題關(guān)心的是概率最大值,這個問題關(guān)心的是概率之和崭倘。解決這個問題的算法叫做前向算法(forward algorithm)聊替。
首先,如果我們只擲一次骰子:
看到結(jié)果為1.產(chǎn)生這個結(jié)果的總概率可以按照如下計算开财,總概率為0.18:
把這個情況拓展汉柒,我們擲兩次骰子:
看到結(jié)果為1误褪,6.產(chǎn)生這個結(jié)果的總概率可以按照如下計算,總概率為0.05:
繼續(xù)拓展碾褂,我們擲三次骰子:
看到結(jié)果為1兽间,6,3.產(chǎn)生這個結(jié)果的總概率可以按照如下計算正塌,總概率為0.03:
同樣的嘀略,我們一步一步的算,有多長算多長乓诽,再長的馬爾可夫鏈總能算出來的帜羊。用同樣的方法,也可以算出不正常的六面骰和另外兩個正常骰子擲出這段序列的概率鸠天,然后我們比較一下這兩個概率大小讼育,就能知道你的骰子是不是被人換了。
Viterbi algorithm
HMM(隱馬爾可夫模型)是用來描述隱含未知參數(shù)的統(tǒng)計模型粮宛,舉一個經(jīng)典的例子:一個東京的朋友每天根據(jù)天氣{下雨窥淆,天晴}決定當(dāng)天的活動{公園散步,購物,清理房間}中的一種,我每天只能在twitter上看到她發(fā)的推“啊巍杈,我前天公園散步忧饭、昨天購物、今天清理房間了筷畦!”词裤,那么我可以根據(jù)她發(fā)的推特推斷東京這三天的天氣。在這個例子里鳖宾,顯狀態(tài)是活動吼砂,隱狀態(tài)是天氣。
任何一個HMM都可以通過下列五元組來描述:
:param obs:觀測序列
:param states:隱狀態(tài)
:param start_p:初始概率(隱狀態(tài))
:param trans_p:轉(zhuǎn)移概率(隱狀態(tài))
:param emit_p: 發(fā)射概率 (隱狀態(tài)表現(xiàn)為顯狀態(tài)的概率)
偽碼如下:
[](javascript:void(0);)
states = ('Rainy', 'Sunny')
observations = ('walk', 'shop', 'clean')
start_probability = {'Rainy': 0.6, 'Sunny': 0.4}
transition_probability = {
'Rainy' : {'Rainy': 0.7, 'Sunny': 0.3},
'Sunny' : {'Rainy': 0.4, 'Sunny': 0.6},
}
emission_probability = {
'Rainy' : {'walk': 0.1, 'shop': 0.4, 'clean': 0.5},
'Sunny' : {'walk': 0.6, 'shop': 0.3, 'clean': 0.1},
}
求解最可能的天氣
求解最可能的隱狀態(tài)序列是HMM的三個典型問題之一鼎文,通常用維特比算法解決渔肩。維特比算法就是求解HMM上的最短路徑(-log(prob),也即是最大概率)的算法拇惋。
稍微用中文講講思路周偎,很明顯,第一天天晴還是下雨可以算出來:
- 定義V[時間][今天天氣] = 概率撑帖,注意今天天氣指的是蓉坎,前幾天的天氣都確定下來了(概率最大)今天天氣是X的概率,這里的概率就是一個累乘的概率了胡嘿。
- ? 因?yàn)榈谝惶煳业呐笥讶ド⒉搅蓑劝缘谝惶煜掠甑母怕蔞[第一天][下雨] = 初始概率[下雨] * 發(fā)射概率[下雨][散步] = 0.6 * 0.1 = 0.06,同理可得V[第一天][天晴] = 0.24 。從直覺上來看勿侯,因?yàn)榈谝惶炫笥殉鲩T了拓瞪,她一般喜歡在天晴的時候散步,所以第一天天晴的概率比較大罐监,數(shù)字與直覺統(tǒng)一了吴藻。
- 從第二天開始,對于每種天氣Y弓柱,都有前一天天氣是X的概率 * X轉(zhuǎn)移到Y(jié)的概率 * Y天氣下朋友進(jìn)行這天這種活動的概率。因?yàn)榍耙惶焯鞖釾有兩種可能侧但,所以Y的概率有兩個矢空,選取其中較大一個作為V[第二天][天氣Y]的概率,同時將今天的天氣加入到結(jié)果序列中
- 比較V[最后一天][下雨]和[最后一天][天晴]的概率禀横,找出較大的哪一個對應(yīng)的序列屁药,就是最終結(jié)果。
算法的代碼可以在github上看到柏锄,地址為:
https://github.com/hankcs/Viterbi
運(yùn)行完成后根據(jù)Viterbi得到結(jié)果:
Sunny Rainy Rainy
Viterbi被廣泛應(yīng)用到分詞酿箭,詞性標(biāo)注等應(yīng)用場景。
以上內(nèi)容均為引用趾娃。
HanLP 原理
上面引用鋪墊了那么多缭嫡,為了解釋清楚HanLP是用什么算法對中國名字進(jìn)行分詞的。具體的抬闷,HanLP實(shí)現(xiàn)了論文《基于角色標(biāo)注的中國人名自動識別研究》妇蛀。
如果有興趣,可以快速理解此文笤成,看這些段落:
如果你掌握貝葉斯公式评架,并且看了上述文章,了解馬爾科夫假設(shè)并不難理解炕泳。
HanLP應(yīng)用
HanLP是一個優(yōu)秀的NLP庫纵诞,可是是用Java寫的,這里我們需要用jpype
包幫助pyhton調(diào)用Jar包培遵。
神奇吧浙芙?Python還能調(diào)用Jar包
Python調(diào)用Jar包
第一步 下載HanLP
去官方指定網(wǎng)址的release中下載jar包和相應(yīng)的data.zip
解壓zip,放置于python的根目錄
https://github.com/hankcs/HanLP
第二步 在啟動的時候啟動Java虛擬機(jī)
startJVM(getDefaultJVMPath(),
"-Djava.class.path=/Users/ivan/d/uobspider/hanlp-1.3.5.jar:/Users/ivan/d/uobspider/",
"-Xms1g", "-Xmx1g") # 啟動JVM荤懂,Linux需替換分號;為冒號:
第三步 創(chuàng)建Jar包對象
JDClass = JClass("com.hankcs.hanlp.seg.CRF.CRFSegment")
第四步 創(chuàng)建分詞對象
jd = JDClass().enableNameRecognize(True)
第四步 提取相關(guān)詞性部分
根據(jù)HanLP的官方給出的詞性標(biāo)注茁裙,可以斷定 /nr 為人名標(biāo)準(zhǔn),我們只需要在python代碼中國呢判斷是否包含 /nr 屬性
if "nr" in str(i.nature):
這就是所謂的拋磚引玉
具體代碼
具體代碼仍然寫在了filter代碼中节仿,會創(chuàng)建一個新表filter_second
晤锥,并將過濾后的數(shù)據(jù)復(fù)制存于此中。
# coding=utf-8
# python version:2.7
from sqlalchemy import create_engine
from jpype import *
import pandas as pd
reload(sys)
sys.setdefaultencoding('utf-8')
import pymysql
from pybloomfilter import BloomFilter
class Filter(object):
def __init__(self):
self.db = pymysql.connect("localhost", "root", "", "uob", use_unicode=True, charset="utf8")
self.engine = create_engine('mysql+pymysql://root:@localhost:3306/uob?charset=utf8')
self.cursor = self.db.cursor()
self.bfilter = BloomFilter(1000, 0.001, 'uob.bloom')
startJVM(getDefaultJVMPath(),
"-Djava.class.path=/Users/ivan/d/uobspider/hanlp-1.3.5.jar:/Users/ivan/d/uobspider/",
"-Xms1g", "-Xmx1g") # 啟動JVM,Linux需替換分號;為冒號:
def distinct(self):
sql = "SELECT * FROM list;"
allData = pd.read_sql(sql, con=self.engine) # 從抓取過來的數(shù)據(jù)庫讀入
allData.drop_duplicates('name', 'first', inplace=True) # 去除重復(fù)name
allData.drop_duplicates('url', 'first', inplace=True) # 去除重復(fù)url
allData.reset_index(drop=True, inplace=True) # index重新計數(shù)
print allData.detail()
allData.to_sql('first_filter', self.engine, if_exists='replace', index=True, index_label='fid') # 輸出到新的數(shù)據(jù)庫表
return allData
def insertData(self, id, name, url):
insertsql = "INSERT INTO filter_second (list_id,name,url) VALUES(" + str(id) + ",\"" + str(
name) + "\",\"" + str(url) + "\");"
print insertsql
try:
self.cursor.execute(insertsql)
self.db.commit()
except:
self.db.rollback()
print "error"
def filterHMM(self):
sql = "SELECT id,name,url FROM list;"
self.cursor.execute(sql)
allData = self.cursor.fetchall()
JDClass = JClass("com.hankcs.hanlp.seg.CRF.CRFSegment")
jd = JDClass().enableNameRecognize(True)
names = []
for data in allData:
s = data[1]
words = jd.seg(jpype.JString(s))
for i in words:
if "nr" in str(i.nature):
tmp = str(i.word)
if len(tmp) > 1:
self.insertData(data[0], data[1], data[2])
break
if __name__ == "__main__":
obj_filter = Filter()
obj_filter.distinct()
obj_filter.filterHMM()
效果
其實(shí)效果并非非常理想矾瘾,還是有很多無用信息和漏下來的信息女轿,但是總體上還是不錯的。
下章預(yù)告:“我是如何收集校友的”之百度百科批量下載器