【AI】Python 实现朴素贝叶斯算法

朴素贝叶斯算法

1. 算法推导

朴素贝叶斯(Naive Bayes)算法是基于贝叶斯定理与特征条件独立假设的分类方法,其特点是结合先验概率和后验概率,既避免了只使用先验概率的主观偏见,也避免了单独使用样本信息的过拟合现象。该算法在数据集较大的情况下表现出较高的准确率,同时算法本身也比较简单。

朴素贝叶斯算法的目标是根据输入的特征,对每一个分类计算其后验概率,选择后验概率最大的那个分类作为模型输出。而后验概率是根据贝叶斯准则从条件概率推导而来的,假定每个样本包含 n n n 个特征,一共分可为 m m m 类, c k c_k ck 表示其中的某一个类别,下面是对朴素贝叶斯算法的公式推导:

① 先验概率:
P ( Y = c k ) P(Y=c_k) P(Y=ck)

② 条件概率:
P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , . . . , X ( n ) = x ( n ) ∣ Y = c k ) P(X=x|Y=c_k)=P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)}|Y=c_k) P(X=xY=ck)=P(X(1)=x(1),...,X(n)=x(n)Y=ck)

x ( j ) x^{(j)} x(j) 平均有 S S S 种取值方法,假设各特征直接相互不独立,则单个样本的 n n n 个特征平均有 S n S^n Sn 种参数,这个范围太大了;实际情况下,训练集往往并没有这么大范围的参数,数据的各特征之间往往也具有一定独立性。因此,可以大胆地假设单个样本的 n n n 个特征之间是相互独立的。这样,条件概率的表达式转化为:

P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , . . . , X ( n ) = x ( n ) ∣ Y = c k ) = ∏ j = 0 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P(X=x|Y=c_k)=P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)}|Y=c_k)=\prod_{j=0}^nP(X^{(j)}=x^{(j)}|Y=c_k) P(X=xY=ck)=P(X(1)=x(1),...,X(n)=x(n)Y=ck)=j=0nP(X(j)=x(j)Y=ck)

③ 后验概率:
P ( Y = c k ∣ X = x ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) ∑ k P ( X = x ∣ Y = c k ) P ( Y = c k ) P(Y=c_k|X=x)=\frac{P(X=x|Y=c_k)P(Y=c_k)}{\sum_{k}P(X=x|Y=c_k)P(Y=c_{k})} P(Y=ckX=x)=kP(X=xY=ck)P(Y=ck)P(X=xY=ck)P(Y=ck)

将条件概率的公式代入到后验概率公式中,后验概率的表达式转化为:
P ( Y = c k ∣ X = x ) = P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) ∑ k P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P(Y=c_k|X=x)=\frac{P(Y=c_k)\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_k)}{\sum_{k}P(Y=c_k)\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_k)} P(Y=ckX=x)=kP(Y=ck)j=1nP(X(j)=x(j)Y=ck)P(Y=ck)j=1nP(X(j)=x(j)Y=ck)

④ 于是,朴素贝叶斯分类器的优化目标可表示为
y = a r g m a x c k P ( Y = c k ∣ X = x ) = a r g m a x c k P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) y=\mathop{argmax}\limits_{c_k}P(Y=c_k|X=x)=\mathop{argmax}\limits_{c_k}P(Y=c_k)\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_k) y=ckargmaxP(Y=ckX=x)=ckargmaxP(Y=ck)j=1nP(X(j)=x(j)Y=ck)

2. 算法流程

以上我们推导出了朴素贝叶斯算法的计算目标,下面通过公式给出算法的运行流程:

① 计算先验概率(其中分母表示一共有 N N N 种类别,分子表示对于样本 i i i,如果其分类 y i = c k y_i=c_k yi=ck,则分子取值为 1,否则取值为 0):

P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) N P(Y=c_k)=\frac{\sum_{i=1}^NI(y_i=c_k)}{N} P(Y=ck)=Ni=1NI(yi=ck)

② 计算条件概率(表示类别为 c k c_k ck 的前提下第 j j j 个特征取值为 x ( j ) x^{(j)} x(j) 的概率):

P ( X ( j ) = x ( j ) ∣ Y = c k ) = ∑ i = 1 N I ( X i ( j ) = a j l , y i = c k ) ∑ i = 1 N I ( y i = c k ) P(X^{(j)}=x^{(j)}|Y=c_k)=\frac{\sum_{i=1}^{N}I(X_i^{(j)}=a_{jl},y_i=c_k)}{\sum_{i=1}^{N}I(y_i=c_k)} P(X(j)=x(j)Y=ck)=i=1NI(yi=ck)i=1NI(Xi(j)=ajl,yi=ck)

④ 对于给定的样本 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) T x=(x^{(1)},x^{(2)},...,x^{(n)})^T x=(x(1),x(2),...,x(n))T,计算一个大小为 k k k 的向量::

P ( Y = c k ) ∏ i = 1 n P ( X ( j ) = x ( j ) ) P(Y=c_k)\prod_{i=1}^nP(X^{(j)}=x^{(j)}) P(Y=ck)i=1nP(X(j)=x(j))

⑤ 在这个大小为 k k k 的样本中取 a r g m a x argmax argmax,确定样本 x x x 的分类

y = a r g m a x c k P ( Y = c k ) ∏ i = 1 n P ( X ( j ) = x ( j ) ) y=\mathop{argmax}\limits_{c_k}P(Y=c_k)\prod_{i=1}^nP(X^{(j)}=x^{(j)}) y=ckargmaxP(Y=ck)i=1nP(X(j)=x(j))

