Как кратко написать формулу с множеством переменных из фрейма данных?

127

Предположим, у меня есть переменная ответа и данные, содержащие три ковариаты (в качестве игрушечного примера):

y = c(1,4,6)
d = data.frame(x1 = c(4,-1,3), x2 = c(3,9,8), x3 = c(4,-4,-2))

Я хочу подобрать линейную регрессию к данным:

fit = lm(y ~ d$x1 + d$x2 + d$y2)

Есть ли способ написать формулу, чтобы мне не приходилось записывать каждую отдельную ковариату? Например, что-то вроде

fit = lm(y ~ d)

(Я хочу, чтобы каждая переменная во фрейме данных была ковариантой.) Я спрашиваю, потому что на самом деле у меня во фрейме данных 50 переменных, поэтому я хочу избежать записи x1 + x2 + x3 + etc.

grautur
источник

Ответы:

204

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

y <- c(1,4,6)
d <- data.frame(y = y, x1 = c(4,-1,3), x2 = c(3,9,8), x3 = c(4,-4,-2))
mod <- lm(y ~ ., data = d)

Вы также можете сделать это, чтобы использовать все переменные, кроме одной (в этом случае x3 исключен):

mod <- lm(y ~ . - x3, data = d)

Технически .означает все переменные, еще не упомянутые в формуле . Например

lm(y ~ x1 * x2 + ., data = d)

где .будет только ссылка, x3поскольку x1и x2уже есть в формуле.

Гэвин Симпсон
источник
Фрейм данных «d» имеет 4 столбца (y, x1, x2 и x3). Итак, если формула - «y ~.», Означает ли правая часть «все столбцы», кроме тех, которые перечислены в левой части?
stackoverflowuser2010
1
@ stackoverflowuser2010 Да, .технически означает, что все переменные еще data не включены в формулу .
Гэвин Симпсон
1
@theforestecologist, если вы имеете в виду, dataчто это список, из которого переменные в формуле ищутся из этого списка, тогда да. Фрейм данных, список или окружение являются приемлемыми вариантами dataаргумента. Если это не то, что вы имеете в виду, вам нужно немного расширить.
Гэвин Симпсон
@Gavin. Вот что я имел в виду. Спасибо. Как я могу использовать этот метод, используя данные [[x]] в качестве переменной в списке вместо фактического имени переменной (например, 'x3')? Например, как мне заставить работать следующее ?:lm(d[[1]] ~ d[[3]] + ., data = d)
theforestecologist
Он работает вне namesсписка; что у вас есть ll <- list(y = rnorm(10), x = rnorm(10), z = rnorm(10), zz = runif(10)), то следующие работы: lm(y ~ x + ., data = ll). Так что нет особых причин для таких данных, если они уже не являются списком, но это работает. Требование, чтобы элементы формулы были одинаковой длины, накладывает некоторые ограничения на то, что у вас есть в списке. Более сложные объекты, вероятно, нуждаются в коде для извлечения нужных вам элементов; если бы d[[1]]это был фрейм данных / матрица, вам нужен код, чтобы это работало
Гэвин Симпсон
66

Немного другой подход - создать формулу из строки. На formulaстранице справки вы найдете следующий пример:

## Create a formula for a model with a large number of variables:
xnam <- paste("x", 1:25, sep="")
fmla <- as.formula(paste("y ~ ", paste(xnam, collapse= "+")))

Тогда, если вы посмотрите на сгенерированную формулу, вы получите:

R> fmla
y ~ x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + 
    x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + 
    x22 + x23 + x24 + x25
Джуба
источник
1
Это очень хорошо работает для чтения этих значений из файла. Спасибо!
Бен Сидхом
Обратите внимание, что часть as.formula является обязательной
Цзиньхуа Ван
7

Да, конечно, просто добавьте ответ в yкачестве первого столбца в фрейм данных и вызовите lm()его:

d2<-data.frame(y,d)
> d2
  y x1 x2 x3
1 1  4  3  4
2 4 -1  9 -4
3 6  3  8 -2
> lm(d2)

Call:
lm(formula = d2)

Coefficients:
(Intercept)           x1           x2           x3  
    -5.6316       0.7895       1.1579           NA  

Кроме того, моя информация о R указывает на то, что назначение с <-рекомендуется более =.

Бернд Элькеманн
источник
Спасибо! Да, я знаю, что все всегда говорят использовать <-, но никто никогда не говорит, почему, а = легче набирать =).
Grautur 09
2
@gratur Одна из причин заключается в том, что такие вещи, как foo(bar <- 1:10)работа (и barсоздается) foo(bar = 1:10), либо не сработают, потому что barне являются аргументом fooи не будут создавать barни то, ни другое.
Гэвин Симпсон
2
Почему коэффициент x3 NA?
ziyuang
6

Расширением метода джубы является использование reformulateфункции, которая специально предназначена для такой задачи.

## Create a formula for a model with a large number of variables:
xnam <- paste("x", 1:25, sep="")

reformulate(xnam, "y")
y ~ x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + 
    x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + 
    x22 + x23 + x24 + x25

Для примера в OP самым простым решением здесь было бы

# add y variable to data.frame d
d <- cbind(y, d)
reformulate(names(d)[-1], names(d[1]))
y ~ x1 + x2 + x3

или

mod <- lm(reformulate(names(d)[-1], names(d[1])), data=d)

Обратите внимание, что добавление зависимой переменной в data.frame в d <- cbind(y, d)предпочтительнее не только потому, что оно позволяет использовать reformulate, но также потому, что оно позволяет использовать lmобъект в будущем в таких функциях, как predict.

LMO
источник
2

Я создаю это решение, reformulateне заботясь о том, есть ли в именах переменных пробелы.

add_backticks = function(x) {
    paste0("`", x, "`")
}

x_lm_formula = function(x) {
    paste(add_backticks(x), collapse = " + ")
}

build_lm_formula = function(x, y){
    if (length(y)>1){
        stop("y needs to be just one variable")
    }
    as.formula(        
        paste0("`",y,"`", " ~ ", x_lm_formula(x))
    )
}

# Example
df <- data.frame(
    y = c(1,4,6), 
    x1 = c(4,-1,3), 
    x2 = c(3,9,8), 
    x3 = c(4,-4,-2)
    )

# Model Specification
columns = colnames(df)
y_cols = columns[1]
x_cols = columns[2:length(columns)]
formula = build_lm_formula(x_cols, y_cols)
formula
# output
# "`y` ~ `x1` + `x2` + `x3`"

# Run Model
lm(formula = formula, data = df)
# output
Call:
    lm(formula = formula, data = df)

Coefficients:
    (Intercept)           x1           x2           x3  
        -5.6316       0.7895       1.1579           NA  

`` `

Кристиан Торрес
источник
0

Вы можете проверить пакет leapsи, в частности, функции regsubsets() функции для выбора модели. Как указано в документации:

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

монах
источник