上回網(wǎng)易云音樂評論抓取實驗(1)接口獲取說到我們已經(jīng)可以結(jié)合爬蟲拿到一首歌下面的所有評論了丧失,然而針對這些評論我們又能做些什么分析呢?由于我自己平時魔性洗腦迄委、抒情古風啥的都在聽谋梭,下面的評論也是哈哈哈表白編段子的都有互广,所以就在想能不能把評論的情緒做個分類踪栋?先看看實驗結(jié)果吧焙格。
輸入了三個評論,判斷其屬于兩首歌的概率從而確定歸屬夷都。(兩首歌分別是雙笙 達拉崩吧 和 雙笙 我的一個道姑朋友)
想法由來
把評論爬到之后首先想的就是先做個詞云看看這首歌的評論大致是什么畫風眷唉,比如《權(quán)御天下》
(呃…這個
大哭
是emoji里面的笑哭
的表情,大家不要誤會了)
好幾個大大的 笑哭 拍到臉上囤官,就知道評論區(qū)應該比較歡樂啦~
也就是說冬阳,歡樂的歌曲里面出現(xiàn)體現(xiàn)歡樂情緒的評論會更多一些,悲傷的同理党饮。如果從里面隨機選評論出來肝陪,我們能知道這個評論屬于哪首歌嗎?
這篇文章的例子是以同一個歌手的兩首不同風格的歌作為樣本刑顺,如果樣本是兩個不同音樂情緒的專輯氯窍,那么是不是就可以根據(jù)評論分出一首歌是快樂還是憂傷呢?
樸素貝葉斯
當然先是到處查啦蹲堂,在這里我首先接觸到的是這篇文章Python做文本情感分析之情感極性分析 - 簡書狼讨,提到了兩種方法,第一種根據(jù)詞匯分類判斷柒竞,第二種基于機器學習暫時還看不懂- -這不是看不懂機器學習嘛政供,就去看了參考書機器學習實戰(zhàn) ,發(fā)現(xiàn)這個樸素貝葉斯很適合這個分析朽基,因為它舉的例子是垃圾郵件分類布隔!感覺和評論分類很像啊踩晶!
其核心為一個公式:
Ci(Class)代表第i個分類执泰,向量w(words)代表一句話中的詞語,含義為:
出現(xiàn)向量w(w1,w2,w3,…)組成的一句話的前提下渡蜻,
它屬于類別*i*的概率
=在類別*i*中出現(xiàn)這句話的概率
*任一句子屬于類別*i*的概率
/出現(xiàn)這句話的概率
而我們需要比較p(c0|w) p(c1|w)誰更大术吝,所以可以忽略這個相同的分母p(w),代碼中我設定兩類均使用2000條評論作為樣本茸苇,所以p(c)也相等可以忽略啦排苍。
“喂喂喂,你快別bb了学密,你說的啥啊淘衙,看不懂!D迥骸彤守!”
咳咳…我也一看到公式就發(fā)懵…那就直觀點說毯侦。來看看我們是如何區(qū)分的吧,如果看到“哈哈哈哈哈哈”什么的具垫,那就是第一首沒跑了侈离;“道姑”“道長”什么的,那就會是第二首啦筝蚕。也就是特定詞匯在兩首歌中出現(xiàn)的概率不同卦碾。
后續(xù)就抄一抄書了。
代碼實現(xiàn)
上面提到起宽,我們只需搞定p(w|c)就行了洲胖,也就是在各個分類下各個詞出現(xiàn)的概率,統(tǒng)計各個詞出現(xiàn)的次數(shù)坯沪,再除以一共有多少個詞就好啦绿映!……嗯,我真想給自己一巴掌屏箍,說的真輕松呢绘梦。
統(tǒng)計出現(xiàn)了哪些詞
把所有的評論的詞語都扔到集合里,就是所有用到的詞了赴魁!但是我們?yōu)榱吮阌诮y(tǒng)計出現(xiàn)的次數(shù),還是得用有序的列表啊钝诚。大概就是這樣一種表示方法:
所以代碼的開頭是這樣的颖御,用來提取爬蟲數(shù)據(jù),轉(zhuǎn)換為詞語凝颇,并構(gòu)造出總的詞語列表出來:
import jieba
from numpy import array
from numpy import log
import numpy
import copy
class nativebayes:
def load(self,songtype):
with open('%s_comment_train.txt'%str(songtype),encoding='utf-8') as f:
comments=f.readlines()
comments_list=[]
for i in comments:
comments_list .append(jieba.lcut(i))
return comments_list
#將所有出現(xiàn)過的詞語轉(zhuǎn)為列表
def createwordslist(self,comments_list):
wordsset=set([])
for words in comments_list:
wordsset=wordsset|set(words)
#轉(zhuǎn)換為有序列表
return list(wordsset)
統(tǒng)計出現(xiàn)的概率
一張圖說明如何操作
把每個評論的向量加起來就是出現(xiàn)次數(shù)了潘拱,再除以總的字數(shù)就是每個詞語出現(xiàn)的概率了啦。
首先是轉(zhuǎn)換為向量表示
def words2vec(self,wordslist,comment):
returnVec=[0]*len(wordslist)
#在之前已經(jīng)被切分好了
for word in comment:
if word in wordslist:
#將評論中出現(xiàn)的詞在Vector中標記
returnVec[wordslist.index(word)]=1
return returnVec
這里是以是否出現(xiàn)作為特征拧略,為詞集模型(set-of-words)芦岂,如果再細一點,以出現(xiàn)次數(shù)作為特征的話垫蛆,則為詞袋模型(bag-of-words)禽最。我想評論里可能存在“啊啊啊啊二狗二狗二狗!8し埂川无!我愛你我!愛虑乖!你懦趋!”這種重復就沒什么意思,所以就用的詞集模型疹味。
然后是計算概率
#計算p(c1),p(w|c1)
def trainNB(self,trainMatrix):
#因為均統(tǒng)計1000條評論仅叫,所以概率相等
p_class=0.5
#Class中詞語的總數(shù) 即一個wordslist的長度
numwords=len(trainMatrix[0])
words_statics=numpy.ones(numwords)
words_totalnum=0.0
for wordslist in trainMatrix:
#將各個詞出現(xiàn)的次數(shù)累加
words_statics+=wordslist
#統(tǒng)計評論中總的詞數(shù)
words_totalnum+=sum(wordslist)
p_vect=log(words_statics/words_totalnum)
return p_class,p_vect
注意帜篇!注意!這里為什么出現(xiàn)log
呢诫咱?先看看如果不加log
運行過程中p和總詞列表是怎樣的吧坠狡。
各個詞出現(xiàn)的概率p很小,如果統(tǒng)計的文本(上面的圖片僅僅是抓了50條評論得出的結(jié)果)特別大的話遂跟,最終的乘積p用float64儲存也會約等于0逃沿,即乘積過小,約等于0幻锁。
所以書上的解決方式是把乘積轉(zhuǎn)為求和凯亮,即取個對數(shù),反正是比較大小嘛哄尔,取對數(shù)不會影響假消。
還有一個地方!為什么統(tǒng)計的變量初始化是
words_statics=numpy.ones(numwords)
岭接,都要從1開始呢富拗?這是因為對種類0來說,種類1的詞不一定會出現(xiàn)(比如種類1中有個人發(fā)了個啥無關痛癢的“特朗普”)鸣戴,所以樣本采集之后啃沪,
P(特朗普|c0)=0
,然后我來測試一條新的評論窄锅,恰好出現(xiàn)了這個詞创千,就會導致種類0的最終乘積為0,從而僅僅因為一個詞導致其最后判定為種類1入偷,有失公允追驴。所以可以把所有詞出現(xiàn)次數(shù)初始化為1,也不會影響最終結(jié)果的裁定疏之。
測試
針對兩首歌各寫一個評論殿雪,再寫一個無法分類的評論,來看看測試效果吧:
if __name__=='__main__':
bayestest=nativebayes()
totalcomments=[]
#這里用append 是因為totalcomment[0] [1]分別為兩種評論锋爪,均為列表
totalcomments.append(bayestest.load(0))
totalcomments.append(bayestest.load(1))
totalcomments_a=copy.deepcopy(totalcomments[0])
#這里用extend是因為totalcomments_a全為評論
totalcomments_a.extend(totalcomments[1])
wordslist=bayestest.createwordslist(totalcomments_a)
p=[0,0]
p_wv=[[],[]]
for i in range(0,2):
wordslist_matrix=[]
for comment in totalcomments[i]:
#將每個評論轉(zhuǎn)換為詞組出現(xiàn)的向量形式丙曙,并加入總的矩陣中用做統(tǒng)計
wordslist_matrix.append(bayestest.words2vec(wordslist,comment))
p[i],p_wv[i]=bayestest.trainNB(array(wordslist_matrix))
# print(p_wv[i])
test_commentV_0=bayestest.words2vec(wordslist,jieba.lcut('哈哈哈笑死我了'))
test_commentV_1=bayestest.words2vec(wordslist,jieba.lcut('劍三的歌!很喜歡的故事几缭!'))
test_commentV_2=bayestest.words2vec(wordslist,jieba.lcut('雙笙的歌真好聽河泳!'))
bayestest.getP(test_commentV_0,p_wv[0],p_wv[1])
bayestest.getP(test_commentV_1,p_wv[0],p_wv[1])
bayestest.getP(test_commentV_2,p_wv[0],p_wv[1])
相比于模棱兩可的第三條
雙笙的歌真好聽
來說,第一條評論哈哈哈笑死我了
明顯P0>P1年栓,屬于第一首歌的情緒風格拆挥;第二條針對歌曲來源的評論劍三的歌!很喜歡的故事!
P1>P0纸兔,屬于第二首歌的情緒風格惰瓜。咩哈哈哈!表現(xiàn)還挺好的呢汉矿!
總結(jié)
之前看機器實戰(zhàn)的書也看過一會兒崎坊,不過這是我第一次實際接觸機器學習,果然有實際需求的時候才最有動力學下去洲拇。這篇文章也是馬馬虎虎完成的奈揍,可以從中看出我有很多地方都對實際進行了簡化,包括P1=P2=0.5等等赋续,有何不當?shù)牡胤侥泻玻埓蠹叶喽嘀附蘜_^,另外感覺NLP這一塊挺有趣的纽乱,如果我有一個人足夠多的評論數(shù)據(jù)蛾绎,我是不是能模仿他說話呢?后續(xù)準備學習一下這篇文章問答機器人的Python分類器鸦列。
代碼地址(包括評論爬取租冠、已經(jīng)爬好的數(shù)據(jù)、詞云薯嗤、樸素貝葉斯)
Github 163music
最后感謝大家的閱讀顽爹,如果對你有幫助,不妨點個喜歡吧应民。
往期批量下載電影排行榜的系列文章:
(番外篇)Python操縱網(wǎng)盤客戶端批量離線下載小電影
Python實現(xiàn)電影排行榜自動網(wǎng)盤下載(4)Cookies免登錄+抓包下載
Python實現(xiàn)電影排行榜自動網(wǎng)盤下載(3)Selenium離線下載
Python實現(xiàn)電影排行榜自動網(wǎng)盤下載(2)Scrapy深入 “打包員”“快遞員”
Python實現(xiàn)電影排行榜自動網(wǎng)盤下載(1)Scrapy爬蟲框架
Python實現(xiàn)電影排行榜自動網(wǎng)盤下載(0)簡介