3. 算法举例

以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。过滤这类内容是一个很常见的需求。对此问题建立两个类型:侮辱类和非侮辱类,使用 1 和 0 分别表示。

我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。

下面的函数给定了一个简单的训练数据集,并把它向量化以方便算法处理。例如,如果训练数据有两个样本,为 [[‘a’, ‘c’, ‘g’], [‘a’, ‘b’, ‘c’. ‘m’]],则词汇表为 [‘a’, ‘b’, ‘c’, ‘g’, ‘m’],样本中含有对应词汇的位置设为 1,否则设为 0。因此,两个样本可以向量化为:[[1, 0, 1, 1, 0], [1, 1, 1, 1, 0]],这样,每个样本都有 5 个特征,后续处理时可以统一标准。

import numpy as np


def vectorization(word_list, vocabulary):
    return_vector = [0] * len(vocabulary)
    for word in word_list:
        if word in vocabulary:
            return_vector[vocabulary.index(word)] = 1
    return return_vector


def load_training_data():
    training_data = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                     ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                     ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                     ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                     ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                     ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    training_labels = [0,1,0,1,0,1]
    
    # 构建词汇表
    vocabulary = set()
    for item in training_data:
        vocabulary = vocabulary | set(item)
    vocabulary = list(vocabulary)
    
    # 将训练数据向量化
    training_mat = []
    for item in training_data:
        training_mat.append(vectorization(item, vocabulary))
    
    return training_mat, training_labels

下面的函数是朴素贝叶斯算法的执行流程,它是参照上文第二部分中的算法流程来编排的。区别的是代码中使用了拉普拉斯平滑,这是为了防止连乘操作中出现 0 而使整个表达式为 0,这显然是不合理的。

def naive_bayes(test_data):
    # 计算先验概率
    training_mat, training_labels = load_training_data()
    feature_size = len(training_mat[0])
    training_size = len(training_mat)
    p1_prior = (sum(training_labels) + 1) / (float(training_size) + 2)
    p0_prior = 1 - p1_prior
    # 计算条件概率
    feature_cnt1 = np.zeros(feature_size)
    feature_cnt0 = np.zeros(feature_size)
    for i in range(training_size):
        if training_labels[i] == 1:
            feature_cnt1 += training_mat[i]
        else:
            feature_cnt0 += training_mat[i]
    p1_condition = (feature_cnt1 + 1) / (feature_cnt1.sum() + feature_size)
    p0_condition = (feature_cnt0 + 1) / (feature_cnt0.sum() + feature_size)
    # 计算目标函数
    p1_pred, p0_pred = p1_prior, p0_prior
    test_data = vectorization(test_data, vocabulary)
    for i in range(feature_size):
        if test_data[i] == 1:
            p1_pred *= p1_condition[i]
        else:
            p0_pred *= p0_condition[i]
    if p1_pred > p0_pred:
        return 1
    else:
        return 0
    

test_data = ['stupid', 'stop', 'how', 'problems']
pred_label = naive_bayes(test_data)
print('test_data = ', test_data)
print('pred_label = ', pred_label)

运行上面给出的代码,执行结果为:

test_data =  ['stupid', 'stop', 'how', 'problems']
pred_label =  1
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
抱歉,作为AI语言模型,我不能提供完整的源代码,但是我可以提供一些参考,希望能帮到你。 贝叶斯算法是一种基于概率统计的分类算法,它的主要思想是根据已知的先验概率和观测数据,求出每个类别的后验概率,然后选择后验概率最大的类别作为分类结果。在手写数字识别的问题中,可以使用贝叶斯算法来判断一个手写数字属于哪个数字类别。 具体实现过程可以分为以下几个步骤: 1. 数据预处理 手写数字的识别需要大量的训练数据,可以使用MNIST数据集。需要将数据集处理成特定的格式,例如将28x28的像素矩阵转换成一维的向量。 2. 计算先验概率 根据训练数据集中每个数字类别的数量,可以计算出每个数字类别的先验概率。 3. 计算条件概率 对于每个数字类别,需要计算出每个像素点上出现某个灰度值的条件概率。可以采用极大似然估计或贝叶斯估计来计算条件概率。 4. 计算后验概率 对于一个测试样本,可以根据贝叶斯公式计算出它属于每个数字类别的后验概率。然后选择后验概率最大的类别作为分类结果。 5. 模型评估 使用测试数据集对模型进行评估,可以使用准确率、精确率、召回率等指标来评估模型的性能。 下面是一个使用朴素贝叶斯算法实现手写数字识别的参考代码: ```python import numpy as np from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score from sklearn.datasets import fetch_openml # 加载MNIST数据集 mnist = fetch_openml('mnist_784') X, y = mnist.data, mnist.target # 数据预处理 X = X.astype(np.float32) / 255.0 y = y.astype(np.int32) # 将数据集分为训练集和测试集 train_size = 60000 X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] # 训练朴素贝叶斯模型 clf = GaussianNB() clf.fit(X_train, y_train) # 在测试集上进行预测 y_pred = clf.predict(X_test) # 计算模型的准确率 accuracy = accuracy_score(y_test, y_pred) print('Accuracy:', accuracy) ``` 这里使用了`sklearn`库中的`GaussianNB`类来实现朴素贝叶斯算法。具体实现过程中,需要注意对数据集进行预处理,将像素矩阵转换成一维的向量,并将数据归一化到0-1范围内。然后使用`fit`方法对模型进行训练,使用`predict`方法对测试集进行预测,最后使用`accuracy_score`函数计算模型的准确率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值