貝葉斯分類器-對文本的分類

前言

翻看貝葉斯的案例,我們就會發(fā)現(xiàn)90%以上的案例都是文本分類鲸鹦,如果想以后轉(zhuǎn)做文本數(shù)據(jù)數(shù)據(jù)挖掘慧库,那么貝葉斯應該是必須點亮的技能燈〔鍪龋“真的是任重道遠啊齐板,希望三天時間能skip到下一個算法「鸸剑”

正文

我們將文本數(shù)據(jù)的標簽用c表示甘磨,c包含多個變量,c_i眯停,特征用w表示济舆,w_i,也就是下面說的詞條莺债,同時假設滋觉,特征之間是相互獨立的签夭。

另外在實際做的過程中,也會發(fā)現(xiàn)椎瘟,相比于之前做的貝葉斯分類器覆致,特征是二維變量侄旬,而在文本分類器中肺蔚,實際上特征只是一維變量,這在計算類條件概率上會簡單一些儡羔。當然宣羊,復雜的貝葉斯分類器應該也會涉及到多特征維度的情況。當特征太多的時候汰蜘,也就到了貝葉斯的極限了仇冯,除非我們依然可以保證相互獨立性,負責貝葉斯的預測誤差就會出現(xiàn)族操。#僅為個人理解苛坚,希望指正,以后有新的認識色难,我會回來修正這個理解泼舱。

下面是偽代碼:

#計算每個類別中的文檔數(shù)目  #也就是$P(C_i)$,各類標簽的文檔數(shù)目
#對每篇訓練文檔:
#    對每個類別
#        如果詞條出現(xiàn)在文檔中:增加該詞條計數(shù)值
#        增加該詞條計數(shù)值 
#    對每個類別:
#        對每個詞條:
#            將該詞條的數(shù)目除以總詞條數(shù)目得到條件概率   #求$P(w|c_i)$

核心思想:利用文本構(gòu)建詞庫向量

有關詞向量的概念解釋枷莉,參考:https://blog.csdn.net/michael_liuyu09/article/details/78029062

其實這里的只是簡單的向量化娇昙,方便我們統(tǒng)計詞頻,但是深入到NLP的研究中笤妙,詞庫向量就會被利用計算相關性冒掌,這在NLP中應該比較重要,現(xiàn)在沒有涉及蹲盘,以后希望有機會

import numpy as np
#數(shù)據(jù)導入模塊
def loadDataSet():
    postingList=[['my','dog','has','flea','problems','help','please'],
                 ['maybe','not','take','him','to','dog','park','stupid'],
                 ['my','dalmation','id','so','cute','I','love','him'],
                 ['stop','posting','stupid','worthless','garbage'],
                 ['mr','licks','ate','my','steak','how','to','stop','him'],
                 ['quit','buying','worthless','dog','food','stupid']]
    classVec=[0,1,0,1,0,1]
    return(postingList, classVec)
#詞庫構(gòu)建模塊股毫,詞庫中的詞保證是唯一的
def createVocabList(dataSet):  #dataSet是指loadDataSet的反饋文本
    vocabSet = set([])  #python中的set是一個無序,去重的集合
    for document in dataSet:
        vocabSet = vocabSet | set(document)  #set(document)對每一個句子進行去重唯一召衔,然后與vocabSet進行合并铃诬,擴充vocabSet
    return(list(vocabSet))
#構(gòu)建詞庫向量
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)  #構(gòu)建0向量,[0,1]分布
    for word in inputSet: #對樣本數(shù)據(jù)的進行遍歷薄嫡,出現(xiàn)詞匯表單詞的氧急,則在對應值輸出1
        if word in vocabList:
            returnVec[vocabList.index(word)]=1
        else: print("the word: %s is  not in my Vocabulary" %word)
    return(returnVec)    
