多项式朴素贝叶斯分类疑问:是否需归一化?预测结果不符排查
简单来说:不需要。
多项式朴素贝叶斯(MultinomialNB)的核心逻辑是基于特征的计数或频率分布计算概率,它关注的是特征在不同类别中的相对出现次数,而非特征的绝对数值范围。
举个例子:如果把所有特征值都乘以2,某个特征在类别A中的计数从10变成20,在类别B中从5变成10,它们的相对比例(2:1)并没有改变,这对MultinomialNB的概率计算完全没有影响。
传统的归一化方法(比如MinMaxScaler把特征缩放到[0,1]、StandardScaler标准化到均值0方差1)主要是为了适配对特征数值范围敏感的模型(比如SVM、线性回归),但对MultinomialNB这类基于计数的模型来说,完全没有必要。甚至有时候,归一化反而会破坏特征的计数意义(比如把整数计数变成小数,虽然不影响比例,但毫无必要)。
不过要注意:如果你的特征是TF-IDF这类已经做过归一化的文本特征,那是可以直接用的——但这是特征工程的一部分,不是模型强制要求的归一化。
我们一步步拆解你的代码问题:
核心问题1:测试数据的有效特征全为0
你用DictVectorizer训练时,只拟合了训练数据里的特征:house、street、shop、car、tree、river。而测试数据里的testname、Hi、Blue都是训练集从未出现过的特征,DictVectorizer会直接忽略这些特征。最终转换后的测试样本是一个全0向量(训练集中的特征在测试数据里要么没提及,要么值为0)。
核心问题2:全0输入下的概率计算逻辑
当输入全0向量时,MultinomialNB计算后验概率的公式里,特征项的贡献会全部为0,只剩下类先验概率。你的训练集里两个类别(10和20)各有1个样本,所以先验概率都是0.5。这时候模型会默认返回训练集中先出现的类别(也就是10),这就是你得到[10]的原因。
为什么预期[20]不合理?
你的测试数据里没有任何和类别20强相关的特征——类别20的标志性特征是tree:500和river:1,但测试数据里这两个特征的值都是0(因为没提),模型找不到任何理由把它归为20类。
修复方案
如果想让测试数据预测为20,需要在测试数据中加入类别20的典型特征,比如:
test_data1 = [ {'tree': 600, 'river': 1}, # 加入类别20的高计数特征 ]
这样转换后的测试样本会有tree和river的非0值,模型计算时会倾向于类别20,就能得到你预期的结果。
内容的提问来源于stack exchange,提问作者nmathew

