Jak zwięźle napisać formułę z wieloma zmiennymi z ramki danych?

127

Załóżmy, że mam zmienną odpowiedzi i dane zawierające trzy zmienne towarzyszące (jako przykład zabawki):

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

Chcę dopasować regresję liniową do danych:

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

Czy istnieje sposób na zapisanie wzoru, aby nie musieć zapisywać poszczególnych zmiennych towarzyszących? Na przykład coś takiego

fit = lm(y ~ d)

(Chcę, aby każda zmienna w ramce danych była współzmienną). Pytam, ponieważ mam w ramce danych 50 zmiennych, więc chcę uniknąć pisania x1 + x2 + x3 + etc.

grautur
źródło

Odpowiedzi:

203

Istnieje specjalny identyfikator, którego można użyć we wzorze do oznaczenia wszystkich zmiennych, jest to .identyfikator.

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)

Możesz także zrobić takie rzeczy, aby użyć wszystkich zmiennych oprócz jednej (w tym przypadku x3 jest wykluczone):

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

Technicznie .oznacza wszystkie zmienne niewymienione we wzorze . Na przykład

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

gdzie .odniesie się tylko x3jako x1i x2już są w formule.

Gavin Simpson
źródło
Ramka danych „d” ma 4 kolumny (y, x1, x2 i x3). Więc jeśli formuła to „y ~.”, Czy prawa strona oznacza „wszystkie kolumny” z wyjątkiem tych wymienionych po lewej stronie?
stackoverflowuser2010
1
@ stackoverflowuser2010 Tak, .technicznie oznacza , że wszystkie zmienne data nie znajdują się jeszcze w formule .
Gavin Simpson,
1
@theforestecologist, jeśli masz na myśli, datato lista, z której wyszukuje się zmienne w formule z tej listy, to tak. Ramka danych, lista lub środowisko to dopuszczalne opcje dataargumentu. Jeśli nie to masz na myśli, musisz trochę bardziej rozwinąć.
Gavin Simpson
@Gavin. To miałem na myśli. Dzięki. Jak poradzić sobie z tą metodą, używając danych [[x]] jako zmiennej wyświetlanej w porównaniu z rzeczywistą nazwą zmiennej (np. „X3”)? Na przykład, jak lm(d[[1]] ~ d[[3]] + ., data = d)
wykonałbym
Działa namesz listy; trzeba powiedzieć ll <- list(y = rnorm(10), x = rnorm(10), z = rnorm(10), zz = runif(10)), to następujące prace: lm(y ~ x + ., data = ll). Nie ma więc powodu, aby mieć takie dane, chyba że jest to już lista, ale działa. Wymóg, aby elementy formuły były tej samej długości, nakłada pewne ograniczenia na zawartość listy. Bardziej złożone obiekty prawdopodobnie wymagają kodu do wyodrębnienia żądanych elementów; gdyby d[[1]]była ramka / macierz danych, potrzebujesz kodu, aby to działało
Gavin Simpson,
66

Nieco innym podejściem jest utworzenie formuły z ciągu znaków. Na stronie formulapomocy znajdziesz następujący przykład:

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

Następnie, jeśli spojrzysz na wygenerowaną formułę, otrzymasz:

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
źródło
1
Działa to bardzo dobrze przy odczytywaniu tych wartości z pliku. Dzięki!
Ben Sidhom
Zauważ, że część as.formula to mustt
Jinhua Wang
7

Tak, oczywiście, po prostu dodaj odpowiedź yjako pierwszą kolumnę w ramce danych i wywołaj lm()ją:

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  

Ponadto moje informacje o R wskazują, że przypisanie z <-jest zalecane powyżej =.

Bernd Elkemann
źródło
Dzięki! Tak, wiem, że każdy zawsze mówi, żeby użyć <-, ale nikt nigdy nie mówi, dlaczego i = łatwiej jest wpisać =).
grautur
2
@gratur Jednym z powodów jest to, że rzeczy takie jak foo(bar <- 1:10)działają (i barsą tworzone), ale foo(bar = 1:10)albo zawiodą, ponieważ barnie są argumentem fooi też nie utworzą bar.
Gavin Simpson,
2
Dlaczego współczynnik x3 NA?
ziyuang,
6

Rozszerzeniem metody Dżuby jest użycie reformulate, funkcja, która została wyraźnie zaprojektowana do takiego zadania.

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

Na przykład w PO najłatwiejszym rozwiązaniem byłoby tutaj

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

lub

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

Zauważ, że dodanie zmiennej zależnej do data.frame w d <- cbind(y, d) jest preferowane nie tylko dlatego, że pozwala na użycie reformulate, ale także dlatego, że pozwala na przyszłe użycie lmobiektu w funkcjach takich jak predict.

lmo
źródło
2

Buduję to rozwiązanie, reformulatenie dbam o to, czy nazwy zmiennych mają spacje.

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
źródło
0

Możesz sprawdzić pakiet, leapsaw szczególności funkcje regsubsets() funkcji wyboru modelu. Jak podano w dokumentacji:

Wybór modelu poprzez wyczerpujące wyszukiwanie, krokowe do przodu lub do tyłu lub sekwencyjną wymianę

amonk
źródło