朴素贝叶斯分类器

时间:2022-06-05 10:04:37

    分类器是根据某一事物一系列特征来判断该事物的类别朴素贝叶斯分类器就是根据先验概率应用贝叶斯公式来求解 后验概率的一种分类器,哪种类别的概率大,就划分为哪种类别。(先验概率和后验概率不熟悉的请看最大似然估计),其实原理很简单,并不需要什么复杂的训练结构,复杂只是计算量,这个交给计算机即可,所以懂了原理,朴素贝叶斯分类器也就掌握了。先不写理论,以例子开始,希望能说的浅显易懂。

一、西瓜的好坏

    这里是要借鉴周志华老师书中西瓜的例子的形式,这用这类例子讲解贝叶斯分类问题容易理解。现作简化如下:

    现已知7个西瓜的好坏,西瓜的特征有三种:色泽{青绿、乌黑、浅白},根蒂{蜷缩、稍蜷、硬挺},敲声{浊响、沉闷、清脆},不同特征之间的组合,对应着西瓜的好坏,如下表:

朴素贝叶斯分类器

    现在拿来一个新的西瓜,只知道它具有如下特征,问这个西瓜是好是坏?

朴素贝叶斯分类器

    要得出好瓜还是坏瓜,就要看他们分别对应的概率,谁大就是谁。

朴素贝叶斯分类器

    怎么求解呢?根据贝叶斯公式可以根据已知条件来求解

朴素贝叶斯分类器朴素贝叶斯分类器

    这两个哪个概率大,西瓜就属于那一类。贝叶斯公式忘记的,请看浅谈全概率公式和贝叶斯公式

朴素贝叶斯分类器

朴素贝叶斯分类器

    由上述公式我们可以看出分母都是一样的,因此在计算的时候这个可以忽略,不影响最终的结果。对与分子中好瓜与坏瓜对应的概率,我们可以根据已知的数据,计算好瓜与坏瓜的比例即可:

朴素贝叶斯分类器

    那么对于朴素贝叶斯分类器,这是关于特征的联合概率,该怎么求呢?直接 根据出现频率来作为概率?那么不好意思,上述情况没有在给出的数据中出现!但是如果这些特征之间是相互独立的,那就容易了,因为每个特征取值出现的频率还是很好求的,分别对应相乘即可。比如p(蜷缩|好瓜=是) = 2/3。上述公式就化为如下形式:

朴素贝叶斯分类器

朴素贝叶斯分类器

为什么要这么做呢?这就要说到朴素贝叶斯的由来了。

二、”朴素”由来

    所谓朴素就是假设特征之间是相互独立的,为什么要这么做呢?本例中西瓜有三个特征:色泽{青绿、乌黑、浅白},根蒂{蜷缩、稍蜷、硬挺},敲声{浊响、沉闷、清脆},每个特征对应着三个取值,那么整个样本空间就有3*3*3=27 种可能的取值,这个例子属性还是相当少的,假如某个事物有100个属性,每个属性有10个值,那么整个样本空间就有10的100次方,这么大的数据,怎么搞?还根据样本出现的频率来计算概率?不现实!

    另外,我们训练样本只是观察到的一部分,既然是一部分,就会有很多情况还没有会出现,那么对于没有出现的情况怎么计 算频率? 直接定义为零?比如,本例子中p(青绿、蜷缩、浊响|好瓜=?),这种情况就没出现,能直接当成0吗?当成0就别计算了,都一样 了全是0,就没意义了!“未出现”和“出现的概率为0”是不一样的!比如“现在是阴天两个小时后会下雨”和“太阳打西边出来”这两个事件是不一样滴。所以为了解决上述问题,假设各特征之间相互独立是合理的,并且可以极大地简化贝叶斯模型,以及计算量。

    现在假设各属性之间是相互独立的,剩下的就好计算了:

朴素贝叶斯分类器

    上述我们已经说了,只计算分子即可,分母相同,可用计算,则有:

