- 视频链接
- 数据集下载地址:无需下载
学习目标:
4. 说明条件概率与联合概率
5. 说明贝叶斯公式、以及特征独立的关系
6. 记忆贝叶斯公式
7. 知道拉普拉斯平滑系数
8. 应用贝叶斯公式实现概率的计算
9. 会使用朴素贝叶斯对商品评论进行情感分析
1. 朴素贝叶斯算法简介
朴素贝叶斯算法主要还是用来分类的。
Q:那么与之前学习的 KNN 算法有什么区别呢?
A:朴素贝叶斯算法和 KNN 算法都是分类算法,但它们之间有一些区别:
- 朴素贝叶斯算法是基于贝叶斯定理和特征条件独立假设的分类方法
- KNN算法是一种基于实例的学习,它通过测量不同特征值之间的距离进行分类
根据上面两张图可以知道,朴素贝叶斯就是根据 概率 来判断所属的类别,这跟我们之前学习的 KNN 和决策树判断类别不同。
KNN 算法是通过测量不同特征值之间的距离来进行分类。它的思路是:如果一个样本在特征空间中的 k 个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
决策树算法则是通过构建一棵决策树来进行分类。它从根节点开始,对实例的某一特征进行测试,根据测试结果将实例分配到其子节点;每一个子节点对应着该特征的一个取值。然后,每个子节点都按照这种方式进行测试,直到所有实例都被正确分类或者没有更多的特征可供选择为止。
2. 概率基础复习
学习目标:
- 了解联合概率、条件概率和相关独立的概念
- 知道贝叶斯公式
- 知道拉普拉斯平滑系数
2.1 概率定义
概率是一种用来衡量事件发生可能性的数值。它通常用一个 [0, 1] 之间的实数来表示,其中0表示事件不可能发生,1表示事件一定会发生。概率的定义有多种方式,其中最常见的是经典概率和频率概率。
- 经典概率是指在一个有限样本空间中,每个基本事件发生的可能性都相等,那么某一事件发生的概率就等于这一事件所包含的基本事件数除以样本空间中所有基本事件的总数。
- 频率概率是指在大量重复试验中,某一事件发生的频率趋于稳定时,这一稳定值就是这一事件发生的概率。
简而言之:概率就是一件事情发生的可能性。
例如:扔出一个硬币,头像朝上的概率为 P ( X ) P(X) P(X),它的取值在 [ 0 , 1 ] [0, 1] [0,1]之间。
2.2 案例:判断女生对男生的喜欢情况
在讲这两个概率之前我们通过一个例子,来计算一些结果:
样本数 | 职业 | 体型 | 女生是否喜欢 |
---|---|---|---|
1 | 程序员 | 超重 | 不喜欢 |
2 | 产品 | 匀称 | 喜欢 |
3 | 程序员 | 匀称 | 喜欢 |
4 | 程序员 | 超重 | 喜欢 |
5 | 美工 | 匀称 | 不喜欢 |
6 | 美工 | 超重 | 不喜欢 |
7 | 产品 | 匀称 | 喜欢 |
问题如下:
- 被女生喜欢的概率?
- 职业是程序员并且体型匀称的概率?
- 在女生喜欢的条件下,职业是程序员的概率?
- 在女生喜欢的条件下,职业是程序员且体重超重的概率?
计算结果为:
P ( 喜欢 ) = 喜欢的人数 总人数 = 4 7 P ( 程序员 , 匀称 ) 联合概率 = 同时满足两个条件的人数 总人数 = 1 7 P ( 程序员 ∣ 喜欢 ) 条件概率 = 女生喜欢且职业是程序员的人数 女生喜欢的人数 = 2 4 = 1 2 P ( 程序员 , 超重 ∣ 喜欢 ) 联合条件概率 = 女生喜欢且职业是程序员且体重超重的人数 女生喜欢的人数 = 1 4 \begin{aligned} &P(喜欢) = \frac{喜欢的人数}{总人数} = \frac{4}{7} \\ &P(程序员,匀称)_{联合概率} = \frac{同时满足两个条件的人数}{总人数} = \frac{1}{7} \\ &P(程序员|喜欢)_{条件概率} = \frac{女生喜欢且职业是程序员的人数}{女生喜欢的人数} = \frac{2}{4} = \frac{1}{2}\\ &P(程序员,超重|喜欢)_{联合条件概率} = \frac{女生喜欢且职业是程序员且体重超重的人数}{女生喜欢的人数} = \frac{1}{4} \end{aligned} P(喜欢)=总人数喜欢的人数=74P(程序员,匀称)联合概率=总人数同时满足两个条件的人数=71P(程序员∣喜欢)条件概率=女生喜欢的人数女生喜欢且职业是程序员的人数=42=21P(程序员,超重∣喜欢)联合条件概率=女生喜欢的人数女生喜欢且职业是程序员且体重超重的人数=41
- 联合概率:表示两个事件同时发生的概率。
- 条件概率:表示在一个事件发生的条件下,另一个事件发生的概率。
- 联合条件概率:表示在一个事件发生的条件下,两个事件同时发生的概率。
P ( 喜欢 ) P(喜欢) P(喜欢) 是一个简单的概率
思考题:在小明是产品经理并且体重超重的情况下,如何计算小明被女生喜欢的概率?
即 P ( 喜欢 ∣ 产品 , 超重 ) = ? P(喜欢|产品,超重)=? P(喜欢∣产品,超重)=?。
在这个例子中,我们无法计算小明被女生喜欢的概率,因为表格中没有关于小明的信息。我们只能根据表格中给出的数据计算概率,而不能推断出不在表格中的人的概率。
而且给出的表格中,所有的产品都是体型匀称的,没有超重的情况。
此时我们需要用到朴素贝叶斯进行求解,在讲解贝叶斯公式之前,首先复习一下联合概率、条件概率和相互独立的概念。
2.3 联合概率、条件概率与相互独立
- 联合概率:包含多个条件,且所有条件同时成立的概率。
- 记作: P ( A , B ) P(A,B) P(A,B)
- 条件概率:就是事件 A 在另外一个事件 B 已经发生条件下的发生概率。
- 记作: P ( A ∣ B ) P(A|B) P(A∣B)
- 相互独立:如果 P ( A , B ) = P ( A ) P ( B ) P(A,B) = P(A)P(B) P(A,B)=P(A)P(B),则称事件 A 与事件 B 相互独立。
2.4 贝叶斯公式
2.4.1 公式介绍
P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A|B) = P(B|A)\frac{P(A)}{P(B)} P(A∣B)=P(B∣A)P(B)P(A)
P ( C ∣ W ) = P ( W ∣ C ) P ( C ) P ( W ) P(C|W) = \frac{P(W|C)P(C)}{P(W)} P(C∣W)=P(W)P(W∣C)P(C)
其中:
- W W W 为给定文档的特征值(频数统计,预测文档提供)
- C C C 为文档类别
2.4.2 案例计算
那么思考题就可以套用贝叶斯公式来解决:
P ( C ∣ W ) = P ( W ∣ C ) P ( C ) P ( W ) P ( 喜欢 ∣ 产品 , 超重 ) = P ( 产品 , 超重 ∣ 喜欢 ) P ( 喜欢 ) P ( 产品 , 超重 ) \begin{aligned} & P(C|W) = \frac{P(W|C)P(C)}{P(W)} \\ & P(喜欢|产品, 超重) = \frac{P(产品, 超重|喜欢)P(喜欢)}{P(产品,超重)} \end{aligned} P(C∣W)=P(W)P(W∣C)P(C)P(喜欢∣产品,超重)=P(产品,超重)P(产品,超重∣喜欢)P(喜欢)
上式中, P ( 产品 , 超重 ∣ 喜欢 ) P(产品,超重|喜欢) P(产品,超重∣喜欢) 和 P ( 产品 , 超重 ) P(产品,超重) P(产品,超重) 的结果均为0,导致无法计算结果。这是因为我们的样本量太少了,不具有代表性。
本来现实生活中,肯定是存在职业是产品经理并且体重超重的人的, P ( 产品 , 超重 ) P(产品,超重) P(产品,超重) 不可能为0。而且事件“职业是产品经理”和事件“体重超重”通常被认为是相互独立的事件,但是根据我们有限的7个样本计算 P ( 产品 , 超重 ) = P ( 产品 ) P ( 超重 ) P(产品, 超重) = P(产品) P(超重) P(产品,超重)=P(产品)P(超重) 不成立。而朴素贝叶斯可以帮助我们解决这个问题。
朴素贝叶斯,简单理解,就是假定了特征与特征之间相互独立的贝叶斯公式。也就是说,朴素贝叶斯,之所以朴素,就在于假定了特征与特征相互独立。所以,思考题如果按照朴素贝叶斯的思路来解决,就可以是:
P ( 产品 , 超重 ) = P ( 产品 ) × P ( 超重 ) = 2 7 ∗ 3 7 = 6 49 P ( 产品 , 超重 ∣ 喜欢 ) = P ( 产品 ∣ 喜欢 ) × P ( 超重 ∣ 喜欢 ) = 1 2 × 1 4 = 1 8 P ( 喜欢 ∣ 产品 , 超重 ) = P ( 产品 , 超重 ∣ 喜欢 ) × P ( 喜欢 ) P ( 产品 , 超重 ) = 1 8 × 4 7 × 6 49 = 7 12 \begin{aligned} & P(产品, 超重) = P(产品) \times P(超重) = \frac{2}{7} * \frac{3}{7} = \frac{6}{49}\\ & P(产品, 超重 | 喜欢) = P(产品 | 喜欢) \times P(超重 | 喜欢) = \frac{1}{2} \times \frac{1}{4} = \frac{1}{8}\\ & P(喜欢 | 产品, 超重) = P(产品, 超重 | 喜欢) \times \frac{P(喜欢)}{P(产品, 超重)} = \frac{1}{8} \times \frac{4}{7} \times \frac{6}{49} = \frac{7}{12} \end{aligned} P(产品,超重)=P(产品)×P(超重)=72∗73=496P(产品,超重∣喜欢)=P(产品∣喜欢)×P(超重∣喜欢)=21×41=81P(喜欢∣产品,超重)=P(产品,超重∣喜欢)×P(产品,超重)P(喜欢)=81×74×496=127
那么这个公式如果应用在文章分类的场景当中,我们可以这样看:
公式可以理解为:
P ( C ∣ F 1 , F 2 , . . . ) = P ( F 1 , F 2 , . . . ∣ C ) P ( C ) P ( F 1 , F 2 , . . . ) P(C|F1, F2, ...) = \frac{P(F1, F2, ... | C)P(C)}{P(F1, F2, ...)} P(C∣F1,F2,...)=P(F1,F2,...)P(F1,F2,...∣C)P(C)
其中 C C C 可以是不同类别。
公式分为三个部分:
- P ( C ) P(C) P(C):每个文档类别的概率(某文档类别数/总文档数量)
-
P
(
W
∣
C
)
P(W|C)
P(W∣C):给定类别下特征(被预测文档中出现的词)的概率
- 计算方法:
P
(
F
1
∣
C
)
=
N
i
N
P(F1 | C) = \frac{N_i}{N}
P(F1∣C)=NNi(训练文档中去计算)
- N i N_i Ni 为该 F 1 F1 F1 词在 C C C 类别所有文档中出现的次数
- N N N 为所属类别 C C C 下的文档所有词出现的次数和
- 计算方法:
P
(
F
1
∣
C
)
=
N
i
N
P(F1 | C) = \frac{N_i}{N}
P(F1∣C)=NNi(训练文档中去计算)
- P ( F 1 , F 2 , . . . ) P(F1,F2,...) P(F1,F2,...) 预测文档中每个词的概率
如果计算两个类别概率比较,所以我们只要比较前面的大小就可以,得出谁的概率大。
2.4.3 文章分类计算
需求:通过前四个训练样本(文章),判断第五篇文章,是否属于China类。
文档ID | 文档中的词 | 属于C=China类 | |
---|---|---|---|
训练集 | 1 | Chinese Beijing Chinese | Yes |
2 | Chinese Chinese Shanghai | Yes | |
3 | Chinese Macao | Yes | |
4 | Tokyo Japan Chinese | No | |
测试集 | 5 | Chinese Chinese Chinese Tokyo Japan | ? |
计算结果:
P ( C ∣ C h i n e s e , C h i n e s e , C h i n e s e , T o k y o , J a p a n ) = P ( C h i n e s e , C h i n e s e , C h i n e s e , T o k y o , J a p a n ∣ C ) × P ( C ) P ( C h i n e s e , C h i n e s e , C h i n e s e , T o k y o , J a p a n ) = P ( C h i n e s e ) 3 × P ( T o k y o ∣ C ) × P ( J a p a n ∣ C ) × P ( C ) [ P ( C h i n e s e ) 3 × P ( T o k y o ) × P ( J a p a n ) ] \begin{aligned} P(C|Chinese, Chinese, Chinese, Tokyo, Japan) & = P(Chinese, Chinese, Chinese, Tokyo, Japan|C) \\ & \times \frac{P(C)}{P(Chinese, Chinese, Chinese, Tokyo, Japan)}\\ & = P(Chinese)^3 \times P(Tokyo|C) \times P(Japan | C) \\ & \times \frac{P(C)}{[P(Chinese)^3 \times P(Tokyo) \times P(Japan)]} \end{aligned} P(C∣Chinese,Chinese,Chinese,Tokyo,Japan)=P(Chinese,Chinese,Chinese,Tokyo,Japan∣C)×P(Chinese,Chinese,Chinese,Tokyo,Japan)P(C)=P(Chinese)3×P(Tokyo∣C)×P(Japan∣C)×[P(Chinese)3×P(Tokyo)×P(Japan)]P(C)
这个文章是需要计算是不是China类,是或者不是最后的分母值都相同。
首先计算是China类的概率:
P ( C h i n e s e ∣ C ) = 5 / 8 P ( T o k y o ∣ C ) = 0 / 8 P ( J a p a n ∣ C ) = 0 / 8 \begin{aligned} & P(Chinese|C) = 5/8 \\ & P(Tokyo|C) = 0/8\\ & P(Japan|C) = 0/8 \end{aligned} P(Chinese∣C)=5/8P(Tokyo∣C)=0/8P(Japan∣C)=0/8
接着计算不是China类的概率:
P ( C h i n e s e ∣ C ) = 1 / 3 P ( T o k y o ∣ C ) = 1 / 3 P ( J a p a n ∣ C ) = 1 / 3 \begin{aligned} & P(Chinese|C) = 1/3\\ & P(Tokyo|C) = 1/3\\ & P(Japan|C) = 1/3\\ \end{aligned} P(Chinese∣C)=1/3P(Tokyo∣C)=1/3P(Japan∣C)=1/3
问题:从上面的例子我们得到 P ( T o k y o ∣ C ) P(Tokyo|C) P(Tokyo∣C) 和 P ( J a p a n ∣ C ) P(Japan|C) P(Japan∣C) 都为0,这是不合理的。如果词频列表里面有很多出现次数都为0,很可能计算结果都为零。
主要还是因为样本数量太少了,不具有普遍性和规律性。
解决方法:拉普拉斯平滑系数
P ( F 1 ∣ C ) = N i + α N + α m P(F1|C) = \frac{N_i + \alpha}{N + \alpha m} P(F1∣C)=N+αmNi+α
其中:
- α \alpha α 为指定的系数,一般为1
- m m m 为训练文档中统计出的特征词个数(重复只计算一次)
这个文章是需要计算是不是China类:
首先计算是China类的概率:0.0003
P ( C h i n e s e ∣ C ) = 5 8 → 5 + 1 8 + 6 = 6 14 P ( T o k y o ∣ C ) = 0 8 → 0 + 1 8 + 6 = 1 14 P ( J a p a n ∣ C ) = 0 8 → 0 + 1 8 + 6 = 1 14 \begin{aligned} & P(Chinese|C) = \frac{5}{8} \rightarrow \frac{5 + 1}{8 + 6} = \frac{6}{14}\\ & P(Tokyo|C) = \frac{0}{8} \rightarrow \frac{0 + 1}{8 + 6} = \frac{1}{14}\\ & P(Japan|C)= \frac{0}{8} \rightarrow \frac{0 + 1}{8 + 6} = \frac{1}{14}\\ \end{aligned} P(Chinese∣C)=85→8+65+1=146P(Tokyo∣C)=80→8+60+1=141P(Japan∣C)=80→8+60+1=141
m m m 为训练集中特征词的个数,重复不计,这里为6
接着计算不是China类的概率:0.0001
P ( C h i n e s e ∣ C ) = 1 3 → 1 + 1 3 + 6 = 2 9 P ( T o k y o ∣ C ) = 1 3 → 1 + 1 3 + 6 = 2 9 P ( J a p a n ∣ C ) = 1 3 → 1 + 1 3 + 6 = 2 9 \begin{aligned} & P(Chinese|C) = \frac{1}{3} \rightarrow \frac{1+1}{3+6} = \frac{2}{9}\\ & P(Tokyo|C)= \frac{1}{3} \rightarrow \frac{1+1}{3+6} = \frac{2}{9}\\ & P(Japan|C)= \frac{1}{3} \rightarrow \frac{1+1}{3+6} = \frac{2}{9}\\ \end{aligned} P(Chinese∣C)=31→3+61+1=92P(Tokyo∣C)=31→3+61+1=92P(Japan∣C)=31→3+61+1=92
0.0003 > 0.0001 0.0003 > 0.0001 0.0003>0.0001,所以我们认为文章属于China的概率大一些。
小结:
- 概率【了解】:一件事情发生的可能性
- 联合概率【知道】:包含多个条件,且所有条件同时成立的概率
- 条件概率【知道】:事件 A 在另外一个事件 B 已经发生条件下的发生概率
- 贝叶斯公式【掌握】: P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A|B) = P(B|A)\frac{P(A)}{P(B)} P(A∣B)=P(B∣A)P(B)P(A)
3. 案例:商品评论情感分析
学习目标:
- 应用朴素贝叶斯 API 实现商品评论情感分析
3.1 API 介绍
sklearn.naive_bayes.MultinomialINB(alpha=1.0)
- 作用:
sklearn.naive_bayes.MultinomialNB
是一个朴素贝叶斯分类器,适用于具有离散特征的分类,例如文本分类中的单词计数。多项式分布通常需要整数特征计数。但是,在实践中,分数计数(如tf-idf)也可以工作。 - 参数:
alpha
:浮点型或形状为(n_features,)的数组,可选,默认为1.0。添加(拉普拉斯/ Lidstone)平滑参数(设置alpha = 0和force_alpha = True,以获得无平滑)。fit_prior
:布尔型,可选,默认为True。是否学习类先验概率。如果为false,则将使用均匀先验。class_prior
:形状为(n_classes,)的数组,可选,默认为None。类的先验概率。如果指定,则根据数据不调整先验概率。
- 方法:
fit(X, y[, sample_weight])
:根据X,y拟合朴素贝叶斯分类器。
3.2 商品评论情感分析
数据集创建如下:
{"Unnamed: 0":{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"11":11,"12":12},"\u5185\u5bb9":{"0":"\u4ece\u7f16\u7a0b\u5c0f\u767d\u7684\u89d2\u5ea6\u770b\uff0c\u5165\u95e8\u6781\u4f73\u3002","1":"\u5f88\u597d\u7684\u5165\u95e8\u4e66\uff0c\u7b80\u6d01\u5168\u9762\uff0c\u9002\u5408\u5c0f\u767d\u3002","2":"\u8bb2\u89e3\u5168\u9762\uff0c\u8bb8\u591a\u5c0f\u7ec6\u8282\u90fd\u6709\u987e\u53ca\uff0c\u4e09\u4e2a\u5c0f\u9879\u76ee\u53d7\u76ca\u532a\u6d45\u3002","3":"\u524d\u534a\u90e8\u5206\u8bb2\u6982\u5ff5\u6df1\u5165\u6d45\u51fa\uff0c\u8981\u8a00\u4e0d\u70e6\uff0c\u5f88\u8d5e","4":"\u770b\u4e86\u4e00\u904d\u8fd8\u662f\u4e0d\u4f1a\u5199\uff0c\u6709\u4e2a\u6982\u5ff5\u800c\u5df2","5":"\u4e2d\u89c4\u4e2d\u77e9\u7684\u6559\u79d1\u4e66\uff0c\u96f6\u57fa\u7840\u7684\u770b\u4e86\u4f9d\u65e7\u770b\u4e0d\u61c2","6":"\u5185\u5bb9\u592a\u6d45\u663e\uff0c\u4e2a\u4eba\u8ba4\u4e3a\u4e0d\u9002\u5408\u6709\u5176\u5b83\u8bed\u8a00\u7f16\u7a0b\u57fa\u7840\u7684\u4eba","7":"\u7834\u4e66\u4e00\u672c","8":"\u9002\u5408\u5b8c\u5b8c\u5168\u5168\u7684\u5c0f\u767d\u8bfb\uff0c\u6709\u5176\u4ed6\u8bed\u8a00\u7ecf\u9a8c\u7684\u53ef\u4ee5\u53bb\u770b\u522b\u7684\u4e66\u3002","9":"\u57fa\u7840\u77e5\u8bc6\u5199\u7684\u633a\u597d\u7684!","10":"\u592a\u57fa\u7840","11":"\u7565_\u55e6\u3002\u3002\u9002\u5408\u5b8c\u5168\u6ca1\u6709\u7f16\u7a0b\u7ecf\u9a8c\u7684\u5c0f\u767d","12":"\u771f\u7684\u771f\u7684\u4e0d\u5efa\u8bae\u4e70"},"\u8bc4\u4ef7":{"0":"\u597d\u8bc4","1":"\u597d\u8bc4","2":"\u597d\u8bc4","3":"\u597d\u8bc4","4":"\u5dee\u8bc4","5":"\u5dee\u8bc4","6":"\u5dee\u8bc4","7":"\u5dee\u8bc4","8":"\u5dee\u8bc4","9":"\u597d\u8bc4","10":"\u5dee\u8bc4","11":"\u5dee\u8bc4","12":"\u5dee\u8bc4"}}
复制上述JSON代码,保存到本地,然后使用pd.read_json()
方法读取即可。
3.2.1 步骤分析
- 获取数据
- 数据基本处理
- 取出内容列,对数据进行分析
- 判定评判标准
- 选择停用词
- 把内容转化成标准格式
- 统计词的个数
- 准备训练集和测试集
- 模型训练
- 模型评估
3.2.2 代码实现
import pandas as pd
import numpy as np
import jieba
import matplotlib.pyplot as plt
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
3.2.2.1 获取数据
# 1. 获取数据
data = pd.read_csv("./data/书籍评价.csv", encoding='gbk')
3.2.2.2 数据基本处理
# 2. 数据基本处理
## 2.1 取出内容列,对数据进行分析
content = data["内容"]
content.head()
0 从编程小白的角度看,入门极佳。
1 很好的入门书,简洁全面,适合小白。
2 讲解全面,许多小细节都有顾及,三个小项目受益匪浅。
3 前半部分讲概念深入浅出,要言不烦,很赞
4 看了一遍还是不会写,有个概念而已
Name: 内容, dtype: object
## 2.2 选择停用词
# 加载停用词
stopwords = []
with open("./data/stopwords.txt", 'r', encoding="utf-8") as f:
lines = f.readlines()
for tmp in lines:
line = tmp.strip()
stopwords.append(line)
stopwords
['!',
'"',
'#',
'$',
'%',
'&',
"'",
'(',
...
'当着',
'形成',
'彻夜',
'彻底',
'彼',
'彼时',
...]
停用词大全:https://blog.csdn.net/Dorisi_H_n_q/article/details/82114913
## 2.3 把“内容”转换为标准格式
comment_lst = []
for tmp in content:
print("原始数据:", tmp)
# 通过结巴分词对文本数据进行切割(把一句句话变成一个个词)
seg_lst = jieba.cut(tmp, cut_all=False)
print("切割后的数据", seg_lst)
# 拼接字符串
seg_str = ','.join(seg_lst)
print("拼接后的字符串:", seg_str)
comment_lst.append(seg_str)
print()
comment_lst
原始数据: 从编程小白的角度看,入门极佳。
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAD070>
拼接后的字符串: 从,编程,小白,的,角度看,,,入门,极佳,。
原始数据: 很好的入门书,简洁全面,适合小白。
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAD4D0>
拼接后的字符串: 很,好,的,入门,书,,,简洁,全面,,,适合,小白,。
原始数据: 讲解全面,许多小细节都有顾及,三个小项目受益匪浅。
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCADD90>
拼接后的字符串: 讲解,全面,,,许多,小,细节,都,有,顾及,,,三个,小,项目,受益匪浅,。
原始数据: 前半部分讲概念深入浅出,要言不烦,很赞
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC7B0>
拼接后的字符串: 前半部,分讲,概念,深入浅出,,,要言不烦,,,很赞
原始数据: 看了一遍还是不会写,有个概念而已
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAD700>
拼接后的字符串: 看,了,一遍,还是,不会,写,,,有个,概念,而已
原始数据: 中规中矩的教科书,零基础的看了依旧看不懂
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC580>
拼接后的字符串: 中规中矩,的,教科书,,,零,基础,的,看,了,依旧,看不懂
原始数据: 内容太浅显,个人认为不适合有其它语言编程基础的人
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC0B0>
拼接后的字符串: 内容,太,浅显,,,个人,认为,不,适合,有,其它,语言,编程,基础,的,人
原始数据: 破书一本
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC040>
拼接后的字符串: 破书,一本
原始数据: 适合完完全全的小白读,有其他语言经验的可以去看别的书。
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAD2A0>
拼接后的字符串: 适合,完完全全,的,小白读,,,有,其他,语言,经验,的,可以,去,看,别的,书,。
原始数据: 基础知识写的挺好的!
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCADE70>
拼接后的字符串: 基础知识,写,的,挺,好,的,!
原始数据: 太基础
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC120>
拼接后的字符串: 太,基础
原始数据: 略_嗦。。适合完全没有编程经验的小白
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC430>
拼接后的字符串: 略,_,嗦,。,。,适合,完全,没有,编程,经验,的,小白
原始数据: 真的真的不建议买
切割后的数据 <generator object Tokenizer.cut at 0x00000200FBCAC350>
拼接后的字符串: 真的,真的,不,建议,买
['从,编程,小白,的,角度看,,,入门,极佳,。',
'很,好,的,入门,书,,,简洁,全面,,,适合,小白,。',
'讲解,全面,,,许多,小,细节,都,有,顾及,,,三个,小,项目,受益匪浅,。',
'前半部,分讲,概念,深入浅出,,,要言不烦,,,很赞',
'看,了,一遍,还是,不会,写,,,有个,概念,而已',
'中规中矩,的,教科书,,,零,基础,的,看,了,依旧,看不懂',
'内容,太,浅显,,,个人,认为,不,适合,有,其它,语言,编程,基础,的,人',
'破书,一本',
'适合,完完全全,的,小白读,,,有,其他,语言,经验,的,可以,去,看,别的,书,。',
'基础知识,写,的,挺,好,的,!',
'太,基础',
'略,_,嗦,。,。,适合,完全,没有,编程,经验,的,小白',
'真的,真的,不,建议,买']
## 2.4 统计词的个数
# 实例化统计词对象
cv = CountVectorizer(stop_words=stopwords)
# 进行词数统计
X = cv.fit_transform(comment_lst) # 计算出各个词语出现的次数
name = cv.get_feature_names_out() # 获取词袋中所有文本的关键字
print(X.toarray()) # 查看词频矩阵
print(name)
[[0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0
0]
[0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0
0]
[0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1
1]
[0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0
0]
[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 1 0
0]
[1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0
0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0
0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0
0]]
['一本' '一遍' '三个' '中规中矩' '依旧' '入门' '内容' '分讲' '前半部' '受益匪浅' '基础' '基础知识' '完完全全'
'小白' '小白读' '建议' '很赞' '教科书' '有个' '极佳' '概念' '浅显' '深入浅出' '看不懂' '真的' '破书'
'简洁' '细节' '经验' '编程' '要言不烦' '角度看' '讲解' '语言' '适合' '项目' '顾及']
## 2.5 准备训练集和测试集(因为总共才13条数据,因此我们手动分训练集和测试集就行,不用sklearn的方法了)
# 准备训练集
x_train = X.toarray()[:10, :]
y_train = data["评价"][:10]
# 准备测试集
x_test = X.toarray()[10:, :]
y_test = data["评价"][10:]
print("训练集:\r\n", x_train, "\r\n", y_train)
print("测试集:\r\n", x_test, "\r\n", y_test)
训练集:
[[0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0
0]
[0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0
0]
[0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1
1]
[0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0
0]
[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 1 0
0]
[1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0
0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0]]
0 好评
1 好评
2 好评
3 好评
4 差评
5 差评
6 差评
7 差评
8 差评
9 好评
Name: 评价, dtype: object
测试集:
[[0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0
0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0
0]]
10 差评
11 差评
12 差评
Name: 评价, dtype: object
3.2.2.3 模型训练
# 3. 模型训练
# 构建朴素贝叶斯算法分类器
mnb = MultinomialNB(alpha=1) # alpha为Laplace平滑系数
# 训练数据
mnb.fit(x_train, y_train)
# 预测数据
y_pred = mnb.predict(x_test)
# 预测值与真实值展示
print("预测值:", y_pred)
print("真实值:\r\n", y_test)
预测值:['差评' '差评' '差评']
真实值:
10 差评
11 差评
12 差评
Name: 评价, dtype: object
3.2.2.4 模型评估
score = mnb.score(x_test, y_test)
print("模型准确率为:", score * 100, "%")
模型准确率为: 100.0 %
上述案例中,我们的目标值设置的是汉字,其实对于大型项目而言,最好是设置为数字,这样会好一些。
应用案例:百度AI情感倾向分析
小结:
- 朴素贝叶斯分类
- API:
sklearn.naive_bayes.MultinomialNB(alpha=1.0)
alpha
:拉普拉斯平滑系数
- API:
4. 朴素贝叶斯算法总结
4.1 朴素贝叶斯优缺点
4.1.1 优点
- 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
- 对缺失数据不太敏感,算法也比较简单,常用于文本分类。
- 分类准确度高,速度快
- 它易于实现并且快速预测训练数据集的类别。
- 它在多类预测中表现良好。
- 当假设独立变量时,它的表现优于其他模型,如逻辑回归。
- 它需要较少的训练数据。
- 它在分类离散输入变量时表现优于数值变量。
4.1.2 缺点
- 由于使用了样本属性独立性的假设,所以如果特征属性有关联时其效果不好
- 需要计算先验概率,而先验概率很多时候取决于假设。假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。
- 它假设所有特征之间都是独立的,这在现实生活中并不总是成立的。这种假设可能会影响算法的准确性。
- 它对于具有连续特征的数据集可能不太适用。
4.2 朴素贝叶斯内容汇总
4.2.1 原理
朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。
- 对于给定的待分类项 x x x,通过学习到的模型计算后验概率分布
- 即:在此项出现的条件下各个目标类别出现的概率,将后验概率最大的类作为 x x x 所属的类别。
Q:什么叫做先验,什么叫做后验?
A:先验概率(prior probability)是指在考虑新证据之前,我们对某个假设的不确定性的度量。它通常基于以往的经验或背景知识得出。
后验概率(posterior probability)是指在考虑新证据之后,我们对某个假设的不确定性的度量。它是根据贝叶斯定理计算出来的,结合了先验概率和新证据的可能性。
举个例子,假设你想知道明天是否会下雨。你知道这个季节下雨的概率是30%,所以你的先验概率是30%。然后你看了天气预报,发现预报说明天有90%的概率会下雨。你可以使用贝叶斯定理来结合这两个信息,计算出明天下雨的后验概率。
4.2.2 朴素贝叶斯朴素在哪里?
在计算条件概率分布 P ( X = x ∣ Y = c k ) P(X=x | Y=c_k) P(X=x∣Y=ck) 时,朴素贝叶斯引入了一个很强的条件独立假设,即,当 Y Y Y 确定时, X X X 的各个特征分量取值之间相互独立。
朴素贝叶斯算法之所以被称为“朴素”,是因为它假设所有特征之间都是相互独立的。这意味着,它假设每个特征对分类结果的影响都是独立的,不受其他特征的影响。
然而,在现实生活中,这种假设并不总是成立的。特征之间可能存在相关性,这可能会影响算法的准确性。尽管如此,朴素贝叶斯算法仍然在许多应用中表现良好。
4.2.3 为什么引入条件独立性假设?
为了避免贝叶斯定理求解时面临的组合爆炸、样本稀疏问题。
假设条件概率分为:
P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , x ( 2 ) , . . . , x ( n ) ∣ Y = c k ) P(X=x|Y=c_k) = P(X^{(1)} = x^{(1)}, x^{(2)}, ..., x^{(n)} | Y=c_k) P(X=x∣Y=ck)=P(X(1)=x(1),x(2),...,x(n)∣Y=ck)
其中: x ( j ) x^{(j)} x(j) 可能取值有 S j S_j Sj 个, j = 1 , 2 , . . . , n j = 1,2,..., n j=1,2,...,n, Y Y Y 可能取值有 K K K 个,那么参数个数为 K ∏ j = 1 m S j K \prod^m_{j=1}S_j K∏j=1mSj 个,这就导致条件概率分布的参数数量为指数级别。
朴素贝叶斯算法引入条件独立性假设,是为了简化计算。根据贝叶斯定理,我们需要计算每个类别的后验概率,然后选择具有最大后验概率的类别作为预测结果。为了计算后验概率,我们需要计算联合概率分布,即所有特征同时发生的概率。
如果不引入条件独立性假设,则计算联合概率分布需要考虑所有特征之间的相关性,这会使计算变得非常复杂。但是,如果我们假设所有特征之间都是条件独立的,则可以将联合概率分布简化为每个特征的概率的乘积,这大大简化了计算。
尽管条件独立性假设在现实生活中并不总是成立,但朴素贝叶斯算法仍然在许多应用中表现良好。
4.2.4 在估计条件概率 P ( X ∣ Y ) P(X|Y) P(X∣Y) 时出现概率为 0 的情况怎么办?
在估计条件概率 P(X∣Y) 时,如果出现概率为0的情况,会导致整个后验概率为0。为了避免这种情况,可以使用平滑技术来调整概率估计。
简单来说,引入 λ \lambda λ:
- 当 λ = 0 \lambda=0 λ=0 时,就是普通的极大似然估计
- 当 λ = 1 \lambda=1 λ=1 时称为拉普拉斯平滑
4.2.5 为什么属性独立性假设在实际情况中很难成立,但朴素贝叶斯仍能取得较好的效果?
人们在使用分类器之前,首先做的第一步(也是最重要的一步)往往是特征选择,这个过程的目的就是为了排除特征之间的共线性,即选择相对较为独立的特征。
对于分类任务来说,只要各类别的条件概率排序正确,无需精准概率值就可以得出正确分类。如果属性间依赖对所有类别影响相同,或依赖关系的影响能相互抵消,则属性条件独立性假设在降低计算复杂度的同时不会对性能产生负面影响。
尽管朴素贝叶斯算法的属性独立性假设在实际情况中很难成立,但它仍然能够在许多应用中取得较好的效果。这主要是因为朴素贝叶斯算法的目标是选择具有最大后验概率的类别,而不是准确地估计后验概率。
即使属性之间存在相关性,朴素贝叶斯算法仍然能够在大多数情况下正确地对类别进行排序。这意味着,具有最大后验概率的类别通常仍然是正确的类别,即使后验概率的绝对值并不准确。
此外,朴素贝叶斯算法通常在数据量较大时表现良好。当数据量足够大时,算法能够从数据中学习到足够的信息来弥补属性独立性假设的不足。
4.2.6 朴素贝叶斯与逻辑回归(LR)的区别
朴素贝叶斯和逻辑回归(LR)都是常用的分类算法,但它们之间存在一些重要的区别。
- 模型类型:朴素贝叶斯是一种生成模型,它试图学习每个类别的概率分布以及每个特征与类别之间的关系。逻辑回归是一种判别模型,它试图学习一个决策边界来直接区分不同的类别。
- 假设:朴素贝叶斯假设所有特征之间都是条件独立的,这使得计算变得简单,但也可能影响算法的准确性。逻辑回归没有这种假设,因此可以更好地处理特征之间存在相关性的情况。
- 数据需求:朴素贝叶斯通常需要较少的数据就能取得较好的效果,而逻辑回归则需要更多的数据来准确地估计模型参数。
区别一:朴素贝叶斯是生成模型,而 LR 是判别模型。
朴素贝叶斯:
- 根据已有样本进行贝叶斯估计学习出先验概率 P ( Y ) P(Y) P(Y) 和条件概率 P ( X ∣ Y ) P(X|Y) P(X∣Y),进而求出联合分布概率 P ( X Y ) P(XY) P(XY)
- 最后利用贝叶斯定理求解 P ( Y ∣ X ) P(Y|X) P(Y∣X)
逻辑回归LR:
- 根据极大化对数似然函数直接求出条件概率 P ( Y ∣ X ) P(Y|X) P(Y∣X)
从概率框架的角度来理解机器学习,主要有两种策略:
- 第一种:给定 x x x,可通过直接建模 P ( c ∣ x ) P(c|x) P(c∣x) 来预测 c c c,这样得到的是“判别式模型”(Discriminative Models)
- 第二种:也可先对联合概率分布 P ( x , c ) P(x, c) P(x,c) 建模,然后再由此获得 P ( c ∣ x ) P(c|x) P(c∣x),这样得到的是“生成式模型”(Generative Models)
显然,前面介绍的逻辑回归、决策树都可归入判别式模型的范畴,还有后面学到的 BP 神经网络、支持向量机等。
对生成式模型来说,必然需要考虑 P ( c ∣ x ) = P ( x , c ) P ( x ) P(c|x) = \frac{P(x, c)}{P(x)} P(c∣x)=P(x)P(x,c)
区别二:
- 朴素贝叶斯是基于很强的条件独立假设(在已知分类 Y Y Y 的条件下,各个特征变量取值是相互独立的)
- 而 LR 则对此没有要求
区别三:
- 朴素贝叶斯适用于数据集少的情景
- 而 LR 适用于大规模数据集
进一步说明:
前者是生成式模型,后者是判别式模型,二者的区别就是生成式模型与判别式模型的区别。
首先,Naive Bayes通过已知样本求得先验概率 P ( Y ) P(Y) P(Y) 及条件概率 P ( X ∣ Y ) P(X|Y) P(X∣Y)。对于给定的实例,计算联合概率,进而求出后验概率。也就是说,它尝试去找到底这个数据是怎么生成的(产生的),然后再进行分类。哪个类别最有可能产生这个信号,就属于那个类别。
优点:
- 样本容量增加时,收敛更快
- 隐变量存在时也可适用
缺点:
- 时间长
- 需要样本多
- 浪费计算资源
相比之下,LR 不关心样本中类别的比例及类别下出现特征的概率,它直接给出预测模型的式子。设每个特征都有一个权重,训练样本数据更新权重 w w w,得出最终表达式。
优点:
- 直接预测往往准确率更高
- 简化问题
- 可以反应数据的分布情况和类别的差异特征
- 适用于较多类别的识别
缺点:
- 收敛慢
- 不适用于有隐变量的情况