## ========== svm_ui.R ========== ## 1. plot 列表 ---------------------------------------------------------- svm_plots <- c( "none", "dist", "correlations", "scatter", "vip", "pred_plot", "pdp", "dashboard", "residuals", "coef", "influence" ) names(svm_plots) <- c( i18n$t("None"), i18n$t("Distribution"), i18n$t("Correlations"), i18n$t("Scatter"), i18n$t("Permutation Importance"), i18n$t("Prediction plots"), i18n$t("Partial Dependence"), i18n$t("Dashboard"), i18n$t("Residuals vs fitted"), i18n$t("Coefficient plot"), i18n$t("Influential observations") ) ## 2. 函数缺省参数 ------------------------------------------------------- svm_args <- as.list(formals(svm)) ## 3. 用户输入收集 ------------------------------------------------------- svm_inputs <- reactive({ svm_args$data_filter <- if (input$show_filter) input$data_filter else "" svm_args$arr <- if (input$show_filter) input$data_arrange else "" svm_args$rows <- if (input$show_filter) input$data_rows else "" svm_args$dataset <- input$dataset for (i in r_drop(names(svm_args))) { svm_args[[i]] <- input[[paste0("svm_", i)]] } svm_args }) ## 4. predict 参数 ------------------------------------------------------- svm_pred_args <- as.list(if (exists("predict.svm")) { formals(predict.svm) } else { formals(e1071:::predict.svm) }) svm_pred_inputs <- reactive({ for (i in names(svm_pred_args)) { svm_pred_args[[i]] <- input[[paste0("svm_", i)]] } svm_pred_args$pred_cmd <- svm_pred_args$pred_data <- "" if (input$svm_predict == "cmd") { svm_pred_args$pred_cmd <- gsub("\\s{2,}", " ", input$svm_pred_cmd) %>% gsub(";\\s+", ";", .) %>% gsub("\"", "\'", .) } else if (input$svm_predict == "data") { svm_pred_args$pred_data <- input$svm_pred_data } else if (input$svm_predict == "datacmd") { svm_pred_args$pred_cmd <- gsub("\\s{2,}", " ", input$svm_pred_cmd) %>% gsub(";\\s+", ";", .) %>% gsub("\"", "\'", .) svm_pred_args$pred_data <- input$svm_pred_data } svm_pred_args }) ## 5. plot 参数 --------------------------------------------------------- svm_plot_args <- as.list(if (exists("plot.svm")) { formals(plot.svm) } else { formals(e1071:::plot.svm) }) svm_plot_inputs <- reactive({ for (i in names(svm_plot_args)) { svm_plot_args[[i]] <- input[[paste0("svm_", i)]] } svm_plot_args }) ## 6. pred-plot 参数 ---------------------------------------------------- svm_pred_plot_args <- as.list(if (exists("plot.model.predict")) { formals(plot.model.predict) } else { formals(radiant.model:::plot.model.predict) }) svm_pred_plot_inputs <- reactive({ for (i in names(svm_pred_plot_args)) { svm_pred_plot_args[[i]] <- input[[paste0("svm_", i)]] } svm_pred_plot_args }) ## 7. 响应变量 ---------------------------------------------------------- output$ui_svm_rvar <- renderUI({ withProgress(message = i18n$t("Acquiring variable information"), value = 1, { if (input$svm_type == "classification") { vars <- two_level_vars() } else { isNum <- .get_class() %in% c("integer", "numeric", "ts") vars <- varnames()[isNum] } }) init <- if (input$svm_type == "classification") { if (is.empty(input$logit_rvar)) isolate(input$svm_rvar) else input$logit_rvar } else { if (is.empty(input$reg_rvar)) isolate(input$svm_rvar) else input$reg_rvar } selectInput( inputId = "svm_rvar", label = i18n$t("Response variable:"), choices = vars, selected = state_single("svm_rvar", vars, init), multiple = FALSE ) }) ## 8. 分类时选正类 ------------------------------------------------------ output$ui_svm_lev <- renderUI({ req(input$svm_type == "classification") req(available(input$svm_rvar)) levs <- .get_data()[[input$svm_rvar]] %>% as_factor() %>% levels() init <- if (is.empty(input$logit_lev)) isolate(input$svm_lev) else input$logit_lev selectInput( inputId = "svm_lev", label = i18n$t("Choose level:"), choices = levs, selected = state_init("svm_lev", init) ) }) ## 9. 解释变量 ---------------------------------------------------------- output$ui_svm_evar <- renderUI({ if (not_available(input$svm_rvar)) return() vars <- varnames() if (length(vars) > 0) vars <- vars[-which(vars == input$svm_rvar)] init <- if (input$svm_type == "classification") { if (is.empty(input$logit_evar)) isolate(input$svm_evar) else input$logit_evar } else { if (is.empty(input$reg_evar)) isolate(input$svm_evar) else input$reg_evar } selectInput( inputId = "svm_evar", label = i18n$t("Explanatory variables:"), choices = vars, selected = state_multiple("svm_evar", vars, init), multiple = TRUE, size = min(10, length(vars)), selectize = FALSE ) }) ## 10. 权重变量 --------------------------------------------------------- output$ui_svm_wts <- renderUI({ isNum <- .get_class() %in% c("integer", "numeric", "ts") vars <- varnames()[isNum] if (length(vars) > 0 && any(vars %in% input$svm_evar)) { vars <- base::setdiff(vars, input$svm_evar) names(vars) <- varnames() %>% { .[match(vars, .)] } %>% names() } vars <- c("None", vars) selectInput( inputId = "svm_wts", label = i18n$t("Weights:"), choices = vars, selected = state_single("svm_wts", vars), multiple = FALSE ) }) ## 11. 存储预测/残差名 -------------------------------------------------- output$ui_svm_store_pred_name <- renderUI({ init <- state_init("svm_store_pred_name", "pred_svm") %>% sub("\\d{1,}$", "", .) %>% paste0(., ifelse(is.empty(input$svm_cost), "", input$svm_cost)) textInput( "svm_store_pred_name", i18n$t("Store predictions:"), init ) }) output$ui_svm_store_res_name <- renderUI({ req(input$dataset) textInput("svm_store_res_name", i18n$t("Store residuals:"), "", placeholder = i18n$t("Provide variable name")) }) ## 12. 预测与绘图重置 --------------------------------------------------- observeEvent(input$dataset, { updateSelectInput(session, "svm_predict", selected = "none") updateSelectInput(session, "svm_plots", selected = "none") }) observeEvent(input$svm_type, { updateSelectInput(session, "svm_predict", selected = "none") updateSelectInput(session, "svm_plots", selected = "none") }) ## 13. 预测控制 ---------------------------------------------------------- output$ui_svm_predict_plot <- renderUI({ predict_plot_controls("svm") }) ## 14. 绘图数量 ---------------------------------------------------------- output$ui_svm_plots <- renderUI({ req(input$svm_type) if (input$svm_type != "regression") { svm_plots <- head(svm_plots, -1) # 去掉 regression 专用图 } selectInput( "svm_plots", i18n$t("Plots:"), choices = svm_plots, selected = state_single("svm_plots", svm_plots) ) }) ## 15. 绘图点数 ---------------------------------------------------------- output$ui_svm_nrobs <- renderUI({ nrobs <- nrow(.get_data()) choices <- c("1,000" = 1000, "5,000" = 5000, "10,000" = 10000, "All" = -1) %>% .[. < nrobs] selectInput( "svm_nrobs", i18n$t("Number of data points plotted:"), choices = choices, selected = state_single("svm_nrobs", choices, 1000) ) }) ## 16. 刷新按钮 ---------------------------------------------------------- run_refresh(svm_args, "svm", tabs = "tabs_svm", label = i18n$t("Estimate model"), relabel = i18n$t("Re-estimate model")) ## 17. 主 UI 组装 -------------------------------------------------------- output$ui_svm <- renderUI({ req(input$dataset) tagList( conditionalPanel( condition = "input.tabs_svm == 'Summary'", wellPanel( actionButton("svm_run", i18n$t("Estimate model"), width = "100%", icon = icon("play", verify_fa = FALSE), class = "btn-success") ) ), wellPanel( conditionalPanel( condition = "input.tabs_svm == 'Summary'", radioButtons( "svm_type", label = NULL, choices = c("classification", "regression") %>% { names(.) <- c(i18n$t("Classification"), i18n$t("Regression")); . }, inline = TRUE ), uiOutput("ui_svm_rvar"), uiOutput("ui_svm_lev"), uiOutput("ui_svm_evar"), uiOutput("ui_svm_wts"), selectInput( "svm_kernel", label = i18n$t("Kernel:"), choices = c("linear", "polynomial", "radial", "sigmoid") %>% { names(.) <- c(i18n$t("Linear"), i18n$t("Polynomial"), i18n$t("Radial"), i18n$t("Sigmoid")); . }, selected = state_init("svm_kernel", "radial") ), fluidRow( column(6, numericInput( "svm_cost", label = i18n$t("Cost (C):"), min = 0.01, max = 100, value = state_init("svm_cost", 1), step = 0.01, width = "100%" ) ), column(6, conditionalPanel( "input.svm_kernel != 'linear'", numericInput( "svm_gamma", label = i18n$t("Gamma:"), min = 0.001, max = 10, value = state_init("svm_gamma", "auto"), step = 0.001, width = "100%" ) ) ) ), fluidRow( column(6, conditionalPanel( "input.svm_kernel %in% c('polynomial', 'sigmoid')", numericInput( "svm_coef0", label = i18n$t("Coef0:"), min = 0, max = 100, value = state_init("svm_coef0", 0), width = "100%" ) ) ), column(6, conditionalPanel( "input.svm_type == 'regression'", numericInput( "svm_epsilon", label = i18n$t("Epsilon (tube):"), min = 0.001, max = 1, value = state_init("svm_epsilon", 0.1), step = 0.001, width = "100%" ) ) ) ), numericInput( "svm_seed", label = i18n$t("Seed:"), value = state_init("svm_seed", 12345), width = "90px" ), conditionalPanel( "input.svm_type == 'classification'", checkboxInput( "svm_probability", label = i18n$t("Estimate class probabilities"), value = state_init("svm_probability", FALSE) ) ), ), conditionalPanel( condition = "input.tabs_svm == 'Predict'", selectInput( "svm_predict", label = i18n$t("Prediction input type:"), choices = reg_predict, selected = state_single("svm_predict", reg_predict, "none") ), conditionalPanel( "input.svm_predict == 'data' | input.svm_predict == 'datacmd'", selectizeInput( inputId = "svm_pred_data", label = i18n$t("Prediction data:"), choices = c("None" = "", r_info[["datasetlist"]]), selected = state_single("svm_pred_data", c("None" = "", r_info[["datasetlist"]])), multiple = FALSE ) ), conditionalPanel( "input.svm_predict == 'cmd' | input.svm_predict == 'datacmd'", returnTextAreaInput( "svm_pred_cmd", i18n$t("Prediction command:"), value = state_init("svm_pred_cmd", ""), rows = 3, placeholder = i18n$t("Type a formula to set values for model variables (e.g., carat = 1; cut = 'Ideal') and press return") ) ), conditionalPanel( condition = "input.svm_predict != 'none'", checkboxInput("svm_pred_plot", i18n$t("Plot predictions"), state_init("svm_pred_plot", FALSE)), conditionalPanel( "input.svm_pred_plot == true", uiOutput("ui_svm_predict_plot") ) ), conditionalPanel( "input.svm_predict == 'data' | input.svm_predict == 'datacmd'", tags$table( tags$td(uiOutput("ui_svm_store_pred_name")), tags$td(actionButton("svm_store_pred", i18n$t("Store"), icon = icon("plus", verify_fa = FALSE)), class = "top") ) ) ), conditionalPanel( condition = "input.tabs_svm == 'Plot'", uiOutput("ui_svm_plots"), conditionalPanel( condition = "input.svm_plots == 'pdp' | input.svm_plots == 'pred_plot'", uiOutput("ui_svm_incl"), uiOutput("ui_svm_incl_int") ), conditionalPanel( condition = "input.svm_plots == 'dashboard'", uiOutput("ui_svm_nrobs") ) ), conditionalPanel( condition = "input.tabs_svm == 'Summary'", tags$table( tags$td(uiOutput("ui_svm_store_res_name")), tags$td(actionButton("svm_store_res", i18n$t("Store"), icon = icon("plus", verify_fa = FALSE)), class = "top") ) ) ), help_and_report( modal_title = i18n$t("Support Vector Machine (SVM)"), fun_name = "svm", help_file = inclMD(file.path(getOption("radiant.path.model"), "app/tools/help/svm.md")) ) ) }) ## 18. 绘图尺寸动态计算 ------------------------------------------------- svm_plot <- reactive({ if (svm_available() != "available") return() if (is.empty(input$svm_plots, "none")) return() plot_width <- 650 if (input$svm_plots == "dashboard") { plot_height <- 750 } else if (input$svm_plots %in% c("pdp", "pred_plot")) { nr_vars <- length(input$svm_incl) + length(input$svm_incl_int) plot_height <- max(250, ceiling(nr_vars / 2) * 250) if (length(input$svm_incl_int) > 0) { plot_width <- plot_width + min(2, length(input$svm_incl_int)) * 90 } } else { plot_height <- 500 } list(plot_width = plot_width, plot_height = plot_height) }) svm_plot_width <- function() svm_plot() %>% (function(x) if (is.list(x)) x$plot_width else 650) svm_plot_height <- function() svm_plot() %>% (function(x) if (is.list(x)) x$plot_height else 500) svm_pred_plot_height <- function() if (input$svm_pred_plot) 500 else 1 ## 19. 输出注册 ---------------------------------------------------------- output$svm <- renderUI({ register_print_output("summary_svm", ".summary_svm") register_print_output("predict_svm", ".predict_print_svm") register_plot_output("predict_plot_svm", ".predict_plot_svm", height_fun = "svm_pred_plot_height") register_plot_output("plot_svm", ".plot_svm", height_fun = "svm_plot_height", width_fun = "svm_plot_width") svm_output_panels <- tabsetPanel( id = "tabs_svm", tabPanel(i18n$t("Summary"), value = "Summary", download_link("dl_svm_coef"), br(), verbatimTextOutput("summary_svm")), tabPanel(i18n$t("Predict"), value = "Predict", conditionalPanel( "input.svm_pred_plot == true", download_link("dlp_svm_pred"), plotOutput("predict_plot_svm", width = "100%", height = "100%") ), download_link("dl_svm_pred"), br(), verbatimTextOutput("predict_svm")), tabPanel(i18n$t("Plot"), value = "Plot", download_link("dlp_svm"), plotOutput("plot_svm", width = "100%", height = "100%")) ) stat_tab_panel( menu = i18n$t("Model > Estimate"), tool = i18n$t("Support Vector Machine (SVM)"), tool_ui = "ui_svm", output_panels = svm_output_panels ) }) ## 20. 可用性检查 ------------------------------------------------------- svm_available <- reactive({ req(input$svm_type) if (not_available(input$svm_rvar)) { if (input$svm_type == "classification") { i18n$t("This analysis requires a response variable with two levels and one\nor more explanatory variables. If these variables are not available\nplease select another dataset.\n\n") %>% suggest_data("titanic") } else { i18n$t("This analysis requires a response variable of type integer\nor numeric and one or more explanatory variables.\nIf these variables are not available please select another dataset.\n\n") %>% suggest_data("diamonds") } } else if (not_available(input$svm_evar)) { if (input$svm_type == "classification") { i18n$t("Please select one or more explanatory variables.") %>% suggest_data("titanic") } else { i18n$t("Please select one or more explanatory variables.") %>% suggest_data("diamonds") } } else { "available" } }) ## 21. 模型估计 ---------------------------------------------------------- .svm <- eventReactive(input$svm_run, { svmi <- svm_inputs() svmi$envir <- r_data withProgress(message = i18n$t("Estimating SVM"), value = 1, do.call(svm, svmi)) }) ## 22. summary ------------------------------------------------------------ .summary_svm <- reactive({ if (not_pressed(input$svm_run)) return(i18n$t("** Press the Estimate button to estimate the model **")) if (svm_available() != "available") return(svm_available()) summary(.svm()) }) ## 23. predict ------------------------------------------------------------ .predict_svm <- reactive({ if (not_pressed(input$svm_run)) return(i18n$t("** Press the Estimate button to estimate the model **")) if (svm_available() != "available") return(svm_available()) if (is.empty(input$svm_predict, "none")) return(i18n$t("** Select prediction input **")) if ((input$svm_predict == "data" || input$svm_predict == "datacmd") && is.empty(input$svm_pred_data)) return(i18n$t("** Select data for prediction **")) if (input$svm_predict == "cmd" && is.empty(input$svm_pred_cmd)) return(i18n$t("** Enter prediction commands **")) withProgress(message = i18n$t("Generating predictions"), value = 1, { spi <- svm_pred_inputs() spi$object <- .svm() spi$envir <- r_data do.call(predict, spi) }) }) .predict_print_svm <- reactive({ .predict_svm() %>% { if (is.character(.)) cat(., "\n") else print(.) } }) ## 24. pred-plot ---------------------------------------------------------- .predict_plot_svm <- reactive({ req(pressed(input$svm_run), input$svm_pred_plot, available(input$svm_xvar), !is.empty(input$svm_predict, "none")) withProgress(message = i18n$t("Generating prediction plot"), value = 1, do.call(plot, c(list(x = .predict_svm()), svm_pred_plot_inputs()))) }) ## 25. plot -------------------------------------------------------------- .plot_svm <- reactive({ if (not_pressed(input$svm_run)) return(i18n$t("** Press the Estimate button to estimate the model **")) if (svm_available() != "available") return(svm_available()) if (is.empty(input$svm_plots, "none")) return(i18n$t("Please select an SVM plot from the drop-down menu")) pinp <- svm_plot_inputs() pinp$shiny <- TRUE if (input$svm_plots == "dashboard") req(input$svm_nrobs) withProgress(message = i18n$t("Generating plots"), value = 1, do.call(plot, c(list(x = .svm()), pinp))) }) ## 26. 存储 -------------------------------------------------------------- observeEvent(input$svm_store_res, { req(pressed(input$svm_run)) robj <- .svm() if (!is.list(robj)) return() fixed <- fix_names(input$svm_store_res_name) updateTextInput(session, "svm_store_res_name", value = fixed) withProgress(message = i18n$t("Storing residuals"), value = 1, r_data[[input$dataset]] <- store(r_data[[input$dataset]], robj, name = fixed)) }) observeEvent(input$svm_store_pred, { req(!is.empty(input$svm_pred_data), pressed(input$svm_run)) pred <- .predict_svm() if (is.null(pred)) return() fixed <- fix_names(input$svm_store_pred_name) updateTextInput(session, "svm_store_pred_name", value = fixed) withProgress(message = i18n$t("Storing predictions"), value = 1, r_data[[input$svm_pred_data]] <- store(r_data[[input$svm_pred_data]], pred, name = fixed)) }) ## 27. report ------------------------------------------------------------ svm_report <- function() { if (is.empty(input$svm_evar)) return(invisible()) outputs <- c("summary") inp_out <- list(list(prn = TRUE), "") figs <- FALSE if (!is.empty(input$svm_plots, "none")) { inp <- check_plot_inputs(svm_plot_inputs()) inp_out[[2]] <- clean_args(inp, svm_plot_args[-1]) inp_out[[2]]$custom <- FALSE outputs <- c(outputs, "plot") figs <- TRUE } if (!is.empty(input$svm_store_res_name)) { fixed <- fix_names(input$svm_store_res_name) updateTextInput(session, "svm_store_res_name", value = fixed) xcmd <- paste0(input$dataset, " <- store(", input$dataset, ", result, name = \"", fixed, "\")\n") } else { xcmd <- "" } if (!is.empty(input$svm_predict, "none") && (!is.empty(input$svm_pred_data) || !is.empty(input$svm_pred_cmd))) { pred_args <- clean_args(svm_pred_inputs(), svm_pred_args[-1]) if (!is.empty(pred_args$pred_cmd)) pred_args$pred_cmd <- strsplit(pred_args$pred_cmd, ";\\s*")[[1]] else pred_args$pred_cmd <- NULL if (!is.empty(pred_args$pred_data)) pred_args$pred_data <- as.symbol(pred_args$pred_data) else pred_args$pred_data <- NULL inp_out[[2 + figs]] <- pred_args outputs <- c(outputs, "pred <- predict") xcmd <- paste0(xcmd, "print(pred, n = 10)") if (input$svm_predict %in% c("data", "datacmd")) { fixed <- fix_names(input$svm_store_pred_name) updateTextInput(session, "svm_store_pred_name", value = fixed) xcmd <- paste0(xcmd, "\n", input$svm_pred_data, " <- store(", input$svm_pred_data, ", pred, name = \"", fixed, "\")") } if (input$svm_pred_plot && !is.empty(input$svm_xvar)) { inp_out[[3 + figs]] <- clean_args(svm_pred_plot_inputs(), svm_pred_plot_args[-1]) inp_out[[3 + figs]]$result <- "pred" outputs <- c(outputs, "plot") figs <- TRUE } } svm_inp <- svm_inputs() if (input$svm_type == "regression") svm_inp$lev <- NULL update_report( inp_main = clean_args(svm_inp, svm_args), fun_name = "svm", inp_out = inp_out, outputs = outputs, figs = figs, fig.width = svm_plot_width(), fig.height= svm_plot_height(), xcmd = xcmd ) } ## 28. 下载 -------------------------------------------------------------- dl_svm_pred <- function(path) { if (pressed(input$svm_run)) { write.csv(.predict_svm(), file = path, row.names = FALSE) } else { cat(i18n$t("No output available. Press the Estimate button to generate results"), file = path) } } download_handler( id = "dl_svm_pred", fun = dl_svm_pred, fn = function() paste0(input$dataset, "_svm_pred"), type = "csv", caption = i18n$t("Save SVM predictions") ) download_handler( id = "dlp_svm_pred", fun = download_handler_plot, fn = function() paste0(input$dataset, "_svm_pred"), type = "png", caption = i18n$t("Save SVM prediction plot"), plot = .predict_plot_svm, width = plot_width, height = svm_pred_plot_height ) download_handler( id = "dlp_svm", fun = download_handler_plot, fn = function() paste0(input$dataset, "_svm"), type = "png", caption = i18n$t("Save SVM plot"), plot = .plot_svm, width = svm_plot_width, height = svm_plot_height ) ## 29. report / screenshot 监听 ----------------------------------------- observeEvent(input$svm_report, { r_info[["latest_screenshot"]] <- NULL svm_report() }) observeEvent(input$svm_screenshot, { r_info[["latest_screenshot"]] <- NULL radiant_screenshot_modal("modal_svm_screenshot") }) observeEvent(input$modal_svm_screenshot, { svm_report() removeModal() })