1 概述
朴素贝叶斯(Naive Bayesian)法是基于贝叶斯定理与特征条件独立假设的分类方法(注意:朴素贝叶斯法与贝叶斯估计(Beyesian estimation)是不同的概念)。
2 算法
2.1 学习与分类
基本方法
设输入空间为n维向量的集合,输出空间为类标记集合。输入为特征向量,输出为类标记(class label)。是定义在输入空间上的随机向量,是定义在输出空间上的随机变量。是X和Y的联合概率分布。训练数据集
由独立同分布产生。
朴素贝叶斯法通过训练数据集学习联合概率分布。具体地,学习一下先验概率分布及条件概率分布。先验概率分布
(2.1)
条件概率分布
(2.2)
于是学习得到联合概率分布。
条件概率分布有指数级数量的参数,其估计实际是不可行的。实时上,假设可取值有个,,可取值有个,那么参数个数为.
朴素贝叶斯法对条件概率分布做了条件独立性的假设。由于这是一个较强的假设,朴素贝叶斯法也由此得名。具体地,条件独立性假设是
(2.3)
朴素贝叶斯法实际上学习到生成数据的机制,所以属于生成模型。条件独立假设等于是说用于分类的特征在类确定的条件下都是条件独立的。这一假设使朴素贝叶斯法变得简单,但有时会牺牲一定的分类准确率。
朴素贝叶斯法分类时,对给定的输入,通过学习到的模型计算后验概率分布,将后验概率最大的类作为的类输出。后验概率计算根据贝叶斯定理进行:
(2.4)
将式(2.3)带入(2.4),有
(2.5)
这是朴素贝叶斯法分类的基本公式。于是,朴素贝叶斯分类器可表示为
(2.6)
注意到,在式(2.6)中分母对所有都是相同的,所以
(2.7)
后验概率最大化的含义
朴素贝叶斯法将实例分到后验概率最大的类中。这等价于期望风险最小化。假设选择0-1损失函数:
式中是分类决策函数。这时,期望风险函数为
期望是对联合分布取的。由此取条件期望
为了使期望风险最小化,只需对逐个极小化,由此得到:
这样一来,根据期望风险最小化准则就得到了后验概率最大化准则:
即朴素贝叶斯法所采用的的原理。
2.2 参数估计
极大似然估计
在朴素贝叶斯法中,学习意味着估计和。可以应用极大似然估计法估计相应的概率。先验概率的极大似然估计是
(2.8)
设第个特征可能取值的集合为,条件概率的极大似然估计是
式中,是第个样本的第个特征;是第个特征可能去的第个值;为指示函数。
学习与分类算法
算法2.1 (朴素贝叶斯算法(naive Bayes algorithm))
输入:训练数据,其中,是第个样本的第个特征,,是第个特征可能去的第个值,,,;实例;
输出,实例的分类。
(1)计算先验概率及条件概率
(2)对于给定的实例,计算
(3)确定实例的类
3 实现
3.1 原始算法实现
# -*- coding: UTF-8 -*-
import numpy as np
from functools import reduce
def load_dataset():
"""
创建实验样本
:returns posting_list: 实验样本切分的词条
:returns class_vec: 类别标签向量
"""
posting_list = [['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']]
class_vec = [0, 1, 0, 1, 0, 1] # 类别标签向量,1代表侮辱性词汇,0代表不是
return posting_list, class_vec # 返回实验样本切分的词条和类别标签向量
def create_vocab_list(data_set):
"""
将切分的实验样本词条整理成不重复的词条列表,也就是词汇表
:param data_set: 整理的样本数据集
:returns vocab_set: 返回不重复的词条列表,也就是词汇表
"""
vocab_set = set([]) # 创建一个空的不重复列表
for document in data_set:
vocab_set = vocab_set | set(document) # 取并集
return list(vocab_set)
def set_off_words2vec(vocab_list, input_set):
"""
根据vocab_list词汇表,将input_set向量化,向量的每个元素为1或0
:param vocab_list: create_vocab_list返回的列表 input_set - 切分的词条列表
:returns return_vec: 文档向量,词集模型
"""
return_vec = [0] * len(vocab_list) # 创建一个其中所含元素都为0的向量
for word in input_set: # 遍历每个词条
if word in vocab_list: # 如果词条存在于词汇表中,则置1
return_vec[vocab_list.index(word)] = 1
else:
print("the word: %s is not in my Vocabulary!" % word)
return return_vec
def train_nb0(train_matrix, train_category):
"""
朴素贝叶斯分类器训练函数
:param train_matrix: 训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
:param train_category: 训练类别标签向量,即loadDataSet返回的classVec
:returns p0_vect: 非的条件概率数组
:returns p1_vect: 侮辱类的条件概率数组
:returns p_abusive: 文档属于侮辱类的概率
"""
num_train_docs = len(train_matrix) # 计算训练的文档数目
num_words = len(train_matrix[0]) # 计算每篇文档的词条数
p_abusive = sum(train_category) / float(num_train_docs) # 文档属于侮辱类的概率
p0_num = np.zeros(num_words);
p1_num = np.zeros(num_words) # 创建numpy.zeros数组,
p0_denim = 0.0;
p1_denim = 0.0 # 分母初始化为0.0
for i in range(num_train_docs):
if train_category[i] == 1: # 统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···
p1_num += train_matrix[i]
p1_denim += sum(train_matrix[i]) ## 该词条的总的词数目 这压样求得每个词条出现的概率 P(w1),P(w2), P(w3)...
else: # 统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···
p0_num += train_matrix[i]
p0_denim += sum(train_matrix[i])
p1_vect = p1_num / p1_denim # 相除
p0_vect = p0_num / p0_denim
return p0_vect, p1_vect, p_abusive # 返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率
def classify_nb(vec2classify, p0vec, p1_vec, p_class1):
"""
朴素贝叶斯分类器分类函数
:param vec2classify: 待分类的词条数组
:param p0vec: 非侮辱类的条件概率数组
:param p1_vec: 侮辱类的条件概率数组
:param p_class1: 文档属于侮辱类的概率
:returns 类别: 0 - 属于非侮辱类、1 - 属于侮辱类
"""
p1 = reduce(lambda x, y: x * y, vec2classify * p1_vec) * p_class1 # 对应元素相乘 这里需要好好理解一下
p0 = reduce(lambda x, y: x * y, vec2classify * p0vec) * (1.0 - p_class1)
print('p0:', p0)
print('p1:', p1)
if p1 > p0:
return 1
else:
return 0
def testing_nb():
"""
测试朴素贝叶斯分类器
"""
list_o_posts, list_classes = load_dataset() # 创建实验样本
my_vocab_list = create_vocab_list(list_o_posts) # 创建词汇表
train_mat = []
for postin_doc in list_o_posts:
train_mat.append(set_off_words2vec(my_vocab_list, postin_doc)) # 将实验样本向量化
p0_v, p1_v, p_ab = train_nb0(np.array(train_mat), np.array(list_classes)) # 训练朴素贝叶斯分类器
test_entry = ['love', 'my', 'dalmation'] # 测试样本1
this_doc = np.array(set_off_words2vec(my_vocab_list, test_entry)) # 测试样本向量化
if classify_nb(this_doc, p0_v, p1_v, p_ab):
print(test_entry, '属于侮辱类') # 执行分类并打印分类结果
else:
print(test_entry, '属于非侮辱类') # 执行分类并打印分类结果
test_entry = ['stupid', 'garbage'] # 测试样本2
this_doc = np.array(set_off_words2vec(my_vocab_list, test_entry)) # 测试样本向量化
if classify_nb(this_doc, p0_v, p1_v, p_ab):
print(test_entry, '属于侮辱类') # 执行分类并打印分类结果
else:
print(test_entry, '属于非侮辱类') # 执行分类并打印分类结果
if __name__ == '__main__':
testing_nb()
4 实践
4.1 一般使用流程
4.2 超参数和模型参数
4.3 基于scikit-learn的使用
5 问题集合
1. 用极大似然估计退出朴素贝叶斯发中的概率估计公式(2.8)及公式(2.9)。
2. 用贝叶斯估计法推出朴素贝叶斯法中的概率估计公式(2.10)及公式(2.11)。
6 继续阅读
详见《统计机器学习》第二版参考文献
CHANGELOG
2020年12月15日20:40:11
第一版更新,参考自《统计机器学习》第二版 -