一.樸素貝葉斯進(jìn)行文本分類

最近在做一個(gè)商品評(píng)論分類的需求,主要是將商品的差評(píng)根據(jù)主題進(jìn)行多次二分類,例如評(píng)論的內(nèi)容是不是質(zhì)量問題,物流問題等。

由于對(duì)機(jī)器學(xué)習(xí)屬于小白水平,所以先從最簡(jiǎn)單的樸素貝葉斯算法下手。

優(yōu)點(diǎn):易懂易實(shí)現(xiàn),文本容易向量化? ??

缺點(diǎn):分類效果一般

樸素貝葉斯算法是用統(tǒng)計(jì)學(xué)的方法來對(duì)數(shù)據(jù)進(jìn)行二分類,其主要思想就是貝葉斯公式,這個(gè)公式大學(xué)本科就學(xué)過,所以它的原理很容易理解,

? ? ? ? ? ? ? ? ? ? ? P(B|A)=P(A|B)P(B)/P(A)

即 事件A在事件B發(fā)生的前提下發(fā)生的概率=事件A在事件B發(fā)生的前提下發(fā)生的概率*事件B發(fā)生的概率/事件A發(fā)生的概率。

我們這里的事件主要是兩類:

?1)這個(gè)評(píng)論是A分類的概率是多大,記做P(A)

?2)某個(gè)詞Bi在A分類下出現(xiàn)的概率是多大,記做P(Bi|A),其中i為某個(gè)詞?

通過大數(shù)定律可知,當(dāng)樣本的數(shù)量足夠大,某件事情發(fā)生的概率是收斂于這件事發(fā)生的期望的。所以當(dāng)訓(xùn)練樣本數(shù)量足夠多時(shí),我們就可以把某件事發(fā)生的概率近似作為期望。而上述兩類事情的概率,都是可以通過訓(xùn)練集統(tǒng)計(jì)到的。然后對(duì)于一個(gè)新的文本,可以根據(jù)它的詞向量來判斷各種分類的概率,然后取最大概率的分類即可。

一.文本分詞

使用python的結(jié)巴中文分詞庫對(duì)文本進(jìn)行處理,由于評(píng)論主要是用戶的主觀感受,文本異常字符較多,所以這里需要對(duì)文本進(jìn)行清洗,例如特殊字符,標(biāo)點(diǎn)符號(hào),停用詞等;而對(duì)于某些領(lǐng)域,需要自己添加分詞詞典,方便提取有用的關(guān)鍵詞(這里不考慮詞頻,所以分詞的最終結(jié)果都做去重處理)。

訓(xùn)練集分詞前:

訓(xùn)練集分詞后:

二.構(gòu)建分詞向量

首先創(chuàng)建一個(gè)所有評(píng)論中不重復(fù)詞的列表,然后向量化所有的評(píng)論,函數(shù)代碼如下:

def setOfWords2Vec(vocabList,inputSet):

? ? ? returnVec=[0]*len(vocabList)

? ? ? for word in inputSet:

? ? ? ? ? if word in vocabList:

? ? ? ? ? ? ? returnVec[vocabList.index(word)]=1

? ? ? ? ? else:

? ? ? ? ? ? ? pass

? ? ? ? ? ? ? # print "the word:%s is not in myVocabulary!" % word

? ? ? return returnVec

其中 vocabList為所有訓(xùn)練集中不重復(fù)詞的列表,可以選擇集合作為它的數(shù)據(jù)類型,由于集合中每個(gè)元素都是唯一的,所以不需要考慮去重的問題。inputSet為評(píng)論分詞后的結(jié)果,這樣就將一個(gè)評(píng)論轉(zhuǎn)化為一個(gè)向量,對(duì)于測(cè)試集或測(cè)試數(shù)據(jù)中的詞如果在vocabList不存在則不予考慮。這個(gè)向量的維數(shù)就是vocabList的長(zhǎng)度,如果某個(gè)詞存在,則這個(gè)詞的位數(shù)為1,否則為0.

選中20條評(píng)論作為訓(xùn)練數(shù)據(jù),一共分出了129個(gè)詞,生成的詞向量組成的矩陣為20*129

三.訓(xùn)練??

根據(jù)上文的描述,假設(shè) P(A)表示這個(gè)評(píng)論是A分類的概率是多大,P(Bi|A)表示在A分類的前提下詞Bi出現(xiàn)的概率,則向量B在A分類下的概率為P(B|A)=P(b0,b1,b2...bn|A),假設(shè)所有的詞都互相獨(dú)立,則上面的表達(dá)式也可寫為P(b0|A)P(b1|A)P(b2|A)...P(bn|A)。根據(jù)訓(xùn)練數(shù)據(jù),可以求出P(A),P(bi|A)。

若要判斷一個(gè)向量C是屬于A1還是A2,則求出向量C是A1和A2分類的概率并比較大小,哪個(gè)類別的概率大,則將其歸為哪個(gè)類。其中:

