使用scikit-learn混合类别数据和连续数据在朴素贝叶斯分类器中

78

我正在使用Python的scikit-learn来开发一个分类算法,以预测特定客户的性别。其中,我想使用朴素贝叶斯分类器,但我的问题是我有混合了分类数据(例如:“在线注册”,“接受电子邮件通知”等)和连续数据(例如:“年龄”,“会员时长”等)。我之前没有使用过scikit,但我认为高斯朴素贝叶斯适用于连续数据,伯努利朴素贝叶斯可以用于分类数据。然而,由于我想在模型中有同时包含分类和连续数据,我不知道该如何处理。非常感谢任何想法!


4
你能告诉我哪一个解决方案对你最有效吗? - ksiomelo
6个回答

75

你至少有两个选择:

  • 通过计算每个连续变量的百分位数,并使用这些百分位数作为分界点对连续变量进行分组,将所有数据转换为分类表示。例如,对于人的身高,创建以下组:"非常矮"、"矮"、"正常"、"高"、"非常高",确保每个组包含大约训练集人口的20%。我们在scikit-learn中没有自动执行此操作的实用程序,但自己做应该不太复杂。然后,在这些数据的分类表示上拟合一个唯一的多项式NB。

  • 在数据的连续部分上独立地拟合高斯NB模型,在分类部分上拟合多项式NB模型。然后通过采用类别分配概率(使用predict_proba方法)作为新特征来转换整个数据集:np.hstack((multinomial_probas,gaussian_probas)),然后在新特征上重新拟合模型(例如新的高斯NB)。


8
我理解您的意思是第二种方法可能会忽略连续和分类数据之间的相关性,例如,假设在线注册的年轻人通常是男性,而没有在线注册的年轻人通常是女性。但是为了具体起见,假设高斯朴素贝叶斯模型预测年轻人(不知道分类数据)通常是男性。由于第二阶段高斯朴素贝叶斯只传递这个概率,它将忽略这种相关性。 - unutbu
14
朴素贝叶斯分类器假设在给定类别的情况下,特征之间是独立的。上述列出的第一种方法将独立地学习P(age | gender)P(registration_type | gender)。对于给定性别,年龄和注册类型之间的相关性将不会被捕捉到。 - Sam
@ogrisel,我们可以使用一位有效编码将分类变量转换为0到n-1之间的值,其中n表示类别数,并保留高斯朴素贝叶斯分类器中连续变量的原始值吗?这是基于以下文章:http://dataaspirant.com/2017/02/20/gaussian-naive-bayes-classifier-implementation-python/。 - jai
1
@jai,不!首先,独热编码与将变量转换为0到n-1之间的值并不相同。其次,将分类变量转换为0到n-1之间的值,然后将它们视为连续变量是没有意义的。第三,独热编码的分类变量非常非高斯,将它们视为高斯变量(GaussianNB所假设的)在我的经验中并不能产生良好的结果。 - Him
@ogrisel,我认为predict_proba是用于预测“测试”数据的概率。例如,我在训练数据上创建了2个单独的分类器,然后我可以使用它来预测我的剩余“测试”数据的概率。如果我然后从“测试”数据的predict_proba结果中训练另一个高斯模型,那么我就没有什么可测试的了吗?我理解得对吗?干杯 - Chuck
关于第二个要点。我无法完全理解将高斯朴素贝叶斯拟合到连接概率上的实际作用,以及结果如何与其他答案中描述的正确朴素贝叶斯模型相比。有什么想法吗? - paperskilltrees

17

希望我不算太晚。我最近编写了一个名为Mixed Naive Bayes的库,使用NumPy编写。它可以假定在训练数据特征上有高斯分布和分类(multinoulli)分布的混合。

https://github.com/remykarem/mixed-naive-bayes

该库的API与scikit-learn类似。

在下面的示例中,假设前两个特征来自分类分布,后两个来自高斯分布。在fit()方法中,只需指定categorical_features = [0,1],这表示列0和1将遵循分类分布。

