查询包 e1071 R 中的朴素贝叶斯算法

Posted

技术标签:

【中文标题】查询包 e1071 R 中的朴素贝叶斯算法【英文标题】:Query regarding Naive Bayes algorithm in package e1071 R 【发布时间】:2016-06-23 20:14:28 【问题描述】:

下面是我在 R(使用 e1071 包)中用于朴素贝叶斯实现的训练数据集,其中:X、Y、Z 是不同的类,V1、V2、V3、V4、V5 是属性:-

Class   V1  V2  V3  V4  V5
X       Yes Yes No  Yes Yes
X       Yes Yes No  No  Yes
X       Yes Yes No  No  Yes
X       Yes Yes No  No  Yes
X        No Yes No  No  Yes
X        No Yes No  No  Yes
X        No Yes No  No  Yes
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
X        No No  No  No  No
Y       Yes Yes Yes No  Yes
Y        No No  No  No  Yes
Y        No No  No  No  Yes
Y        No No  No  No  No
Y        No No  No  No  No
Y        No No  No  No  No
Y        No No  No  No  No
Z        No Yes Yes No  Yes
Z        No No  No  No  Yes
Z        No No  No  No  Yes
Z        No No  No  No  No
Z        No No  No  No  No
Z        No No  No  No  No
Z        No No  No  No  No

上述数据集的先验概率为 X->0.5333333 Y->0.2333333 Z->0.2333333

条件概率是:-

V1
Y          No       Yes
   X 0.7500000 0.2500000
   Y 0.8571429 0.1428571
   Z 1.0000000 0.0000000

V2
Y          No       Yes
   X 0.5625000 0.4375000
   Y 0.8571429 0.1428571
   Z 0.8571429 0.1428571

V3
 Y          No       Yes
   X 1.0000000 0.0000000
   Y 0.8571429 0.1428571
   Z 0.8571429 0.1428571

V4
 Y       No    Yes
   X 0.9375 0.0625
   Y 1.0000 0.0000
   Z 1.0000 0.0000

V5
 Y          No       Yes
   X 0.5625000 0.4375000
   Y 0.5714286 0.4285714
   Z 0.5714286 0.4285714

案例 1:- 未使用拉普拉斯平滑

我想知道 V3 属于哪个类,给定值 Yes。所以我有我的测试数据:-

V3
Yes

所以,我必须找出每个类的概率,即概率(X| V3=Yes),概率(Y| V3=Yes),概率(Z| V3=Yes),并从三个中取最大值.现在,

概率(X| V3=Yes)= 概率(X) * 概率(V3=Yes|X)/ P(V3)

从上面提到的条件概率,我们知道Probability(V3=Yes|X)=0 因此,Probability(X| V3=Yes) 应该为 0,Probability(Y| V3=Yes),Probability(Z| V3=Yes) 应该分别为 0.5。

但是在 R 中输出是不同的。从包 e1071 我使用了 naiveBayes 函数。下面是代码及其对应的输出:-

#model_nb<-naiveBayes(Class~.,data = train,laplace=0)
#results<-predict(model_nb,test,type = "raw")
#print(results)

#         X         Y         Z
#[1,] 0.5714286 0.2142857 0.2142857

有人可以解释一下为什么 R 中的输出是这样的吗?

案例 2:- 使用拉普拉斯平滑

与 Case1 w.r.t 相同的场景。测试数据,使用拉普拉斯的唯一区别是1。所以,我必须再次找出每个类的概率,即概率(X| V3=Yes),概率(Y| V3=Yes),概率(Z| V3=Yes ) 并从三个中取最大值。

以下是拉普拉斯平滑(k=1)后的条件概率

V1
Y          No       Yes
   X 0.7222222 0.2777778
   Y 0.7777778 0.2222222
   Z 0.8888889 0.1111111

V2
Y          No       Yes
   X 0.5555556 0.4444444
   Y 0.7777778 0.2222222
   Z 0.7777778 0.2222222