#統(tǒng)計頻數(shù),計算后驗概率
def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix) #計算我們的文本容量毫深,文件數(shù)
    numwords = len(trainMatrix[0]) #計算樣本庫詞匯數(shù)
    pAbusive = sum(trainCategory)/float(numTrainDocs) #計算$P_c_i$
    p0Num=np.zeros(numwords)
    p1Num=np.zeros(numwords)
    p0Denom = 0.0; p1Denom = 0.0
    for i in range(numTrainDocs): #遍歷每一篇文本
        if trainCategory[i]==1: #條件概率分類1的情況
            p1Num += trainMatrix[i] #累計每個詞匯出現(xiàn)的次數(shù)
            p1Denom += sum(trainMatrix[i]) #累計分類1中的所有詞匯的出現(xiàn)次數(shù)
        else:  #條件概率分類0的情況
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect=p1Num/p1Denom   #計算每個詞匯在分類1中出現(xiàn)的概率 P(w_i|c_1)
    p0Vect=p0Num/p0Denom   #計算每個詞匯在分類1中出現(xiàn)的概率 P(w_i|c_0)
    return(p0Vect, p1Vect, pAbusive)     
#main函數(shù)
if __name__ == "__main__":
    listOPosts, listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:  #對文本內(nèi)容逐行遍歷秧倾,進行向量化
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB0(trainMat,listClasses) #
    print(p0V, p1V, pAb)
output1

其實現(xiàn)在,我們正常情況下就可以計算了

套用我們的公式宿礁,P(c_i|w) = \frac{P(w|c_i)P(c_i)}{P(w)}

如果單純考慮后驗概率最大化,我們只需要計算分子部分弧呐,上面的P(w|c_i)我們可以通過p0V,p1V連乘得到嵌纲。然后分開比較大小就可以幫助我們做出判斷俘枫。

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): #vec2Classify是我們將目標文本向量化的產(chǎn)物
    p1 = sum(vec2Classify * p1Vec) * pClass1
    p0 = sum(vec2Classify * p0Vec) * (1 - pClass1)
    if (p1 > p0):
        return(1)
    if (p1 < p0):
        return(0)
testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as', classifyNB(thisDoc, p0V, p1V, pAb))
testEntry = ['stupid']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as', classifyNB(thisDoc, p0V, p1V, pAb))
output2

但是現(xiàn)實情況并非如此完美,如果我們已有的樣本中某分類下并沒有該特征詞逮走,會導致p(w_i|c_i)=0鸠蚪,這會進而導致我們在計算似然函數(shù)時結(jié)果為0的情況,因此為了避免這個問題师溅,我們引入“拉普拉斯修正”茅信。在條件概率式子中分子分母分別加入一個正數(shù),\lambda>0墓臭。當\lambda=0的時候蘸鲸,就是我們平時說的極大似然函數(shù),當\lambda=1的時候窿锉,我們稱為拉普拉斯平滑酌摇。

公式為:p(w|c_i) = \frac{\sum_{i=1}^N(I(x_j|c_i))+\lambda}{\sum_{i=1}^N(I(c_i))+S_j\lambda}p(ci)=\frac{\sum_{i=1}^NI(c_i)+\lambda}{N+K\lambda} 嗡载,其中窑多,S_j為每一種X的種類數(shù),K為屬性個數(shù)

在這里我們用拉普拉斯平滑鼻疮,令\lambda=1怯伊,因為我們樣本標簽分為2類,一類是好的語言判沟,一類是有侮辱性的語言耿芹,那么,在我們令K=2挪哄,同時我們的樣本每個單詞同屬一類特征吧秕,那么,S=1

在代碼里迹炼,我們初始化p0Num=1, p1Num=1, p0Denom=2.0, p1Denom=2.0

在這里我們會遇到一個新的問題砸彬,那就是數(shù)據(jù)溢出,在計算中斯入,當數(shù)字非常小的時候砂碉,而我們還在做連乘的時候,會出現(xiàn)數(shù)字下溢出的問題刻两,為了避免這個問題實際中增蹭,我們用轉(zhuǎn)換函數(shù),換種方式計算磅摹,避免數(shù)字過小的問題滋迈。我們引入ln(a*b)=ln(a)+ln(b)

我們先比較f(x)ln(f(x))的區(qū)別

import matplotlib.pyplot as plt
x=np.linspace(0.01,0.9*np.pi,30)
f=np.sin(x)  #我們假設原函數(shù)f(x)為sin函數(shù)
g=np.log(f)  #我們假設實際函數(shù)為log(f(x))
plt.plot(x,f)
plt.plot(x,g)
plt.legend(['f(x)','log(f(x))'])
plt.show()
output3

