Ошибка “Объект типа ‘symbol’ не может быть подмножеством” при отображении таблицы выживаемости с gtsummary в shiny.

Вопрос или проблема

Я пытаюсь создать простое приложение в shiny, чтобы создать из базы данных таблицу с процентом выживаемости в определенный момент времени, сравнивая 2 группы (женщины против мужчин, препарат а против препарата б и т.д.).

Приложение имеет боковую панель с вводом (переменная времени и переменная статуса), чтобы рассчитать выживаемость. Для описательной таблицы без сравнения групп (просто выживаемость на 24 месяц в %) это работает нормально (код ниже с примером датафрейма).

library(shiny)
library(gtsummary)
library(survival)
library(dplyr)
library(DT)
library(cards)
library(cardx)
library(gt)

# Создание вымышленного датафрейма
set.seed(123)
data <- data.frame(
  gender = sample(c("male", "female"), 100, replace = TRUE),
  age = sample(18:70, 100, replace = TRUE),
  stage = sample(1:4, 100, replace = TRUE),
  OS = runif(100, 2, 70),
  status = sample(0:1, 100, replace = TRUE),
  ECOG24 = sample(0:1, 100, replace = TRUE)
)

# Определение интерфейса
ui <- fluidPage(
  navbarPage("Приложение клинических данных",
             tabPanel("Анализ выживаемости",
                      sidebarLayout(
                        sidebarPanel(
                          selectInput("time_var", "Выберите переменную времени:",
                                      choices = names(data), selected = "OS"),
                          selectInput("status_var", "Выберите переменную статуса:",
                                      choices = names(data), selected = "status"),
                          numericInput("timepoint", "Введите момент времени:", 24, min = 1, max = 70)
                        ),
                        mainPanel(
                          tabsetPanel(
                            tabPanel("Таблица выживаемости", gt_output("surv_table"))
                          )
                        )
                      )
             )
  )
)

# Определение логики сервера
server <- function(input, output, session) {
  
  output$surv_table <- render_gt({
    # Проверка вводимых данных
    req(input$time_var, input$status_var, input$timepoint)
    
    # Создание объекта выживаемости
    surv_obj <- Surv(time = data[[input$time_var]], event = data[[input$status_var]])
    
    # Создание tbl_survival с использованием вводимых значений
    tbl_survival <- 
      survfit(surv_obj ~ 1, data) |> 
      cardx::ard_survival_survfit(times = c(input$timepoint)) |>  
      cards::update_ard_fmt_fn(
        stat_names = c("estimate", "conf.low", "conf.high"),
        fmt_fn = label_style_sigfig(digits = 2, scale = 100)
      ) |> 
      tbl_ard_summary(
        label = list(time = paste0(input$timepoint, " месяцев вероятность выживания")),
        statistic = time ~ "{estimate}%"
      )
    
    # Преобразование в таблицу gt перед рендерингом
    gt_table <- as_gt(tbl_survival)
    
    # Отрисовка таблицы
    gt_table
  })
}

# Запуск приложения 
shinyApp(ui = ui, server = server)

Я ожидаю, что таблица будет создана с этим кодом:

survfit(Surv(OS, status) ~ gender, data) |> 
  cardx::ard_survival_survfit(times = c(24)) |>  
  cards::update_ard_fmt_fn(
    stat_names = c("estimate", "conf.low", "conf.high"),
    fmt_fn = label_style_sigfig(digits = 2, scale = 100)
  ) |> 
  tbl_ard_summary(
    by = gender,
    label = list(time = paste0("24 ", " месяцев вероятность выживания")),
    statistic = time ~ "{estimate}%"
  )

Проблема возникает в shiny, когда я добавляю переменную для сравнения групп (например, пол).

с этим кодом:

ui <- fluidPage(
  navbarPage("Приложение клинических данных",
             tabPanel("Анализ выживаемости",
                      sidebarLayout(
                        sidebarPanel(
                          selectInput("time_var", "Выберите переменную времени:",
                                      choices = names(data)),
                          selectInput("status_var", "Выберите переменную статуса:",
                                      choices = names(data)),
                          selectInput("group_var", "Выберите переменную группировки:",
                                      choices = c("Нет", names(data))),
                          numericInput("timepoint", "Введите момент времени:", 12, min = 1, max = 70)
                        ),
                        mainPanel(
                          tabsetPanel(
                            tabPanel("Таблица выживаемости", gt_output("surv_table"))
                          )
                        )
                      )
             )
  )
)

# Определение логики сервера
server <- function(input, output, session) {
  
  output$surv_table <- render_gt({
    # Проверка вводимых данных
    req(input$time_var, input$status_var, input$timepoint)
    
    # Создание объекта выживаемости
    surv_obj <- Surv(time = data[[input$time_var]], event = data[[input$status_var]])
    print("Объект выживаемости создан:")
    print(surv_obj)
    
    # Определение формулы группировки
    if (input$group_var == "Нет") {
      formula <- surv_obj ~ 1
    } else {
      formula <- as.formula(paste("surv_obj ~", input$group_var))
    }
    
    # Печать формулы для отладки
    print("Формула выживаемости:")
    print(formula)
    
    # Подгонка модели выживаемости с правильными данными
    fit <- survfit(formula, data = data)
    print("Модель выживаемости адаптирована:")
    print(summary(fit))
    
    # Создание tbl_survival с использованием вводимого значения
    tbl_survival <- 
      fit |> 
      cardx::ard_survival_survfit(times = input$timepoint) |> 
      cards::update_ard_fmt_fn(
        stat_names = c("estimate", "conf.low", "conf.high"),
        fmt_fn = label_style_sigfig(digits = 2, scale = 100)
      ) |> 
      dplyr::mutate(context = "categorical") |> # принуждаем сводку к "категориям"
      tbl_ard_summary(
        by = if (input$group_var == "Нет") NULL else input$group_var,
        label = list(time = paste0(input$timepoint, " месяцев вероятность выживания")),
        statistic = time ~ "{estimate}% (95% CI {conf.low}%, {conf.high}%)"
      )
    
    print("Таблица сводки:")
    print(tbl_survival)
    
    # Преобразование в таблицу gt перед рендерингом
    gt_table <- as_gt(tbl_survival)
    
    # Отрисовка таблицы
    gt_table
  })
}

