vlambda博客
学习文章列表

朴素贝叶斯(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个朴素贝叶斯的分类算法类:分别是GaussianNBMultinomialNBBernoulliNB。其中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