机器学习之朴素贝叶斯三、拉普拉斯平滑技术、优化改进情感分析

文章介绍了在情感分析中遇到的零概率问题,以及如何通过拉普拉斯平滑技术进行优化。通过添加虚拟样本和使用对数运算防止下溢上溢,优化了条件概率和后验概率的计算,提升了模型性能。此外,还提到了数据不平衡对结果的影响和特征工程的重要性。

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

一、前文问题

改进前情感分析实践

1. 先看下改进前我们的代码计算部分

条件概率计算部分

在这里插入图片描述看下训练后的结果展示

在这里插入图片描述

2. 问题分析

可以看到此时的训练后的结果是,在开心和伤心的条件概率中存在0,的结果。那么在计算后验概率P(C|X)其中X是特征C是label。发现:计算的结果为0
原因是什么?
来看下我们的条件概率计算过程是什么:

'''
	在计算样本 x 属于某个类别 C 的后验概率时,朴素贝叶斯假设各个特征之间相互独立,即 
	p(x|C) = p(x1|C)p(x2|C)...p(xn|C),其中 x1, x2, ..., xn 分别是特征向量的不同维
	度。这个假设简化了计算过程,但是忽略了特征之间的相关性。	
	根据贝叶斯公式,朴素贝叶斯可表示为: p(C|x) = p(x|C)p(C)/p(x) 其中,p(x|C) 表示在类
	别 C 下特征向量 x 出现的概率,p(C) 表示类别 C 的先验概率,p(x) 表示特征向量出现的概
	率。由于对于所有类别都是相同的,所以可以省略分母 p(x)

	可以看到vec_0 =  array_0/_0计算的就是p(x|C) = p(x1|C)p(x2|C)...p(xn|C)
	也就是当是开心样本的时候,是特征 X 的概率。
	array_0,中的每一个维度就是一个特征,那么array_0将所有开行样本中的数据相加,也就计算出
	了,每个特征发生次数。那么就可以计算,当开心label时候,特征X发生的概率。即 每个特征发生
	次数/总的样本发生次数
	_0 计算的就是,开心样本数据中,总的样本发生次数。
'''

可以看到,array_0计算的是 每个特征发生次数/总的样本发生次数,那么如果我们的样本中某个特征发生次数为0,这个时候这进行p(x|C) = p(x1|C)p(x2|C)...p(xn|C)计算的时候,就会出现为0的情况。

二、针对问题进行解决

我们经过分析知道问题所在那么可以针对问题进行解决了。

1. 什么是拉普拉斯平滑技术

拉普拉斯平滑是一种用于解决朴素贝叶斯算法中零概率问题的技术。在计算条件概率时,有些情况下会出现某个特征在某个类别下没有出现过的情况导致概率为零,这就无法使用贝叶斯公式进行计算。为了避免这种情况,可以对概率进行平滑处理,使得每个特征在每个类别下至少出现一次,从而避免概率为零的情况。而拉普拉斯平滑就是一种常用的平滑方法,它在计算概率时将每个特征的计数都加上一个常数k,从而保证每个特征至少出现k次

2. 拉普拉斯优化-下溢上溢问题

在进行拉普拉斯平滑时,条件概率的计算会涉及多个特征的连乘积,这容易导致数值过小而出现下溢(underflow)或者上溢(overflow)的问题。因此,为了避免这种问题,在实际应用中通常会使用对数操作将连乘积转换成加和运算,从而方便计算。同时,取对数还有一个好处是可以简化计算,因为对数具有以下常用的运算规则:

log(a*b) = log(a) + log(b)
log(a/b) = log(a) - log(b)
通过这些运算规则,可以大大简化计算,并且防止由于浮点数的精度限制而导致的计算误差。因此,在进行拉普拉斯优化时,经常会使用对数操作来计算条件概率

3. 改进地方分析:

在这里插入图片描述
看到我们在进行初始化的时候,使用的是np.zeros()函数,也就造成前面说的问题。

4.改进优化

1.优化一,对条件概率计算进行优化

def train(data,label):
    '''
    :param data: 这里的数据是样本经过向量化后的向量信息
    :param label:  样本所对应的标签信息
    :return:
    1. vec_0 --- 开心的条件概率组
    2. vec_1 --- 伤心的条件概率组
    3. simple_1 --- 样本数据属于伤心的概率
    '''
    num_simple = len(data) #样本的数量
    num_words = len(data[0]) #统计每个样本的词的数据量

    simple_1 = sum(label)/float(num_simple)  #计算的是伤心的
    '''
    这里说明一下,为什么使用的是sum(label) 来进行计算:
    正常这里应该是,属于伤心的样本数据/总的样本数
    那么我们这里用sum的效果就是,伤心样本的数量,因为伤心
    的label为1,开心为0,所有label的和就是,伤心的数量
    这里取巧了。
    '''
    #todo 改进一
    # 进行条件概率数组初始化
    # array_0,array_1 = np.zeros(num_words),np.zeros(num_words)
    array_0,array_1 = np.ones(num_words),np.ones(num_words) #todo 改进一
    _0 = 2.0 #todo 改进
    _1 = 2.0 #这里是多求条件概率的分母进行初始化,至于怎么用后面说
	'''
	这里为甚使用np.ones,和2来进行优化,这个没有定数,你可以自己指定,
	用这个主要还是好计算
	'''


    #todo 对所有伤心的样本进行计算条件概率
    for i in range(num_simple):
        if label[i] == 1: #伤心
            array_1 += data[i]
            _1 += sum(data[i])
        else: #开心
            array_0 += data[i]
            _0 += sum(data[i])

    #todo 改进优化二
    # vec_0 =  array_0/_0
    vec_0 =  np.log(array_0/_0)
    vec_1 =  np.log(array_1/_1)
    return vec_0,vec_1,simple_1

