关于包 e1071 R 中朴素贝叶斯算法的查询
Query regarding Naive Bayes algorithm in package e1071 R
下面是我在 R 中用于实现朴素贝叶斯的训练数据集(使用 e1071 包),其中:X、Y、Z 是不同的 classes 和 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属于哪个class,给定值是。所以我的测试数据为:-
V3
Yes
所以,我必须找出每个 class 的概率,即 Probability(X| V3=Yes)、Probability(Y| V3=Yes)、Probability(Z| V3=Yes) 并取三者中的最大值。现在,
概率(X| V3=是)=概率(X) * 概率(V3=是|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:- 使用拉普拉斯平滑
与案例 1 相同的场景 w.r.t。测试数据,使用拉普拉斯的唯一区别是 1。因此,我必须再次找出每个 class 的概率,即概率(X| V3=是),概率(Y| V3=是),概率(Z | V3=是)并从三个中取最大值。
下面是拉普拉斯平滑后的条件概率(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=是)=概率(Y)*概率(V3=是|X)/ P(V3)
概率(Z|V3=是)=概率(Z)*概率(V3=是|X)/ P(V3)
经过我的计算,
概率(X| V3=是)= 0.53 * 0.05555556 / P(V3)=0.029/P(V3)
概率(Y| V3=是)= 0.23 * 0.22222222 / P(V3)=0.051/P(V3)
概率(Z| V3=是)= 0.23 * 0.22222222 / P(V3)=0.051/P(V3)
根据上面的计算,class Y 和 Z 之间应该有一个平局。但是在 R 中输出是不同的。 Class X 显示为输出 class。下面是代码及其相应的输出:-
#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) 的解释。
提前致谢!
问题是您只使用一个样本作为测试数据集,只有一个值 V3
。如果你提供更多的测试数据,你会得到 sensible/expected 结果(只关注你的 case 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为"Yes"时的第2列条件概率,从而得到正确的结果。
我很确定您的 案例 2 与此类似。
希望对您有所帮助。
评论后编辑: 我想解决它的更简单方法是将所有数据放在一个 data.frame 和 select 索引中您用于 training/testing 您的模型。许多函数接受 subset
到 select 用于训练的数据,naiveBayes
也不例外。但是,对于 predict.naiveBayes
你必须 select 索引。像这样。
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
EDIT2 评论后: 关于为什么会发生这种情况的更多详细信息。
当你定义你的 test
数据帧时只包含一个等于 "No" 的值,data.matrix
执行的转换实际上无法知道你的变量 V3
有 2 个可能的值,"Yes" 和 "No"。 test$V3
其实是一个因子:
test <- data.frame(V3="Yes")
class(test$V3)
[1] "factor"
如前所述,它只有一层(data.frame 无法知道实际上有 2 层)
levels(test$V3)
[1] "Yes"
如您在 docs 中所见,data.matrix
的实施使用了以下因素的水平:
Factors and ordered factors are replaced by their internal codes.
因此,当将 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
我遇到了同样的问题,这确实是所有关于因素的问题!您必须同步训练数据和为预测提供的新数据之间的因素水平。 (如 Rinzcig 在上面 'edit 2' 中所述。)
e1071 中的朴素贝叶斯函数将所有字符数据转换为因子。您必须控制此转换,否则您会得到意想不到的结果。
您只需要这行代码:
test <- data.frame(V3=factor("Yes", levels=levels(all_data$V3)))
你可以看到我有 same issue and solution here.
下面是我在 R 中用于实现朴素贝叶斯的训练数据集(使用 e1071 包),其中:X、Y、Z 是不同的 classes 和 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属于哪个class,给定值是。所以我的测试数据为:-
V3
Yes
所以,我必须找出每个 class 的概率,即 Probability(X| V3=Yes)、Probability(Y| V3=Yes)、Probability(Z| V3=Yes) 并取三者中的最大值。现在,
概率(X| V3=是)=概率(X) * 概率(V3=是|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:- 使用拉普拉斯平滑
与案例 1 相同的场景 w.r.t。测试数据,使用拉普拉斯的唯一区别是 1。因此,我必须再次找出每个 class 的概率,即概率(X| V3=是),概率(Y| V3=是),概率(Z | V3=是)并从三个中取最大值。
下面是拉普拉斯平滑后的条件概率(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=是)=概率(Y)*概率(V3=是|X)/ P(V3)
概率(Z|V3=是)=概率(Z)*概率(V3=是|X)/ P(V3)
经过我的计算,
概率(X| V3=是)= 0.53 * 0.05555556 / P(V3)=0.029/P(V3)
概率(Y| V3=是)= 0.23 * 0.22222222 / P(V3)=0.051/P(V3)
概率(Z| V3=是)= 0.23 * 0.22222222 / P(V3)=0.051/P(V3)
根据上面的计算,class Y 和 Z 之间应该有一个平局。但是在 R 中输出是不同的。 Class X 显示为输出 class。下面是代码及其相应的输出:-
#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) 的解释。
提前致谢!
问题是您只使用一个样本作为测试数据集,只有一个值 V3
。如果你提供更多的测试数据,你会得到 sensible/expected 结果(只关注你的 case 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为"Yes"时的第2列条件概率,从而得到正确的结果。
我很确定您的 案例 2 与此类似。
希望对您有所帮助。
评论后编辑: 我想解决它的更简单方法是将所有数据放在一个 data.frame 和 select 索引中您用于 training/testing 您的模型。许多函数接受 subset
到 select 用于训练的数据,naiveBayes
也不例外。但是,对于 predict.naiveBayes
你必须 select 索引。像这样。
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
EDIT2 评论后: 关于为什么会发生这种情况的更多详细信息。
当你定义你的 test
数据帧时只包含一个等于 "No" 的值,data.matrix
执行的转换实际上无法知道你的变量 V3
有 2 个可能的值,"Yes" 和 "No"。 test$V3
其实是一个因子:
test <- data.frame(V3="Yes")
class(test$V3)
[1] "factor"
如前所述,它只有一层(data.frame 无法知道实际上有 2 层)
levels(test$V3)
[1] "Yes"
如您在 docs 中所见,data.matrix
的实施使用了以下因素的水平:
Factors and ordered factors are replaced by their internal codes.
因此,当将 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
我遇到了同样的问题,这确实是所有关于因素的问题!您必须同步训练数据和为预测提供的新数据之间的因素水平。 (如 Rinzcig 在上面 'edit 2' 中所述。)
e1071 中的朴素贝叶斯函数将所有字符数据转换为因子。您必须控制此转换,否则您会得到意想不到的结果。
您只需要这行代码:
test <- data.frame(V3=factor("Yes", levels=levels(all_data$V3)))
你可以看到我有 same issue and solution here.