V3
Y          No        Yes
   X 0.94444444 0.05555556
   Y 0.77777778 0.22222222
   Z 0.77777778 0.22222222

V4
Y          No       Yes
   X 0.8888889 0.1111111
   Y 0.8888889 0.1111111
   Z 0.8888889 0.1111111

V5
Y          No       Yes
   X 0.5555556 0.4444444
   Y 0.5555556 0.4444444
   Z 0.5555556 0.4444444

从朴素贝叶斯定义,

概率(X| V3=是)= 概率(X) * 概率(V3=是|X)/ P(V3)

概率(Y| V3=Yes)= 概率(Y) * 概率(V3=Yes|X)/ P(V3)

概率(Z| V3=Yes)= 概率(Z) * 概率(V3=Yes|X)/ P(V3)

经过计算,

概率(X| V3=Yes)= 0.53 * 0.05555556 / P(V3)=0.029/P(V3)

概率(Y| V3=是)= 0.23 * 0.22222222 / P(V3)=0.051/P(V3)

概率(Z| V3=Yes)= 0.23 * 0.22222222 / P(V3)=0.051/P(V3)

从上面的计算来看,Y 类和 Z 类之间应该有一个平局。但是在 R 中输出是不同的。 X 类显示为输出类。下面是代码及其对应的输出:-

#model_nb<-naiveBayes(Class~.,data = train,laplace=1)
#results<-predict(model_nb,test,type = "raw")
#print(results)


#        X         Y         Z
#[1,] 0.5811966 0.2094017 0.2094017

再次,有人可以解释为什么 R 中的输出是这样的吗?我的计算有问题吗?

另外,需要一些关于在完成拉普拉斯平滑时如何计算 P(V3) 的解释。

提前致谢!

【问题讨论】:

【参考方案1】:

问题是您只使用一个样本作为测试数据集,只有一个值V3。如果您提供更多测试数据,您将获得合理/预期的结果(仅关注您的 案例 1):

test <- data.frame(V3=c("Yes", "No"))
predict(model_nb, test, type="raw")
               X         Y         Z
[1,] 0.007936508 0.4960317 0.4960317
[2,] 0.571428571 0.2142857 0.2142857

请注意,对于 V3="Yes",您不会得到准确的 0、0.5、0.5,因为该函数使用了一个阈值 - 您可以调整该阈值,请通过 ?predict.naiveBayes 获取更多信息。

问题实际上是由于predict.naiveBayes的内部实现(源代码在CRAN存储库)。细节我就不一一赘述了,但基本上我已经调试过函数了,在某个步骤里面有这一行,

newdata <- data.matrix(newdata)

稍后将决定使用哪一列条件概率。使用您的原始数据,data.matrix 如下所示:

data.matrix(data.frame(V3="Yes"))
     V3
[1,]  1

因此,它稍后假设条件概率将从第 1 列中获取,即 V3="No" 的值为 1.0000000、0.8571429 和 0.8571429,这就是为什么您得到的结果好像 V3 实际上是“No”。

然而,

data.matrix(data.frame(V3=c("Yes", "No")))
     V3
[1,]  2
[2,]  1

在 V3 为“是”时给出条件概率的第 2 列,因此您会得到正确的结果。

我很确定您的 案例 2 是类似的。

希望对你有帮助。

在 cmets 之后编辑: 我想更简单的解决方法是将所有数据放在一个 data.frame 中,然后选择用于训练/测试模型的索引。许多函数接受subset 来选择您用于训练的数据,naiveBayes 也不例外。但是,对于predict.naiveBayes,您必须选择索引。像这样。

all_data <- rbind(train, c(NA, NA, NA, "Yes", NA, NA))
trainIndex <- 1:30
model_nb <- naiveBayes(Class~., data=all_data, laplace=0, subset=trainIndex)
predict(model_nb, all_data[-trainIndex,], type="raw")

