公式
Bayes公式:
是联合概率,表示x,c同时发生的概率
是条件概率,表示c出现的条件下, x出现的概率
考虑分类的问题,表示第j种类别。
假设x为特征向量, 表示特征向量为x时,样本属于类别
的概率。
表示j类中特征量为x的概率。
假设x的n个分量是不相关的,则有 。
表示第j类中特征分量为第i个的概率。
那么有:
具有特征量x的样本属于第j类的概率等于第j类的概率与第j类中特征量为x的概率之积。
例子
现在我们用一个例子来演示一下。
样本 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
厚薄 | 厚 | 厚 | 薄 | 薄 | 厚 | 薄 | 薄 | 厚 |
甜咸 | 甜 | 咸 | 咸 | 甜 | 咸 | 咸 | 甜 | 甜 |
喜欢 | F | F | T | F | F | T | F | F |
那我们来计算下X = (厚,甜) 属于 F 的概率, 以及它属于T的概率。 先算前者(我们只计算分子就可以了)。
不喜欢的样本共有6个,其中4个为厚的,4个为甜的。
= 6/8
= 4/6 * 4/6
= 6/8 * 4/6 * 4/6
然后我们来计算下X = (厚,甜) 属于 T 的概率。
不喜欢的样本共有6个,其中4个为厚的,4个为甜的。
= 2/8
= 0 * 0
= 2/8 * 0 = 0
很显然,它属于F的概率大于属于T的概率,我们判断厚而甜的比萨是某人不喜欢的。
训练过程
对这种离散型的分类问题,我们可以描述为:
假设样本有个属性值,记为
, 其中
表示其中第
个属性值是否为真。 那么
个样本的属性构成矩阵
。
对于上面的样本例子,我们用python 的array记为
##X有属性值 厚,薄,甜,咸
##样本矩阵记为, 每一行为一个样本的属性值向量
X = np.array([[1,0,1,0],
[1,0,0,1],
[0,1,0,1],
[0,1,1,0],
[1,0,0,1],
[0,1,0,1],
[0,1,1,0],
[1,0,1,0]])
假设类别有个类, 记为
, 其中
表示其中第
个类的值(0或1)。
的分量中应该有且有一个的值为1,其余为0。
# 喜欢,不喜欢
In [43]: Y = np.array([[0,1],
...: [0,1],[1,0],[0,1],[0,1],[1,0],[0,1],[0,1]])
样本属于第个类的概率为
。
In [46]: Y.sum(axis=0)*1.0/Y.shape[0] ##按列求和
Out[46]: array([ 0.25, 0.75])
##样本中有0.25为喜欢, 0.75为不喜欢
第个类值为1的条件下,属性
的值为1的概率计算步骤如下:
- 找出属于第c个类的所有样本
#获取属于第c类的所有样本
F = (Y == 1)
S = X[F[:,c]]
- 遍历所有的类别,统计属于各个类别的样本中,属性
的值为1的样本个数K与总数的比值。
M = np.zeros((Y.shape[1],X.shape[1]))
for i in range(Y.shape[1]):
S = X[F[:, i]] #获取属于第i类的样本
#计算属于第i类的样本中,各个属性值的条件概率
M[i] = S.sum(axis=0) / (1.0 * S.shape[0])
python 代码
# -*- coding: utf-8 -*-
import numpy as np
class NaiveBayes:
def __init__(self):
self.M = None
self.Pc = None
def fit(self,X:np.array,Y:np.array):
XRows, XCols = X.shape
YRows, YCols = Y.shape
## XRows = YRows 代表样本数量
## XCols 代表特征向量分量数目
## YCols 代表类别数
## 计算每个类别的概率 P(Yi) 0 < i < Y.shape[0]
## 按列(沿着0轴)求和 然后除以总数
## 类别概率矩阵
self.Pc = Y.sum(axis=0)/(1.0* YRows)
## 条件概率矩阵
self.M = np.zeros((YCols,XCols))
## 类别真值表
F = (Y == 1)
## 计算每个类别的每个特征分量的条件概率 P(Xi|Yi)
for i in range(YCols):
## F[:, i] 标记属于第i个类别的index
a = X[F[:, i]] ## 表示属于第i类的样本特征向量
## 属于第i类的各个特征分量的概率
self.M[i] = a.sum(axis=0) / (1.0 * a.shape[0])
def predict(self,x:np.array)->(int, float):
## 计算向量对应的条件概率
T = self.M[:,(x==1)]
## 计算联合P(x|Yi)
C = (T.prod(axis=1))
## 计算条件概率P(Yi|x) = P(Yi)P(x|Yi)/P(x); P(x) 可以不用参与计算了。
## 因为我们只要比较概率的大小关系,不需要概率的值。
P = self.Pc*C
idx = np.argmax(P)
return (idx,P[idx]/P.sum())
if __name__ == "__main__":
## 特征向量(例子有4个分量), 如果为1则表示该分量为真
X = np.array(
[[1, 0, 1, 0],
[1, 0, 0, 1],
[0, 1, 0, 1],
[0, 1, 1, 0],
[1, 0, 0, 1],
[0, 1, 0, 1],
[0, 1, 1, 0],
[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 1, 1, 0],
])
## 类别向量, 如果为1则表示属于该类
## 类别向量只能有一个分量为1。
Y = np.array( [ [0,1],
[0,1],
[1,0],
[0,1],
[0,1],
[1,0],
[1,0],
[0,1],
[1,0],
[1,0]])
x = np.array([0,1,1,0])
nbayes = NaiveBayes()
nbayes.fit(X,Y)
idx,confidence = nbayes.predict(x)
print("类别index=",idx, "可信度:",round(confidence,2))