You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Shiny中多个selectizeInput联动筛选个体级数据的实现方案

R Shiny多selectizeInput联动筛选优化方案

核心需求回顾

17.5万行个体记录数据,需通过FirstName、LastName、SSN、PatientID、Facility等任意字段联动筛选,最终定位唯一人员,所有筛选控件放在shinydashboard侧边栏,支持清空搜索功能。

核心优化点

  • 去掉重复的renderUI逻辑,仅在UI中声明一次控件,通过updateSelectizeInput动态更新选项,大幅减少UI重绘带来的性能损耗
  • 统一筛选逻辑,无需手动拼接搜索字符串,直接基于输入条件生成筛选向量
  • 优先处理唯一ID(SSN、PatientID)的筛选,一旦选中直接定位到单条记录,跳过其他非必要计算

适配shinydashboard的完整实现代码

library(shiny)
library(shinydashboard)
library(dplyr)

# 模拟17.5万条测试数据,替换为你实际的readRDS逻辑
set.seed(123)
full_data <- data.frame(
  SSN = sprintf("%09d", sample(1e8:9e8, 175000, replace = FALSE)),
  PATIENT_ID = sprintf("PAT%07d", 1:175000),
  FIRST_NAME = sample(c("Michael", "John", "David", "Mary", "Sarah"), 175000, replace = TRUE),
  LAST_NAME = sample(c("Smith", "Johnson", "Williams", "Brown", "Jones"), 175000, replace = TRUE),
  FACILITY = sample(c("Central Hospital", "East Clinic", "West Medical Center", "North Ward"), 175000, replace = TRUE)
)
# 预存字段对应关系,后续新增筛选字段直接修改此处即可
field_config <- list(
  ssn = list(input_id = "patient", col = "SSN", label = "按SSN选择患者"),
  pid = list(input_id = "pid", col = "PATIENT_ID", label = "按患者ID选择"),
  fname = list(input_id = "fname", col = "FIRST_NAME", label = "按名字搜索"),
  lname = list(input_id = "lname", col = "LAST_NAME", label = "按姓氏搜索"),
  facility = list(input_id = "facility", col = "FACILITY", label = "按机构搜索")
)

ui <- dashboardPage(
  dashboardHeader(title = "患者查询系统"),
  dashboardSidebar(
    # 直接声明所有筛选控件,无需renderUI动态生成
    selectizeInput("patient", label = field_config$ssn$label, choices = c("--", sort(full_data$SSN)), selected = "--"),
    selectizeInput("pid", label = field_config$pid$label, choices = c("--", sort(full_data$PATIENT_ID)), selected = "--"),
    selectizeInput("fname", label = field_config$fname$label, choices = c("--", sort(unique(full_data$FIRST_NAME))), selected = "--"),
    selectizeInput("lname", label = field_config$lname$label, choices = c("--", sort(unique(full_data$LAST_NAME))), selected = "--"),
    selectizeInput("facility", label = field_config$facility$label, choices = c("--", sort(unique(full_data$FACILITY))), selected = "--"),
    actionButton("clear", "清空搜索", width = "100%")
  ),
  dashboardBody(
    # 此处替换为选中患者后的表格、图表渲染逻辑
    h3("选中患者信息"),
    tableOutput("selected_patient_info")
  )
)

server <- function(input, output, session) {
  # 存储全量数据
  rv <- reactiveValues(
    full_data = full_data,
    filtered_data = full_data
  )
  
  # 响应式生成筛选后的数据
  filtered_data <- reactive({
    df <- rv$full_data
    # 优先处理唯一ID筛选,选中直接返回单条记录
    if (input$patient != "--") {
      return(filter(df, SSN == input$patient))
    }
    if (input$pid != "--") {
      return(filter(df, PATIENT_ID == input$pid))
    }
    # 处理非唯一字段筛选
    if (input$fname != "--") {
      df <- filter(df, FIRST_NAME == input$fname)
    }
    if (input$lname != "--") {
      df <- filter(df, LAST_NAME == input$lname)
    }
    if (input$facility != "--") {
      df <- filter(df, FACILITY == input$facility)
    }
    return(df)
  })
  
  # 监听筛选结果变化,更新所有select的选项
  observeEvent(filtered_data(), {
    df <- filtered_data()
    # 筛选到唯一记录时,自动填充所有输入框
    if (nrow(df) == 1) {
      updateSelectizeInput(session, "patient", selected = df$SSN)
      updateSelectizeInput(session, "pid", selected = df$PATIENT_ID)
      updateSelectizeInput(session, "fname", selected = df$FIRST_NAME)
      updateSelectizeInput(session, "lname", selected = df$LAST_NAME)
      updateSelectizeInput(session, "facility", selected = df$FACILITY)
      return()
    }
    # 未筛选到唯一记录时,只更新未选中的输入框的可选选项
    if (input$patient == "--") {
      updateSelectizeInput(session, "patient", choices = c("--", sort(df$SSN)), server = TRUE)
    }
    if (input$pid == "--") {
      updateSelectizeInput(session, "pid", choices = c("--", sort(df$PATIENT_ID)), server = TRUE)
    }
    if (input$fname == "--") {
      updateSelectizeInput(session, "fname", choices = c("--", sort(unique(df$FIRST_NAME))), server = TRUE)
    }
    if (input$lname == "--") {
      updateSelectizeInput(session, "lname", choices = c("--", sort(unique(df$LAST_NAME))), server = TRUE)
    }
    if (input$facility == "--") {
      updateSelectizeInput(session, "facility", choices = c("--", sort(unique(df$FACILITY))), server = TRUE)
    }
  })
  
  # 清空按钮逻辑
  observeEvent(input$clear, {
    updateSelectizeInput(session, "patient", choices = c("--", sort(rv$full_data$SSN)), selected = "--", server = TRUE)
    updateSelectizeInput(session, "pid", choices = c("--", sort(rv$full_data$PATIENT_ID)), selected = "--", server = TRUE)
    updateSelectizeInput(session, "fname", choices = c("--", sort(unique(rv$full_data$FIRST_NAME))), selected = "--", server = TRUE)
    updateSelectizeInput(session, "lname", choices = c("--", sort(unique(rv$full_data$LAST_NAME))), selected = "--", server = TRUE)
    updateSelectizeInput(session, "facility", choices = c("--", sort(unique(rv$full_data$FACILITY))), selected = "--", server = TRUE)
  })
  
  # 示例:渲染选中的患者信息,替换为实际的图表/表格逻辑
  output$selected_patient_info <- renderTable({
    req(filtered_data(), nrow(filtered_data()) == 1)
    filtered_data()
  })
}

shinyApp(ui, server)

性能提升说明

  • 所有selectizeInput开启server=TRUE参数,选项在服务端处理,不会把全量选项一次性推送到前端,17万行数据场景下加载速度提升明显
  • 移除了不必要的响应式变量和字符串拼接逻辑,筛选逻辑直接基于dplyr的向量运算,速度远高于逐行判断
  • 仅更新未选中的控件的选项,避免重复渲染已选控件,减少不必要的计算

内容的提问来源于stack exchange,提问作者quickreaction

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 00:15:04