1

I am building a ShinyDashboard assessment tool with a Bayesian network engine using bnlearn. It is a discrete network created using expert knowledge to build the conditional probability tables. The shiny front end is used to elicit evidence, however, when I try and apply the evidence at the back-end using cpquery, it is not working. If I hard code the evidence in the backend shiny server, it works. So I think it is something to do with accessing the input variables I am missing.

I have tried various ways of formatting the evidence for cpquery but to no avail and as I have said, tried hard coding values, which worked fine.

This works fine!

Index <- shiny::reactive({
  cpquery(fitted = tdag,
          event = (A == "High"),              # event
          evidence = ( (B == "Yes") &      # evidence
                       (C == "Medium") &
                       (D == "Medium") &
                       (E == "Yes") &
                       (G == "High") &
                       (H == "Low") 
          ), # end evidence
          n = 1000000,                       # no of samples generated
          debug = TRUE
  ) # end cpqery
}) # end reactive

This does not:

Index <- shiny::reactive({
  # Create a string of the selected evidence
  str1 <<- paste0(
    "(B == '", input$BChoiceInp, "') & ",
    "(C == '", input$CChoiceInp, "') & ",
    "(D == '", input$DChoiceInp, "') & ",
    "(E == '", input$EChoiceInp, "') & ",
    "(G == '", input$GChoiceInp, "') & ",
    "(H == '", input$HChoiceInp, "')"
  )

  cpquery(fitted = tdag,
          event = (A == "High"),              # event
          evidence = (eval(parse(text = str1))),       # evidence
          n = 1000000,                       # no of samples generated
          debug = TRUE
  ) # end cpqery
}) # end reactive

I have also tried using

str2 = "(A == "'High'")"

eval(parse(text = paste("cpquery(fitted,",str2,",",str1,", n = 100000, debug=TRUE)")))

Same result. The network runs but the result is as below - it does not seem to see the inputs.:

* checking which nodes are needed.
  > event involves the following nodes: A
  > evidence involves the following nodes: B C D E G H
  > upper closure is ' A B C D E F G H I J  '
  > generating observations from 10 / 10 nodes.
* generated 10000 samples from the bayesian network.
  > evidence matches 0 samples out of 10000 (p = 0).
  > event matches 0 samples out of 0 (p = 0).
* generated 10000 samples from the bayesian network.
  > evidence matches 0 samples out of 10000 (p = 0).
  > event matches 0 samples out of 0 (p = 0).

This is the result with evidence hardcoded - works fine:

* generated 10000 samples from the bayesian network.
  > evidence matches 39 samples out of 10000 (p = 0.0039).
  > event matches 30 samples out of 39 (p = 0.7692308).
* generated 10000 samples from the bayesian network.
  > evidence matches 33 samples out of 10000 (p = 0.0033).
  > event matches 21 samples out of 33 (p = 0.6363636).
* generated 10000 samples from the bayesian network.
  > evidence matches 36 samples out of 10000 (p = 0.0036).
  > event matches 23 samples out of 36 (p = 0.6388889).
* generated a grand total of 1e+06 samples.
  > event matches 2666 samples out of 4173 (p = 0.6388689)

Heeeelllp!

ingrid
  • 47
  • 1
  • 7
  • bnlearn makes inference a bit tricky programmatically due to how it parses the event/evidence strings. [This answer](https://stackoverflow.com/questions/44676501/r-bnlearn-eval-inside-function) shows one way to do this inside functions. From a quick test this provides one way to proceed in shiny as otherwise cpquery was having a hard time recognising the evidence. – user20650 Sep 17 '19 at 16:05
  • OK, so cpquery doesn't work in Shiny - many thanks for confirming. ..sigh. My dataset is created from expert knowledge, not from learning a dataset. So how do I get a dataset to use this other method? – ingrid Sep 18 '19 at 06:02
  • Hi Ingrid; it does work. It is just that you have to use some work around, for example the `eval(parse(...))` from the question I linked. I have added an example in the chat room: https://chat.stackoverflow.com/rooms/199619/ingrid . You may find it easier to use `cpdist` as this works better programmatically but means you have to mess about with the sampling weights if using `lw`, or use `lw` in `cpquery` which also work well 9programmatically but the range of queries that can be asked is reduced (but may e okay for your use case) ... – user20650 Sep 18 '19 at 09:52
  • Dear user20650, thank you **soooooo much**! That worked for me as I was really stumped. And is it so simple with that change. Again many, many thanks! I could not respond in the chat as I don't have enough reputation points apparently! best regards - Ingrid – ingrid Sep 25 '19 at 03:08

1 Answers1

1

The solution, many thanks to user20650, is to use renderText around the whole calculation. Works beautifully.

library(shiny)
library(bnlearn)

tdag = bn.fit(hc(learning.test[5:6]), learning.test[5:6])

shinyApp(

ui = basicPage(
selectInput("e", "E:", choices=letters[1:3] ),
selectInput("f", "F:", choices=letters[1:2] ),
textOutput("prob")
),

server = function(input, output, session) {
output$prob <- renderText({
event <- paste0("(F == '", input$f, "')")
evidence <- paste0("(E == '", input$e, "')")
eval(parse(text=paste(
'cpquery(fitted=tdag,
event = ', event, ',
evidence = ', evidence, ',
n = 100000,
debug = TRUE)'
)))})}
)
ingrid
  • 47
  • 1
  • 7