1. 程式人生 > >【python】機器學習實戰之樸素貝葉斯分類

【python】機器學習實戰之樸素貝葉斯分類

一,引言

  前兩章的KNN分類演算法和決策樹分類演算法最終都是預測出例項的確定的分類結果,但是,有時候分類器會產生錯誤結果;本章要學的樸素貝葉斯分類演算法則是給出一個最優的猜測結果,同時給出猜測的概率估計值。

1 準備知識:條件概率公式

相信學過概率論的同學對於概率論絕對不會陌生,如果一時覺得生疏,可以查閱相關資料,在這裡主要是想貼出條件概率的計算公式:

  P(A|B)=P(A,B)/P(B)=P(B|A)*P(A)/P(B)

2 如何使用條件概率進行分類

  假設這裡要被分類的類別有兩類,類c1和類c2,那麼我們需要計算概率p(c1|x,y)和p(c2|x,y)的大小並進行比較:

如果:p(c1|x,y)>p(c2|x,y),則(x,y)屬於類c1

         p(c1|x,y)<p(c2|x,y),則(x,y)屬於類c2

  我們知道p(x,y|c)的條件概率所表示的含義為:已知類別c1條件下,取到點(x,y)的概率;那麼p(c1|x,y)所要表達的含義呢?顯然,我們同樣可以按照條件概率的方法來對概率含義進行描述,即在給定點(x,y)的條件下,求該點屬於類c1的概率值。那麼這樣的概率該如何計算呢?顯然,我們可以利用貝葉斯準則來進行變換計算:
  p(ci|x,y)=p(x,y|ci)*p(ci)/p(x,y)

利用上面的公式,我們可以計算出在給定例項點的情況下,分類計算其屬於各個類別的概率,然後比較概率值,選擇具有最大概率的那麼類作為點(x,y)的預測分類結果。

  以上我們知道了通過貝葉斯準則來計算屬於各個分類的概率值,那麼具體而言,就是計算貝葉斯公式中的三個概率,只要得到了這三個概率值,顯然我們就能通過貝葉斯演算法預測分類的結果了。因此,到了這裡,我們就知道了朴樹貝葉斯演算法的核心所在了。

3 樸素貝葉斯中樸素含義

   "樸素"含義:本章演算法全稱叫樸素貝葉斯演算法,顯然除了貝葉斯準備,樸素一詞同樣重要。這就是我們要說的條件獨立性假設的概念。條件獨立性假設是指特徵之間的相互獨立性假設,所謂獨立,是指的是統計意義上的獨立,即一個特徵或者單詞出現的可能性與它和其他單詞相鄰沒有關係。舉個例子來說,假設單詞bacon出現在unhealthy後面是與delisious後面的概率相同。當然,我們知道其實並不正確,但這正是樸素一詞的含義。同時,樸素貝葉斯另外一個含義是,這些特徵同等重要。雖然這些假設都有一定的問題,但是樸素貝葉斯的實際效果卻很好。

二,樸素貝葉斯完成文件分類

      樸素貝葉斯的一個非常重要的應用就是文件分類。在文件分類中,整個文件(比如一封電子郵件)是例項,那麼郵件中的單詞就可以定義為特徵。說到這裡,我們有兩種定義文件特徵的方法。一種是詞集模型,另外一種是詞袋模型。顧名思義,詞集模型就是對於一篇文件中出現的每個詞,我們不考慮其出現的次數,而只考慮其在文件中是否出現,並將此作為特徵;假設我們已經得到了所有文件中出現的詞彙列表,那麼根據每個詞是否出現,就可以將文件轉為一個與詞彙列表等長的向量。而詞袋模型,就是在詞集模型的基礎上,還要考慮單詞在文件中出現的次數,從而考慮文件中某些單詞出現多次所包含的資訊。

#---------------------------從文字中構建詞條向量-------------------------
#1 要從文字中獲取特徵,需要先拆分文字,這裡特徵是指來自文字的詞條,每個詞
#條是字元的任意組合。詞條可以理解為單詞,當然也可以是非單詞詞條,比如URL
#IP地址或者其他任意字串 
#  將文字拆分成詞條向量後,將每一個文字片段表示為一個詞條向量,值為1表示出現
#在文件中,值為0表示詞條未出現


#匯入numpy
from numpy import *

def loadDataSet():
#詞條切分後的文件集合,列表每一行代表一個文件
    postingList=[['my','dog','has','flea',\
                  'problems','help','please'],
                 ['maybe','not','take','him',\
                  'to','dog','park','stupid'],
                 ['my','dalmation','is','so','cute',
                  'I','love','him'],
                 ['stop','posting','stupid','worthless','garbage'],
                 ['my','licks','ate','my','steak','how',\
                  'to','stop','him'],
                 ['quit','buying','worthless','dog','food','stupid']]
    #由人工標註的每篇文件的類標籤
    classVec=[0,1,0,1,0,1]
    return postingList,classVec

