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

基于Shiny App实现临床试验数据筛选的结构化数据处理方案咨询

基于Shiny App实现临床试验数据筛选的结构化数据处理方案咨询

嗨,这个问题在临床研究数据处理里挺常见的,核心是解决多变量多取值的结构化矛盾——既要保证数据能支持灵活筛选,又要让用户最终看到的是每个研究一行的清晰视图。我给你几个实用的落地方案,你可以根据自己的需求和数据规模选择:

方案一:数据规范化(长表拆分+筛选后合并)

这是最容易上手且不易出错的方案,核心是先把Excel里的“一行多值”数据拆成“一行一值”的长格式,筛选后再合并回单行展示给用户。

步骤1:预处理拆分多值字段

用tidyverse工具包的separate_rows()函数,把包含多个干预、终点的字段拆成单独行,每个研究对应多个行(每个干预/终点一行):

library(tidyverse)
# 假设你的原始数据框是clinical_trials,包含study_id, intervention, endpoint等列
cleaned_trials <- clinical_trials %>%
  # 按逗号分隔拆分干预列,根据你实际的分隔符调整
  separate_rows(intervention, sep = ", ") %>%
  # 同样拆分终点列
  separate_rows(endpoint, sep = ", ")

步骤2:Shiny中筛选并合并结果

在Shiny的Server逻辑里,先基于拆分后的长表筛选符合条件的行,再按研究ID合并回单行,保证用户看到的是每个研究一行的结构:

# Shiny Server部分的筛选逻辑
filtered_data <- reactive({
  # 获取用户选择的干预和终点
  selected_intervs <- input$selected_interventions
  selected_endpoints <- input$selected_endpoints
  
  cleaned_trials %>%
    # 筛选包含用户选择项的行
    filter(
      intervention %in% selected_intervs,
      endpoint %in% selected_endpoints
    ) %>%
    # 按研究ID分组,合并多值字段
    group_by(study_id) %>%
    summarise(
      intervention = paste(unique(intervention), collapse = ", "),
      endpoint = paste(unique(endpoint), collapse = ", "),
      # 其他字段根据需求处理,比如保留第一个值或合并
      study_name = first(study_name),
      phase = first(phase)
    ) %>%
    ungroup()
})

方案二:直接在Shiny中处理多值字符串(不修改原始数据)

如果不想改动原始数据的结构,也可以直接在筛选逻辑里识别多值字段。适合原始数据已经固定、不想重新整理的场景。

步骤1:预处理转列表列(可选但推荐)

先把多值字符串转成列表列,避免字符串匹配的误判问题:

clinical_trials <- clinical_trials %>%
  mutate(
    intervention_list = str_split(intervention, ", "),
    endpoint_list = str_split(endpoint, ", ")
  )

步骤2:Shiny中基于列表筛选

用purrr的map_lgl()函数判断每个研究的干预/终点列表是否包含用户选择的项:

filtered_data <- reactive({
  selected_intervs <- input$selected_interventions
  selected_endpoints <- input$selected_endpoints
  
  clinical_trials %>%
    filter(
      # 判断干预列表是否和用户选择有交集
      map_lgl(intervention_list, ~ any(.x %in% selected_intervs)),
      # 终点同理
      map_lgl(endpoint_list, ~ any(.x %in% selected_endpoints))
    )
})

方案三:关系型数据关联(长期维护最优解)

如果你的干预、终点有标准化的编码,推荐用关系型数据结构:拆分出主表(研究基本信息)、关联表(研究-干预、研究-终点)、字典表(干预/终点的名称-编码映射)。这种结构最规范,适合数据量扩展或后续对接其他系统的场景。

示例数据结构

# 研究主表
study_main <- tibble(
  study_id = c("STUDY001", "STUDY002", "STUDY003"),
  study_name = c("XX癌症治疗研究", "XX心血管研究", "XX糖尿病研究"),
  phase = c("III", "II", "IV")
)

# 研究-干预关联表
study_interv <- tibble(
  study_id = rep(c("STUDY001", "STUDY002"), c(3, 2)),
  interv_id = c(1, 2, 3, 1, 4)
)

# 干预字典表
interv_dict <- tibble(
  interv_id = 1:4,
  interv_name = c("免疫治疗", "化疗", "靶向治疗", "安慰剂")
)

Shiny中基于关联表筛选

先通过字典表找到用户选择的干预编码,再关联到研究ID,最后匹配主表:

filtered_study_ids <- reactive({
  # 获取用户选择的干预名称对应的编码
  selected_interv_ids <- interv_dict %>%
    filter(interv_name %in% input$selected_interventions) %>%
    pull(interv_id)
  
  # 找到对应研究ID
  study_interv %>%
    filter(interv_id %in% selected_interv_ids) %>%
    pull(study_id) %>%
    unique()
})

# 筛选主表数据
filtered_data <- reactive({
  study_main %>%
    filter(study_id %in% filtered_study_ids())
})

额外优化:提升用户体验

在Shiny的UI部分,推荐用shinyWidgets包的pickerInput组件做多选下拉框,支持搜索、批量选择,比原生的selectInput体验更好:

library(shinyWidgets)
pickerInput(
  inputId = "selected_interventions",
  label = "选择干预措施",
  choices = unique(cleaned_trials$intervention), # 或从字典表获取
  multiple = TRUE,
  options = list(
    `actions-box` = TRUE,
    `live-search` = TRUE
  )
)

备注:内容来源于stack exchange,提问作者yusefsoliman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 13:49:32