from mixed_naive_bayes import MixedNB
X = [[0, 0, 180.9, 75.0],
     [1, 1, 165.2, 61.5],
     [2, 1, 166.3, 60.3],
     [1, 1, 173.0, 68.2],
     [0, 2, 178.4, 71.0]]
y = [0, 0, 1, 1, 0]
clf = MixedNB(categorical_features=[0,1])
clf.fit(X,y)
clf.predict(X)

可以通过pip install mixed-naive-bayes来安装。有关用法的更多信息请参阅README.md文件。欢迎贡献代码 :)


15
简单答案:乘积。结果是一样的。
朴素贝叶斯是基于贝叶斯定理的应用,它假设每对特征之间相互独立 - 这意味着在计算一个特定特征的贝叶斯概率时不考虑其他特征,这意味着该算法将从一个特征中的每个概率值乘以第二个特征中的概率值(因为分母只是一个标准化常数,完全可以忽略)。
因此,正确答案如下:
1. 计算分类变量的概率。 2. 计算连续变量的概率。 3. 将步骤1和步骤2的概率值相乘。

高斯朴素贝叶斯为先验提供了密度估计。我不确定您所说的第二部分意思是什么。 - Davis
我的意思是现在没有Pr(x_i | y)了,而是用Norm(mu_i, sig_i)来替代先验概率,因为随机变量X_i是连续的,所以Pr(X_i = x | y)的概率为零。Norm(mu_i, sig_i)是密度估计。 - Davis
我认为你的问题与主题无关,但你可以从以下链接中获取答案:https://stats.stackexchange.com/questions/26624/pdfs-and-probability-in-naive-bayes-classification - Yaron
Yaron,当你说“计算概率”时,这是在测试数据还是训练数据上进行的?你会使用哪个函数来完成这个任务?你是否在训练数据上使用predict-proba函数并进行拟合?我很难弄清楚应该乘以什么...谢谢。 - Chuck
@Chuck,当然不是,你应该只在测试集上使用predict。 - Yaron
显示剩余3条评论

1

@Yaron的方法需要额外的一步(第4步):

  1. 从分类变量计算概率。
  2. 从连续变量计算概率。
  3. 将1和2相乘
  4. 将3除以1和2的乘积之和。编辑:我实际上想表达的是分母应该是(在假设为“是”的情况下给出事件的概率)+(在假设为“否”的情况下给出证据的概率)(假设为二元问题,不失一般性)。因此,给定证据的假设()的概率总和为1。
第四步是标准化步骤。以@remykarem的mixed-naive-bayes为例(参见268-278行):
        if self.gaussian_features.size != 0 and self.categorical_features.size != 0:
            finals = t * p * self.priors
        elif self.gaussian_features.size != 0:
            finals = t * self.priors
        elif self.categorical_features.size != 0:
            finals = p * self.priors

        normalised = finals.T/(np.sum(finals, axis=1) + 1e-6)
        normalised = np.moveaxis(normalised, [0, 1], [1, 0])

        return normalised

高斯和分类模型的概率(分别用和

表示)在第269行(上面提取的第2行)相乘,然后像上面提取的底部第四行中的4.一样进行归一化,在第275行进行。


1
您需要执行以下步骤:
  1. 从分类变量中计算概率(使用BernoulliNBpredict_proba方法)
  2. 从连续变量中计算概率(使用GaussianNBpredict_proba方法)
  3. 将步骤1和2相乘 AND
  4. 除以先验概率(可以使用从数据中学习到的BernoulliNBGaussianNB的先验概率,因为它们相同) AND THEN
  5. 将步骤4除以步骤4在所有类别上的总和。这是归一化步骤。
您可以很容易地看到如何添加自己的先验概率而不是使用从数据中学习到的概率。

1

针对混合功能,您可以查看this的实现。

作者在他的Quora答案中提供了数学证明,您可能想要查看。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接