离散型朴素贝叶斯分类器的设计

本文介绍了朴素贝叶斯分类器的基本原理,并通过一个具体的匹萨喜好预测案例展示了其工作流程。文中详细解释了如何利用Python实现朴素贝叶斯算法,并给出了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

公式

Bayes公式:P(x|c)P(c) = P(c|x)P(x) = P(x,c) 

P(x,c)是联合概率,表示x,c同时发生的概率

P(x|c)是条件概率,表示c出现的条件下, x出现的概率

考虑分类的问题,c_{j}表示第j种类别。

假设x为特征向量, P(c_{j}|x)表示特征向量为x时,样本属于类别c_{j}的概率。 P(x|c{_{j}})表示j类中特征量为x的概率。

假设x的n个分量是不相关的,则有 P(x|c{_{j}}) = \prod_{i=1}^{n}P(x{_{i}}|c{_{j}})。 P(x{_{i}}|c{_{j}}) 表示第j类中特征分量为第i个的概率。 

那么有:

  P(c{_{j}}|x) = P(c{_{j}})\cdot \prod_{i=1}^{n}P(x{_{i}}|c{_{j}})/P(x)

具有特征量x的样本属于第j类的概率等于第j类的概率与第j类中特征量为x的概率之积。 

例子

现在我们用一个例子来演示一下。 

某人的匹萨喜好
样本12345678
厚薄
甜咸
喜欢FFTFFTFF

那我们来计算下X = (厚,甜) 属于 F 的概率, 以及它属于T的概率。 先算前者(我们只计算分子就可以了)。 

P(F|(thick,sweet)) = P(F)\cdot P((thick,sweet)|F)

P((thick,sweet)|F) = P(thick|F)\cdot P(sweet|F)

不喜欢的样本共有6个,其中4个为厚的,4个为甜的。 

P(F) = 6/8    P(thick|F)\cdot P(sweet|F) = 4/6 * 4/6 

P(F|(thick,sweet)) = 6/8 * 4/6 * 4/6

然后我们来计算下X = (厚,甜) 属于 T 的概率。 

P(T|(thick,sweet)) = P(T)\cdot P((thick,sweet)|T)

P((thick,sweet)|T) = P(thick|T)\cdot P(sweet|T)

不喜欢的样本共有6个,其中4个为厚的,4个为甜的。 

P(T) = 2/8    P(thick|T)\cdot P(sweet|T) = 0 * 0

P(T|(thick,sweet)) = 2/8 * 0  = 0 

很显然,它属于F的概率大于属于T的概率,我们判断厚而甜的比萨是某人不喜欢的。

训练过程

对这种离散型的分类问题,我们可以描述为:

假设样本有I个属性值,记为X, 其中_{}_{}X_{i} 表示其中第i个属性值是否为真。 那么J个样本的属性构成矩阵X_{j,i}

对于上面的样本例子,我们用python 的array记为 

##X有属性值 厚,薄,甜,咸
##样本矩阵记为, 每一行为一个样本的属性值向量
X = np.array([[1,0,1,0],
[1,0,0,1],
[0,1,0,1],
[0,1,1,0],
[1,0,0,1],
[0,1,0,1],
[0,1,1,0],
[1,0,1,0]])
           

假设类别有C个类, 记为Y, 其中Y_{c}表示其中第c个类的值(0或1)。 Y的分量中应该有且有一个的值为1,其余为0。

# 喜欢,不喜欢
In [43]: Y = np.array([[0,1],
    ...: [0,1],[1,0],[0,1],[0,1],[1,0],[0,1],[0,1]])

样本属于第c个类的概率为\sum _{c=0}^{c=C}(Y_{c})/J

In [46]: Y.sum(axis=0)*1.0/Y.shape[0]  ##按列求和
Out[46]: array([ 0.25,  0.75])

##样本中有0.25为喜欢, 0.75为不喜欢

c个类值为1的条件下,属性X_{i} 的值为1的概率计算步骤如下:

  • 找出属于第c个类的所有样本
#获取属于第c类的所有样本
F = (Y == 1)
S = X[F[:,c]]
  • 遍历所有的类别,统计属于各个类别的样本中,属性X_{i} 的值为1的样本个数K与总数的比值。

M = np.zeros((Y.shape[1],X.shape[1]))
for i in range(Y.shape[1]):
    S = X[F[:, i]]  #获取属于第i类的样本
  #计算属于第i类的样本中,各个属性值的条件概率
    M[i] = S.sum(axis=0) / (1.0 * S.shape[0])

python 代码

# -*- coding: utf-8 -*-

import numpy as np

class NaiveBayes:
    def __init__(self):
        self.M = None 
        self.Pc = None
        
    def fit(self,X:np.array,Y:np.array):
        XRows, XCols = X.shape
        YRows, YCols = Y.shape

        ## XRows = YRows 代表样本数量 
        ## XCols 代表特征向量分量数目
        ## YCols 代表类别数


        ## 计算每个类别的概率 P(Yi)  0 < i < Y.shape[0]
        ## 按列(沿着0轴)求和 然后除以总数
        ## 类别概率矩阵
        self.Pc = Y.sum(axis=0)/(1.0* YRows)


        ## 条件概率矩阵
        self.M = np.zeros((YCols,XCols))

        ## 类别真值表
        F = (Y == 1)

        ## 计算每个类别的每个特征分量的条件概率 P(Xi|Yi)
        for i in range(YCols):
            ## F[:, i] 标记属于第i个类别的index
            a = X[F[:, i]]  ## 表示属于第i类的样本特征向量
            
            ## 属于第i类的各个特征分量的概率
            self.M[i] = a.sum(axis=0) / (1.0 * a.shape[0])
            
            
    def predict(self,x:np.array)->(int, float):

        ## 计算向量对应的条件概率
        T = self.M[:,(x==1)]

        ## 计算联合P(x|Yi) 
        C = (T.prod(axis=1))

        ## 计算条件概率P(Yi|x) = P(Yi)P(x|Yi)/P(x);  P(x) 可以不用参与计算了。
        ## 因为我们只要比较概率的大小关系,不需要概率的值。
        P = self.Pc*C
        idx = np.argmax(P)
        return (idx,P[idx]/P.sum())

        



if __name__ == "__main__":

    ## 特征向量(例子有4个分量), 如果为1则表示该分量为真
    X = np.array(
        [[1, 0, 1, 0],
         [1, 0, 0, 1],
         [0, 1, 0, 1],
         [0, 1, 1, 0],
         [1, 0, 0, 1],
         [0, 1, 0, 1],
         [0, 1, 1, 0],
         [1, 0, 1, 0],
         [0, 1, 0, 1],
         [0, 1, 1, 0],
         ])

    ## 类别向量, 如果为1则表示属于该类
    ## 类别向量只能有一个分量为1。
    Y = np.array( [ [0,1],
                    [0,1],
                    [1,0],
                    [0,1],
                    [0,1],
                    [1,0],
                    [1,0],
                    [0,1],
                    [1,0],
                    [1,0]])
                    
    x = np.array([0,1,1,0])
                    
                    
    nbayes = NaiveBayes()
    nbayes.fit(X,Y)
    idx,confidence = nbayes.predict(x)
    
    print("类别index=",idx, "可信度:",round(confidence,2))








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值