欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

朴素贝叶斯原理及python实现

程序员文章站 2022-03-08 17:27:04
...

朴素贝叶斯原理及python实现

朴素贝叶斯原理

如果你压根不知道贝叶斯是啥,建议你先读读如何理解贝叶斯以便更好地读懂本文。

朴素贝叶斯在分类问题中有很广泛的应用。具体是如何应用的呢?

老祖宗贝叶斯公式给出了答案—事件A发生了,是由事件B造成的概率为:
P(BiA)=P(Bi)P(ABi)j=1nP(Bj)P(ABj)P({B_i}|A) = \frac{{P({B_i})P(A|{B_i})}}{{\sum\limits_{j = 1}^n {P({B_j})P(A|{B_j})} }}

对于我们实际的问题:
给定数据集T={(x1y1),(x2,y2),...,(xN,yN)}T=\{(x_1y_1),(x_2,y_2),...,(x_N,y_N)\},其中xx为特征,yy为特征xx对应的标签,标签YY的取值集合为{c1,c2,...,cK}\{c_1,c_2,...,c_K\};这样的数据集通常是已知的,一个或一连串的特征对应一个标签,在大量的可观测的已知数据(训练集)给出后,突然来一个或好多数据(测试集),我们想知道这些未知应该属于哪个类,即:
P(Y=ckX=x)P(Y = {c_k}|X = x)(在XXxx的条件下,YYckc_k的概率)— 我们观测到了某个数据的特征,而且还知道了该数据属于每个类别的概率,我们只要找到最有可能(概率最大)属于的类别不就是这个数据的分类了?

那么问题来了,P(Y=ckX=x)P(Y = {c_k}|X = x)怎么算呢?— 套贝叶斯公式
P(Y=ckX=x)=P(X=xY=ck)P(Y=ck)kP(X=xY=ck)P(Y=ck)                                                                      (1)P(Y = {c_k}|X = x) = \frac{{P(X = x|Y = {c_k})P(Y = {c_k})}}{{\sum\nolimits_k {P(X = x|Y = {c_k})P(Y = {c_k})} }} \;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;(1)

在已知数据集给出后,先验概率P(Y=ck)P(Y=c_k)yy的标签为ckc_k的概率是很容易得到的(每个标签的总数除以总的标签数),但P(X=xY=ck)P(X = x|Y = {c_k})呢?
P(X=xY=ck)=P(X(1)=x(1),...,X(n)=x(n)Y=ck)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)=P(X(1)=x(1)Y=ck)×P(X(2)=x(2)Y=ck)××P(X(n)=x(n)Y=ck)=j=1nP(X(j)=x(j)Y=ck)\begin{array}{l} P(X = x|Y = {c_k}) = P({X^{(1)}} = {x^{(1)}},...,{X^{(n)}} = {x^{(n)}}|Y = {c_k}) = P({X^{(1)}}\\ = {x^{(1)}}|Y = {c_k}) \times P({X^{(2)}} = {x^{(2)}}|Y = {c_k}) \times \cdots \times P({X^{(n)}} = {x^{(n)}}|Y = {c_k})\\ = \prod\limits_{j = 1}^n {P({X^{(j)}} = {x^{(j)}}|Y = {c_k})} \end{array}

OK,现在先验概率和条件概率都有了,我们只需要将它带入(1)(1)中即可,带入得到:
P(Y=ckX=x)=P(Y=ck)jP(X(j)=x(j)Y=ck)kP(Y=ck)jP(X(j)=x(j)Y=ck)P(Y = {c_k}|X = x) = \frac{{P(Y = {c_k})\prod\nolimits_j {P({X^{(j)}} = {x^{(j)}}|Y = {c_k})} }}{{\sum\nolimits_k {P(Y = {c_k})\prod\nolimits_j {P({X^{(j)}} = {x^{(j)}}|Y = {c_k})} } }}
终于算出来了,现在给定特征xx,我们就可以找到它最有可能属于哪个类了,我们只需要把属于每个类的概率算一下,然后找到概率最大的那个就可以了。

总结一下:

