probabilistischer Multiple-Choice-Test, sliderInputs summieren sich zu 1 Einschränkung

Ich entwickle ein kleines shinyapp zur Durchführung probabilistischer Multiple-Choice-Tests sieheBernardo, 1997. Für jede Frage im Test gibt es 4 mögliche Antworten. Jeder Teilnehmer sollte jeder Alternative einige Werte zuweisen, die den Grad seiner Überzeugung widerspiegeln, dass jede Alternative die richtige Antwort ist. Ich nehme diesen Eingang mit dem @ asliderInput Funktion. Da die vier Wahrscheinlichkeiten 1 ergeben müssen, skaliere ich alle vier Wahrscheinlichkeiten der aktuellen Frage neu (eine Zeile in einer Matrix, die als @ gespeichert istprob <- reactiveValues( )), um diese Einschränkung zu erfüllen. Dies wird ausgelöst durchobserveEvent(input$p1, ) etc

Wenn sich diese Wahrscheinlichkeiten ändern, werden Änderungen in den viersliderInput reintunrenderUI( ) innerhalb der Serverfunktion, sodass alle Schieberegler aktualisiert werden. Dies wiederum löst weitere Aufrufe der Funktion update @ auprob aber da die Wahrscheinlichkeiten zu diesem Zeitpunkt bereits 1 ergeben,prob bleiben unverändert, daher sollten keine weiteren Änderungen an den Schiebereglern vorgenommen werden. Sie können sich selbst davon überzeugen, indem Sie die auf shinyapps.io gehostete App ausführen.

Das funktioniert normalerweise sehr gut, außer dass in einigen seltenen Fällen eine Endlosschleife ausgelöst wird, sodass sich alle vier Schieberegler für immer ändern. Ich glaube, dies passiert, wenn der Benutzer eine zweite Änderung an einem der Schieberegler vornimmt, bevor die drei anderen Schieberegler Zeit zum Einstellen hatten.

So ist meine Frage wirklich, ob es eine Möglichkeit gibt, diese Schleife zu umgehen, oder ob es eine bessere Möglichkeit gibt, die obige Idee umzusetzen. Mir ist aufgefallen, dass es auch ein @ giupdateSliderInput Funktion, aber ich sehe nicht wirklich, wie dies helfen könnte, das Problem zu lösen.

Update: Ich glaube dasLösung zu einer ähnlichen Frage mit nur zwei in diesem Thread vorgeschlagenen Schiebereglern leidet unter dem gleichen Problem aufgrund der gegenseitigen Abhängigkeit zwischenslider1 undslider2.

library(shiny)
digits=3
step <- .1^digits

# Dummy questions and alternatives
n <- 5

# Miscellaneous functions
updateprob <- function(oldprobs, new, i) {
  cat(oldprobs, new, i)
  if (new==oldprobs[i]) {
    cat("-\n")
    oldprobs 
  } else {
    newprobs <- rep(0,4)
    oldprobs <- oldprobs + 1e-6 # hack to avoid 0/0 = NaN in special cases
    newprobs[-i] <- round(oldprobs[-i]/sum(oldprobs[-i])*(1-new),digits=digits)
    newprobs[i] <- new
    cat("*\n")
    newprobs
  }
}
# wrapper function around sliderInput
probsliderInput <- function(inputId,value,submitted=FALSE) {
  if (!submitted)
    sliderInput(inputId=inputId,
                value=value,
                label=NULL,
                min=0,
                max=1,
                step=step,
                round=-digits,
                ticks=FALSE)
}

server <- function(input, output) {
  # Initialize the quiz here, possibly permute the quiz
  prob <- reactiveValues(prob=matrix(rep(.25,4*n),n,4)) # current choice of probabilities
  question <- reactiveValues(i=1) # question number

  # Actions to take if pressing next and previous buttons
  observeEvent(input$nextquestion,{question$i <- min(question$i+1,n)}) 
  observeEvent(input$previousquestion,{question$i <- max(question$i-1,1)}) 

  # If any of the probability sliders change, then recalculate probabilities to satisfy sum to 1 constraint
  observeEvent(input$p1, 
               prob$prob[question$i,] <- updateprob(prob$prob[question$i,], input$p1, 1)
  )
  observeEvent(input$p2, 
               prob$prob[question$i,] <- updateprob(prob$prob[question$i,], input$p2, 2)
  )
  observeEvent(input$p3, 
               prob$prob[question$i,] <- updateprob(prob$prob[question$i,], input$p3, 3)
  )
  observeEvent(input$p4, 
               prob$prob[question$i,] <- updateprob(prob$prob[question$i,], input$p4, 4)
  )

  # If the probabilities change, update the sliders
  output$p1ui <- renderUI({
    probsliderInput("p1",prob$prob[question$i,1])
  })
  output$p2ui <- renderUI({
    probsliderInput("p2",prob$prob[question$i,2])
  })
  output$p3ui <- renderUI({
    probsliderInput("p3",prob$prob[question$i,3])
  })
  output$p4ui <- renderUI({
    probsliderInput("p4",prob$prob[question$i,4])
  })

  # Render the buttons sometimes greyed out
  output$previousbutton <- renderUI({
    actionButton("previousquestion",icon=icon("angle-left"),label="Previous",
                 style=if (question$i > 1) "color: #000" else "color: #aaa")
  })
  output$nextbutton <- renderUI({
    actionButton("nextquestion",icon=icon("angle-right"),label="Next",
                 style=if (question$i < n) "color: #000" else "color: #aaa")
  })

  # Current question number
  output$number <- renderText(paste("Question",question$i))
}

ui <- fluidPage(
  uiOutput("previousbutton", inline = TRUE),
  uiOutput("nextbutton", inline = TRUE),
  textOutput("number"),
  uiOutput("p1ui"),
  uiOutput("p2ui"),
  uiOutput("p3ui"),
  uiOutput("p4ui")
)

shinyApp(ui=ui , server=server)

Antworten auf die Frage(8)

Ihre Antwort auf die Frage