朴素贝叶斯分类器

    由此可知好瓜的概率大于坏瓜的概率,因此判定该瓜是好瓜。这里两类的概率都比较小,是因为给出的训练集数据量也比较小导致的。

    到此整个朴素贝叶斯分类器的思想就体现出来了。现在来总结一下贝叶斯分类器是怎么分类的,如下:

朴素贝叶斯分类器

    给定一组特征值来判断该事物的类别,怎么判断?根据给定的特征来求解属于每一类的概率(后验概率),哪个概率大,就属于那个类别,因此就化为如何求解后验概率,而求解后验概率又可以利用贝叶斯公式,化为条件概率和先验概率(等于训练数据中,各类别所占的频率),先验概率是已知的,再加上个属性之间是相互独立的,条件概率也变为已知,因此后验概率即可求得。这就是朴素贝叶斯分类器的理论解释。

三、拉普拉斯修正

    上例有一个问题,比如再给你一个有{乌黑、稍蜷、清脆}的西瓜,判断其好坏的时候,需要求p(清脆|好瓜= 是),但是上述数据中好瓜没有出现{响声=清脆}的情况,出现概率为零的情况,没出现并不代表没有这种情况,因此这会导致很大误差,因此在计算的时候,分子通常加1,分母加上该属性取值的个数(拉普拉斯修正),比如:

朴素贝叶斯分类器

用这种方法,可以按照上述求后验概率的方式再求解一遍,形式是一样的,这里就不再赘述了。

四、例子

在机器学习实战上找两个例子,体会体会,需要的可以从这里下载。

1、使用朴素贝叶斯分类器,来判断一句话是否是脏话。