P(A1|C)=P(C|A1)*P(A1)/P(C)

P(A2|C)=P(C|A2)*P(A2)/P(C)

要比較P(A1|C)和P(A2|C)的大小,只需要比較P(C|A1)*P(A1)和P(C|A2)*P(A2)的大小即可。

#樸素貝葉斯分類器訓(xùn)練函數(shù),trainCategory為分類數(shù)組,trainMatrix為所有的評(píng)論向量

def trainNB0(trainMatrix,trainCategory):

? ? numTrainDocs=len(trainMatrix)

? ? numWords=len(trainMatrix[0])

? ? #pAbusive表示為所有評(píng)論中出現(xiàn),是該分類的概率

? ? pAbusive=sum(trainCategory)/float(numTrainDocs)

? ? p0Num=zeros(numWords);p1Num=zeros(numWords) #p0Num和p1Num為兩個(gè)全0數(shù)組,長(zhǎng)度為numWords,

? ? # 這兩個(gè)向量用來統(tǒng)計(jì)P0分類中每個(gè)詞的個(gè)數(shù)和P1中每個(gè)詞的個(gè)數(shù)

? ? p0Denom=0.0;p1Denom=0.0#初始化

? ? #for循環(huán)掃描每一個(gè)評(píng)論生成的向量

? ? for i in range(numTrainDocs):

? ? ? ? # 如果向量判定為1,p1Num加上每個(gè)詞的個(gè)數(shù)

? ? ? ? if trainCategory[i]==1:

? ? ? ? ? ? p1Num =p1Num+trainMatrix[i]

? ? ? ? ? ? #p1Denom是詞向量中關(guān)鍵詞的個(gè)數(shù)

? ? ? ? ? ? p1Denom =p1Denom+sum(trainMatrix[i])

? ? ? ? # 如果向量判定為0,p1Num加上每個(gè)詞的個(gè)數(shù)

? ? ? ? else:

? ? ? ? ? ? p0Num =p0Num+ trainMatrix[i]

? ? ? ? ? ? p0Denom =p0Denom+ sum(trainMatrix[i])

? ? p1Vect=p1Num/p1Denom

? ? p0Vect=p0Num/p0Denom

? ? return p0Vect,p1Vect,pAbusive

p0Vect:P0分類下每個(gè)詞的概率

p1Vect:P1分類下每個(gè)詞的概率

pAbusive:P1分類的概率。

上面的算法有兩個(gè)問題:

1)P(b0|A)P(b1|A)P(b2|A)...P(bn|A),如果其中一個(gè)概率值為0,那么最后的乘積也為0,所以我們將所有詞的出現(xiàn)次數(shù)初始化為1,將出現(xiàn)的總次數(shù)初始化為2

?p0Num=ones(numWords);p1Num=ones(numWords)

?p0Denom=2.0;p1Denom=2.0

2)P(b0|A)P(b1|A)P(b2|A)...P(bn|A)大部分因子都很小,所以結(jié)果很容易四舍五入得到0,為了降低這種影響,我們對(duì)其取對(duì)數(shù)則,雖然函數(shù)并不一樣,但是對(duì)他們比較大小的結(jié)果并不影響,所以

?p1Vect=log(p1Num/p1Denom)

?p0Vect=log(p0Num/p0Denom)

四.分類

傳入一個(gè)新的向量,判斷它是那種分類,即比較P(A1|C)和P(A2|C)的大小

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):

? ? p1=sum(vec2Classify*p1Vec)+log(pClass1)

? ? p0=sum(vec2Classify*p0Vec)+log(1-pClass1)

? ? if p1>p0:

? ? ? ? return 1

? ? else:

? ? ? ? return 0


其中vec2Classify為需要判定的向量,p0Vec表示每個(gè)詞在分類0中的概率的對(duì)數(shù)向量,p1Vec表示每個(gè)詞在分類1中的對(duì)數(shù)向量,pClass1為分類為1的概率,由于是二分類問題,可知pClass0=1-pClass1

由于p0Vec和p1Vec是概率的對(duì)數(shù),所以對(duì)概率的乘積大小比較和對(duì)其對(duì)數(shù)求和的大小比較,結(jié)果是一致的。

五.測(cè)試正確率

將測(cè)試數(shù)據(jù)進(jìn)行判定,將返回的結(jié)果值和人工判定值進(jìn)行對(duì)比,如果結(jié)果一致則表示分類成功。

def testing(testVec,predictVec):

? ? vecLen=len(testVec)

? ? count=0.0

? ? for i in range(vecLen):

? ? ? ? if testVec[i]-predictVec[i]==0:

? ? ? ? ? ? count=count+1

? ? return count/vecLen

testVec表示人工判定的分類向量,predictVec表示算法判定的分類向量,即可算出正確率。

#分類效果不能令人滿意,需要繼續(xù)嘗試其他方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容