给定训练集和测试集,先提取特征,然后计算先验概率和条件概率。之后对于给定测试数据,计算一下属于每个类别的概率,然后返回概率最大的那个标签就完成了预测或分类。

朴素贝叶斯的python实现

实验数据用的是李航老师《统计学习方法》里的数据,当然,上面的很多东西参考了该书。
训练数据:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
X(1){X^{(1)}} 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
X(1){X^{(1)}} S M M S S S M M L L L M M L L
YY -1 -1 1 1 -1 -1 -1 1 1 1 1 1 1 1 -1

测试数据:
给定输入第一个特征为11,第二个特征为SS
实验结果:
预测结果为1-1

import  numpy as np
def judge(actual,prediction):
    '''
    该函数用于判断实际值和预测值是否一致
    :param actual: 实际值
    :param prediction: 预测值
    :return: 如果实际值和预测值一致,返回为True,否则返回False
    '''
    return actual==prediction
def generate_data():
    '''
    该函数用于生成数据
    :return: 生成好的数据,特征对应于标签
    '''
    feature=[(1,'S'),(1,'M'),(1,'M'),(1,'S'),(1,'S'),
             (2,'S'),(2,'M'),(2,'M'),(2,'L'),(2,'L'),
             (3,'L'),(3,'M'),(3,'M'),(3,'L'),(3,'L')]
    label=[-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1]
    return feature,label
class bayes:
    ### bayes类,用于bayes相关
    def transform(self,feature):
        '''
        对原始输入的特征进行相应的转换,以更好地进行模型训练
        :param feature: 需要转换的特征
        :return: 转换后的特征 
        '''
        fea_transform=[]
        for seq in feature:
            for i in range(seq.__len__()):
                try:
                    fea_transform[i].append(seq[i])
                except:
                    fea_transform.append([])
                    fea_transform[i].append(seq[i])
        return fea_transform
    def train(self,feature,label):
        '''
        训练函数
        :param feature: 特征集
        :param label: 标签集
        :return: 训练好的模型(相应的条件概率和先验概率)
        '''
        feature=np.array(self.transform(feature))
        label=np.array(label)
        classifier=set(label)
        probability_classifier={}
        probability_feature={}
        feature_record={}
        ### 计算先验概率
        for i in classifier:
            probability_classifier[i]=label.tolist().count(i)/label.__len__()
        for fea in range(feature.__len__()):
            feature_record[fea]=set(feature[fea])
        ### 计算条件概率
        for fea in range(feature.__len__()):
            for f in feature_record[fea]:
                for c in classifier:
                    position= np.where(label==c)### 找到分类为 c 的那些位置
                    numerator=feature[fea][position][feature[fea][position]==f].__len__()### 找到类别为 c,同时该特征为 f 的元素个数
                    denominator=feature[fea][label==c].__len__()
                    try:
                        probability_feature[(fea,c)][f]=numerator/denominator
                    except:
                        probability_feature[(fea,c)]={}
                        probability_feature[(fea,c)][f]=numerator/denominator
        return probability_feature,probability_classifier
    def predict(self,actual,model):
        '''
        预测函数
        :param actual: 想要预测的实际值
        :param model: 训练好的模型
        :return: 预测结果
        '''
        actual=np.array(actual)
        probability_feature,probability_classifier=model
        prediction={}
        for classifier in probability_classifier:
            multi=1
            for i in range(actual.__len__()):
                multi*=probability_feature[(i,classifier)][actual[i]]
            prediction[classifier]=probability_classifier[classifier]*multi
        return max(prediction,key=prediction.get)
if __name__ == '__main__':
    feature,label=generate_data()
    bayes=bayes()
    model=bayes.train(feature,label)
    print("预测结果为:",bayes.predict([1,"S"],model))

运行结果:

朴素贝叶斯原理及python实现
才疏学浅,难免有错误和不当之处,欢迎交流批评指正!
同时有问题的话欢迎留言或邮箱联系(aaa@qq.com)。

Reference:

李航.《统计学习方法》[M].2012.3.北京:清华大学出版社,2019.5(重印):14-15.

创作不易,觉得写得不错就微信扫码奖励一下吧!

朴素贝叶斯原理及python实现

相关标签: 机器学习