改进后的结果

在这里插入图片描述

2.优化二,对后延概率计算进行优化

在这里插入图片描述
这里分析一下为什么使用对数优化

pro_0 = sum(vec_test*vec_0) * np.log(1 - simple_1)
print('pro_0:',pro_0)
#pro_1 = reduce(lambda x,y:x*y,vec_test*vec_1) * simple_1
pro_1 = sum(vec_test*vec_1) * np.log(simple_1)
'''
这里pro_0 计算的是后验概率P(C|X),我们的vec_0计算的是条件概率,
我们知道朴素贝叶斯:后验概率=先验概率*条件概率
根据 log(后验概率)=log(先验概率) + log(条件概率)
vec_0在训练的时候已经进行log()过了。
'''


print('pro_1:',pro_1)
if pro_0 > pro_1:
    return 0
else:
    return 1

改进后结果展示

在这里插入图片描述

3. 优化结果分析

可以看到优化后的结果,效果直线上升。
后续问题::::
但是我在进行优化后的代码执行的的时候,依然会遇到,不能识别的类别的情况,甚至,分类的记过都是一种情况,经过试验我发现是因为,样本数据不均衡导致的,我适当优化下数据集,就好了。
由此可以看到,机器学习,对数据特征工程依赖还是很大的,到没有深度端到端来的爽,但是机器学习有着深度不可替代的能力。

三、源码

改进后的源码

致谢

四、下一篇 学习如何做舆情分析

参考资源链接:[Python实现朴素贝叶斯分类器详解](https://wenku.youkuaiyun.com/doc/645ba61695996c03ac2d8655?utm_source=wenku_answer2doc_content) 要在Python中实现朴素贝叶斯分类器并使用拉普拉斯平滑处理未出现的属性值,我们可以参考《Python实现朴素贝叶斯分类器详解》一文,其中详细解释了朴素贝叶斯算法的原理及其实现步骤。以下是一个简化的代码实现示例: ```python import numpy as np from collections import defaultdict class NaiveBayesClassifier: def __init__(self): self.tag_probablity = {} self.feature_conditional_prob = {} self.fillNa = 1 def train(self, X_train, y_train): # 计算每个标签的概率 for tag in set(y_train): self.tag_probablity[tag] = np.sum(y_train == tag) / len(y_train) # 计算特征的条件概率 for i in range(len(X_train[0])): for tag in set(y_train): feature_prob = defaultdict(lambda: self.fillNa) for x, y in zip(X_train, y_train): if y == tag: feature_prob[x[i]] += 1 self.feature_conditional_prob[(i, tag)] = feature_prob def predict(self, X): y_pred = [] for x in X: posteriors = [] for tag in self.tag_probablity: prior = np.log(self.tag_probablity[tag]) cond_prob = sum( np.log(self.feature_conditional_prob[(i, tag)][x_i]) for i, x_i in enumerate(x) ) posteriors.append(prior + cond_prob) y_pred.append(np.argmax(posteriors)) return y_pred # 示例数据 X_train = [[1,0],[1,1],[0,1],[1,1]] y_train = [1, 1, 0, 1] # 训练模型 nb_classifier = NaiveBayesClassifier() nb_classifier.train(X_train, y_train) # 预测新数据 X_test = [[1,0],[1,1]] print(nb_classifier.predict(X_test)) ``` 在此代码中,我们首先初始化了一个朴素贝叶斯分类器类`NaiveBayesClassifier`,它包含了训练和预测两个方法。`train`方法用于计算每个类别的先验概率和每个特征在给定类别下的条件概率。在计算条件概率时,我们使用了一个字典`feature_conditional_prob`来存储每个特征在每个类别下的概率。当遇到一个在训练集中未出现的特征值时,通过`fillNa`值(默认为1)来进行拉普拉斯平滑,确保概率不为零。 在`predict`方法中,我们通过计算后验概率来预测新数据的标签。后验概率是通过将先验概率与条件概率相乘得到的,并取对数以防止数值下溢。 此代码示例展示了如何在Python中实现朴素贝叶斯分类器,并处理了未出现的特征值的情况。读者可以通过《Python实现朴素贝叶斯分类器详解》了解更多细节和实例,以深入理解算法的实现过程和背后的概率统计原理。 参考资源链接:[Python实现朴素贝叶斯分类器详解](https://wenku.youkuaiyun.com/doc/645ba61695996c03ac2d8655?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QuietNightThought

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值