¿Cómo escribir sucintamente una fórmula con muchas variables de un marco de datos?

127

Supongamos que tengo una variable de respuesta y datos que contienen tres covariables (como un ejemplo de juguete):

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

Quiero ajustar una regresión lineal a los datos:

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

¿Hay alguna manera de escribir la fórmula, para que no tenga que escribir cada covariable individual? Por ejemplo, algo como

fit = lm(y ~ d)

(Quiero que cada variable en el marco de datos sea una covariable). Pregunto porque en realidad tengo 50 variables en mi marco de datos, por lo que quiero evitar escribirlas x1 + x2 + x3 + etc.

grautur
fuente

Respuestas:

202

Hay un identificador especial que se puede usar en una fórmula para referirse a todas las variables, es el .identificador.

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)

También puede hacer cosas como esta, para usar todas las variables menos una (en este caso, se excluye x3):

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

Técnicamente, .significa todas las variables no mencionadas en la fórmula . Por ejemplo

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

donde .solo haría referencia x3como x1y x2ya están en la fórmula.

Gavin Simpson
fuente
El marco de datos 'd' tiene 4 columnas (y, x1, x2 y x3). Entonces, si la fórmula es "y ~.", ¿Significa el lado derecho "todas las columnas", excepto las enumeradas en el lado izquierdo?
stackoverflowuser2010
1
@ stackoverflowuser2010 Sí, .técnicamente significa que todas las variables aún data no están en la fórmula .
Gavin Simpson,
1
@theforestecologist si quiere decir que dataes una lista de la cual las variables en la fórmula se buscan desde esa lista, entonces sí. Un marco de datos, una lista o un entorno son opciones aceptables para el dataargumento. Si eso no es lo que quieres decir, necesitarás expandirte un poco más.
Gavin Simpson
@Gavin. Eso es a lo que me refiero. Gracias. ¿Cómo seguiría este método usando los datos [[x]] como una variable listada versus el nombre de la variable real (por ejemplo, 'x3')? Por ejemplo, ¿cómo iba a hacer el siguiente trabajo ?:lm(d[[1]] ~ d[[3]] + ., data = d)
theforestecologist
Funciona fuera namesde la lista; supongamos que tiene ll <- list(y = rnorm(10), x = rnorm(10), z = rnorm(10), zz = runif(10)), a continuación, los siguientes trabajos: lm(y ~ x + ., data = ll). Entonces, no hay muchas razones para tener sus datos de esta manera a menos que ya sea una lista, pero funciona. El requisito de que los elementos de la fórmula tengan la misma longitud impone algunas restricciones sobre lo que tiene en una lista. Los objetos más complejos probablemente necesiten código para extraer los elementos que desea; si d[[1]]eran una trama de datos / Matrix necesita código para hacer que el trabajo
Gavin Simpson
66

Un enfoque ligeramente diferente es crear su fórmula a partir de una cadena. En la formulapágina de ayuda encontrará el siguiente ejemplo:

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

Luego, si observa la fórmula generada, obtendrá:

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
fuente
1
Esto funciona muy bien para leer estos valores de un archivo. ¡Gracias!
Ben Sidhom
Tenga en cuenta que la parte as.formula es imprescindible
Jinhua Wang
7

Sí, por supuesto, solo agregue la respuesta ycomo primera columna en el marco de datos y solicítela 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  

Además, mi información sobre R señala que <-se recomienda terminar la tarea con =.

Bernd Elkemann
fuente
¡Gracias! Sí, sé que todos siempre dicen que use <-, pero nadie dice por qué y = es más fácil escribir =).
Grautur
2
@gratur Una razón es que cosas como el foo(bar <- 1:10)trabajo (y barse crean) pero foo(bar = 1:10)fallarían porque barno es un argumento fooy tampoco crearán bar.
Gavin Simpson
2
¿Por qué es el coeficiente de x3 NA?
ziyuang
6

Una extensión del método de juba es usar reformulateuna función que está explícitamente diseñada para tal tarea.

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

Para el ejemplo en el OP, la solución más fácil aquí sería

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

o

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

Tenga en cuenta que d <- cbind(y, d)se prefiere agregar la variable dependiente al data.frame in no solo porque permite el uso de reformulate, sino también porque permite el uso futuro del lmobjeto en funciones como predict.

lmo
fuente
2

Construyo esta solución, reformulateno me importa si los nombres de las variables tienen espacios en blanco.

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
fuente
0

Puede consultar el paquete leapsy, en particular, las funciones de regsubsets() función para la selección del modelo. Como se indica en la documentación:

Selección de modelo por búsqueda exhaustiva, hacia adelante o hacia atrás paso a paso, o reemplazo secuencial

un monje
fuente