//加了下面的代码,博客会禁止复制(代码还可以复制) // document.body.onselectstart = document.body.ondrag = function(){return false;}

贝叶斯分类器

前言

朴素贝叶斯算法是有监督的学习算法,解决的是分类问题,如客户是否流失、是否值得投资、信用等级评定等多分类问题。该算法的优点在于简单易懂、学习效率高、在某些领域的分类问题中能够与决策树、神经网络相媲美。但由于该算法以自变量之间的独立(条件特征独立)性和连续变量的正态性假设为前提,就会导致算法精度在某种程度上受影响。

朴素贝叶斯理论

朴素贝叶斯是贝叶斯决策理论的一部分。

贝叶斯决策理论

假设现在我们有一个数据集,它由两类数据组成。
我们现在用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|B) = P(A)\frac{P(B|A)}{P(B)} \]

我们把P(A)称为"先验概率"(Prior probability),即在B事件发生之前,我们对A事件概率的一个判断。

P(A|B)称为"后验概率"(Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。

P(B|A)/P(B)称为"可能性函数"(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率。

所以,条件概率可以理解成下面的式子:

后验概率 = 先验概率 x 调整因子

这就是贝叶斯推断的含义。我们先预估一个"先验概率",然后加入试验结果,看这个试验到底是增强还是削弱了"先验概率",由此得到更接近事实的"后验概率"。

朴素贝叶斯推断

贝叶斯和朴素贝叶斯的区别在于,朴素贝叶斯对条件概率分布做了条件独立性的假设。比如:

\[P(X|a)p(a) = {p(x_1|a) \times p(x_2|a) \times p(x_3|a)\times \dots p(x_n|a)}p(a) \]

拉普拉斯平滑

在计算事件的概率时,如果某个事件在观察样本库(训练集)中没有出现过,会导致该事件的概率结果是0。这是不合理的,不能因为一个事件没有观察到,就被认为该事件一定不可能发生(即该事件的概率为0)。
拉普拉斯平滑(Laplacian smoothing) 是为了解决零概率的问题。
对于一个随机变量\(z\),它的取值范围是\(\{1,2,3\dots,k\}\),对于\(m\)次试验后的观测结果\(\{z^{(1)},z^{(2)},z^{(3)}\cdots,z^{(m)}\}\),极大似然估计按照下式计算:

\[\varphi_{j}=\frac{\sum_{i=1}^{m}I\{z^{(i)}=j\}}{m} \]

使用\(Laplace\),计算公式变为:

\[\varphi_{j}=\frac{\sum_{i=1}^{m}I\{z^{(i)}=j\}+1}{m+\mathrm{k}} \]

即在分母上加上取值范围的大小,在分子加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)

posted @ 2024-06-06 11:18  龙鳞墨客  阅读(38)  评论(0)    收藏  举报