Using bnlearn Function "cpquery" Within a Loop
Asked Answered
I

3

8

I'm attempting to use the bnlearn package to calculate conditional probabilities, and I'm running into a problem when the "cpquery" function is used within a loop. I've created an example, shown below, using data included with the package. When using the cpquery function in a loop, a variable created in the loop ("evi" in the example) is not recognized by the function. I receive the error:

Error in parse(text = evi) : object 'evi' not found

The creation steps of "evi" are based on examples provided by the author.

Any help you could provide would be great. I'm desperate to find a way that I can apply the cpquery function for a large number of observations.

library(bnlearn)
data(learning.test)
fitted = bn.fit(hc(learning.test), learning.test)

bn.function <- function(network, evidence_data) {
  a <- NULL
  b <- nrow(evidence_data)
  for (i in 1:b) {
    evi <- paste("(", names(evidence_data), "=='",
               sapply(evidence_data[i,], as.character), "')",
               sep = "", collapse = " & ")
    a[i] <- cpquery(network, (C=='c'), eval(parse(text=evi)))
  }
  return(a)
}

test <- bn.function(fitted, learning.test)

Thanks in advance!

Injection answered 8/10, 2013 at 23:51 Comment(3)
I've been in contact with the author of the bnlearn package, and it appears the error I am receiving is due to a scoping problem with the cpquery function. This is evident when I'm able to get the cpquery function to work properly in a for-loop that is constructed outside of a user-defined function, but have the error when the same for-loop is used inside of a user-defined function.Injection
I was having a similar issue with cpquery in loops and a quick workaround that worked for me was to include a line evi <<- evi before the cpquery call. This defines the variable in the global environment.Confessor
I guess your problem was solved here: #44677001Mueller
K
0

To avoid the scoping problem, you can postpone the call to eval and do it inside the cpquery function. If you directly pass evi (the character variable) to cpquery and then parse it inside the definition, the chain of environments gets shifted and cpquery will have access to evi.

You can use m.cpquery <- edit(cpquery) to fork your own version of the function and insert the following line at its beginning:

evidence = parse(text = evidence)

and then save your new function.

So the heading of m.cpquery will look like:

> m.cpquery
function (fitted, event, evidence, cluster = NULL, method = "ls", 
    ..., debug = FALSE) 
{
    evidence = parse(text = evidence)
    check.fit(fitted)
    check.logical(debug)
...

Now you can use m.cpquery in your own function like before, except we'll pass the plain character variable to it:

a[i] <- m.cpquery(network, (C=='c'), evi)

Note that in the first line of m.cpquery, we only parsed the evidence character variable and didn't call eval on it. cpquery is a front-end to conditional.probability.query (see here) and we're relying on conditional.probability.query's subsequent call to eval.

I should say that this is a rather ugly workaround. And it only works if you are using logic sampling (method='ls'). But if you want to use likelihood weighting, the check.mutilated.evidence function will raise an error. I haven't checked if injecting an eval expression before it gets called would result in a mayhem of subsequent errors leading to hell.

Kerseymere answered 2/10, 2016 at 13:22 Comment(0)
B
0

I don't know if this is due to a bugfix or just because I tried another approach - anyways, looping works if you iteratively build up the evidence list outside of the cpquery-function.

An example for an iteration through a list called evidenceData with all-positive evidences:

for(i in names(evidenceData)){
  loopEvidenceList <- list()
  loopEvidenceList[[i]] <- "TRUE"
  a =cpquery(fitted = bayesNet, event = queryNode == "TRUE", 
             evidence = loopEvidenceList, method = "lw", n = 100000)
  print(a)
  }

Depending on the way your evidence is availible, you might need more sophisticated preparation of the "loopEvidenceList" but once you got that prepared, it works fine.

Bigamist answered 7/5, 2018 at 9:56 Comment(0)
G
0

I feel like the problem is you are using the same variable in evidence as well as event. Learning.test contains the values of "C" variable. then we are trying to predict C as the event. Maybe using a subset of the original dataset excluding C will do the trick

Golconda answered 6/8, 2021 at 11:26 Comment(1)
Could you provide sample code of for how that would work?Barbed

© 2022 - 2024 — McMap. All rights reserved.