#統計所有文件中出現的詞條列表    
def createVocabList(dataSet):
    #新建一個存放詞條的集合
    vocabSet=set([])
    #print('vocabSet=',vocabSet)
    #遍歷文件集合中的每一篇文件
    for document in dataSet:
        #將文件列表轉為集合的形式,保證每個詞條的唯一性
        #然後與vocabSet取並集,向vocabSet中新增沒有出現
        #的新的詞條  
        
        vocabSet=vocabSet|set(document)
        #print('vocabSet1=',vocabSet)
    #再將集合轉化為列表,便於接下來的處理
    return list(vocabSet)

#根據詞條列表中的詞條是否在文件中出現(出現1,未出現0),將文件轉化為詞條向量    
def setOfWords2Vec(vocabSet,inputSet):
    #新建一個長度為vocabSet的列表,並且各維度元素初始化為0
    returnVec=[0]*len(vocabSet)
    #print('inputSet=',inputSet)
    #print('vocabSet=',vocabSet)
    #遍歷文件中的每一個詞條
    for word in inputSet:
        #如果詞條在詞條列表中出現
        if word in vocabSet:
            #通過列表獲取當前word的索引(下標)
            #將詞條向量中的對應下標的項由0改為1
            returnVec[vocabSet.index(word)]=1
        else: print('the word: %s is not in my vocabulary! '%'word')
    #返回inputet轉化後的詞條向量
    return returnVec
#訓練演算法,從詞向量計算概率p(w0|ci)...及p(ci)
#@trainMatrix:由每篇文件的詞條向量組成的文件矩陣
#@trainCategory:每篇文件的類標籤組成的向量
def trainNB0(trainMatrix,trainCategory):
    print('trainCategory=',trainCategory)
    #獲取文件矩陣中文件的數目
    numTrainDocs=len(trainMatrix)
    #獲取詞條向量的長度
    numWords=len(trainMatrix[0])
    #所有文件中屬於類1所佔的比例p(c=1)
    pAbusive=sum(trainCategory)/float(numTrainDocs)
    print('sum(trainCategory)=',sum(trainCategory))
    print(' pAbusive=', pAbusive)
    #建立一個長度為詞條向量等長的列表
    p0Num=zeros(numWords);p1Num=zeros(numWords)
    print('p0Num',p0Num)
    p0Denom=0.0;p1Denom=0.0
    #遍歷每一篇文件的詞條向量
    for i in range(numTrainDocs):
        print('i=',i)
        #如果該詞條向量對應的標籤為1
        if trainCategory[i]==1:
            #統計所有類別為1的詞條向量中各個詞條出現的次數
            p1Num+=trainMatrix[i]
            print('p1Num=',p1Num)
            #統計類別為1的詞條向量中出現的所有詞條的總數
            #即統計類1所有文件中出現單詞的數目
            p1Denom+=sum(trainMatrix[i])
            print('p1Denom=',p1Denom)
        else:
            #統計所有類別為0的詞條向量中各個詞條出現的次數
            p0Num+=trainMatrix[i]
            #統計類別為0的詞條向量中出現的所有詞條的總數
            #即統計類0所有文件中出現單詞的數目
            p0Denom+=sum(trainMatrix[i])
    print('p0Num',p0Num)
    print('p1Denom',p1Denom)
    #利用NumPy陣列計算p(wi|c1)
    p1Vect=p1Num/p1Denom  #為避免下溢位問題,後面會改為log()
    print('p1Vect=',p1Vect)
    #利用NumPy陣列計算p(wi|c0)
    p0Vect=p0Num/p0Denom  #為避免下溢位問題,後面會改為log()
    print('p0Vect=',p0Vect)

    return p0Vect,p1Vect,pAbusive
#樸素貝葉斯分類函式
#vec2Classify:待測試分類的詞條向量
#p0Vec:類別0所有文件中各個詞條出現的頻數p(wi|c0)
#p0Vec:類別1所有文件中各個詞條出現的頻數p(wi|c1)
#pClass1:類別為1的文件佔文件總數比例
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    #根據樸素貝葉斯分類函式分別計算待分類文件屬於類1和類0的概率
    p1=sum(vec2Classify*p1Vec)+log(pClass1)   #通過sum將向量轉化為數值以便進行比較。但是沒有使用log(sum)原因是可能sum=0,無意義
    
    print('p1Vec=',p1Vec)
    print('vec2Classify=',vec2Classify)
    print('vec2Classify*p1Vec=',vec2Classify*p1Vec)
    print('sum=',sum(vec2Classify*p1Vec))
    print('pclass=',pClass1)
    print('p1=',p1)
    p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1)
    if p1>p0:
        return 1
    else:
        return 0

