朴素贝叶斯——连续型数据

关于朴素贝叶斯的原理及离散型的朴素贝叶斯,参见上一篇博文:https://blog.csdn.net/gongfuxiongmao_/article/details/116062023?spm=1001.2014.3001.5502

对于连续型的数据,在假定数据符合正态分布的前提下,可以对训练数据中每个特征进行高斯处理,得到一个特征的高斯曲线,利用高斯曲线来估计预测数据属于某一类的概率。

比如下面的例子中,数据有四个特征值:x1,x2,x3,x4 ; 同时有三个分类结果:生男孩,生女孩,没怀孕。

对应就有12条高斯曲线(分类数*特征数条高斯曲线),分别为:

1. 生男孩这个分类中,x1,x2,x3,x4四个特征对应的四条高斯曲线

2.生女孩这个分类中,x1,x2,x3,x4四个特征对应的四条高斯曲线

3.没怀孕这个分类中,x1,x2,x3,x4四个特征对应的四条高斯曲线

对于一个给定的,新的待预测值,x1,x2,x3,x4,分别代入每个类对于的高斯曲线,就可以得到P(B\A)即属于这个类的概率。

连续型数据的朴素贝叶斯中,不会出现P(B\A)=0的情况(对于文本分类,一个词没有出现时,其P(B\A)=0,但连续型的数据中,根据高斯分布计算P(B\A)不可能为零),

因此连续型的朴素贝叶斯可以不考虑拉普拉斯平滑。

先来回顾一下高斯分布,原理和代码如下:

import numpy
import matplotlib.pyplot as plot
import math

#均值
mean = 2  
#标准差
var = 32 
#创建一个50个元素的数组,收尾与均值相差三个标准差 的 等差数列
x = numpy.linspace(mean - 3 * var, mean + 3 * var, 50) 
#根据正太分布的公式写出y 
y = numpy.exp(-(x - mean) ** 2 / (2 * var ** 2)) / (math.sqrt(2 * math.pi) * var) 
#以x,y为横纵坐标,'r-'表示红色线,'ro-表示红色线加原点',linewidth为线的粗细度 
plot.plot(x, y, 'ro-', linewidth=2) 
#或者也可以:用'go'表示绿色原点,markersize为原点大小 
#plot.plot(x, y, 'r-', x, y, 'go', linewidth=2, markersize=8) 
#有灰色格子 
plot.grid(True) 
#显示 
plot.show()


#生成标准正态分布的数组
'''
loc:float
此概率分布的均值(对应着整个分布的中心centre)
scale:float
此概率分布的标准差(对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高)
size:int or tuple of ints
输出的shape,默认为None,只输出一个值
'''
samples = numpy.random.normal(loc=0.0, scale=1.0, size=10)
x = numpy.linspace(mean - 3 * var, mean + 3 * var, 10) 
#等价于 samples = numpy.random.randn(10)


#求均值
mean = numpy.mean(samples)
#求一个数组的方差
var = numpy.var(samples)
#求概率
y = numpy.exp(-(x - mean) ** 2 / (2 * var ** 2)) / (math.sqrt(2 * math.pi) * var) 

#求概率,x可以是一个数,或者一个numpy数组
def getGaussianProbability(samples,x):
    #求均值
    mean = numpy.mean(samples)
    #求一个数组的方差
    var = numpy.var(samples)
    #求概率
    y = numpy.exp(-(x - mean) ** 2 / (2 * var ** 2)) / (math.sqrt(2 * math.pi) * var) 
    return y

#测试    
samples = numpy.array([0.3,0.4,0.6,0.9])
x=numpy.array([0.5,0])
print(getGaussianProbability(samples,x))

其中我们需要用到的:

#求均值
mean = numpy.mean(samples)
#求一个数组的标准差
std= numpy.std(samples)
#求概率,其中x可以是一个数,或者一个numpy数组
y = numpy.exp(-(x - mean) ** 2 / (2 * std** 2)) / (math.sqrt(2 * math.pi) * std) 

