定义
在机器学习中,贝叶斯分类器是一种简单的概率分类器,它基于应用贝叶斯定理。朴素贝叶斯分类器使用的特征模型做出了很强的独立性假设。这意味着一个类的特定特征的存在与其他所有特征的存在是独立的或无关的。
独立事件的定义:
两个事件 E 和 F 是独立的,如果 E 和 F 都有正概率并且如果 P(E|F) = P(E) 和 P(F|E) = P(F)
正如我们在定义中所述,朴素贝叶斯分类器基于贝叶斯定理。贝叶斯定理基于条件概率,我们现在将定义:
条件概率
磷(一个|乙)代表“A 的条件概率给定 B”,或“A 在条件 B 下的概率”,即在假设事件 B 发生的情况下某个事件 A 的概率。当在随机实验中已知事件 B 已经发生时,实验的可能结果减少到 B,因此 A 发生的概率从无条件概率变为给定 B 的条件概率。 联合概率是两个事件同时发生的概率。也就是说,它是两个事件一起发生的概率。A 和 B 的联合概率有 3 种记法,可以写成
- 磷(一个∩乙)
- 磷(一个乙) 或者
- 磷(一个,乙)
条件概率定义为
磷(一个|乙)=磷(一个∩乙)磷(乙)
条件概率示例
德语瑞士演讲者
大约有 840 万人居住在瑞士。大约 64% 的人会说德语。地球上大约有75亿人。
如果一些外星人随机地向地球人发出光芒,那么他是说德语的瑞士人的可能性有多大?
我们有活动
S:是瑞士人
GS:德语口语
随机选择的人是瑞士人的概率:
磷(秒)=8.47500=0.00112
如果我们知道某人是瑞士人,说德语的概率是 0.64。这对应于条件概率
磷(G秒|秒)=0.64
所以地球人是瑞士人说德语的概率,可以用下面的公式计算:
磷(G秒|秒)=磷(G秒∩秒)磷(秒)
插入上面的值给我们:
0.64=磷(G秒∩秒)0.00112
和
磷(G秒∩秒)=0.0007168
因此,我们的外星人最终有 0.07168 % 的机会成为讲德语的瑞士人。
假阳性和假阴性
一家医学研究实验室提议进行一项筛查,以测试一大群人是否患有某种疾病。反对这种筛选的一个论点是假阳性筛选结果的问题。
假设该组中有 0.1% 的人患有这种疾病,其余的人都很好:
磷(”秒一世C克”)=0,1
和
磷(”瓦电子升升”)=99,9
以下是筛选测试的真实情况:
如果您患有这种疾病,则测试结果有 99% 的时间会呈阳性,如果您没有患病,则测试结果有 99% 的时间会呈阴性:
P(“测试阳性”|“很好”)= 1 %
和
P(“测试阴性”|“很好”)= 99 %。
最后,假设当测试应用于患有这种疾病的人时,有 1% 的机会出现假阴性结果(并且有 99% 的机会得到真阳性结果),即
P("测试阴性" | "生病") = 1 %
和
P("测试阳性" | "生病") = 99 %
生病的 | 健康 | 总计 | |
---|---|---|---|
检测结果阳性 | 99 | 999 | 1098 |
测试结果阴性 | 1 | 98901 | 98902 |
总计 | 100 | 99900 | 100000 |
有 999 个误报和 1 个误报。
问题:
在许多情况下,甚至医疗专业人员都认为“如果您患有这种疾病,则检测结果在 99% 的情况下会呈阳性,如果您没有感染,则检测结果在 99% 的情况下会呈阴性。在 1098仅报告阳性结果的病例 99 (9 %) 例是正确的,999 例是假阳性 (91 %),即如果一个人的检测结果呈阳性,则他或她实际患有该疾病的概率仅为 9 % . P("生病" | "测试阳性") = 99 / 1098 = 9.02 %
贝叶斯定理
我们计算了条件概率 磷(G秒|秒),这是一个人说德语的概率,如果他或她被称为瑞士人。为了计算这一点,我们使用了以下等式:
磷(G秒|秒)=磷(G秒,秒)磷(秒)
如何计算概率 磷(秒|G秒),即假设某人说德语的情况下某人是瑞士人的概率?
该等式如下所示:
磷(秒|G秒)=磷(G秒,秒)磷(G秒)
让我们隔离两个方程 磷(G秒,秒):
磷(G秒,秒)=磷(G秒|秒)磷(秒)磷(G秒,秒)=磷(秒|G秒)磷(G秒)
由于左侧相等,因此右侧也必须相等:
磷(G秒|秒)*磷(秒)=磷(秒|G秒)磷(G秒)
这个方程可以转化为:
磷(秒|G秒)=磷(G秒|秒)磷(秒)磷(G秒)
结果符合贝叶斯定理
为了解决我们的问题,即一个人是瑞士人的概率,如果我们知道他或她说德语——我们所要做的就是计算右边。我们从之前的练习中已经知道
磷(G秒|秒)=0.64
和
磷(秒)=0.00112
世界上以德语为母语的人数相当于 1.01 亿,所以我们知道
磷(G秒)=1017500=0.0134667
最后,我们可以计算 磷(秒|G秒) 通过替换我们方程中的值:
磷(秒|G秒)=磷(G秒|秒)磷(秒)磷(G秒)=0.64*0.001120.0134667=0.0532276
大约有 840 万人居住在瑞士。大约 64% 的人会说德语。地球上大约有75亿人。
如果一些外星人随机地向地球人发出光芒,那么他是说德语的瑞士人的可能性有多大?
我们有活动
秒: 瑞士人 G秒: 德语
磷(秒)=8.47500=0.00112磷(一个|乙)=磷(乙|一个)磷(一个)磷(乙)
磷(一个|乙) 是条件概率 一个,给定 乙 (后验概率), 磷(乙) 是先验概率 乙 和 磷(一个) 的先验概率 一个. 磷(乙|一个) 是条件概率 乙 给予 一个,称为可能性。
朴素贝叶斯分类器的一个优点是它只需要少量的训练数据来估计分类所需的参数。因为假设了自变量,所以只需要确定每个类的变量的方差,而不是整个协方差矩阵。
入门练习
让我们踏上火车之旅,创建我们的第一个非常简单的朴素贝叶斯分类器。假设我们在汉堡市,我们想前往慕尼黑。我们将不得不在美因河畔法兰克福换乘火车。我们从以前的火车旅行中知道,我们从汉堡出发的火车可能会晚点,我们将赶不上法兰克福的转机火车。我们无法赶上接驳列车的可能性取决于我们可能的延误有多高。接驳列车的等待时间不会超过五分钟。有时另一列火车也会晚点。
以下列表“in_time”(从汉堡出发的火车及时到达以赶上前往慕尼黑的连接火车)和“too_late”(错过连接火车)是显示几周内情况的数据。每个元组的第一个组件显示火车晚点的分钟数,第二个组件显示发生这种情况的时间。
# 元组包括(train1 的延迟时间,次数)# 元组是 (分钟, 次数)
in_time = [( 0 , 22 ), ( 1 , 19 ), ( 2 , 17 ), ( 3 , 18 ), ( 4 , 16 ), ( 5 , 15 ), ( 6 , 9 ), ( 7 , 7 ), ( 8 , 4 ), ( 9 , 3 ), ( 10 , 3), ( 11 , 2 )]
too_late = [( 6 , 6 ), ( 7 , 9 ), ( 8 , 12 ), ( 9 , 17 ), ( 10 , 18 ), ( 11 , 15 ), ( 12 , 16 ), ( 13 , 7 ), ( 14 , 8 ), ( 15 , 5 )]
% matplotlib内联导入 matplotlib.pyplot 作为 pltX , Y = zip ( * in_time )X2 , Y2 = zip ( * too_late )bar_width = 0.9
plt 。bar ( X , Y , bar_width , color = "blue" , alpha = 0.75 , label = "in time" )
bar_width = 0.8
plt . bar ( X2 , Y2 , bar_width , color = "red" , alpha = 0.75 , label = "too late" )
plt . 传奇( loc = '右上角' )
plt 。显示()
从这个数据我们可以推断出,如果我们迟到一分钟,赶上接驳列车的概率是 1,因为我们有 19 个成功案例并且没有错过,即在 'too_late' 中没有以 1 作为第一个组件的元组。
我们将表示事件“火车及时到达以赶上连接的火车” 秒 (成功)和“不幸”事件“火车来得太晚,无法赶上连接的火车” 米 (错过)
我们现在可以正式定义“因为我们迟到 1 分钟而赶上火车”的概率:
磷(秒|1)=19/19=1
我们使用了元组的事实 (1,19) 在 'in_time' 中,并且在 'too_late' 中没有第一个组件 1 的元组
如果我们迟到 6 分钟,那么赶上前往慕尼黑的联运火车就变得至关重要了。然而,机会仍然是 60%:
磷(秒|6)=9/9+6=0.6
因此,知道我们迟到 6 分钟而错过火车的概率是:
磷(米|6)=6/9+6=0.4
我们可以编写一个“分类器”函数,它会给出赶上连接列车的概率:
in_time_dict = dict ( in_time )
too_late_dict = dict ( too_late )def catch_the_train ( min ): s = in_time_dict 。get ( min , 0 )如果 s == 0 :返回 0否则:m = too_late_dict 。get ( min , 0 )返回 s / ( s + m )对于 分钟 在 范围(- 1 , 13 ):打印(分钟, catch_the_train (分钟))
输出:
-1 0
0 1.0
1 1.0
2 1.0
3 1.0
4 1.0
5 1.0
6 0.6
7 0.4375
8 0.25
9 0.15
10 0.14285714285714285
11 0.11764705882352941
12 0
朴素贝叶斯分类器示例
准备好数据
我们将使用一个名为'person_data.txt'的文件。它包含 100 个随机人物数据,男性和女性,带有体型、体重和性别标签。
将 numpy 导入为 np性别 = [ “男” , “女” ]
人 = []
与 打开(“数据/ person_data.txt” ) 作为 FH :用于 线 在 FH :人。追加(行。带()。分裂())firstnames = {}
高度 = {}
为 性别 在 性别:firstnames [性别] = [ X [ 0 ] 为 X 中 的人 如果 X [ 4 ] ==性别]高度[性别] = [ X [ 2 ] 对于 X 在 人 如果 x [ 4 ] ==性别]高度[性别] = np . 数组(高度[性别], np . int )用于 性别 的 (“女性” , “男” ):打印(性别 + “:” )打印(firstnames [性别] [:10 ])打印(高度[性别] [:10 ])
输出:
女性:
[“斯蒂芬妮”、“辛西娅”、“凯瑟琳”、“伊丽莎白”、“卡罗尔”、“克里斯蒂娜”、“贝弗利”、“莎伦”、“丹尼斯”、“丽贝卡”]
[149 174 183 138 145 161 179 162 148 196]
男性:
[“兰迪”、“杰西”、“大卫”、“斯蒂芬”、“杰瑞”、“比利”、“厄尔”、“托德”、“马丁”、“肯尼思”]
[184 175 187 192 204 180 184 174 177 200]
警告:Python 类和朴素贝叶斯类之间可能存在一些混淆。我们尽可能通过明确说明其含义来避免它!
设计要素类
我们现在将为特征定义一个 Python 类“Feature”,稍后我们将使用它进行分类。
Feature 类需要一个标签,例如“heights”或“firstnames”。如果特征值是数字的,我们可能希望将它们“装箱”以减少可能的特征值的数量。我们的人的身高范围很大,我们的朴素贝叶斯类“男性”和“女性”只有 50 个测量值。我们将通过将 bin_width 设置为 5 将它们分为“130 到 134”、“135 到 139”、“140 到 144”等范围。没有办法对名字进行分箱,因此 bin_width 将设置为 None。
方法频率返回特定特征值或分箱范围的出现次数。
from collections import Counter
import numpy as np课程 特点:def __init__ ( self , data , name = None , bin_width = None ): self 。姓名 = 姓名自我。bin_width = bin_width如果 bin_width : self 。分钟, 自我。max = min ( data ), max ( data ) bins = np 。范围((自我。分钟 // bin_width ) * bin_width , (自我。最大 // bin_width ) * bin_width ,bin_width )频率, 仓 = NP 。直方图(数据, 箱)自我。freq_dict = dict ( zip ( bins , freq )) self 。freq_sum = sum ( freq ) else : self. freq_dict = dict ( Counter ( data )) self 。freq_sum = 总和(自我。freq_dict 。值())def 频率(self , value ):如果 self 。bin_width : value = ( value // self . bin_width ) * self . bin_width如果 值 在 self 中。freq_dict :返回 self 。freq_dict [值]否则:返回 0
我们现在将为人物数据集的高度值创建两个要素类 Feature。一个要素类包含朴素贝叶斯类“男性”的高度和一类“女性”的高度:
FTS = {}
为 性别 在 性别:FTS [性别] = 特性(高度[性别], 名称=性别, bin_width = 5 )打印(性别, FTS [性别] 。freq_dict )
输出:
男 {160: 5, 195: 2, 180: 5, 165: 4, 200: 3, 185: 8, 170: 6, 155: 1, 190: 8, 175: 7}
女性 {160: 8, 130: 1, 165: 11, 135: 1, 170: 7, 140: 0, 175: 2, 145: 3, 180: 4, 150: 5, 185: 0, } 155: 7
频率分布条形图
我们打印了我们的 bin 的频率,但在条形图中看到这些值要好得多。我们将使用以下代码执行此操作:
对于 性别 中的 性别:频率 = 列表(fts [性别] . freq_dict . items ())频率。排序(键=拉姆达 X : X [ 1 ])X , ÿ = 拉链(*频率)颜色 = “蓝色” 如果 性别== “男性” 其他 “红色” bar_width = 4 ,如果 性别== “男性” 否则 3 plt 。bar ( X , Y , bar_width , 颜色=颜色, alpha = 0.75 , 标签=性别)PLT 。图例(loc = '右上角' )
plt 。显示()
我们现在必须用 Python 设计一个朴素贝叶斯类。我们将其称为 NBclass。一个 NBclass 包含一个或多个要素类。NBclass 的名称将存储在 self.name 中。
类 NBclass :def __init__ ( self , name , * features ): self 。特征 = 特征自我。姓名 = 姓名DEF probability_value_given_feature (自, FEATURE_VALUE ,特征):“”“
p_value_given_feature返回概率P
为特征的FEATURE_VALUE‘值’到occurr
对应于P(d_i | p_j)
其中d_i是特征的特征变量i
‘’”如果 功能。freq_sum == 0 :返回 0 else :返回 特征。频率(FEATURE_VALUE ) / 特征。频率总和
在下面的代码中,我们将创建具有一个特征的 NBclasses,即高度特征。我们将使用我们之前创建的 fts 的要素类:
cls = {}
用于 性别 中的 性别:cls [性别] = NBclass (性别, fts [性别])
创建简单朴素贝叶斯分类器的最后一步是编写一个类“Classifier”,它将使用我们的类“NBclass”和“Feature”。
类 分类器:def __init__ ( self , * nbclasses ): self 。nbclasses = nbclassesdef prob ( self , * d , best_only = True ):nbclasses = self 。nbclasses probability_list = []为 nbclass 在 nbclasses : FTRS = nbclass 。特征prob = 1 for i in range ( len ( ftrs )): prob *= nbclass 。probability_value_given_feature ( d [ i ], ftrs [ i ])概率列表。追加( (概率, nbclass 。名称) )prob_values = [ ˚F [ 0 ] 为 ˚F 在 probability_list ] prob_sum = 总和(prob_values )如果 prob_sum == 0 :number_classes = LEN (自我。nbclasses )PL = []为 prob_element 在 probability_list :PL 。追加( (( 1 / number_classes ), prob_element [ 1]))probability_list = PL否则:probability_list = [ (p [ 0 ] / prob_sum , p [ 1 ]) 为 p 在 probability_list ]如果 best_only :返回 最大值(probability_list )否则:返回 probability_list
我们将创建一个具有一个要素类“高度”的分类器。我们使用 130 到 220 厘米之间的值对其进行检查。
c = 分类器( cls [ "male" ], cls [ "female" ])对于 我 在 范围(130 , 220 , 5 ):打印(我, Ç 。概率(我, best_only =假))
输出:
130 [(0.0, '男'), (1.0, '女')]
135 [(0.0, '男'), (1.0, '女')]
140 [(0.5, '男'), (0.5, '女')]
145 [(0.0,'男性'),(1.0,'女性')]
150 [(0.0, '男'), (1.0, '女')]
155 [(0.125,'男性'),(0.875,'女性')]
160 [(0.38461538461538469, '男'), (0.61538461538461542, '女')]
165 [(0.26666666666666666, '男'), (0.733333333333333328, '女')]
170 [(0.46153846153846162, '男'), (0.53846153846153855, '女')]
175 [(0.77777777777777779, '男'), (0.222222222222222224, '女')]
180 [(0.55555555555555558, '男'), (0.444444444444444448, '女')]
185 [(1.0, '男'), (0.0, '女')]
190 [(1.0, '男'), (0.0, '女')]
195 [(1.0, '男'), (0.0, '女')]
200 [(1.0, '男'), (0.0, '女')]
205 [(0.5, '男'), (0.5, '女')]
210 [(0.5, '男'), (0.5, '女')]
215 [(0.5, '男'), (0.5, '女')]
在我们的学习集中没有人 - 不是男性也不是女性 - 身高在 140 到 144 之间。这就是为什么我们的分类器不能基于学习数据得出结果,因此返回 fify-50 的原因结果。
我们还可以用我们的名字训练一个分类器:
fts = {}
cls = {}
用于 性别 中的 性别:fts_names = Feature (名字[性别], 姓名=性别)cls [性别] = NBclass (性别, fts_names )c = 分类器( cls [ "male" ], cls [ "female" ])testnames = [ '埃德加' , '本杰明' , '弗瑞德, '阿尔伯特' , '劳拉' , 'Maria的, '保' , '沙龙' , '杰西' ]
为 名称 在 testnames :打印(名称, Ç 。问题(名称))
输出:
埃德加(0.5,'男性')
本杰明(1.0,'男性')
弗雷德(1.0,'男性')
阿尔伯特(1.0,'男性')
劳拉(1.0,'女性')
玛丽亚(1.0,'女性')
宝拉(1.0,'女性')
莎伦 (1.0, '女性')
杰西 (0.6666666666666667, '女性')
“杰西”这个名字是一个模棱两可的名字。每 100 个女孩中大约有 66 个男孩使用这个名字。我们可以从之前的分类结果中了解到,“Jessie”这个名字是“女性”的概率大约是三分之二,这是从我们的数据集“人”中计算出来的:
[人 对 人 的 人 ,如果 人[ 0 ] == “杰西” ]
输出:
[['杰西','摩根','175','67.0','男'],['杰西','贝尔','165','65','女性'],['杰西','华盛顿','159','56','女性'],['杰西','戴维斯','174','45','女性'],['杰西'、'约翰逊'、'165'、'30.0'、'男']、['杰西'、'托马斯'、'168'、'69'、'女性']]
杰西华盛顿只有 159 厘米高。如果我们看一下用身高训练的分类器的结果,我们会发现身高 159 厘米的人是“女性”的可能性为 0.875。那么身高 159 厘米、名叫“杰西”的不知名人士呢?这个人是女的还是男的?
为了回答这个问题,我们将训练一个具有两个特征类的朴素贝叶斯分类器,即高度和名字:
cls = {}
用于 性别 中的 性别:fts_heights = Feature ( heights [性别], name = "heights" , bin_width = 5 ) fts_names = Feature ( firstnames [性别], name = "names" )cls [性别] = NBclass (性别, fts_names , fts_heights )c = 分类器( cls [ "male" ], cls [ "female" ])对于 d 在 [( "Maria" , 140 ), ( "Anthony" , 200 ), ( "Anthony" , 153 ), ( "Jessie" , 188 ) , ( "Jessie" , 159 ), ( "Jessie" , 160 ) ]:打印( d , c . prob ( * d , best_only = False ))
输出:
('玛丽亚', 140) [(0.5, '男'), (0.5, '女')]
('安东尼', 200) [(1.0, '男性'), (0.0, '女性')]
('安东尼', 153) [(0.5, '男性'), (0.5, '女性')]
('杰西', 188) [(1.0, '男'), (0.0, '女')]
('杰西', 159) [(0.0666666666666666666, '男性'), (0.933333333333333335, '女性')]
('杰西', 160) [(0.23809523809523817, '男性'), (0.76190476190476197, '女性')]
基本理论
Python学习资源汇总腾讯文档-在线PDFhttps://docs.qq.com/pdf/DR3dMaE1CSkZ6RlBZ
我们上一示例中的分类器基于贝叶斯定理:
磷(Cj|d)=磷(d|Cj)磷(Cj)磷(d)
在哪里
-
磷(Cj|d) 是实例 d 在类 c_j 中的概率,它是我们想要用分类器计算的结果
-
磷(d|Cj) 是生成实例 d 的概率,如果类 Cj 给出
-
磷(Cj) 是类出现的概率 Cj 我们没有在我们的分类器中使用它,因为我们示例中的两个类都有同样的可能性。
- P(d) 是实例 d 出现的概率,计算中不需要,因为对于所有类都是一样的。
在之前的示例中,我们只使用了一个特征,即“高度”或名称。
可以定义具有多个特征的贝叶斯分类器,例如 d=(d1,d2,...,dn)
我们得到以下公式:
磷(Cj|d)=1磷(d)∏一世=1n磷(d一世|Cj)磷(Cj)
1磷(d) 仅取决于值 d1,d2,...dn. 这意味着它是一个常数,因为特征变量的值是已知的。