龙空技术网

朴素贝叶斯原理及代码

哲科学习坊 399

前言:

目前兄弟们对“朴素贝叶斯算法r代码”大概比较关切,咱们都想要分析一些“朴素贝叶斯算法r代码”的相关内容。那么小编在网络上汇集了一些对于“朴素贝叶斯算法r代码””的相关知识,希望咱们能喜欢,看官们一起来了解一下吧!

1 介绍

朴素贝叶斯 (Naive Bayes) 是贝叶斯分类算法中最简单的一个,一般用于处理二分类或多分类任务。该算法围绕着一个核心进行展开:贝叶斯定理。本文会从易于理解的角度对朴素贝叶斯的原理进行介绍,然后是代码的实现,以加深对算法的理解。

2 原理2.1 贝叶斯定理

首先看一下算法的核心,贝叶斯定理。

定理由来:

对于事件A与事件B, 有条件概率公式:

因为 P(AB) = P(BA) , 所以:

将 P(A) 除到左边,即得到贝叶斯定理:

贝叶斯定理有什么用呢?

一般对于 P(B|A) 难以计算时,会利用贝叶斯定理,将计算转换成对 P(A|B)、P(B)、P(A)的计算。

2.2 朴素贝叶斯算法

那么如何将朴素贝叶斯用于实际的分类任务呢?

将贝叶斯定理中的事件A看作特征,将事件B看作类别,即得到以下形式:

其中,左式 P(类别|特征) 的含义是:在指定特征的情况下,某一类别出现的概率。就相当于在知道某样本各个特征的情况下,计算该样本属于每个类别的概率。如果能计算出这个概率值,取最大概率对应的类别作为样本的预测类别就行了。

那么 P(类别|特征) 好不好求呢?答案是否定的。此时就可以利用朴素贝叶斯公式将 P(类别|特征) 的计算转换成 P(特征|类别)、P(类别)、P(特征) 的计算,这三个概率值是比较容易计算的,在训练样本的特征及类别上进行统计即可得到。

在实际的分类任务中,特征通常不只一个,即:

计算这个概率值时,如果直接去统计在某一类别的条件下,同时符合这些特征的样本个数,然后再相除,得到的概率结果会非常小。因为同时符合这些特征的样本个数非常少,所以朴素贝叶斯算法将这个概率拆分成多个条件概率的累乘。

朴素贝叶斯算法假设各个特征是相互独立的,所以可以将概率拆分成多个条件概率累乘。这也是算法名称中朴素二字的由来,该算法需要预先假设样本各个特征之间相互独立。 同理,分母 P(特征) 也可拆分计算。

此时,有了P(特征|类别)、P(类别)、P(特征) 三个概率值,然后根据得到的 P(类别|特征) 的概率值将测试样本分类即可。

需要注意的问题:

1 、特征太多时,多个小于1的概率值累乘可能会造成下溢出,可以将使用 log 计算将累乘转换成累加,避免下溢出。

这段话的意思是,当特征数量较多且每个特征的概率值都小于1时,进行多个概率值的累乘操作可能导致数值过小而出现下溢出(underflow)的情况。为了解决这个问题,可以使用对数计算将累乘转换为累加,以避免下溢出的问题。下面是一段代码示例,说明了如何使用对数计算来避免下溢出问题:

import numpy as np# 假设有一组小于1的概率值probabilities = [0.3, 0.5, 0.2, 0.4, 0.6]# 使用累乘计算概率的乘积product = np.prod(probabilities)print("Product:", product)  # 输出结果可能会接近零# 使用对数计算将累乘转换为累加log_product = np.sum(np.log(probabilities))print("Log Product:", log_product)  # 输出结果较为稳定,不会接近零

2 、如果某一类别下特征m没有出现,此时 P(特征m|类别)=0, 这会造成最终的概率值为0, 所以可使用贝叶斯平滑,就是在分子分母分别加1,可避免0概率出现的情况。在样本量充足的情况下,平滑不会对结果产生影响。