此案例中用到的包:pandas,numpy,Counter,math

# 导入相关工具包
import pandas
import numpy as np
from collections import Counter
import math

# 读取训练数据 特征部分(机器人传感器收集的112个顾客气色,气味,脉象,体温等特征)

"""
pandas将数据读取出来以后是dataframe的格式,要转成numpy的二维数组的形式才能继续使用:
1.读取以后.value
2.y = np.array(y)
"""
# 以.values最终取出来的是numpy的形式
x = pandas.read_csv('train_X.csv').values
# print(f'我是test_x:{x}')
# print(np.mean(x),np.std(x))

# 读取训练数据 实际结果部分(上述112位顾客真实的怀孕状态,0表示女娃,1表示男孩,2表示没有怀孕)
y = pandas.read_csv('train_y.csv')
y = np.array(y)
"""
此处用tolist()把numpy的矩阵转换成list
随后再用_flatten把二维的list拉平

"""
class byes_qingdaifu(object):
    def fit(self, x, y):
        self.x = x
        self.y = y
        self.rMean,self.rStd,self.P = self.getP()

    def getP(self):
        """
        根据训练数据得到12条特征高斯曲线(均值mean和方差str)以及3种结果分类分别占的概率p
        :return: mean,str及p的矩阵
        """
        # 此处将x转化为一个二维列表
        list_x = self.x.tolist()
        # 此处将二维矩阵y转化成一维的列表
        list_y = self.y.flatten().tolist()
        # 利用Counter统计list中每个元素及其出现的次数
        dict_y = Counter(list_y)
        # dict_y:Counter({2: 41, 0: 37, 1: 34})
        # 求得其中的数据的总条数
        sumNum = sum(dict_y.values())
        # 对字典进行排序
        t = sorted(dict_y.items(),key=lambda item: item[0])
        # [(0,37),(1,34),(2,41)]
        # 将字典转换成一个二维列表(列表有序)
        rl = list(list(items) for items in list(t))
        # 求每一种分类的概率p,形成列表P
        P = [(rl[i][-1]/sumNum) for i in range(len(rl))]
        # 建立一个空列表rMean
        rMean = []
        # 列表式得到一个rMean的n*4 矩阵;分别是n个类别的4个特征的mean向量
        [rMean.append((np.mean(self.getClass(i), axis=0))) for i in range(len(P))]
        # 将列表转换成array,便于后续计算
        rMean = np.array(rMean)
        # 建立一个空列表rStd
        rStd = []
        # 列表式得到一个rStd的n*4 矩阵;分别是n个类别的rStd
        [rStd.append((np.std(self.getClass(i), axis=0))) for i in range(len(P))]
        # 将列表转换成array,便于后续计算
        rStd = np.array(rStd)
        return rMean,rStd,P

    def predict(self,x_test):
        pResult = []
        # 列表式,得到一个n*38的预测矩阵,每一行代表38待预测值在一个分类中的概率
        [(pResult.append(np.prod((np.exp(-(x_test - self.rMean[i]) ** 2 / (2 * self.rStd[i] ** 2)) / (
                    math.sqrt(2 * math.pi) * self.rStd[i])),axis=1) * self.P[i])) for i in range(len(self.P))]
        # 将列表转换成array,便于后续计算
        pResult = np.array(pResult)
        # print(f'我是pResult:{pResult}')
        # 得到n*38预测矩阵每一列最大值的行索引
        result = (pResult.argmax(axis=0))
        return result

    # 得到结果为c的数据对应的x,制作c类的x数据矩阵
    def getClass(self,c):
        x = []
        for i in range(len(self.y)):
            if self.y[i][-1] == c:
                x.append(self.x[i])
        # print(f'我是x:{x}')
        return x


# 创建一个机器人
doctor = byes_qingdaifu()
# 训练机器人
doctor.fit(x,y)

# 下面使用38位顾客的数据测试机器人诊断效果
# 读取38位顾客的气色,气味,脉象,体温等特征数据
test_x = pandas.read_csv('test_X.csv').values
# print(f'我是x:{test_x}')