#分類測試整體函式        
def testingNB():
    #由資料集獲取文件矩陣和類標籤向量
    listOPosts,listClasses=loadDataSet()
    #統計所有文件中出現的詞條,存入詞條列表
    myVocabList=createVocabList(listOPosts)
    #建立新的列表
    trainMat=[]
    for postinDoc in listOPosts:
        #將每篇文件利用words2Vec函式轉為詞條向量,存入文件矩陣中
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
    #將文件矩陣和類標籤向量轉為NumPy的陣列形式,方便接下來的概率計算
    #呼叫訓練函式,得到相應概率值
    p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))
    
    #測試文件
    testEntry=['love','my','dalmation']
    #將測試文件轉為詞條向量,並轉為NumPy陣列的形式
    thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
    #利用貝葉斯分類函式對測試文件進行分類並列印
    print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))
    #第二個測試文件
    testEntry1=['stupid','garbage']
    #同樣轉為詞條向量,並轉為NumPy陣列的形式
    thisDoc1=array(setOfWords2Vec(myVocabList,testEntry1))
    print(testEntry1,'classified as:',classifyNB(thisDoc1,p0V,p1V,pAb))

例項:樸素貝葉斯的另一個應用--過濾垃圾郵件

 切分資料

  對於一個文字字串,可以使用python的split()方法對文字進行切割,比如字串'hello, Mr.lee.',分割結果為['hell0,','Mr.lee.'] 這樣,標點符合也會被當成詞的一部分,因為此種切割方法是基於詞與詞之間的空格作為分隔符的

  此時,我們可以使用正則表示式來切分句子,其中分割符是除單詞和數字之外的其他任意字串,即

  import re

  re.compile('\\W*')

這樣就得到了一系列片語成的詞表,但是裡面的空字串還是需要去掉,此時我們可以通過字元的長度,去掉長度等於0的字元。並且,由於我們是統計某一詞是否出現,不考慮其大小寫,所有還可以將所有詞轉為小寫字元,即lower(),相應的,轉為大寫字元為upper()

  此外,需要注意的是,由於是URL,因而可能會出現en和py這樣的單詞。當對URL進行切分時,會得到很多的詞,因此在實現時也會過濾掉長度小於3的詞。當然,也可以根據自己的實際需要來增加相應的文字解析函式。

程式碼如下:

#貝葉斯演算法例項:過濾垃圾郵件
#處理資料長字串
#1 對長字串進行分割,分隔符為除單詞和數字之外的任意符號串
#2 將分割後的字串中所有的大些字母變成小寫lower(),並且只
#保留單詞長度大於3的單詞
def testParse(bigString):
    import re
    listOfTokens=re.split(r'\W*',bigString)#\w 和 \W 表示以單詞字元[a-zA-Z0-9]和非單詞字元切分 *切分0到無窮次
    return [tok.lower()for tok in listOfTokens if len(tok)>2]

def spamTest():
    #新建三個列表
    docList=[];classList=[];fullTest=[]
    #i 由1到26
    for i in range(1,26):
        #開啟並讀取指定目錄下的本文中的長字串,並進行處理返回
        wordList=testParse(open('C:\\Users\\Desktop\\機器學習實戰原始碼\\machinelearninginaction\\Ch04\\email\\spam\\%d.txt' %i).read())
        #將得到的字串列表新增到docList
        docList.append(wordList)
        #將字串列表中的元素新增到fullTest
        fullTest.extend(wordList)
        #類列表新增標籤1
        classList.append(1)
        #開啟並取得另外一個類別為0的檔案,然後進行處理,開啟檔案有兩種方式第一種是路徑前加'r'表示轉義功能。第二種是直接使用轉義字元\\表示\
        wordList=testParse(open(r'C:\Users\\Desktop\機器學習實戰原始碼\machinelearninginaction\Ch04\email\ham\%d.txt'%i).read())
        docList.append(wordList)
        fullTest.extend(wordList)
        classList.append(0)
    #將所有郵件中出現的字串構建成字串列表
    vocabList=createVocabList(docList)
    #構建一個大小為50的整數列表和一個空列表
    trainingSet=list(range(50));testSet=[]   #range(50)返回的是range物件不是陣列物件得轉化成陣列
    for i in range(10):
        #隨機選取1~50中的10個數,作為索引,構建測試集
        #隨機選取1~50中的一個整型數
        randIndex=int(random.uniform(0,len(trainingSet)))
        #將選出的數的列表索引值新增到testSet列表中
        testSet.append(trainingSet[randIndex])
        #從整數列表中刪除選出的數,防止下次再次選出
        #同時將剩下的作為訓練集
        del(trainingSet[randIndex])
    print('trainingSet=',trainingSet)
    #新建兩個列表
    trainMat=[];trainClasses=[]
   
    #遍歷訓練集中的嗎每個字串列表
    for docIndex in trainingSet:
        #將字串列表轉為詞條向量,然後新增到訓練矩陣中
        trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
        
        #將該郵件的類標籤存入訓練類標籤列表中
        trainClasses.append(classList[docIndex])
    #計算貝葉斯函式需要的概率值並返回
    p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))
    errorCount=0
    #遍歷測試集中的字串列表
    for docIndex in testSet:
        #同樣將測試集中的字串列表轉為詞條向量
        wordVector=setOfWords2Vec(vocabList,docList[docIndex])
        #對測試集中字串向量進行預測分類,分類結果不等於實際結果
        if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
            errorCount+=1
    print('the error rate is:',float(errorCount)/len(testSet))

