一、概述
贝叶斯算法是一系列分类算法的总称,这类算法均是以贝叶斯定理为基础,所以将之统称为贝叶斯分类。而朴素贝叶斯(Naive Bayesian)是其中应用最为广泛的分类算法之一。
朴素贝叶斯分类器是基于一个简单的假定:给定目标值时属性之间相互条件独立。
二、核心思想
用p1(x, y)表示数据点(x, y)输入类别1的概率,用p2(x, y)表示数据点(x, y)属于类别2的概率,
a、如果p1(x, y) > p2(x, y), 那么类别为1
b、如果p2(x, y) > p1(x, y), 那么类别为2
也就是说,我们会选择高概率对应的类别,即选择具有最高概率的决策。
三、优缺点
(1)优点
在数据较少的情况下仍然有效,可以处理多类别问题。
(2)缺点
对于输入数据的准备方式较为敏感
综上,适用的数据类型:标称型数据
四、贝叶斯准则(公式)
五、方法步骤
# ##################################################
# 使用朴素贝叶斯对电子邮件进行分类
# 步骤:
# 1、收集数据:提供文本文件
# 2、准备数据:将文本文件解析成词条向量
# 3、分析数据:检查词条确保解析的正确性
# 4、训练算法:使用trainNBO()函数
# 5、测试算法:使用classifyNB()函数,并且构建一个新的测试函数来计算文档集的错误率
# 6、使用算法:构建一个完整的程序对一组文件进行分类,将错分的文档输出到屏幕上
# ##################################################
六、使用朴素贝叶斯进行垃圾邮件过滤
(1)收集数据
# 步骤一: 收集数据:提供文本文件
def create_dataset(file_name):
# file_name = "email/ham/6.txt"
try:
email_text = open(file_name).read()
except:
email_text = open(file_name, encoding="utf-8").read()
return email_text
(2)准备数据(数据预处理)
# 步骤二: 准备数据:将文本文件解析成词条向量
import re
def text_parse(big_string):
list_of_tokens = re.split("\\W*", big_string)
return [tok.lower() for tok in list_of_tokens if len(tok) > 2]
(3)分析数据
def set_of_word2vec(vocab_list, input_set):
return_vec = [0] * len(vocab_list)
for word in input_set:
if word in vocab_list:
return_vec[vocab_list.index(word)] = 1
else:
print("the word: %s is not in my Vocabulary!" % word)
return return_vec
def bag_of_word2vec(vocab_list, input_set):
return_vec = [0] * len(vocab_list)
for word in input_set:
if word in vocab_list:
return_vec[vocab_list.index(word)] += 1
return return_vec
(4)训练算法
# 用朴素贝叶斯分类器训练函数
def trainNBO(train_matrix, train_category):
num_of_train_docs = len(train_matrix)
num_of_words = len(train_matrix[0])
pAbusive = sum(train_category) / float(num_of_train_docs)
# #########################################################
# p0Num = zeros(num_of_words)
# 不同zeros的原因是:
# 利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(a | l) * p(b | l) * p(c | l)
# 如果其中某一个概率为0, 那么最后的乘积也为0,为降低这种影响,将所有的词的出现次数初始化为1,分母初始化为2
# #########################################################
p0Num = ones(num_of_words)
p1Num = ones(num_of_words)
p0Denom = 2.0
p1Denom = 2.0
for i in range(num_of_train_docs):
if train_category[i] == 1:
p1Num += train_matrix[i]
p1Denom += sum(train_matrix[i])
else:
p0Num += train_matrix[i]
p0Denom += sum(train_matrix[i])
# #########################################################
# p1Vect = p1Num / p1Denom
# 下溢出问题:
# 由于太多很小的数相乘造成的。当计算乘积p(w0|Ci)p(w1|Ci)...p(wn|Ci)时,由于大部分因子都非常小,
# 导致最后相乘的结果四舍五入会得到0,所以程序会下溢出或者得到不正确的答案
# #########################################################
p1Vect = -log(p1Num / p1Denom)
p0Vect = -log(p0Num / p0Denom)
return p1Vect, p0Vect,pAbusive
(5)测试算法
# 步骤五: 测试算法:使用classifyNB()函数,并且构建一个新的测试函数来计算文档集的错误率(使用朴素贝叶斯进行交叉验证)
def read_file(index, list_of_doc, full_text, list_of_class, flag):
if flag == 1:
file_name = "email/spam/%d.txt" % index
else:
file_name = "email/ham/%d.txt" % index
dataset = create_dataset(file_name)
list_of_word = text_parse(dataset)
list_of_doc.append(list_of_word)
full_text.extend(list_of_word)
list_of_class.append(flag)
import random
from numpy import *
def spam_test():
list_of_doc = []
list_of_class = []
full_text = []
for i in range(1, 26):
read_file(i, list_of_doc, full_text, list_of_class, 1)
read_file(i, list_of_doc, full_text, list_of_class, 0)
list_of_vocab = create_vocab_list(list_of_doc)
training_set = list(range(50))
test_set = []
for i in range(10):
randIndex = int(random.uniform(0, len(training_set)))
test_set.append(training_set[randIndex])
del training_set[randIndex]
training_matrix = []
training_classes = []
for doc_index in training_set:
training_matrix.append(nb.set_of_word2vec(list_of_vocab, list_of_doc[doc_index]))
training_classes.append(list_of_class[doc_index])
p0V,p1V, pSpam = trainNBO(training_matrix, training_classes)
error_count = 0
for docIndex in test_set:
word_vector = set_of_word2vec(list_of_vocab, list_of_doc[docIndex])
if nb.classifyNB(array(word_vector), p0V, p1V, pSpam) != list_of_class[docIndex]:
error_count += 1
print("the error rate is : ", float(error_count) / len(test_set))