# 诊断! 结果存放到result数组中
result = doctor.predict(test_x)
# print(f'我是result:{result}')

# 打印输出诊断结果,与实际的结果比较
# 读取38位顾客怀孕状态的实际值(0表示女娃,1表示男娃,2表示没有怀孕)
test_y = pandas.read_csv('test_y.csv')
# print(f'我是y_test:/n{test_y}')

labels=['女娃','男孩','没有怀孕']
i = 0
# 正确的诊断数
predictOKNum = 0
print("编号,诊断值,实际值,")
while i < test_y.shape[0]:
    # 第i个诊断结果与实际的第i个结果比较,相等表示诊断正确

    # if result[i] == (test_y.values[i,0]):
    if result[i] == (test_y.values[i,0]):
        predictOKNum = predictOKNum + 1
        okOrNo = '准确'
    else:
        okOrNo = '错误'
    print("%s,%s,%s,%s" %(i+1, labels[result[i]],labels[test_y.values[i,0]],okOrNo))
    i = i+1

print("诊断正确率:%s" % (predictOKNum/i))

在代码测试完以后,可以调用sklearn中自带的byes的API验证一下自己写的代码准确性,GaussianNB;

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
朴素贝叶斯算法是一种常用的分类算法,它将待分类的样本看作是由多个特征组成的向量,然后根据这些特征的先验概率和条件概率,计算出每个类别的后验概率,最终将样本分到概率最大的那个类别中。 在天气预报中,我们可以使用朴素贝叶斯算法来预测明天是否会下雨。假设我们有以下三个特征:今天是否下雨、今天是否多云、今天的气温,它们的取值分别为是或否、是或否、高、中、低。我们可以根据这些特征来构建训练数据集,例如: | 是否下雨 | 是否多云 | 气温 | 是否下雨(标签) | | -------- | -------- | ---- | ---------------- | | 是 | 是 | 高 | 是 | | 否 | 是 | 中 | 否 | | 否 | 否 | 低 | 否 | | 否 | 是 | 低 | 否 | | 是 | 否 | 中 | 是 | | 是 | 是 | 中 | 是 | 现在我们要预测明天是否会下雨,假设明天的气温为“中”,天气情况为“多云”,我们可以使用朴素贝叶斯算法来计算下雨和不下雨的后验概率。 首先,我们需要计算每个类别(下雨和不下雨)出现的先验概率,即: $$P(下雨)=\frac{3}{6}=0.5$$ $$P(不下雨)=\frac{3}{6}=0.5$$ 然后,我们需要计算每个特征在每个类别下的条件概率。以“是否多云”为例,当天不下雨的样本中,“是否多云”为“是”的概率为: $$P(是否多云=是|不下雨)=\frac{1}{3}=0.33$$ 同理,当天不下雨的样本中,“是否多云”为“否”的概率为: $$P(是否多云=否|不下雨)=\frac{2}{3}=0.67$$ 当天下雨的样本中,“是否多云”为“是”的概率为: $$P(是否多云=是|下雨)=\frac{2}{3}=0.67$$ 同理,当天下雨的样本中,“是否多云”为“否”的概率为: $$P(是否多云=否|下雨)=\frac{1}{3}=0.33$$ 其他特征的条件概率也可以用同样的方法计算。最后,我们可以根据贝叶斯公式计算下雨和不下雨的后验概率: $$P(下雨|气温=中,是否多云=是)=\frac{P(气温=中|下雨)P(是否多云=是|下雨)P(下雨)}{P(气温=中)P(是否多云=是)}$$ $$P(不下雨|气温=中,是否多云=是)=\frac{P(气温=中|不下雨)P(是否多云=是|不下雨)P(不下雨)}{P(气温=中)P(是否多云=是)}$$ 其中,$P(气温=中)$和$P(是否多云=是)$可以通过所有样本中对应特征的出现次数计算得到。 最后,比较两个后验概率的大小,即可得出明天是否会下雨的预测结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值