Wie schreibe ich kurz und bündig eine Formel mit vielen Variablen aus einem Datenrahmen?

126

Angenommen, ich habe eine Antwortvariable und Daten mit drei Kovariaten (als Spielzeugbeispiel):

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

Ich möchte eine lineare Regression an die Daten anpassen:

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

Gibt es eine Möglichkeit, die Formel zu schreiben, damit ich nicht jede einzelne Kovariate aufschreiben muss? Zum Beispiel so etwas wie

fit = lm(y ~ d)

(Ich möchte, dass jede Variable im Datenrahmen eine Kovariate ist.) Ich frage, weil ich tatsächlich 50 Variablen in meinem Datenrahmen habe, also möchte ich das Ausschreiben vermeiden x1 + x2 + x3 + etc.

grautur
quelle

Antworten:

201

Es gibt einen speziellen Bezeichner, den man in einer Formel verwenden kann, um alle Variablen zu bezeichnen. Es ist der .Bezeichner.

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)

Sie können auch Folgendes tun, um alle Variablen außer einer zu verwenden (in diesem Fall ist x3 ausgeschlossen):

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

Technisch .bedeutet dies alle Variablen, die nicht bereits in der Formel erwähnt wurden . Beispielsweise

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

wo .würde nur x3als verweisen x1und x2sind bereits in der Formel.

Gavin Simpson
quelle
Der Datenrahmen 'd' hat 4 Spalten (y, x1, x2 und x3). Wenn die Formel also "y ~" lautet, bedeutet die rechte Seite "alle Spalten" mit Ausnahme der auf der linken Seite aufgeführten?
stackoverflowuser2010
1
@ stackoverflowuser2010 Ja, .technisch bedeutet, dass alle Variablen data nicht bereits in der Formel enthalten sind .
Gavin Simpson
1
@theforestecologist Wenn Sie meinen, dataist eine Liste, aus der Variablen in der Formel von dieser Liste nachgeschlagen werden, dann ja. Ein Datenrahmen, eine Liste oder eine Umgebung sind akzeptable Optionen für das dataArgument. Wenn Sie das nicht meinen, müssen Sie etwas mehr erweitern.
Gavin Simpson
@ Gavin. Das habe ich gemeint. Vielen Dank. Wie würde ich bei dieser Methode Daten [[x]] als aufgelistete Variable im Vergleich zum tatsächlichen Variablennamen (z. B. 'x3') verwenden? Wie würde ich zum Beispiel die folgende Arbeit machen?:lm(d[[1]] ~ d[[3]] + ., data = d)
Theforestecologist
Es funktioniert namesvon der Liste; sagen Sie haben ll <- list(y = rnorm(10), x = rnorm(10), z = rnorm(10), zz = runif(10)), dann funktioniert folgendes : lm(y ~ x + ., data = ll). Es gibt also nicht viel Grund, Ihre Daten so zu haben, es sei denn, es handelt sich bereits um eine Liste, aber es funktioniert. Die Anforderung, dass die Elemente der Formel dieselbe Länge haben müssen, schränkt die Inhalte einer Liste ein. Komplexere Objekte benötigen wahrscheinlich Code, um die gewünschten Elemente zu extrahieren. Wenn d[[1]]es sich um einen Datenrahmen / eine Matrix handelt, benötigen Sie Code, damit dies funktioniert
Gavin Simpson,
66

Ein etwas anderer Ansatz besteht darin, Ihre Formel aus einer Zeichenfolge zu erstellen. In demformula Hilfeseite finden Sie folgendes Beispiel:

## 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= "+")))

Wenn Sie sich dann die generierte Formel ansehen, erhalten Sie:

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
Juba
quelle
1
Dies funktioniert sehr gut zum Lesen dieser Werte aus einer Datei. Vielen Dank!
Ben Sidhom
Beachten Sie, dass der as.formula-Teil ein Muss ist
Jinhua Wang
7

Ja, fügen Sie einfach die Antwort yals erste Spalte im Datenrahmen hinzu und rufen Sie lm()sie auf:

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  

Außerdem weisen meine Informationen zu R darauf hin, dass eine Zuordnung mit <-empfohlen wird =.

Bernd Elkemann
quelle
Vielen Dank! Ja, ich weiß, dass jeder immer sagt, <- zu verwenden, aber niemand sagt jemals, warum und = einfacher zu tippen ist =).
Grautur
2
@gratur Ein Grund ist, dass Dinge wie foo(bar <- 1:10)Arbeit (und barerstellt werden) aber foo(bar = 1:10)entweder fehlschlagen würden, weil dies barkein Argument ist foound auch nicht erstellt wird bar.
Gavin Simpson
2
Warum ist der Koeffizient von x3 NA?
Ziyuang
6

Eine Erweiterung der Methode von juba ist die Verwendung reformulateeiner Funktion, die explizit für eine solche Aufgabe ausgelegt ist.

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

Für das Beispiel im OP wäre hier die einfachste Lösung

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

oder

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

Beachten Sie, dass das Hinzufügen der abhängigen Variablen zum data.frame in d <- cbind(y, d)nicht nur bevorzugt wird, weil es die Verwendung von ermöglicht reformulate, sondern auch, weil es die zukünftige Verwendung des lmObjekts in Funktionen wie ermöglicht predict.

lmo
quelle
2

Ich baue diese Lösung, reformulatekümmere mich nicht darum, ob Variablennamen Leerzeichen haben.

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  

`` `

Christian Torrez
quelle
0

Sie können das Paket leapsund insbesondere die regsubsets() Funktionsfunktionen für die Modellauswahl überprüfen . Wie in der Dokumentation angegeben:

Modellauswahl durch umfassende Suche, schrittweise vorwärts oder rückwärts oder sequentielles Ersetzen

ein Mönch
quelle