Як коротко написати формулу з багатьма змінними з фрейму даних?


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.



Відповіді:


202

Існує спеціальний ідентифікатор, який можна використовувати у формулі для позначення всіх змінних, це .ідентифікатор.

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)
гостестеколог

Це працює зі 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 є обов'язковою
Jinhua Wang,

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 вказує на те, що призначення з <-рекомендується виконувати =.


Дякую! Так, я знаю, що всі завжди кажуть використовувати <-, але ніхто ніколи не каже, чому і = простіше набрати =).
гратур

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

Для прикладу в ОП, найпростішим рішенням було б тут

# 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.


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() функції для вибору моделі. Як зазначено в документації:

Вибір моделі шляхом вичерпного пошуку, крок уперед або назад або послідовна заміна

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.