程式碼中,採用隨機選擇的方法從資料集中選擇訓練集,剩餘的作為測試集。這種方法的好處是,可以進行多次隨機選擇,得到不同的訓練集和測試集,從而得到多次不同的錯誤率,我們可以通過多次的迭代,求取平均錯誤率,這樣就能得到更準確的錯誤率。這種方法稱為留存交叉驗證。

總結:

優點:
1.生成式模型,通過計算概率來進行分類,可以用來處理多分類問題,
2.對小規模的資料表現很好,適合多分類任務,適合增量式訓練,演算法也比較簡單。
缺點:
1.對輸入資料的表達形式很敏感,
2.由於樸素貝葉斯的“樸素”特點,所以會帶來一些準確率上的損失。
3.需要計算先驗概率,分類決策存在錯誤率。

相關推薦

python機器學習實戰樸素分類

一,引言   前兩章的KNN分類演算法和決策樹分類演算法最終都是預測出例項的確定的分類結果,但是,有時候分類器會產生錯誤結果;本章要學的樸素貝葉斯分類演算法則是給出一個最優的猜測結果,同時給出猜測的概率估計值。 1 準備知識:條件概率公式 相信學過概率論的同學對於概

機器學習實戰樸素

問題1 來源:使用樸素貝葉斯過濾垃圾郵件 描述:spamTest()和textParse()讀檔案時編譯通不過 報錯:UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199: illegal

機器學習實戰樸素_程式碼註釋

#-*- coding: UTF-8 -*- from numpy import * def loadDataSet():#建立包含文件的訓練集和各文件對應的標籤列表 postinglist = [['my','dog','has','flea','problems',

機器學習實戰樸素--學習筆記

一、工作原理 我們用 p1(x,y) 表示資料點 (x,y) 屬於類別 1的概率,用 p2(x,y) 表示資料點 (x,y) 屬於類別 2的概率; 那麼對於一個新資料點 (x,y),可以用下面的規則來判斷它的類別: 如果 p1(x,y)

機器學習演算法樸素(Naive Bayes)--第二篇

引言 這篇文章主要介紹將樸素貝葉斯模型應用到文字分類任務的技巧和方法。 詞袋模型(The Bag of Words Model) 對於機器學習演算法來說,特徵的選擇是一個很重要的過程。那麼如何從文字訓練集中選出好的特徵呢?在自然語言處理中,一個常見

機器學習演算法樸素(Naive Bayes)--第一篇

引言 先前曾經看了一篇文章,一個老外程式設計師寫了一些很牛的Shell指令碼,包括晚下班自動給老婆發簡訊啊,自動衝Coffee啊,自動掃描一個DBA發來的郵件啊, 等等。於是我也想用自己所學來做一點有趣的事情。我的想法如下: 首先我寫個scrapy指令碼來

機器學習入門樸素

樸素貝葉斯法 樸素貝葉斯法是基於貝葉斯定理和特徵條件獨立假設分類方法。對於給定訓練集,首先基於特徵條件獨立性的假設,學習輸入/輸出聯合概率(計算出先驗概率和條件概率,然後求出聯合概率)。然後基於此模型,給定輸入x,利用貝葉斯概率定理求出最大的後驗概率作為輸出y

python機器學習庫sklearn——樸素分類

