【问题标题】:R Shiny: Creating factor variables and defining levelsR Shiny:创建因子变量并定义水平
【发布时间】:2020-11-10 12:29:33
【问题描述】:

我试图用 Shiny 创建一个机器学习应用程序。

在此应用程序中,用户可以选择输入变量的规格(通过输入小部件),这些规格将用于估计响应变量。 为此,我从选定的输入创建了一个数据框,并将其保存为本地数据表。

当我再次加载数据表时会出现问题,因为这会导致所有分类变量变成字符变量。但是,我可以使用 factor() 函数手动更改这些并使用 levels= 规范。

问题是我不想每次使用新数据集时都手动执行此操作,因为这很可能会改变数据集中分类变量的位置。新数据集中也很可能不会有相同数量的分类变量。

数据框"DATA" 是主数据集,其中包含第 1 列中的响应变量。

数据框"test" 是从所选输入构造的数据框,将用作 用于预测的测试集,将仅包含 1 个指定的观察值。由于数据帧的构造方式,此数据帧将始终将响应变量作为数据帧中的最后一列。因此DATA[ ,5] 中的因子变量将始终对应于测试数据框中的前一列:test[ ,4]

测试数据框需要指定因子级别,因为当它仅包含 1 个观察值时,它不会自动知道类别的数量。

test[4] <- factor(test[4], levels = unique(DATA[,5]))

我正在尝试编写代码,将factor 函数应用于数据集中的所有字符变量,并指定levels 无论位置如何数据集中的字符变量。

这是我目前写的代码:

library(shiny)
library(tidyverse)
library(shinythemes)
library(data.table)
library(RCurl)
library(randomForest)
library(mlbench)
library(janitor)


# Read data
DATA <- BostonHousing

# Rearrange data so the response variable is located in column 1
DATA <- DATA[,c(names(BostonHousing)[14],names(BostonHousing)[-14])]

# Creating a simple RF model
model <- randomForest(medv ~ ., data = DATA, ntree = 500, mtry = 4, importance = TRUE)


# UI -------------------------------------------------------------------------
ui <- fluidPage(
  
  sidebarPanel(
    
    h3("Parameters Selected"),
    br(),
    tableOutput('show_inputs'),
    hr(),
    actionButton("submitbutton", label = "calculate", class = "btn btn-primary", icon("calculator")),
    hr(),
    tableOutput("tabledata")

    
  ), # End sidebarPanel
  
  mainPanel(
    
    h3("Input widgets"),
    uiOutput("select")
    
  ) # End mainPanel
  
) # End UI bracket



# Server -------------------------------------------------------------------------
server <- function(input, output, session) {
  
# Create input widgets from dataset  
  output$select <- renderUI({
    df <- req(DATA)
    tagList(map(
      names(df[-1]),
      ~ ifelse(is.numeric(df[[.]]),
               yes = tagList(sliderInput(
                 inputId = paste0(.),
                 label = .,
                 value = mean(df[[.]], na.rm = TRUE),
                 min = round(min(df[[.]], na.rm = TRUE),2),
                 max = round(max(df[[.]], na.rm = TRUE),2)
               )),
               no = tagList(selectInput(
                 inputId = paste0(.),
                 label = .,
                 choices = sort(unique(df[[.]])),
                 selected = sort(unique(df[[.]]))[1],
               ))
      )
    ))
  })
  

# creating dataframe of selected values to be displayed
  AllInputs <- reactive({
    id_exclude <- c("savebutton","submitbutton")
    id_include <- setdiff(names(input), id_exclude)
    
    if (length(id_include) > 0) {
      myvalues <- NULL
      for(i in id_include) {
        myvalues <- as.data.frame(rbind(myvalues, cbind(i, input[[i]])))
        
      }
      names(myvalues) <- c("Variable", "Selected Value")
      myvalues %>% 
        slice(match(names(DATA[,-1]), Variable))
    }
  })

  
# render table of selected values to be displayed
  output$show_inputs <- renderTable({
    AllInputs()
  })
  
 
# Creating a dataframe for calculating a prediction
  datasetInput <- reactive({  
    
    df1 <- data.frame(AllInputs(), stringsAsFactors = FALSE)
    input <- transpose(rbind(df1, names(DATA[1])))

    write.table(input,"input.csv", sep=",", quote = FALSE, row.names = FALSE, col.names = FALSE)
    test <- read.csv(paste("input.csv", sep=""), header = TRUE)
    
    
# defining factor levels for factor variables
    test[4] <- factor(test[4], levels = unique(DATA[,5])) # <- This line will cause problems if multiple factors in dataset or if different column location
   

# Making the actual prediction and store it in a data.frame     
    Prediction <- predict(model,test)
    Output <- data.frame("Prediction"=Prediction)
    print(format(Output, nsmall=2, big.mark=","))
  })
  

# display the prediction when the submit button is pressed
  output$tabledata <- renderTable({
    if (input$submitbutton>0) { 
      isolate(datasetInput()) 
    } 
  })
  
  
} # End server bracket



