分類算法——朴素貝葉斯算法python實現(文末附工程代碼)


前言

朴素貝葉斯是一種十分簡單的分類算法,稱其朴素是因為其思想基礎的簡單性,就文本分類而言,他認為詞袋中的兩兩詞之間的關系是相互獨立的,即一個對象的特征向量中的每個維度都是互相獨立的。這是朴素貝葉斯理論的思想基礎。

貝葉斯公式推導

朴素貝葉斯分類的正式定義:

  1. 設x={}為一個待分類項,而每個a為x的一個特征屬性
  2. 有類別集合C={}
  3. 計算P(|x),P(|x),…,P(|x)
  4. 如果P(|x)=max{ P(|x),P(|x),…,P(|x)},則x

那么關鍵就是如何計算第三步中的各個條件概率,我們可以這樣計算:

  1. 找到一個已知分類的待分類項集合,即訓練集
  2. 統計得到在各類別下各個特征屬性的條件概率估計,即:

P(),P(),…,P()

P(),P(),…,P()

P(),P(),…,P()

  1. 如果各個特征屬性是條件獨立的(或者假設他們之間是相互獨立的),根據貝葉斯定理,有如下推導:

 

因為分母對於所有類別為常數,只要將分子最大化即可,又因為各特征屬性是條件獨立的,所以有:

 

根據上述分析,朴素貝葉斯分類的流程可以表示如下:

  1. 訓練數據生成樣本集:TF-IDF
  2. 對每個類別計算P()
  3. 對每個特征屬性計算所有划分的條件概率
  4. 對每個類別計算P(x|)P()
  5. 以P(x|)P()的最大項作為x的所屬類別

朴素貝葉斯的算法實現

首先創建一個Nbayes_pre.py文件來編寫導入的數據和朴素貝葉斯類的代碼

  1. 使用簡單的英文語料作為數據集合,其中postingList是訓練集文本,classVec是每個文本對應的分類

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','my'],
                 ['stop','posting','stupid','worthless','garbage'],
                 ['mr','licks','ate','steak','how','to','stop','hime'],
                 ['quit','buying','worthless','dog','food','stupid']]
    classVec=[0,1,0,1,0,1]#1 is abusive, 0 not
   
return postingList,classVec

 

  1. 下面逐步實現貝葉斯算法,第一步即編寫一個貝葉斯算法類,並創建默認的構造方法
class NBayes(object):
    def _init_(self):
        self.vocabulary=[]#詞典
       
self.idf=0#詞典的IDF權重向量
       
self.tf=0#訓練集的權值矩陣
       
self.tdm=0#P(x│y_i)
       
self.Pcates={}#P(y_i)是一個類別字典
       
self.labels=[]#對應每個文本的分類,是一個外部導入的列表
       
self.doclength=0#訓練集文本數
       
self.vocablen=0#詞典詞長
       
self.testset=0#測試集

 

  1. 導入和訓練數據集,生成算法必須的參數和數據結構
def train_set(self,trainset,classVec):
    self.cate_prob(classVec)#計算每個分類在數據集中的概率P(y_i)
   
self.doclength=len(trainset)
    tempset=set()
    [tempset.add(word) for doc in trainset for word in doc]#生成詞典
   
self.vocabulary=list(tempset)
    self.vocablen=len(self.vocabulary)
    self.calc_wordfreq(trainset)#計算詞頻數據集
   
self.build_tdm()#按分類累計向量空間的每維值P(x|y_i)

 

  1. 計算在數據集中每個分類的概率P(y_i)
def cate_prob(self,classVec):
    self.labels=classVec
    labeltemps=set(self.labels)#獲取全部分類
    
for labeltemp in labeltemps:
        self.labels.count(labeltemp)#統計列表中的重復分類
       
self.Pcates[labeltemp]     =float(self.labels.count(labeltemp))/float(len(self.labels))

 

  1. 生成普通的詞頻向量
def calc_wordfreq(self,trainset):
    self.idf=np.zeros([1,self.vocablen])#1x詞典數
   
self.tf=np.zeros([self.doclength,self.vocablen])#訓練集文件數x詞典數
   
for indx in xrange(self.doclength):#遍歷所有文本
       
for word in trainset[indx]:#遍歷文本中的每個詞
            #找到文本的詞在字典中的位置+1
           
self.tf[indx,self.vocabulary.index(word)]+=1
        for signleword in set(trainset[indx]):
            self.idf[0,self.vocabulary.index(signleword)]+=1

 

  1. 按分類累計計算向量空間的每維值P(x|y_i)
def build_tdm(self):
    self.tdm=np.zeros([len(self.Pcates),self.vocablen])#類別行x詞典列
   
sumlist=np.zeros([len(self.Pcates),1])#統計每個分類的總值
   
for indx in xrange(self.doclength):
        #將同一類別的詞向量空間值加總
       
self.tdm[self.labels[indx]]+=self.tf[indx]
        #統計每個分類的總值——是一個標量
       
sumlist[self.labels[indx]]=np.sum(self.tdm[self.labels[indx]])
    self.tdm=self.tdm/sumlist#生成P(x|y_i)

 

  1. 將測試集映射到當前詞典
def map2vocab(self,testdata):
    self.testset=np.zeros([1,self.vocablen])
    for word in testdata:
        self.testset[0,self.vocabulary.index(word)]+=1

 

  1. 預測分類結果,輸出預測的分類類別
def predict(self,testset):
    if np.shape(testset)[1]!=self.vocablen:#如果測試集長度與詞典長度不相等,則推出程序
       
print("輸入錯誤")
        exit(0)
    predvalue=0#初始化類別概率
   
predclass=""#初始化類別名稱
   
for tdm_vect,keyclass in zip(self.tdm,self.Pcates):
        #P(x|y_i) P(y_i)
        #
變量tdm,計算最大分類值
       
temp=np.sum(testset*tdm_vect*self.Pcates[keyclass])
        if temp>predvalue:
            predvalue=temp
            predclass=keyclass
    return predclass

 

  1. 算法還可以進行一些改進,將步驟e中的函數替換掉,普通的詞頻向量改為使用TF-IDF策略,使之有能力修正多種偏差,下面函數以TF-IDF方式生成向量空間
  2. 評估分類結果,執行我們創建的朴素貝葉斯類,獲取執行結果
j.   def calc_tfidf(self,trainset):
    self.idf=np.zeros([1,self.vocablen])
    self.tf=np.zeros([self.doclength,self.vocablen])
    for indx in xrange(self.doclength):
        for word in trainset[indx]:
            self.tf[indx,self.vocabulary.index(word)]+=1
        #消除不同句廠導致的偏差
       
self.tf[indx]=self.tf[indx]/float(len(trainset[indx]))
        for signleword in set(trainset[indx]):
            self.idf[0,self.vocabulary.index(signleword)]+=1
    self.idf=np.log(float(self.doclength)/self.idf)
    self.tf=np.multiply(self.tf,self.idf)#矩陣與向量的點乘 TFxIDF
l.   import numpy as np
from numpy import *
from Nbayes_pre import *

dataSet,listClasses=loadDataSet()#導入外部數據集
#dataSet:句子的詞向量
#listClass:句子所屬的類別 【0,1,0,1,0,1】
nb=NBayes()#實例化
nb.train_set(dataSet,listClasses)#訓練數據集
nb.map2vocab(dataSet[0])#隨機選擇一個測試句
print(nb.predict(nb.testset))

 工程代碼

不知道為什么顯示不了數學公式了非常尷尬,原文鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM