朴素贝叶斯(Naive Bayes)模型
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了朴素贝叶斯(Naive Bayes)模型相关的知识,希望对你有一定的参考价值。
参考技术A 贝叶斯为了解决一个叫“逆向概率”问题写了一篇文章,尝试解答在没有太多可靠证据的情况下,怎样做出更符合数学逻辑的推测“逆向概率”是相对“正向概率”而言
正向概率,比较容易理解,比如我们已经知道袋子里面有N 个球,不是黑球就是白球,其中M个是黑球,那么把手伸进去摸一个球,就能知道摸出黑球的概率是多少 => 这种情况往往是 上帝视角 ,即了解了事情的全貌再做判断
逆向概率,贝叶斯则从实际场景出发,提了一个问题:如果我们事先不知道袋子里面黑球和白球的比例,而是通过我们摸出来的球的颜色,能判断出袋子里面黑白球的比例么?
贝叶斯原理:
影响了接下来近200年的统计学理论
建立在主观判断的基础上:在我们不了解所有客观事实的情况下,同样可以先估计一个值
先验概率 ,通过经验来判断事情发生的概率
后验概率 ,就是发生结果之后,推测原因的概率
条件概率 ,事件A 在另外一个事件B已经发生条件下的发生概率,表示为P(A|B)
似然函数 ,把概率模型的训练过程理解为求参数估计的过程
比如,一个硬币在10次抛落中正面均朝上 => 那么这个硬币是均匀的可能性是多少?这里硬币均匀就是个参数,似然函数就是用来衡量这个模型的参数
经过推导,贝叶斯推理告诉我们后验概率是与先验概率和似然函数成正比得,即
Thinking:假设有一种病叫做“贝叶死”,它的发病率是万分之一,即10000 人中会有1个人得病。现有一种测试可以检验一个人是否得病的准确率是99.9%,误报率(假阳)是0.1%
那么,如果一个人被查出来患有“叶贝死”,实际上患有的可能性有多大?
查出患有“贝叶死”的准确率是99.9%,是不是实际上患“贝叶死”的概率也是99.9%?)
在10000个人中,还存在0.1%的误查的情况,也就是10个人没有患病但是被诊断成阳性。当然10000个人中,也确实存在一个患有贝叶死的人,他有99.9%的概率被检查出来
可以粗算下,患病的这个人实际上是这11个人里面的一员,即实际患病比例是1/11≈9%
贝叶斯原理就是求解后验概率,假设:A 表示事件 “测出为阳性”, B1 表示“患有贝叶死”, B2 表示“没有患贝叶死”
患有贝叶死的情况下,测出为阳性的概率为 P(A|B1)=99.9%
没有患贝叶死,但测出为阳性的概率为 P(A|B2)=0.1%
患有贝叶死的概率为 P(B1)=0.01%
没有患贝叶死的概率 P(B2)=99.99%
那么我们检测出来为阳性,而且是贝叶死的概率P(B1,A)=P(B1)*P(A|B1)=0.01%*99.9%=0.00999% ≈0.01%
P(B1,A)代表的是联合概率,同样我们可以求得P(B2,A)=P(B2)*P(A|B2)=99.99%*0.1%=0.09999% ≈0.1%
检查为阳性的情况下,患有贝叶死的概率,即P(B1|A)
检查出是阳性的条件下,但没有患有贝叶死的概率为
0.01%+0.1%均出现在了P(B1|A)和P(B2|A)的计算中作为分母,称之为论据因子,也相当于一个权值因子
我们可以总结出贝叶斯公式
从而我们可以得到通用的贝叶斯公式
一种简单但极为强大的预测建模算法
假设每个输入变量是独立的。这是一个强硬的假设,实际情况并不一定,但是这项技术对于绝大部分的复杂问题仍然非常有效
朴素贝叶斯模型由两种类型的概率组成:
每个类别的概率P(Cj)
每个属性的条件概率P(Ai|Cj)
什么是类别概率:
假设我有7个棋子,其中3个是白色的,4个是黑色的
那么棋子是白色的概率就是3/7,黑色的概率就是4/7 => 这个是类别概率
什么是条件概率:
假设我把这7个棋子放到了两个盒子里,其中盒子A里面有2个白棋,2个黑棋;盒子B里面有1个白棋,2个黑棋
那么在盒子A中抓到白棋的概率就是1/2,抓到黑棋的概率也是1/2,这个就是条件概率,也就是在某个条件(比如在盒子A中)下的概率
在朴素贝叶斯中,我们要统计的是属性的条件概率,也就是假设取出来的是白色的棋子,那么它属于盒子A的概率是2/3
Step1:先给出训练数据,以及这些数据对应的分类
Step2,计算类别概率和条件概率
Step3,使用概率模型(基于贝叶斯原理)对新数据进行预测
朴素贝叶斯分类(离散值):
如何根据身高,体重,鞋码,判断是否为男女,比如一个新的数据:身高“高”、体重“中”,鞋码“中” => 男 or 女?
求在A1、A2、A3属性下,Cj的概率
因为一共有2个类别,所以我们只需要求得P(C1|A1A2A3)和P(C2|A1A2A3)的概率即可,然后比较下哪个分类的可能性大,就是哪个分类结果
分别求下这些条件下的概率:
P(A1|C1)=1/2, P(A2|C1)=1/2, P(A3|C1)=1/4
P(A1|C2)=0, P(A2|C2)=1/2, P(A3|C2)=1/2
所以P(A1A2A3|C1)=1/16, P(A1A2A3|C2)=0
因为P(A1A2A3|C1)P(C1)>P(A1A2A3|C2)P(C2),所以应该是C1类别,即男性
身高180、体重120,鞋码41,请问该人是男是女呢
可以假设男性和女性的身高、体重、鞋码都是 正态分布 ,通过样本计算出均值和方差,也就是得到 正态分布 的密度函数。有了密度函数,就可以把值代入,算出某一点的值
比如,男性的身高是 均值 179.5、 标准差 为3.697的正态分布。所以男性的身高为180的概率为0.1069
同理可以计算得出男性体重为120的概率为0.000382324,男性鞋码为41号的概率为0.120304111
P(A1A2A3|C1)=P(A1|C1)P(A2|C1)P(A3|C1)=0.1069*0.000382324*0.120304111=4.9169e-6
P(A1A2A3|C2)=P(A1|C2)P(A2|C2)P(A3|C2)=0.00000147489*0.015354144*0.120306074=2.7244e-9
很明显这组数据分类为男的概率大于分类为女的概率
NORMDIST(x,mean,standard_dev,cumulative)
x:正态分布中,需要计算的数值;
Mean:正态分布的平均值;
Standard_dev:正态分布的标准差;
Cumulative:取值为逻辑值,即False或True,决定了函数的形式当为True时,函数结果为累积分布
当为False时,函数结果为 概率密度
NORMDIST(180,179.5,3.697,0)=0.1069
stats.norm.pdf(x, mu, sigma)
返回参数为 和 的正态分布密度函数在x处的值
from scipy import stats
mu = 179.5
sigma = 3.697
x = 180
prob = stats.norm.pdf(x, mu, sigma)
print(prob)
常用于文本分类,文本过滤、情感预测、推荐系统等,尤其是对于英文等语言来说,分类效果很好
准备阶段,需要确定特征属性,属性值以及label => 训练集
训练阶段,输入是特征属性和训练样本,输出是分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率
应用阶段,使用分类器对新数据进行分类
sklearn工具使用:
高斯朴素贝叶斯:特征变量是连续变量,符合高斯分布(正太分布),比如说人的身高,物体的长度
GaussianNB(priors=None) #模型创建
priors,先验概率大小,如果没有给定,模型则根据样本数据自己计算(利用极大似然法)
查看模型对象的属性:
class_prior_:每个样本的概率
class_count_:每个类别的样本数量
theta_:每个类别中每个特征的均值
sigma_:每个类别中每个特征的方差
多项式朴素贝叶斯:特征变量是离散变量,符合多项分布,在文档分类中特征变量体现在一个单词出现的次数,或者是单词的TF-IDF值等
MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
alpha:先验平滑因子,默认等于1,当等于1时表示拉普拉斯平滑
fit_prior:是否去学习类的先验概率,默认是True
class_prior:各个类别的先验概率,如果没有指定,则模型会根据数据自动学习, 每个类别的先验概率相同,即类别数N分之一
模型对象的属性:
class_count_: 训练样本中各类别对应的样本数
feature_count_: 每个类别中各个特征出现的次数
伯努利朴素贝叶斯:特征变量是布尔变量,符合0/1分布,在文档分类中特征是单词是否出现
BernoulliNB(alpha=1.0, fit_prior=True, class_prior=None)
alpha:平滑因子,与多项式中的alpha一致
fit_prior:是否去学习类的先验概率,默认是True
class_prior:各个类别的先验概率,如果没有指定,则模型会根据数据自动学习, 每个类别的先验概率相同,即类别数N分之一
模型对象的属性:
class_count_: 训练样本中各类别对应的样本数
feature_count_: 每个类别中各个特征出现的次数
# MNIST手写数字分类(多种分类方法)
# 分割数据,将25%的数据作为测试集,其余作为训练集
train_x, test_x, train_y, test_y = train_test_split(data, digits.target, test_size=0.25, random_state=33)
# 创建LR分类器
model = LogisticRegression()
model.fit(train_x, train_y)
predict_y=model.predict(test_x)
print('LR准确率: %0.4lf' % accuracy_score(predict_y, test_y))
# 创建GaussianNB分类器
model = GaussianNB()
model.fit(train_x, train_y)
predict_y=model.predict(test_x)
print('GaussianNB准确率: %0.4lf' % accuracy_score(predict_y, test_y))
# 创建MultinomialNB分类器
model = MultinomialNB()
model.fit(train_x, train_y)
predict_y=model.predict(test_x)
print('MultinomialNB准确率: %0.4lf' % accuracy_score(predict_y, test_y))
# 创建BernoulliNB分类器
model = BernoulliNB()
model.fit(train_x, train_y)
predict_y=model.predict(test_x)
print('BernoulliNB准确率: %0.4lf' % accuracy_score(predict_y, test_y))
根据训练的结果选择最接近的方案
朴素贝叶斯(naive bayes)原理小结
1. 朴素贝叶斯的学习
1.1 基本假设:条件独立性
1.2 朴素贝叶斯分类器
1.3 后验概率的含义
2. 参数估计
2.1 极大似然估计
2.2 贝叶斯估计:极大似然估计+平滑机制
2.3 分类算法
3. 代码示例:朴素贝叶斯 文本分类
(1)加载数据
(2)文本预处理(清洗文本,分词,去除停用词)
(3)抽取文本特征:使用词袋模型
(4)训练贝叶斯模型(多项式贝叶斯)
(5)评价指标&测试
4. 模型评价
参考
本博客中使用到的完整代码请移步至我的github:https://github.com/qingyujean/Magic-NLPer,求赞求星求鼓励~~~
朴素贝叶斯,基于贝叶斯定理
与特征条件独立假设
。
条件概率公式:
全概率公式:
适用问题:多类分类
模型特点:特征与类别的联合概率分布,特征条件独立性
模型类型:生成模型
损失函数:对数似然损失
学习策略:极大似然估计,最大后验概率估计
学习算法:概率计算公式
1. 朴素贝叶斯的学习
1.1 基本假设:条件独立性
设输入空间
,输出为类标记,输出空间为
,设训练集由 联合概率分布
独立用分布
产生。
朴素贝叶斯
,就是基于给定的训练集,在基于 特征条件独立的假设
下,学习联合概率分布
。
就是学得的模型,然后用于预测,预测时要使用到贝叶斯定理。
先验概率分布:
条件概率分布:
后验概率分布:
朴素贝叶斯法对如上条件概率作了
“特征条件独立假设”
:这是一个较强的假设,它使得朴素贝叶斯法实现简单,高效,易于实现,但有时会牺牲一定的分类准确率。不过在实际应用中,朴素贝叶斯也有work的很好的时候,比如垃圾邮件分类,文本分类。
条件概率分布 的参数数量是
指数级
的。假设 的取值有 个, 的取值有 个,则参数总个数为:
1.2 朴素贝叶斯分类器
在给定训练集学习到联合概率分布
后,就可以对给定的输入
做类别预测了,即计算后验概率
,后验概率最大的类作为预测结果
。计算时使用 贝叶斯定理
:
所以,朴素贝叶斯分类器
可表示为:
分母对所有
都一样,所以朴素贝叶斯分类器
可简化为:
1.3 后验概率的含义
后验概率最大化等价于0-1损失的期望风险最小化。
基于后验概率 可知样本 分类为 所产生的期望损失,即在样本 上的条件风险为:
其中
为0-1损失函数
:
那么总体风险(期望风险函数)则为:
显然,对每个样本
若能使得其相应的条件风险
最小化,则总体风险
也将被最小化
。这样就产生了 贝叶斯判定准则
:为最小化总体风险,只需在每个样本上选择那个能使条件风险
最小的类别标记
,即:
期望风险最小化:
如此,根据期望最小化准则,就得到了后验概率最大化准则:
即对每个样本 ,选择能使后验概率 最大的类别标记。
此时, 成为贝叶斯最优分类器,与之对应的总体风险 成为贝叶斯风险。 反映了分类器所能达到的最好性能,即通过机器学习所能产生的模型精度的理论上限。
2. 参数估计
朴素贝叶斯法中,学习就意味着估计先验概率
和条件概率
。
2.1 极大似然估计
先验概率
表达了特种空间中各类样本所占比例,根据大数定律
,当训练集包含充足的独立同分布的样本时,
可通过各类样本出现的频率来进行估计。
先验概率的极大似然估计
:
对于条件概率
来说,由于它涉及
所有属性的联合概率,直接根据样本的频率估计将会遇到严重的困难,显然直接使用频率来估计是不可行。普斯贝叶斯采用了“特征/属性条件独立性
”:对已知类别,假设所有属性相互独立
。即:
此时,便可以使用频率来估计各类样本的某个属性出现的条件概率
,即为每个属性来估计条件概率
。
条件概率的极大似然估计
:
其中N和K分别表示共有N个样本和K个类别, 为指示函数
【注意】
:如果 是连续属性
,则假定,其中 和 分别是第 类样本在第 个属性上取值的均值
和方差
,则有。
2.2 贝叶斯估计:极大似然估计+平滑机制
极大似然估计的计算式中有连乘运算,如果其中一个概率值为0,就会影响后验概率 的计算,使分类结果产生偏差。很多样本的取值在训练集中可能没有出现,但这不代表概率就为0。
此时可在计算中引入一个平滑因子
,
时就是极大似然估计。取
时等价于在随机变量各个取值的频数上都赋予一个正数。
时成为 拉普拉斯平滑
。
先验概率的贝叶斯估计
:
条件概率的贝叶斯估计
:
引入平滑因子后, 仍然具有概率性质,因为有:
表明 确为一种概率分布。
拉普拉斯修正避免了因训练集样本不充分而导致的概率估值为0的问题,并且在训练集变大时,修正所引入的先验影响(拉普拉斯修正实质上假设了属性值与类别均匀分布)也会逐渐变得可忽略,使得估值逐渐趋向于实际概率值。
2.3 分类算法
基于极大似然估计的朴素贝叶斯算法:
在scikit-learn
中,一共有3个朴素贝叶斯的分类算法类:分别是GaussianNB
,MultinomialNB
和BernoulliNB
。其中GaussianNB
就是先验为高斯分布的朴素贝叶斯,MultinomialNB
就是先验为多项式分布的朴素贝叶斯,而BernoulliNB
就是先验为伯努利分布的朴素贝叶斯。
这三个类适用的分类场景各不相同,一般来说,如果样本特征的分布大部分是连续值,使用GaussianNB
会比较好。如果样本特征的分布大部分是多元离散值,使用MultinomialNB
比较合适。而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB
。
3. 代码示例:朴素贝叶斯 文本分类
下面使用朴素贝叶斯,来实现一个中文文本分类的任务,数据是二分类,
-
数据说明:文本二分类,1和0,判断是否属于政治上的出访类事件 -
数据来源:https://github.com/ares5221/ALBERT_text_classification
(1)加载数据
df_train = pd.read_csv(data_dir+'train.txt', encoding='UTF-8', sep='\s', header=None,
names=['label', 'content'], index_col=False)
df_train = df_train.dropna() # 过滤含有NaN的数据
df_test = pd.read_csv(data_dir+'test.txt', encoding='UTF-8', sep='\s', header=None,
names=['label', 'content'], index_col=False)
df_test = df_test.dropna() # 过滤含有NaN的数据
print(df_train.head())
print()
print(df_train['label'].value_counts())
输出:
label content
0 1 当地时间2月10日,白宫发表声明称,美国总统特朗普及夫人梅拉尼娅将于2月24日至25日访问印...
1 0 俄罗斯卫星通讯社11日最新消息,菲律宾总统杜特尔特已下令终止与美国间的《访问部队协定》(VFA)。
2 1 据俄罗斯卫星网6日报道,土耳其总统发言人卡林表示,俄罗斯军事代表团将于近日访问安卡拉,讨论叙...
3 0 先来说说什么是LPDDR5:要知道,手机中有两种内存颗粒,一种就是DRAM也就是大家常说的“...
4 1 在疫情的关键时刻,出现了一件令人感动的事情,让我们明白这才是真正的好朋友,不惧疫情访问我国,...
0 151
1 149
Name: label, dtype: int64
查看训练集,测试集各多少条样本:
print(df_train.shape, df_test.shape)
输出:
(300, 2) (80, 2)
(2)文本预处理(清洗文本,分词,去除停用词)
# 保留文本中文、数字、英文、短横线
def clear_text(text):
p = re.compile(r"[^\u4e00-\u9fa5^0-9^a-z^A-Z\-、,。!?:;()《》【】,!\?:;[\]()]") # 匹配不是中文、数字、字母、短横线的部分字符
return p.sub('', text) # 将text中匹配到的字符替换成空字符
# 加载停用词表
def load_stopwords_file(filename):
print('加载停用词...')
stopwords=pd.read_csv(filename, index_col=False, quoting=3, sep="\t", names=['stopword'], encoding='utf-8')
#quoting:控制引用字符引用行为,QUOTE_MINIMAL (0), QUOTE_ALL (1), QUOTE_NONNUMERIC (2) or QUOTE_NONE (3).
stopwords = set(stopwords['stopword'].values)
print('停用词表大小:', len(stopwords))
return stopwords
# 文本预处理:清洗,分词,并去除停用词
def preprocess_text(df_content):
stopwords_set = load_stopwords_file(stopwords_file) # 加载停用词表
content_seg = []#分词后的content
for i,text in enumerate(df_content):
text = clear_text(text.strip())
segs = jieba.lcut(text, cut_all=False) # cut_all=False是精确模式,True是全模式;默认模式是False 返回分词后的列表
segs = filter(lambda x: len(x.strip())>1, segs) # 词长度要>1,没有保留标点符号
segs = filter(lambda x: x not in stopwords_set, segs)
# print(segs) # segs是一个filter object
# segs = list(segs) # segs需要一次类似“持久化”的操作,否则每次被操作一次后segs就为空了
content_seg.append(" ".join(segs))
return content_seg
df_train['content_seg'] = preprocess_text(df_train['content'])
df_test['content_seg'] = preprocess_text(df_test['content'])
print(df_train.head()) #
print(df_train.shape)
输出:
加载停用词...
停用词表大小:2613
加载停用词...
停用词表大小:2613
label content \
0 1 当地时间2月10日,白宫发表声明称,美国总统特朗普及夫人梅拉尼娅将于2月24日至25日访问印...
1 0 俄罗斯卫星通讯社11日最新消息,菲律宾总统杜特尔特已下令终止与美国间的《访问部队协定》(VFA)。
2 1 据俄罗斯卫星网6日报道,土耳其总统发言人卡林表示,俄罗斯军事代表团将于近日访问安卡拉,讨论叙...
3 0 先来说说什么是LPDDR5:要知道,手机中有两种内存颗粒,一种就是DRAM也就是大家常说的“...
4 1 在疫情的关键时刻,出现了一件令人感动的事情,让我们明白这才是真正的好朋友,不惧疫情访问我国,...
content_seg
0 时间 白宫 发表声明 美国 总统 特朗普 夫人 拉尼 日至 访问 印度 特朗普 上任 首次 ...
1 俄罗斯 卫星 通讯社 最新消息 菲律宾 总统 杜特 尔特 下令 终止 美国 访问 部队 协定...
2 俄罗斯 卫星 报道 土耳其 总统 发言人 卡林 俄罗斯 军事 代表团 近日 访问 安卡拉 讨...
3 LPDDR5 手机 中有 两种 内存 颗粒 一种 DRAM 常说 运行 内存 提到 LPDD...
4 疫情 关键时刻 一件 令人感动 事情 明白 这才 朋友 疫情 访问 我国 王毅 机场 迎接
(300, 3)
(3)抽取文本特征:使用词袋模型
vectorizer = CountVectorizer(analyzer='word', # 以词为粒度做ngram
max_features=4000, # 保留最常见的4000个词
)
vectorizer.fit(df_train['content_seg'].tolist())
print('CountVectorizer train finished!')
train_features = vectorizer.transform(df_train['content_seg'])
输出:
CountVectorizer train finished!
(4)训练贝叶斯模型(多项式贝叶斯)
bayes_classifier = MultinomialNB() # 使用多项式贝叶斯
bayes_classifier.fit(train_features, df_train['label'])
print('MultinomialNB train finished!')
输出:
MultinomialNB train finished!
(5)评价指标&测试
查看准确率accuracy:
test_features = vectorizer.transform(df_test['content_seg'])
bayes_classifier.score(test_features, df_test['label']) # Return the mean accuracy
输出:
0.9375
进一步查看精准率precision、召回率recall、f1值:
from sklearn.metrics import precision_score, recall_score, f1_score
y_pred = bayes_classifier.predict(test_features)
print('precision_score: %.3f' % precision_score(y_pred, df_test['label']))
print('recall_score: %.3f' % recall_score(y_pred, df_test['label']))
print('f1_score: %.3f' % f1_score(y_pred, df_test['label']))
输出:
precision_score: 0.952
recall_score: 0.930
f1_score: 0.941
分类结果还不错!
4. 模型评价
朴素贝叶斯法实现简单,高效,易于实现,但由于特征条件独立的假设太强,有时会牺牲一定的分类准确率。不过在实际应用中,朴素贝叶斯也有work的很好的时候,比如垃圾邮件分类,文本分类。
下面对该模型做一个评价总结。评价内容摘自刘建平老师的朴素贝叶斯算法原理小结 https://www.cnblogs.com/pinard/p/6069267.html:
优点:
-
1)朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。 -
2)对 小规模的数据
表现很好,能个处理多分类任务,适合增量式训练
,尤其是数据量超出内存时,我们可以一批批的去增量训练。 -
3)对缺失数据不太敏感,算法也比较简单, 常用于文本分类
。
缺点:
-
1)理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有 半朴素贝叶斯
之类的算法通过考虑部分关联性适度改进。 -
2)需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。 -
3)由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。 -
4)对输入数据的表达形式很敏感。
完整代码地址
完整代码请移步至我的github:https://github.com/qingyujean/Magic-NLPer,求赞求星求鼓励~~~
最后:如果本文中出现任何错误,请您一定要帮忙指正,感激~
参考
[1] 统计学习方法(第2版) 李航
[2] 西瓜书-机器学习 周志华
[3] 朴素贝叶斯算法原理小结 刘建平 https://www.cnblogs.com/pinard/p/6069267.html
以上是关于朴素贝叶斯(Naive Bayes)模型的主要内容,如果未能解决你的问题,请参考以下文章