# -*- coding: utf-8 -*-
"""
Created on Thu Jul 13 15:33:35 2017

@author: abner
"""
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'],
['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



######################################
##### Generate a Vocabulary List #####
######################################

def createVocabList(data_set):#data_set is a 2-dim list
vocab_set = set([]) #create an empty set
for document_list in data_set:
vocab_set = vocab_set | set(document_list) #union of the two sets
return list(vocab_set) #make a set to be a list


################################################################
## ##
## make a word list to be a vector ##
## eg: ##
## vocab_set = ['my', 'has', 'a', 'so', 'is', 'food'] ##
## w = ['he', 'is', 'a', 'student'] ===>v = [0, 0, 1, 0, 1, 0]##
## ##
################################################################

def setOfWords2Vec(vocab_set, input_set):
word_vec = [0] * len(vocab_set)
for word in input_set:
if word in vocab_set:
word_vec[vocab_set.index(word)] = 1
else:
print "the word: %s is not in my Vocabulary!" % word
return word_vec

def trainNB0(train_matrix, train_label):
num_train_sens = len(train_matrix)
num_words = len(train_matrix[0])
pclass1 = sum(train_label)/float(num_train_sens)

p0_num_vec = np.ones(num_words)
p1_num_vec = np.ones(num_words)

p0_sum = 2.0
p1_sum = 2.0
for i in range(num_train_sens):
if train_label[i] == 1:
p1_num_vec += train_matrix[i]
p1_sum += sum(train_matrix[i])
else:
p0_num_vec += train_matrix[i]
p0_sum += sum(train_matrix[i])

p1_vec = np.log(p1_num_vec/p1_sum)
p0_vec = np.log(p0_num_vec/p0_sum)

return p0_vec, p1_vec, pclass1


def classifyNB(vec2classify, p0_vec, p1_vec, pclass1):
p1 = sum(vec2classify * p1_vec) + np.log(pclass1)
p0 = sum(vec2classify * p0_vec) + np.log(1.0 - pclass1)

if p1 > p0:
return 1
else:
return 0



if __name__ == '__main__':
sentence_matrix, labels = loadDataSet()

vocab_set = createVocabList(sentence_matrix)
# vec = setOfWords2Vec(vocab_set, sen)
train_matrix = []
for sen in sentence_matrix:
train_matrix.append(setOfWords2Vec(vocab_set, sen))
p0v, p1v, pc1 = trainNB0(train_matrix, labels)
test_sentence = ['you', 'like', 'a', 'dog']
test_vec = setOfWords2Vec(vocab_set, test_sentence)
print test_sentence, 'classified as: ', classifyNB(test_vec, p0v, p1v, pc1)

test_sentence = ['stupid', 'garbage']
test_vec = setOfWords2Vec(vocab_set, test_sentence)
print test_sentence, 'classified as: ', classifyNB(test_vec, p0v, p1v, pc1)

2、使用朴素贝叶斯分类器,来对垃圾邮件分类,数据可以在 这里下载

# -*- coding: utf-8 -*-
"""
Created on Thu Jul 13 15:33:35 2017

@author: abner
"""
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'],
['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



######################################
##### Generate a Vocabulary List #####
######################################

def createVocabList(data_set):#data_set is a 2-dim list
vocab_set = set([]) #create an empty set
for document_list in data_set:
vocab_set = vocab_set | set(document_list) #union of the two sets
return list(vocab_set) #make a set to be a list


################################################################
## ##
## make a word list to be a vector ##
## eg: ##
## vocab_set = ['my', 'has', 'a', 'so', 'is', 'food'] ##
## w = ['he', 'is', 'a', 'student'] ===>v = [0, 0, 1, 0, 1, 0]##
## ##
################################################################

def setOfWords2Vec(vocab_set, input_set):
word_vec = [0] * len(vocab_set)
for word in input_set:
if word in vocab_set:
word_vec[vocab_set.index(word)] = 1
else:
print "the word: %s is not in my Vocabulary!" % word
return word_vec

###############################################################
###### calculate p(ci), p(w1\ci),p(w2|ci).....p(wn|ci) #$#####
###############################################################

def trainNB0(train_matrix, train_label):
num_train_sens = len(train_matrix)
num_words = len(train_matrix[0])
pclass1 = sum(train_label)/float(num_train_sens)

p0_num_vec = np.ones(num_words)
p1_num_vec = np.ones(num_words)

p0_sum = 2.0
p1_sum = 2.0
for i in range(num_train_sens):
if train_label[i] == 1:
p1_num_vec += train_matrix[i]
p1_sum += sum(train_matrix[i])
else:
p0_num_vec += train_matrix[i]
p0_sum += sum(train_matrix[i])

p1_vec = np.log(p1_num_vec/p1_sum)
p0_vec = np.log(p0_num_vec/p0_sum)

return p0_vec, p1_vec, pclass1


def classifyNB(vec2classify, p0_vec, p1_vec, pclass1):
p1 = sum(vec2classify * p1_vec) + np.log(pclass1)
p0 = sum(vec2classify * p0_vec) + np.log(1.0 - pclass1)

if p1 > p0:
return 1
else:
return 0


def textParse(big_string):
import re
list_of_token = re.split(r'\w*', big_string)
return [tok.lower() for tok in list_of_token if len(tok) > 2]

def spamTest():
docList=[]; classList = []; fullText =[]
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList = textParse(open('email/ham/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)#create vocabulary
trainingSet = range(50); testSet=[] #create test set
for i in range(10):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]; trainClasses = []
for docIndex in trainingSet:#train the classifier (get probs) trainNB0
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet: #classify the remaining items
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1
print "classification error",docList[docIndex]
print 'the error rate is: ',float(errorCount)/len(testSet)
#return vocabList,fullText

if __name__ == '__main__':

spamTest()
# sentence_matrix, labels = loadDataSet()
#
# vocab_set = createVocabList(sentence_matrix)
## vec = setOfWords2Vec(vocab_set, sen)
# train_matrix = []
# for sen in sentence_matrix:
# train_matrix.append(setOfWords2Vec(vocab_set, sen))
# p0v, p1v, pc1 = trainNB0(train_matrix, labels)
# test_sentence = ['you', 'like', 'a', 'dog']
# test_vec = setOfWords2Vec(vocab_set, test_sentence)
# print test_sentence, 'classified as: ', classifyNB(test_vec, p0v, p1v, pc1)
#
# test_sentence = ['stupid', 'garbage']
# test_vec = setOfWords2Vec(vocab_set, test_sentence)
# print test_sentence, 'classified as: ', classifyNB(test_vec, p0v, p1v, pc1)