Формула з динамічною кількістю змінних


83

Припустимо, є деякий data.frame foo_data_frame, і хочеться знайти регресію цільового стовпця Y за деякими іншими стовпцями. Для цього зазвичай використовують якусь формулу та модель. Наприклад:

linear_model <- lm(Y ~ FACTOR_NAME_1 + FACTOR_NAME_2, foo_data_frame)

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

for (i in seq_len(factor_number)) {
  for (j in seq(i + 1, factor_number)) {
    linear_model <- lm(Y ~ F1 + F2, list(Y=foo_data_frame$Y,
                                         F1=foo_data_frame[[i]],
                                         F2=foo_data_frame[[j]]))
    # linear_model further analyzing...
  }
}

Моє питання полягає в тому, як зробити такий самий вплив, коли кількість змінних динамічно змінюється під час запуску програми?

for (number_of_factors in seq_len(5)) {
   # Then root over subsets with #number_of_factors cardinality.
   for (factors_subset in all_subsets_with_fixed_cardinality) {
     # Here I want to fit model with factors from factors_subset.
     linear_model <- lm(Does R provide smth to write here?)
   }
}

2
Дякую! Ваш середній приклад змусив мене зрозуміти, що мені не потрібно рішення вашого питання, і я можу зробити щось набагато простіше!
Марк Адамсон,

Відповіді:


105

Див. ?as.formula, Наприклад:

factors <- c("factor1", "factor2")
as.formula(paste("y~", paste(factors, collapse="+")))
# y ~ factor1 + factor2

де factorsвектор символів, що містить назви факторів, які ви хочете використовувати в моделі. Це ви можете вставити в lmмодель, наприклад:

set.seed(0)
y <- rnorm(100)
factor1 <- rep(1:2, each=50)
factor2 <- rep(3:4, 50)
lm(as.formula(paste("y~", paste(factors, collapse="+"))))

# Call:
# lm(formula = as.formula(paste("y~", paste(factors, collapse = "+"))))

# Coefficients:
# (Intercept)      factor1      factor2  
#    0.542471    -0.002525    -0.147433

66

Часто забутою функцією є reformulate. Від ?reformulate:

reformulate створює формулу з вектора символів.


Простий приклад:

listoffactors <- c("factor1","factor2")
reformulate(termlabels = listoffactors, response = 'y')

дасть таку формулу:

y ~ factor1 + factor2


Хоча це не чітко задокументовано, ви також можете додати умови взаємодії:

listofintfactors <- c("(factor3","factor4)^2")
reformulate(termlabels = c(listoffactors, listofintfactors), 
    response = 'y')

дасть:

y ~ factor1 + factor2 + (factor3 + factor4)^2


3
@JorisMeys І це набагато приємніше, оскільки дозволяє додавати умови взаємодії! Я шукав подібне рішення роками ..
landroni

Що робити, якщо змінні x містять пробіли? Скажіть "фактор 1", "фактор 2" тощо.
аксіома

11

Іншим варіантом може бути використання матриці у формулі:

Y = rnorm(10)
foo = matrix(rnorm(100),10,10)
factors=c(1,5,8)

lm(Y ~ foo[,factors])

3
+1, але пам’ятайте, що це не дозволяє використовувати ефекти взаємодії. Для цього також можна побудувати матрицю моделі (див. ?model.matrix)
Джоріс Мейс

4

Насправді вам не потрібна формула. Це працює:

lm(data_frame[c("Y", "factor1", "factor2")])

як це робиться:

v <- c("Y", "factor1", "factor2")
do.call("lm", list(bquote(data_frame[.(v)])))

+1 Дуже правильно, але знову ж таки, вам доведеться використовувати model.matrix для побудови матриці з ефектами взаємодії.
Джоріс Мейс

0

Зазвичай я вирішую це шляхом зміни назви мого стовпця відповідей. Це простіше робити динамічно і, можливо, чистіше.

model_response <- "response_field_name"
setnames(model_data_train, c(model_response), "response") #if using data.table
model_gbm <- gbm(response ~ ., data=model_data_train, ...)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.