# ShinyApp -------------------------------------------------------------------------
shinyApp(ui, server)

【问题讨论】:

  • 请贴出你到目前为止所做的代码。
  • 我已编辑问题以包含我使用的代码。请注意,应用程序的重点是它将适应数据集。所以我正在努力做到完全不进行硬编码。

标签: r shiny


【解决方案1】:

要概括因子变量,您可以使用以下代码:

# defining factor levels for factor variables
#test[4] <- factor(test[4], levels = unique(DATA[,5])) # <- This line will cause problems if multiple factors in dataset or if different column location

cnames <- colnames(DATA[sapply(DATA,class)=="factor"])
if (length(cnames)>0){
  lapply(cnames, function(par) {
    test[par] <<- factor(test[par], levels = unique(DATA[,par]))
  })
}

您可以将其应用于 BostonHousing2 数据,如下所示

# Read data
BH <- BostonHousing2
DATA <- BH

# Rearrange data so the response variable is located in column 1
#DATA <- DATA[,c(names(BH)[14],names(BH)[-14])]
DATA <- DATA[,c(names(BH)[5],names(BH)[-5])]   ## for BostonHousing2

# Creating a simple RF model
model <- randomForest(medv ~ ., data = DATA[,-2], ntree = 500, mtry = 4, importance = TRUE)


# UI -------------------------------------------------------------------------
ui <- fluidPage(
  
  sidebarPanel(
    
    h3("Parameters Selected"),
    br(),
    tableOutput('show_inputs'),
    hr(),
    actionButton("submitbutton", label = "calculate", class = "btn btn-primary", icon("calculator")),
    hr(),
    tableOutput("tabledata")
    
  ), # End sidebarPanel
  
  mainPanel(
    
    h3("Input widgets"),
    uiOutput("select")
    
  ) # End mainPanel
  
) # End UI bracket


# Server -------------------------------------------------------------------------
server <- function(input, output, session) {
  
  # Create input widgets from dataset  
  output$select <- renderUI({
    df <- req(DATA)
    tagList(map(
      names(df[-1]),
      ~ ifelse(is.numeric(df[[.]]),
               yes = tagList(sliderInput(
                 inputId = paste0(.),
                 label = .,
                 value = mean(df[[.]], na.rm = TRUE),
                 min = round(min(df[[.]], na.rm = TRUE),2),
                 max = round(max(df[[.]], na.rm = TRUE),2)
               )),
               no = tagList(selectInput(
                 inputId = paste0(.),
                 label = .,
                 choices = sort(unique(df[[.]])),
                 selected = sort(unique(df[[.]]))[1],
               ))
      )
    ))
  })
  
  
  # creating dataframe of selected values to be displayed
  AllInputs <- reactive({
    id_exclude <- c("savebutton","submitbutton")
    id_include <- setdiff(names(input), id_exclude)
    
    if (length(id_include) > 0) {
      myvalues <- NULL
      for(i in id_include) {
        myvalues <- as.data.frame(rbind(myvalues, cbind(i, input[[i]])))
        
      }
      names(myvalues) <- c("Variable", "Selected Value")
      myvalues %>% 
        slice(match(names(DATA[,-1]), Variable))
    }
  })
  
  
  # render table of selected values to be displayed
  output$show_inputs <- renderTable({
    AllInputs()
  })
  
  
  # Creating a dataframe for calculating a prediction
  datasetInput <- reactive({  
    
    df1 <- data.frame(AllInputs(), stringsAsFactors = FALSE)
    input <- transpose(rbind(df1, names(DATA[1])))
    
    write.table(input,"input.csv", sep=",", quote = FALSE, row.names = FALSE, col.names = FALSE)
    test <- read.csv(paste("input.csv", sep=""), header = TRUE)
    
    
    # defining factor levels for factor variables
    #test[4] <- factor(test[4], levels = unique(DATA[,5])) # <- This line will cause problems if multiple factors in dataset or if different column location

    cnames <- colnames(DATA[sapply(DATA,class)=="factor"])
    if (length(cnames)>0){
      lapply(cnames, function(par) {
        test[par] <<- factor(test[par], levels = unique(DATA[,par]))
      })
    }
    
    # Making the actual prediction and store it in a data.frame     
    Prediction <- predict(model,test)
    Output <- data.frame("Prediction"=Prediction)
    print(format(Output, nsmall=2, big.mark=","))
  })
  
  # display the prediction when the submit button is pressed
  output$tabledata <- renderTable({
    if (input$submitbutton>0) { 
      isolate(datasetInput()) 
    } 
  })
  
} # End server bracket

# ShinyApp -------------------------------------------------------------------------
shinyApp(ui, server)

【讨论】:

  • 非常感谢!这正是我一直在寻找的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-21
  • 1970-01-01
  • 2015-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多