这段话的意思是,当某一类别下的特征未在训练集中出现时,计算概率时会出现分母为0的情况,导致最终的概率值为0。为了避免这种情况,可以使用贝叶斯平滑(也称为拉普拉斯平滑或加法平滑),即在分子和分母中都加上一个平滑参数(通常为1),以避免概率值为0的情况发生。

以下是一段代码示例,演示了使用贝叶斯平滑计算概率的过程:

import numpy as npimport pandas as pdclass NaiveBayes(object):    def __init__(self, X_train, y_train, smoothing=1):        self.X_train = X_train  # 样本特征        self.y_train = y_train  # 样本类别        self.smoothing = smoothing  # 平滑参数    def get_frequency(self, data, feature, value):        num = len(data[data[feature] == value])  # 个数        return (num + self.smoothing) / (len(data) + self.smoothing * len(data[feature].unique()))    def predict(self, X_test):        # 预测过程...# 创建一个示例数据集data = pd.DataFrame({'feature': ['A', 'A', 'B', 'B'], 'label': [1, 1, 0, 0]})# 分割特征和标签X = data[['feature']]y = data['label']# 创建朴素贝叶斯模型对象并进行训练model = NaiveBayes(X, y, smoothing=1)
3 总结

优点:

1 不同于线性模型,朴素贝叶斯基于统计而不是基于权重的迭代优化,逻辑简单,容易实现;

2 分类过程的时间与空间复杂度都比较小。

缺点:

1 只能处理分类任务,并且只在样本特征较少的情况下,分类效果最好;

2 特征之间相互独立的假设在实际中通常是不成立的,在特征间相关性较大时或者特征数量较多时效果不好。

4 代码实践

理解算法的最好做法就是用代码实现它。在下面代码中,我加入了充分的注释以易理解。

import numpy as npimport pandas as pdclass NaiveBayes(object):    def __init__(self, X_train, y_train):        self.X_train = X_train  #样本特征        self.y_train = y_train  #样本类别        #训练集样本中每个类别(二分类)的占比,即P(类别),供后续使用        self.P_label = {1: np.mean(y_train.values), 0: 1-np.mean(y_train.values)}    #在数据集data中, 特征feature的值为value的样本所占比例    #用于计算P(特征|类别)、P(特征)    def getFrequency(self, data, feature, value):        num = len(data[data[feature]==value]) #个数        return num / (len(data))    def predict(self, X_test):        self.prediction = [] #预测类别        # 遍历样本        for i in range(len(X_test)):            x = X_test.iloc[i]      # 第i个样本            P_feature_label0 = 1    # P(特征|类别0)之和            P_feature_label1 = 1    # P(特征|类别1)之和            P_feature = 1           # P(特征)之和            # 遍历特征            for feature in X_test.columns:                # 分子项,P(特征|类别)                data0 = self.X_train[self.y_train.values==0]  #取类别为0的样本                P_feature_label0 *= self.getFrequency(data0, feature, x[feature]) #计算P(feature|0)                data1 = self.X_train[self.y_train.values==1]  #取类别为1的样本                P_feature_label1 *= self.getFrequency(data1, feature, x[feature]) #计算P(feature|1)                # 分母项,P(特征)                P_feature *= self.getFrequency(self.X_train, feature, x[feature])            #属于每个类别的概率            P_0 = (P_feature_label0*self.P_label[0]) / P_feature            P_1 = (P_feature_label1 * self.P_label[1]) / P_feature            #选出大概率值对应的类别            self.prediction.append([1 if P_1>=P_0 else 0])        return self.prediction

使用测试:

from sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import accuracy_score#加载数据X, y = load_iris(return_X_y=True)X, y = pd.DataFrame(X[:100]), pd.DataFrame(y[:100])#训练集、测试集划分X_train, X_test, y_train, y_test =  train_test_split(X, y, test_size=0.3)model = NaiveBayes(X_train, y_train)    #训练y_pre = model.predict(X_test)           #预测print(accuracy_score(y_pre, y_test))    #评分:0.8

标签: #朴素贝叶斯算法r代码