# Запуск приложения 
shinyApp(ui = ui, server = server)

Я получаю ошибку “объект типа ‘symbol’ не подлежит индексации” (я пробовал множество различных альтернатив и всегда получаю одну и ту же ошибку).

При отладке формула работает нормально (summary(fit) в порядке).

Кроме того, тот же самый код в простом R (без shiny) с фиксированной переменной группировки (например, пол) работает нормально. (см. код выше)

Таким образом, проблема, вероятно, в построении таблицы с gt_summary, я предполагаю…

У вас есть какие-то идеи? Спасибо!

Ответ или решение

Ошибка "Object of type ‘symbol’ is not subsettable", с которой вы сталкиваетесь при работе с пакетом gtsummary в R Shiny, может возникать из-за неправильного обращения с формулами или переменными внутри вашей функции render_gt. Давайте детально разберем возможные причины и решения данной проблемы.

Причины ошибки

  1. Неправильная передача формулы: При создании формулы для survfit, необходимо убедиться, что она корректно интерпретируется. Поскольку вы используете as.formula, должно соблюдаться соответствие между названием переменных и форматом формулы.

  2. Объект типа ‘symbol’: Данная ошибка может возникать, если вы пытаетесь применить операцию индексации к объекту, который не поддерживает это. Например, когда input$group_var возвращает символ, который невозможно обработать как переменную данных.

Возможные решения

  1. Использование as.formula корректно:
    Убедитесь, что при создании формулы используется правильная структура. Вместо as.formula(paste("surv_obj ~", input$group_var)), попробуйте следующее:

    formula <- as.formula(sprintf("surv_obj ~ %s", input$group_var))
  2. Проверка значения input$group_var:
    Убедитесь, что input$group_var корректно извлекается из выборки. Перед созданием формулы можно добавить отладочные операции, чтобы проверить, что значение действительно соответствует названию переменной в данных.

  3. Упрощение проверки:
    Если input$group_var равен "None", то пропустите группировку в формуле, просто задав формулу surv_obj ~ 1. В противном случае, используйте корректное имя переменной:

    if (input$group_var == "None") {
       formula <- Surv(time = data[[input$time_var]], event = data[[input$status_var]]) ~ 1
    } else {
       formula <- as.formula(paste("Surv(time = data[[input$time_var]], event = data[[input$status_var]]) ~", input$group_var))
    }
  4. Корректная сборка таблицы:
    Убедитесь, что вы правильно формируете tbl_survival. В вашем коде вы используете by = if (input$group_var == "None") NULL else input$group_var, что может вызвать ошибки. При необходимости просто уберите часть с by, если она не нужна.

Улучшенный код

Ниже приведен модифицированный код с учетом вышеперечисленных рекомендаций:

# Define server logic
server <- function(input, output, session) {

  output$surv_table <- render_gt({
    # Validate inputs
    req(input$time_var, input$status_var, input$timepoint)

    # Create the survival object
    surv_obj <- Surv(time = data[[input$time_var]], event = data[[input$status_var]])

    # Determine grouping formula
    formula <- if (input$group_var == "None") {
      Surv(time = data[[input$time_var]], event = data[[input$status_var]]) ~ 1
    } else {
      as.formula(paste("Surv(time = data[[input$time_var]], event = data[[input$status_var]]) ~", input$group_var))
    }

    # Fit the survival model with the correct data
    fit <- survfit(formula, data = data)

    # Build tbl_survival using the input values
    tbl_survival <- 
      fit |>
      cardx::ard_survival_survfit(times = input$timepoint) |>
      cards::update_ard_fmt_fn(
        stat_names = c("estimate", "conf.low", "conf.high"),
        fmt_fn = label_style_sigfig(digits = 2, scale = 100)
      ) |>
      tbl_ard_summary(
        by = if (input$group_var == "None") NULL else input$group_var,
        label = list(time = paste0(input$timepoint, " months Survival Probability")),
        statistic = time ~ "{estimate}% (95% CI {conf.low}%, {conf.high}%)"
      )

    # Convert to gt table before rendering
    gt_table <- as_gt(tbl_survival)

    # Render the table
    gt_table
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Заключение

Использование правильного синтаксиса для формул и проверка значений, получаемых из input, поможет избежать ошибки "object of type ‘symbol’ is not subsettable". Убедитесь, что формирование таблицы происходит корректно, и вы сможете успешно отобразить результаты в Shiny-приложении. Если проблемы будут сохраняться, рассмотрите возможность добавления более детальных отладочных сообщений для лучшего понимания источника проблемы.

Оцените материал
Добавить комментарий

Капча загружается...