在上圖中霎奢,我們發(fā)現(xiàn)雖然兩個函數(shù)不完全相同,但是饼灿,兩個函數(shù)的極值點很接近幕侠,這對于我們貝葉斯在使用極大似然定理里,影響不大碍彭,因此晤硕,我們引入ln函數(shù)替換連乘問題。

接下來硕旗,我們對前面的部分函數(shù)進行優(yōu)化

#統(tǒng)計頻數(shù)窗骑,計算后驗概率
def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix) #計算我們的文本容量,文件數(shù)
    numwords = len(trainMatrix[0]) #計算樣本庫詞匯數(shù)
    pAbusive = sum(trainCategory)/float(numTrainDocs) #計算$P_c_i$
    p0Num=np.ones(numwords)
    p1Num=np.ones(numwords)
    p0Denom = 2.0; p1Denom = 2.0
    for i in range(numTrainDocs): #遍歷每一篇文本
        if trainCategory[i]==1: #條件概率分類1的情況
            p1Num += trainMatrix[i] #累計每個詞匯出現(xiàn)的次數(shù)
            p1Denom += sum(trainMatrix[i]) #累計分類1中的所有詞匯的出現(xiàn)次數(shù)
        else:  #條件概率分類0的情況
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect=np.log(p1Num/p1Denom)   #計算每個詞匯在分類1中出現(xiàn)的概率 P(w_i|c_1)
    p0Vect=np.log(p0Num/p0Denom)   #計算每個詞匯在分類1中出現(xiàn)的概率 P(w_i|c_0)
    return(p0Vect, p1Vect, pAbusive)
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): #vec2Classify是我們將目標文本向量化的產(chǎn)物
    p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + np.log(1 - pClass1)
    if (p1 > p0):
        return(1)
    if (p1 < p0):
        return(0)
if __name__ == "__main__":
    listOPosts, listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:  #對文本內(nèi)容逐行遍歷漆枚,進行向量化
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB0(trainMat,listClasses) #
    print(p0V, p1V, pAb)
output4

在這里,我們可以發(fā)現(xiàn)抵知,文本向量矩陣的值已經(jīng)變了墙基,但是不影響我們的結(jié)果。

testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as', classifyNB(thisDoc, p0V, p1V, pAb))
testEntry = ['stupid','dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as', classifyNB(thisDoc, p0V, p1V, pAb))
output5

到這里刷喜,貝葉斯方法的實踐應該是比較深入了残制,算法的使用也好,還是具體一些細節(jié)問題的思考也好掖疮,接下來就是抽時間看下郵件分類有沒有時間做

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末初茶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子浊闪,更是在濱河造成了極大的恐慌恼布,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搁宾,死亡現(xiàn)場離奇詭異折汞,居然都是意外死亡,警方通過查閱死者的電腦和手機盖腿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門爽待,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人翩腐,你說我怎么就攤上這事鸟款。” “怎么了茂卦?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵何什,是天一觀的道長。 經(jīng)常有香客問我疙筹,道長富俄,這世上最難降的妖魔是什么禁炒? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮霍比,結(jié)果婚禮上幕袱,老公的妹妹穿的比我還像新娘。我一直安慰自己悠瞬,他們只是感情好们豌,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浅妆,像睡著了一般望迎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凌外,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天辩尊,我揣著相機與錄音,去河邊找鬼康辑。 笑死摄欲,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的疮薇。 我是一名探鬼主播胸墙,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼按咒!你這毒婦竟也來了迟隅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤励七,失蹤者是張志新(化名)和其女友劉穎智袭,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呀伙,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡补履,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了剿另。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫锤。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖雨女,靈堂內(nèi)的尸體忽然破棺而出谚攒,到底是詐尸還是另有隱情,我是刑警寧澤氛堕,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布馏臭,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏括儒。R本人自食惡果不足惜绕沈,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帮寻。 院中可真熱鬧乍狐,春花似錦、人聲如沸固逗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烫罩。三九已至惜傲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贝攒,已是汗流浹背盗誊。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饿这,地道東北人浊伙。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像长捧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吻贿,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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