1. 程式人生 > >貝葉斯算法的基本原理和算法實現

貝葉斯算法的基本原理和算法實現

utf shape less 流程 我們 def .sh 詞向量 貝葉斯算法

一. 貝葉斯公式推導

  樸素貝葉斯分類是一種十分簡單的分類算法,叫它樸素是因為其思想基礎的簡單性:就文本分類而言,它認為詞袋中的兩兩詞之間的關系是相互獨立的,即一個對象 的特征向量中每個維度都是相互獨立的。例如,黃色是蘋果和梨共有的屬性,但蘋果 和梨是相互獨立的。這是樸素貝葉斯理論的思想基礎。現在我們將它擴展到多維的情況:

  樸素貝葉斯分類的正式定義如下:

  1.設 x={a1,a2,…,am}為一個待分類項,而每個 a 為 x 的一個特征屬性。
  2.有類別集合 C={y1,y2,…,yn}。
  3.計算 P( y1|x) ,P( y2|x),…, P( yn|x)。
  4.如果 P( yk|x) =max{P( y1|x),P( y2|x),…, P( yn|x)},則 x∈yk。
  那麽現在的關鍵就是如何計算第 3 步中的各個條件概率。我們可以這麽做:
    (1) 找到一個已知分類的待分類項集合,也就是訓練集。
    (2) 統計得到在各類別下各個特征屬性的條件概率估計。即:

         P(a1|y1) , P(a2|y1),…, P(am|y1);
        P(a1|y2) , P(a2|y2),…, P(am|y2);
        P(am|yn) , P(am|yn),…, P(am|yn)。
    (3) 如果各個特征屬性是條件獨立的(或者我們假設它們之間是相互獨立的),則根 據貝葉斯定理有如下推導:
技術分享

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

技術分享

  根據上述分析,樸素貝葉斯分類的流程可以表示如下: 第一階段:訓練數據生成訓練樣本集:TF-IDF

  第二階段:對每個類別計算 P(yi)

  第三階段:對每個特征屬性計算所有劃分的條件概率 第四階段:對每個類別計算 P( x | yi ) P( yi )

  第五階段:以 P( x | yi ) P( yi ) 的最大項作為 x 的所屬類別

  二. 樸素貝葉斯算法實現

  使用簡單的英文語料作為數據集:

  

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

  postList 是訓練集文本,classVec 是每個文本對應的分類。

  根據上節的步驟,逐步實現貝葉斯算法的全過程:

  1.編寫一個貝葉斯算法類,並創建默認的構造方法:

class NBayes(object): def __init__(self):
    self.vocabulary= [] # 詞典
    self.idf=0    #  詞典的 idf 權值向量
    self.tf=0    # 訓練集的權值矩陣
    self.tdm=0    # P(x|yi)
    self.Pcates = {}    # P(yi)--是個類別字典
    self.labels=[]    #  對應每個文本的分類,是個外部導入的列表
    self.doclength = 0    #  訓練集文本數
    self.vocablen = 0    # 詞典詞長
    self.testset = 0    # 測試集

  2.導入和訓練數據集,生成算法必須的參數和數據結構:

def train_set(self,trainset,classVec):
    self.cate_prob(classVec)    # 計算每個分類在數據集中的概率:P(yi)                     
   self.doclength = len(trainset)
tempset = set()   [tempset.add(word) for doc in trainset for word in doc ] # Th成詞典   self.vocabulary= list(tempset)   self.vocablen = len(self.vocabulary)   self.calc_wordfreq(trainset) # 計算詞頻數據集 self.build_tdm() # 按分類累計向量空間的每維值:P(x|yi)

  3.cate_prob 函數:計算在數據集中每個分類的概率:P(yi)

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))
    

  4.calc_wordfreq 函數:生成普通的詞頻向量

# Th成普通的詞頻向量
def calc_wordfreq(self,trainset):
  self.idf = np.zeros([1,self.vocablen]) # 1*詞典數
  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   #  找到文本的詞在字典中的位置+1
    for signleword in set(trainset[indx]):
      self.idf[0,self.vocabulary.index(signleword)] +=1

  5.build_tdm 函數:按分類累計計算向量空間的每維值:P(x|yi)

#按分類累計向量空間的每維值:P(x|yi)
def build_tdm(self):
  self.tdm = np.zeros([len(self.Pcates),self.vocablen]) # 類別行*詞典列 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    #  Th成 P(x|yi)


  6.map2vocab 函數:將測試集映射到當前詞典

def map2vocab(self,testdata):
  self.testset = np.zeros([1,self.vocablen]) for word in testdata:
  self.testset[0,self.vocabulary.index(word)] +=1

  7.predict 函數:預測分類結果,輸出預測的分類類別

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|yi) P(yi)     temp = np.sum(testset*tdm_vect*self.Pcates[keyclass]) # 變量 tdm,計算最大分類值     if temp > predvalue:
      predvalue = temp predclass = keyclass   return predclass

  三. 算法改進

  為普通的詞頻向量使用 TF-IDF 策略,使之有能力修正多種偏差。

  4.calc_tfidf 函數:以 tf-idf 方式Th成向量空間:

#  Th成 tf-idf
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) # 矩陣與向量的點乘 tf x idf

  四. 評估分類結果

# -*- coding: utf-8 -*-

import sys import os
from numpy import * import numpyas np
from Nbayes_lib 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)    # 輸出分類結果

  分類結果

 1

執行我們創建的樸素貝葉斯類,獲取執行結果

貝葉斯算法的基本原理和算法實現