Почему мне нужно жестко запрограммировать формулу в emmeans() вместо динамического извлечения формулы из динамической линейной модели?

Обновлено: добавлен не-Shiny MRE, хотя у него другая ошибка, чем у Shiny...

Рассмотрим следующий MRE (обратите внимание, что приложение не будет отображаться правильно, этот код предназначен только для запуска его для MRE, чтобы вы могли протестировать его в браузере().) Этот MRE имитирует часть более крупного приложения, указанную пользователем. модель, имеющая значение в ANOVA, и собирается провести соответствующие апостериорные исследования. В этом случае апостериорно при наличии гетероскедастичности, поэтому нам нужно построить модель с разными дисперсиями для каждой комбинации эффектов.

library(shiny)
require(emmeans)
require(nlme)
require(DT)

data<-structure(list(percent = c(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 
                                 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 
                                 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
                                 2, 2, 1, 1, 1, 1, 1, 1, 1, 1),
                     cycle = c(4, 4, 4, 4, 4, 4, 4, 
                               4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
                               3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 
                               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
                     density = c(21, 
                                 20, 21, 21, 22, 20, 20, 19, 18, 19, 19, 19, 19, 18, 18, 19, 20, 
                                 22, 22, 21, 22, 22, 20, 21, 20, 20, 19, 19, 19, 19, 19, 19, 23, 
                                 25, 24, 24, 26, 23, 24, 24, 23, 22, 22, 23, 21, 24, 22, 22, 16, 
                                 17, 16, 15, 17, 16, 16, 16, 26, 27, 26, 25, 25, 26, 26, 26), 
                     run = c(8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 4L, 4L, 4L, 4L, 4L, 
                             4L, 4L, 4L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 3L, 3L, 3L, 3L, 
                             3L, 3L, 3L, 3L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 2L, 2L, 2L, 
                             2L, 2L, 2L, 2L, 2L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 1L, 1L, 
                             1L, 1L, 1L, 1L, 1L, 1L)), class = "data.frame", row.names = c(NA, 
                                                                                           -64L))


# Define UI for application
ui <- fluidPage(

    # Application title
    titlePanel("Blah"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
        ),

        # Show a plot of the generated distribution
        mainPanel(
           #plotOutput("distPlot"),
           dataTableOutput("otherthing"),
           textOutput("post_hoc")
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  
  aov_model <- reactiveVal(NULL)
  
  output$otherthing<-renderDataTable({
    formula<-"density~percent*cycle"#selected by user
    aov_mod <-lm(formula = formula(formula),data = data)
    data$cycle<-factor(data$cycle)
    data$percent<-factor(data$percent)
    aov_model(aov_mod)
    #browser()
    print(aov_mod[["coefficients"]])
  })
  
  output$post_hoc<-renderText({
    data$group<-interaction(data[c(1,2)])
    gls_formula<-formula(aov_model())
    #environment(gls_formula) <- .GlobalEnv
    model<-gls(gls_formula, data = data, weights = varIdent(form = ~1 | group))
    model2<-gls(density~percent*cycle, data = data, weights = varIdent(form = ~1 | group))
    browser()
    results<-emmeans(model,
                     pairwise~percent*cycle,
                     adjust = "tukey",
                     type = "response",
                     data=data)
    
    results2<-emmeans(model2,
                     pairwise~percent*cycle,
                     adjust = "tukey",
                     type = "response",
                     data=data)
    print(results2)
  })

Обратите внимание при разрыве браузера, что результаты контрастов работают нормально, если вы вручную наберете «попарно ~ процент * цикл» для формулы gls, которая позже будет использоваться в emmeans() (выполнение результатов2). Но не будет, если вы используете извлеченную формулу из реактивной линейной модели (выполнение результатов) в emmeans(). В этом случае он выдаст: Ошибка в eval(call$model): объект «gls_formula» не найден и из-за этого еще одна ошибка.

В реальном приложении все это динамически выбирается пользователем и потенциально изменяется приложением, поэтому мне действительно нужна модель gls, использующая динамически извлекаемую формулу, чтобы она работала, а не просто перестраивала выбранные эффекты.

Я не понимаю, почему извлеченная формула, которая, насколько я могу судить, идентична жестко запрограммированной, не работает. Я даже пробовал установить среду на извлеченную, но это, похоже, ничего не меняет.

Ниже приведен пример без Shiny. Выдает другую ошибку, но, возможно, это связано с той же проблемой? Эта ошибка: Ошибка в вызове $model[[2]]: объект типа «символ» не является подмножеством.

require(emmeans)
require(nlme)

data<-structure(list(percent = c(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 
                                 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 
                                 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 
                                 2, 2, 1, 1, 1, 1, 1, 1, 1, 1),
                     cycle = c(4, 4, 4, 4, 4, 4, 4, 
                               4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
                               3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 
                               1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
                     density = c(21, 
                                 20, 21, 21, 22, 20, 20, 19, 18, 19, 19, 19, 19, 18, 18, 19, 20, 
                                 22, 22, 21, 22, 22, 20, 21, 20, 20, 19, 19, 19, 19, 19, 19, 23, 
                                 25, 24, 24, 26, 23, 24, 24, 23, 22, 22, 23, 21, 24, 22, 22, 16, 
                                 17, 16, 15, 17, 16, 16, 16, 26, 27, 26, 25, 25, 26, 26, 26), 
                     run = c(8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 4L, 4L, 4L, 4L, 4L, 
                             4L, 4L, 4L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 3L, 3L, 3L, 3L, 
                             3L, 3L, 3L, 3L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 2L, 2L, 2L, 
                             2L, 2L, 2L, 2L, 2L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 1L, 1L, 
                             1L, 1L, 1L, 1L, 1L, 1L)), class = "data.frame", row.names = c(NA, 
                                                                                           -64L))



formula<-"density~percent*cycle" #selected by user
effect<-"percent*cycle" #selected by user
data$cycle<-factor(data$cycle)
data$percent<-factor(data$percent)

aov_mod <-lm(formula = formula(formula),data = data)

#later in the app
data$group<-interaction(data[c(1,2)])
gls_formula<-formula(aov_mod)
#environment(gls_formula) <- .GlobalEnv
model<-gls(gls_formula, data = data, weights = varIdent(form = ~1 | group)) #using extracted formula
model2<-gls(density~percent*cycle, data = data, weights = varIdent(form = ~1 | group)) #using hard coded formula
emmeans(model,
        formula(paste("pairwise ~",gsub(pattern = ":",replacement = "*",x = effect))),
        adjust = "tukey",
        type = "response",
        data=data)
emmeans(model2,
        formula(paste("pairwise ~",gsub(pattern = ":",replacement = "*",x = effect))),
        adjust = "tukey",
        type = "response",
        data=data)

Я не считаю, что блестящее приложение необходимо для демонстрации проблемы масштабирования. Пожалуйста, создайте настоящий MRE (акцент на «минимальном»).

Roland 25.06.2024 07:03

@Роланд, спасибо за комментарий, я добавил не-Shiny MRE. Я не знаю, почему возникает ошибка, и оригинал был обнаружен в приложении Shiny, поэтому мне стало интересно, связано ли это с работой в реактивной среде. Пример без Shiny также выдает ошибку, хотя и другую.

Steven Ouellette 25.06.2024 17:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В какой-то момент emmeans вызывает код, который пытается извлечь формулу из элемента $call модели, чтобы найти переменные, участвующие в модели. Он находит символ gls_model и не может извлечь его второй элемент (который был бы правой частью объекта формулы. (В случае Shiny он даже не может найти этот объект, потому что он находится где-то в другой среде.)

Стандартным решением подобных проблем (как в этом примере) является встраивание вызова модели в do.call(), что приводит к дополнительному этапу оценки:

model <- do.call(gls,
   list(gls_formula, data = data, 
       weights = varIdent(form = ~1 | group)))

Насколько я могу судить, это должно решить как вашу проблему с Shiny, так и вашу проблему без Shiny, но я тестировал только случай без Shiny...

Да, это сделало это. Огромное спасибо, я бы никогда этого не догадался!

Steven Ouellette 25.06.2024 20:42

Будет ли это считаться ошибкой, о которой мне следует сообщить в emmeans?

Steven Ouellette 25.06.2024 20:43

Вы можете открыть проблему. Я не уверен, что назвал бы это ошибкой как таковой, но я думаю, что сопровождающий пакета мог бы сделать это, чтобы облегчить жизнь конечным пользователям...

Ben Bolker 25.06.2024 20:54

Близко, но этот код уже работает. Это похожее место в строке 419, где проверяется настройка Саттертуэйта. Смотрите отчет о проблеме

Russ Lenth 26.06.2024 00:03

Спасибо, извините за немного вводящий в заблуждение отчет...

Ben Bolker 26.06.2024 00:32

Другие вопросы по теме