朴素贝叶斯原理及python实现

朴素贝叶斯原理及python实现

朴素贝叶斯原理

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

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

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

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

那么问题来了, P ( Y = c k ∣ X = x ) P(Y = {c_k}|X = x) P(Y=ckX=x)怎么算呢?— 套贝叶斯公式
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 )                                                                        ( 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=ckX=x)=kP(X=xY=ck)P(Y=ck)P(X=xY=ck)P(Y=ck)(1)

在已知数据集给出后,先验概率 P ( Y = c k ) P(Y=c_k) P(Y=ck) y y y的标签为 c k c_k ck的概率是很容易得到的(每个标签的总数除以总的标签数),但 P ( X = x ∣ Y = c k ) P(X = x|Y = {c_k}) P(X=xY=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)
现实还是很骨感,这可是指数级数量的参数啊!怎么办???
我们可以假设特征是独立的,即每个特征之间互不影响,互相独立。这个假设也有点太强吧。对!就是这么强!这也是朴素贝叶斯的朴素之处。基于条件独立假设,我们刚刚的条件概率就可以表示为:
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 ) × P ( X ( 2 ) = x ( 2 ) ∣ Y = c k ) × ⋯ × P ( X ( n ) = x ( n ) ∣ Y = c k ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) \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} 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)

OK,现在先验概率和条件概率都有了,我们只需要将它带入 ( 1 ) (1) (1)中即可,带入得到:
P ( Y = c k ∣ X = x ) = P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) ∑ k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) 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})} } }} P(Y=ckX=x)=kP(Y=ck)jP(X(j)=x(j)Y=ck)P(Y=ck)jP(X(j)=x(j)Y=ck)
终于算出来了,现在给定特征 x x x,我们就可以找到它最有可能属于哪个类了,我们只需要把属于每个类的概率算一下,然后找到概率最大的那个就可以了。

总结一下:

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

朴素贝叶斯的python实现

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

123456789101112131415
X ( 1 ) {X^{(1)}} X(1)111112222233333
X ( 2 ) {X^{(2)}} X(2)SMMSSSMMLLLMMLL
Y Y Y-1-111-1-1-11111111-1

测试数据:
给定输入第一个特征为 1 1 1,第二个特征为 S S S
实验结果:
预测结果为 − 1 -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))

运行结果:

sign
才疏学浅,难免有错误和不当之处,欢迎交流批评指正!
同时有问题的话欢迎留言或邮箱联系(ljt_IT@163.com)。

Reference:

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

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

Reward

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值