樸素貝葉斯分類原理及Python實現簡單文字分類
阿新 • • 發佈:2019-01-03
貝葉斯定理:
這個定理解決了現實生活裡經常遇到的問題:已知某條件概率,如何得到兩個事件交換後的概率,也就是在已知P(A|B)的情況下如何求得P(B|A)。這裡先解釋什麼是條件概率:表示事件B已經發生的前提下,事件A發生的概率,叫做事件B發生下事件A的條件概率。其基本求解公式為:
貝葉斯定理之所以有用,是因為我們在生活中經常遇到這種情況:我們可以很容易直接得出P(A|B),P(B|A)則很難直接得出,但我們更關心P(B|A),貝葉斯定理就為我們打通從P(A|B)獲得P(B|A)的道路。
下面不加證明地直接給出貝葉斯定理:
其實分類在我們的日常生活當中每時每刻都在用,當我們看見一個蘋果,我們會判斷它為一個蘋果而不是一個梨異或是一頭大象的依據是它的外觀,顏色,重量等等這些特徵。首先我們知道了它是一個待分類的物體A,然後判斷它屬於哪一類,蘋果B1?梨B2?大象B3?獅子B4?姑且就判斷它屬於這四類中的哪一類。其中這四類都有的特徵是[‘顏色’, ‘體重’],事先我們已經有了很多的已經訓練好的樣本,也就是P(B)已知。然後通過求P(A|B)P(B)的最大化來求待分類物體屬於哪一類。可能表達得不太清楚,但實際就是這麼個意思。具體流程參看下面分類流程以及文末的參考部落格。
以下以Python語言實現簡單文字的樸素貝葉斯分類:
Nbayes.py
# -*- coding: utf-8 -*-
from numpy import *
import numpy as np
from Nbayes_lib import *
dataSet,listClasses = loadDataSet() #匯入外部資料集
nb = NBayes() #類的例項化
nb.train_set(dataSet,listClasses) #訓練資料集
nb.map2vocab(dataSet[2 ]) #隨機選擇一個測試句,這裡2表示文字中的第三句話,不是髒話,應輸出0。
print (nb.predict(nb.testset)) #輸出分類結果
Nbayes_lib.py:
# -*- coding: utf-8 -*-
import numpy as np
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 表示髒話, 0 則不是
return postingList,classVec
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 # 測試集
# 載入訓練集並生成詞典,以及tf, idf值
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 ] # 生成詞典
self.vocabulary = list(tempset)
self.vocablen = len(self.vocabulary)
self.calc_wordfreq(trainset)
#self.calc_tfidf(trainset) # 生成tf-idf權值
self.build_tdm() # 按分類累計向量空間的每維值:P(x|yi)
'''
# 生成 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 range(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) # 矩陣與向量的點乘
'''
# 生成普通的詞頻向量
def calc_wordfreq(self,trainset):
self.idf = np.zeros([1,self.vocablen]) # 1*詞典數
self.tf = np.zeros([self.doclength,self.vocablen]) # 訓練集檔案數*詞典數
for indx in range(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
# 計算每個分類在資料集中的概率: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))
#按分類累計向量空間的每維值: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 range(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|yi)
# 測試集對映到當前詞典
def map2vocab(self,testdata):
self.testset = np.zeros([1,self.vocablen])
for word in testdata:
self.testset[0,self.vocabulary.index(word)] +=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|yi)P(yi)
temp = np.sum(testset*tdm_vect*self.Pcates[keyclass])
if temp > predvalue:
predvalue = temp
predclass = keyclass
return predclass
最後輸出結果為0。
程式碼來自鄭潔著的機器學習演算法原理與程式設計實踐這本書。此書用的Python2.7,我用的是Python3.6 。修改了原著中的少部分程式碼。
樸素貝葉斯分類原理基礎參考這篇部落格