Как я могу использовать `I ()` с `paste0`?

#r

#r

Вопрос:

У меня есть несколько фреймов данных, и я хотел бы оценить (несколько) разных моделей для каждого. MWE

 df1 <- data.frame(A3 = c(-5, 5, 1), 
                  B3 = c(0, 10, 1))
df2 <- data.frame(A4 = c(5, 15, 1))
                  B4 = c(10, 20, 1))

myfun <- function(arg1, arg2){ # arg1 =1 or 2
  if (arg2 == 1){
    eqn <- paste0("A", arg1 2) ~ paste0("B", arg1 2)   I(as.name(paste0("B", arg1 2))^2)
  } else {
    eqn <- paste0("A", arg1 2) ~ paste0("B", arg1 2)   I(as.name(paste0("B", arg1 2))^2)  I(as.name(paste0("B", arg1 2))^3)
  }
 
  return (lm(formula = eqn, data = eval(as.name(paste0("df", arg1)))
    )
  )
}
  

Например, если я запускаю myfun(1,2) , я хотел бы получить lm(A4 ~ B4 I(B4^2) I(B4^3), data = df2) . Но что бы я ни пытался, я получаю следующее сообщение об ошибке Error in (paste0("B", arg1 2))^2 : non-numeric argument to binary operator . Из того, что я прочитал ?I , я полагаю, это потому, что R изолирует все, что передается I() , поэтому он не понимает, что я пытаюсь преобразовать переменную: это то, что происходит, и это что-то, что я могу исправить? Кроме того, есть ли лучший способ быстро оценить несколько моделей? Все подобные вопросы, которые я нашел, использовались одинаково data.frame для разных моделей, в то время как я должен учитывать переменные ответа (и предиктора), поступающие из разных фреймов данных для разных моделей.

Ответ №1:

Может быть, это то, что вы ищете:

Проблема в том, что вы выполняете математическую операцию над строкой, то есть (paste0("B", arg1 2))^2 пытаетесь возвести строку в квадрат, вот почему вы получаете ошибку. Inytead вы можете просто склеить формулу в виде строки и преобразовать ее в формулу с помощью as.formula :

 df1 <- data.frame(A3 = c(-5, 5, 1), 
                  B3 = c(0, 10, 1))
df2 <- data.frame(A4 = c(5, 15, 1))
B4 = c(10, 20, 1)

myfun <- function(arg1, arg2){ # arg1 =1 or 2
  if (arg2 == 1){
    eqn <- paste0("A", arg1 2, " ~ B", arg1 2,"   I(B", arg1 2, "^2)")
  } else {
    eqn <- paste0("A", arg1 2, " ~ B", arg1 2,"   I(B", arg1 2, "^2)   I(B", arg1 2, "^3)")
  }
  
  return (lm(formula = as.formula(eqn), data = eval(as.name(paste0("df", arg1)))
  )
  )
}

myfun(2, 1)
#> 
#> Call:
#> lm(formula = as.formula(eqn), data = eval(as.name(paste0("df", 
#>     arg1))))
#> 
#> Coefficients:
#> (Intercept)           B4      I(B4^2)  
#>     0.84795      0.12281      0.02924
  

Ответ №2:

Также можно создать formula с помощью glue

 myfun <- function(arg1, arg2){ 
    eqn <- switch(arg2, 
                 `1` = glue::glue("A{arg1   2}~ B{arg1 2}   I(B{arg1 2}^2)"),
      
                 glue::glue("A{arg1   2}~ B{arg1 2}", 
                                     "  I(B{arg1 2}^2)   I(B{arg1 2}^3)")
       )
    model <- lm(eqn, data = get(paste0('df', arg1), envir = .GlobalEnv))
    model$call <- as.formula(eqn)
    return(model)

      
    }
      
myfun(2, 1)
#Call:
#A4 ~ B4   I(B4^2)

#Coefficients:
#(Intercept)           B4      I(B4^2)  
#    0.84795      0.12281      0.02924