关于 (1),modify
取 alist
或 a atomic vector
。bn_fit
是类的bn.fit, bn.fit.dnet
,但是,在引擎盖下它也是类list
,因为调用typeof()
yield list
。我的猜测是没有用于子集这些类的 S3 通用方法,因此 R 发现它本质上是 alist
并因此剥离了类参数。所以 subsettingbn_fit
把它变成class
list
,因此你可以使用modify
它。子集甚至可以用空括号来完成[]
,它只会返回对象,但这次是class
list
. 我在下面使用的另一种方法是“手动”将class
属性设置为NULL
via attr(bnfit, "class") <- NULL
。
关于(2),我编写了一个tidyverse
基于函数,可用于将prob
每个节点的表更改为bayesm::rdirichlet
分布(参见下面的代码)。用户仍然需要提供部分alpha
参数(长度参数由每个 prob 的长度给出table
)。在引擎盖下,该功能依赖于purrr::modify
. 它通过首先剥离它们并在修改完成后将它们添加回来来处理这些类。我的方法是将 prob table
s 转换为sdata.frame
然后修改Freq
列并针对现有的其他变量(组)进行调整,然后通过.data.frame
table
xtabs
reformulate
我对贝叶斯网络不是很深入,所以我不知道这个函数可以推广到什么程度,或者它是否只适用于你提供的数据集。此外,请测试修改后的对象是否被期望 class 的函数接受bn.fit, bn.fit.dnet
。
我试图评论我的代码的每一步,但请询问是否有不清楚的地方。
(3)关于您的问题,为什么NROW(.x)
在您的代码中不起作用并且您必须使用 NROW(node$prob) 代替:这与modify
在 prob 上循环的方式有关table
。检查循环的元素的一个好方法modify
是使用purrr::pluck
.
library(bnlearn)
library(tidyverse)
data(insurance)
bn <- tabu(insurance, score = "bic")
bn_fit <- bn.fit(bn, insurance, method = 'bayes')
change_bn_prob_table <- function(bnfit, alpha) {
# save class attribute of bnfit object
old_class <- attr(bnfit, "class")
# strip class so that `modify` can be used
attr(bnfit, "class") <- NULL
# loop over `prop` tables of each node
new <- purrr::modify(bnfit, function(x) {
# save attributes of x
old_x_attr <- attributes(x)
# save attributes of x[["prob"]]
old_xprob_attr <- attributes(x[["prob"]])
# turn `table` into data.frame
inp <- as.data.frame(x[["prob"]])
# save names apart from `Freq`
cnames <- inp %>% select(-Freq) %>% colnames
out <- inp %>%
# overwrite column `Freq` with probabilities from bayesm::rdirichlet
# alpha needs to be supplied (the length of alpha is given by `nrow`)
mutate(Freq := bayesm::rdirichlet(c(rep(alpha, nrow(inp))))) %>%
# devide probilities by sum of Freq in all remaining groups
group_by(!!! syms(cnames[-1])) %>%
mutate(Freq := Freq/sum(Freq)) %>%
# turn data.frame back into prob table using formula notation via reformulate
xtabs(reformulate(paste(colnames(.)), "Freq"), .)
# strip `call` attribute from newly generated prob table
attr(out, "call") <- NULL
# add `class` `table` as attribute
attr(out, "class") <- "table"
# restore old attribues and write x out to x$prob
attributes(out) <- old_xprob_attr
x[["prob"]] <- out
# restore old attribues and return x
attributes(x) <- old_x_attr
x
})
# add saved class attributes
attr(new, "class") <- old_class
new
}
# here `2` is the first part of `alpha` of `bayesm::rdirichlet`
bn_fit2 <- change_bn_prob_table(bn_fit, 2)
# test that `logLik` can be used on new modified bnfit object
logLik(bn_fit2, insurance)
#> [1] -717691.8
由reprex 包(v0.3.0)于 2020-06-21 创建