贝叶斯分类器
前言
朴素贝叶斯算法是有监督的学习算法,解决的是分类问题,如客户是否流失、是否值得投资、信用等级评定等多分类问题。该算法的优点在于简单易懂、学习效率高、在某些领域的分类问题中能够与决策树、神经网络相媲美。但由于该算法以自变量之间的独立(条件特征独立)性和连续变量的正态性假设为前提,就会导致算法精度在某种程度上受影响。
朴素贝叶斯理论
朴素贝叶斯是贝叶斯决策理论的一部分。
贝叶斯决策理论
假设现在我们有一个数据集,它由两类数据组成。
我们现在用p1(x,y)表示数据点(x,y)属于类别1(图中红色圆点表示的类别)的概率,用p2(x,y)表示数据点(x,y)属于类别2(图中蓝色三角形表示的类别)的概率,那么对于一个新数据点(x,y),可以用下面的规则来判断它的类别:
\(\cdot\)如果\(p1(x,y) > p2(x,y)\),那么类别为1
\(\cdot\)如果\(p1(x,y) < p2(x,y)\), 那么类别为2
也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想,即选择具有最高概率的决策。
贝叶斯推断
对条件概率公式进行变形,可以得到如下形式:
我们把P(A)称为"先验概率"(Prior probability),即在B事件发生之前,我们对A事件概率的一个判断。
P(A|B)称为"后验概率"(Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。
P(B|A)/P(B)称为"可能性函数"(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率。
所以,条件概率可以理解成下面的式子:
后验概率 = 先验概率 x 调整因子
这就是贝叶斯推断的含义。我们先预估一个"先验概率",然后加入试验结果,看这个试验到底是增强还是削弱了"先验概率",由此得到更接近事实的"后验概率"。
朴素贝叶斯推断
贝叶斯和朴素贝叶斯的区别在于,朴素贝叶斯对条件概率分布做了条件独立性的假设。比如:
拉普拉斯平滑
在计算事件的概率时,如果某个事件在观察样本库(训练集)中没有出现过,会导致该事件的概率结果是0。这是不合理的,不能因为一个事件没有观察到,就被认为该事件一定不可能发生(即该事件的概率为0)。
拉普拉斯平滑(Laplacian smoothing) 是为了解决零概率的问题。
对于一个随机变量\(z\),它的取值范围是\(\{1,2,3\dots,k\}\),对于\(m\)次试验后的观测结果\(\{z^{(1)},z^{(2)},z^{(3)}\cdots,z^{(m)}\}\),极大似然估计按照下式计算:
使用\(Laplace\),计算公式变为:
即在分母上加上取值范围的大小,在分子加1
手写朴素贝叶斯分类器
import pandas as pd
import numpy as np
train_data = pd.read_csv('training_set.csv')
test_data = pd.read_csv('testing_set.csv')
train_data['Species'].replace(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'], [0, 1, 2], inplace=True)
test_data['Species'].replace(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'], [0, 1, 2], inplace=True)
train_data = np.array(train_data)
test_data = np.array(test_data)
train_x = train_data[:, 1:-1]
train_y = train_data[:, -1]
test_x = test_data[:, 1:-1]
test_y = test_data[:, -1]
# 存储每个特征的先验概率
mean = np.zeros((3, train_x.shape[1]))
var = np.zeros((3, train_x.shape[1]))
prior = np.zeros(3)
# 训练
def fit(X, y):
# 计算先验概率、均值和方差
for i, c in enumerate([0, 1, 2]):
X_c = X[y == c] # 获取一个类别的所有样本
mean[i, :] = X_c.mean(axis=0) # 计算均值
var[i, :] = X_c.var(axis=0) # 计算方差
prior[i] = X_c.shape[0] / X.shape[0] # 计算该类别的先验概率
# 训练
def predict(X):
y_pred = np.zeros(X.shape[0]) # 预测值
for i in range(X.shape[0]): # 遍历样本
# 计算每个类别的后验概率
posteriors = []
for c in range(3): # 三个类别
posterior = prior[c] # 初始化为先验概率
for j in range(4): # 四个属性
posterior *= 1 / (np.sqrt(2 * np.pi) * np.sqrt(var[c][j])) * np.exp(
-(X[i][j] - mean[c][j]) ** 2 / (2 * var[c][j]))
posteriors.append(posterior)
# 预测值取后验概率最大值的对应类别
y_pred[i] = np.argmax(posteriors)
return y_pred
fit(train_x, train_y) # 训练
y_pred = predict(test_x) # 预测
accuracy = np.sum(y_pred == test_y) / test_y.shape[0] # 精度
print("均值:", mean)
print("标准差:", np.sqrt(var))
print("先验概率:", prior)
print("精度:", accuracy)

浙公网安备 33010602011771号