在scikit-learn中,一共有3個樸素貝葉斯的分類演算法類。分別是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先驗為高斯分佈的樸素貝葉斯,MultinomialNB就是先驗為多項式分佈的樸素

機器學習系列樸素演算法(監督學習-分類問題)

''' @description :一級分類:監督學習,二級分類:分類(離散問題),三級分類:貝葉斯演算法 演算法優點: a 樸素貝葉斯模型發源於古典數學理論,有穩定的分類效率 b 對缺失的資料不太敏感,演算法也比較簡

機器學習演算法樸素

樸素貝葉斯法是基於貝葉斯定理與特徵條件獨立假設的分類方法。演算法的核心思想就是比較概率的大小,認定概率大的類別為所屬類別下面是公式推導下面是樸素貝葉斯的python程式碼實現import numpy as np from functools import reduce de

機器學習:半樸素分類

請點選上面公眾號,免費訂閱。 主要推送關於對演算法的思考以及應用的訊息。培養思維能力,注重過程,挖掘背後的原理,刨根問底。本著嚴謹和準確的態度,目標是撰寫實用和啟發性的文章,歡迎您的關注。 0

Python機器學習實戰筆記樸素分類

1聯合概率分佈 p(x,y)=p(y)P(x|y)  或者p(A交B)=p(A)xp(B)  p(A交B)不容易求,假設條件獨立拆分成兩個事件的乘積 2基本假設條件獨立性 3利用貝葉斯定理 p(y|x)=P(x,y)/p(x)=p(y)P(x|y)/sum(y-i)[p(

機器學習實戰學習筆記樸素(Naive Bayes)

原理 假如郵箱中有n個單詞, 如果returnVec[i]=0代表這個單詞在這封郵件中不出現, returnVec[i]=1代表這個單詞在郵件中出現了。 設訓練集中每個郵件都有標記為是垃圾郵件和不是垃圾郵件,是垃圾郵件的分類為1,不是垃圾郵件的分類為0。 演算法原理:

機器學習實戰(Machine Learning in Action)學習筆記————04.樸素分類(bayes)

機器學習實戰(Machine Learning in Action)學習筆記————04.樸素貝葉斯分類(bayes)關鍵字:樸素貝葉斯、python、原始碼解析作者:米倉山下時間:2018-10-25機器學習實戰(Machine Learning in Action,@author: Peter Harri

機器學習樸素分類方法

本文轉載自http://holynull.leanote.com/post/Logistic-2 樸素貝葉斯分類方法 前言 樸素貝葉斯分類演算法是機器學習領域最基本的幾種演算法之一。但是對於作者這樣沒有什麼資料基礎的老碼農來說,理解起來確實有一些困難。所以撰寫此文幫

李航統計學習方法樸素法(含python及tensorflow實現)

樸素貝葉斯法 樸素貝葉斯法數學表示式 後驗概率最大化的含義        樸素貝葉斯是一個生成模型。有一個強假設:條件獨立性。我們先看下樸素貝葉斯法的思想,然後看下條件獨立性具體數學表示式是什麼樣的。

機器學習樸素分類器附C++程式碼

一、基本概念: 先驗概率(prior probability):是指根據以往經驗和分析得到的概率,如全概率公式,它往往作為"由因求果"問題中的"因"出現的概率。比如,拋一枚硬幣,正面朝上的概率P(A)=1/2,就是先驗概率。聯合概率:表示兩個事件共同發生的概率。A與B的

機器學習實戰學習筆記:樸素分類演算法

貝葉斯決策理論 選擇高概率對應的類別是貝葉斯決策理論的核心思想,即選擇具有最高概率的決策。 樸素貝葉斯 樸素貝葉斯法是基於貝葉斯定理與特徵條件獨立假設的分類方法  。最為廣泛的兩種分類模型是決策樹模型(Decision Tree Model)和樸素貝葉斯模型(Nai

機器學習樸素分類器實現

問題如下 比如:有如下的需求,要判斷某一句英語是不是侮辱性語句 分析思路 對於機器來說,可能不容易分辨出某一句話是不是侮辱性的句子,但是機器可以機械的進行分析,何為機械的進行分析,就是判斷某一個句子中侮辱性的單詞是不是達到一定數量(當然這

Python機器學習筆記:樸素演算法

  樸素貝葉斯是經典的機器學習演算法之一,也是為數不多的基於概率論的分類演算法。對於大多數的分類演算法,在所有的機器學習分類演算法中,樸素貝葉斯和其他絕大多數的分類演算法都不同。比如決策樹,KNN,邏輯迴歸,支援向量機等,他們都是判別方法,也就是直接學習出特徵輸出Y和特徵X之間的關係,要麼是決策函式,要麼是條