给出预期的结果。

               X         Y         Z
[1,] 0.007936508 0.4960317 0.4960317

请注意,这是可行的,因为在这种情况下,当您执行 data.matrix 操作时,您会得到正确的结果。

data.matrix(all_data[-trainIndex,])
   Class V1 V2 V3 V4 V5
31    NA NA NA  2 NA NA

在 cmets 之后的 EDIT2:更多关于为什么会发生这种情况的详细信息。

当您定义您的 test 数据框时,只包含一个等于“否”的值,data.matrix 执行的转换实际上无法知道您的变量 V3 有 2 个可能的值,“是”和“不”。 test$V3其实是一个因素:

test <- data.frame(V3="Yes")
class(test$V3)
[1] "factor"

正如所说,它只有一个级别(data.frame 无法知道实际上有 2 个)

levels(test$V3)
[1] "Yes"

data.matrix 的实现,如您在docs 中所见,使用因子的水平:

因子和有序因子被它们的内部代码替换。

因此,当将 test 转换为 data.matrix 时,它会解释该因子只有一个可能的值并对其进行解码,

data.matrix(test)
     V3
[1,]  1

但是,当您将训练和测试放入同一个数据框中时,因子水平会得到正确定义。

levels(all_data$V3)
[1] "No"  "Yes"

如果你这样做,结果会是一样的:

test <- data.frame(V3=factor("Yes", levels=levels(all_data$V3)))
test
   V3
1 Yes
levels(test$V3)
[1] "No"  "Yes"
data.matrix(test)
     V3
[1,]  2

【讨论】:

是的,它有帮助!在我的情况下,我会更感兴趣的是只找到这样的实例 P(Class|Attribute="Yes") 。但是由于 predict.naiveBayes 的内部实现,我必须同时提供属性的值,即 Yes 和 No 以获得所需的结果(在我的情况下是 Yes)。有什么办法可以解决这个问题? 我用比提供两个值更实用的解决方案更新了我的答案。如果您仍有疑问或问题,请告诉我。干杯。 谢谢。我喜欢将所有值放在一个 data.frame 中并使用索引来训练/测试模型的部分。最后一个疑问:- 测试数据是什么时候 V3= Yes data.matrix(data.frame(V3="Yes")) V3 [1,] 1 #Here column being taken is 1 测试数据是什么时候 all_data &lt;- rbind(train, c(NA, NA, NA, "Yes", NA, NA)) data.matrix(all_data[-trainIndex,]) Class V1 V2 V3 V4 V5 31 NA NA NA 2 NA NA #Here column being taken is 2 为什么会这样? 嗨。我已经用更多解释更新了答案。希望现在更清楚了。谢谢。 是的。得到了图片。非常感谢!【参考方案2】:

我也遇到了同样的问题,而且确实是所有关于因素!您必须在训练数据和为预测而呈现的新数据之间同步因素水平。 (正如上面“编辑 2”中提到的 Rinzcig。)

e1071 中的朴素贝叶斯函数将所有字符数据转换为因子。您必须控制此转换,否则您会得到意想不到的结果。

正是你需要的这行代码:

test <- data.frame(V3=factor("Yes", levels=levels(all_data$V3)))

你可以看到我有same issue and solution here.

【讨论】:

以上是关于查询包 e1071 R 中的朴素贝叶斯算法的主要内容,如果未能解决你的问题,请参考以下文章

R (e1071) 中的朴素贝叶斯分类器的行为不符合预期(简单示例)

R Shiny 中的朴素贝叶斯实现

带有 R 的朴素贝叶斯分类 - 奇怪的结果

朴素贝叶斯 e1071 将每个姓氏分类为相同的祖先

R 保存朴素贝叶斯进行训练,R 相当于 Python 的 pickle。

译文:朴素贝叶斯算法简介(Python和R中的代码)