Como escrever sucintamente uma fórmula com muitas variáveis ​​de um quadro de dados?

127

Suponha que eu tenha uma variável de resposta e dados que contenham três covariáveis ​​(como um exemplo de brinquedo):

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

Quero ajustar uma regressão linear aos dados:

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

Existe uma maneira de escrever a fórmula, para que eu não precise escrever cada covariável individual? Por exemplo, algo como

fit = lm(y ~ d)

(Quero que cada variável no quadro de dados seja uma covariável.) Estou perguntando porque, na verdade, tenho 50 variáveis ​​no meu quadro de dados, por isso quero evitar escrever x1 + x2 + x3 + etc.

grautur
fonte

Respostas:

202

Existe um identificador especial que pode ser usado em uma fórmula para significar todas as variáveis, é o .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)

Você também pode fazer coisas assim, para usar todas as variáveis, exceto uma (neste caso, x3 é excluído):

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

Tecnicamente, .significa todas as variáveis ​​ainda não mencionadas na fórmula . Por exemplo

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

onde .referenciaria apenas x3como x1e x2já está na fórmula.

Gavin Simpson
fonte
O quadro de dados 'd' possui 4 colunas (y, x1, x2 e x3). Portanto, se a fórmula for "y ~.", O lado direito significa "todas as colunas", exceto as listadas no lado esquerdo?
stackoverflowuser2010
1
@ stackoverflowuser2010 Sim, .tecnicamente significa que todas as variáveis ​​ainda data não estão na fórmula .
Gavin Simpson
1
@ theforestecologist, se você quer dizer que dataé uma lista da qual as variáveis ​​da fórmula são pesquisadas nessa lista, então sim. Um quadro de dados, lista ou ambiente são opções aceitáveis ​​para o dataargumento. Se não é isso que você quer dizer, precisará expandir um pouco mais.
Gavin Simpson
@Gavin. Foi isso que eu quis dizer. Obrigado. Como eu usaria esse método usando dados [[x]] como uma variável listada versus o nome da variável real (por exemplo, 'x3')? Por exemplo, como eu faria o seguinte trabalho?:lm(d[[1]] ~ d[[3]] + ., data = d)
theforestecologist
Funciona fora namesda lista; dizer que você tem ll <- list(y = rnorm(10), x = rnorm(10), z = rnorm(10), zz = runif(10)), em seguida, os seguintes trabalhos: lm(y ~ x + ., data = ll). Portanto, não há muitos motivos para ter seus dados assim, a menos que já sejam uma lista, mas funciona. O requisito de que os elementos da fórmula tenham o mesmo comprimento impõe algumas restrições ao que você possui em uma lista. Objetos mais complexos provavelmente precisam de código para extrair os elementos que você deseja; se d[[1]]fosse um quadro de dados / matriz você precisa código para fazer esse trabalho
Gavin Simpson
66

Uma abordagem um pouco diferente é criar sua fórmula a partir de uma string. Na formulapágina de ajuda, você encontrará o seguinte exemplo:

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

Então, se você olhar para a fórmula gerada, obterá:

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
fonte
1
Isso funciona muito bem para ler esses valores de um arquivo. Obrigado!
21411 Ben Ben Sidhom
Note-se que a parte as.formula é um MUSTT
Jinhua Wang
7

Sim, é claro, basta adicionar a resposta ycomo primeira coluna no quadro de dados e chamar 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  

Além disso, minhas informações sobre R apontam que a atribuição <-é recomendada =.

Bernd Elkemann
fonte
Obrigado! Sim, eu sei que todo mundo sempre diz para usar <-, mas ninguém nunca diz por que e = é mais fácil digitar =).
grautur
2
@gratur Uma razão é que coisas como foo(bar <- 1:10)trabalho (e baré criado), mas foo(bar = 1:10)falhariam porque barnão é um argumento fooe também não serão criadas bar.
Gavin Simpson
2
Por que o coeficiente de x3 NA?
precisa
6

Uma extensão do método juba é usar reformulate, uma função explicitamente projetada para essa tarefa.

## 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 o exemplo no OP, a solução mais fácil aqui seria

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

ou

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

Observe que a adição da variável dependente ao data.frame d <- cbind(y, d)é preferida não apenas porque permite o uso de reformulate, mas também porque permite o uso futuro do lmobjeto em funções como predict.

lmo
fonte
2

Eu construo esta solução, reformulatenão tome cuidado se os nomes das variáveis ​​tiverem espaços em branco.

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

Você pode verificar o pacote leapse, em particular, as funções das regsubsets() funções para a seleção do modelo. Conforme declarado na documentação:

Seleção de modelo por busca exaustiva, substituição progressiva ou progressiva ou sequencial

um monge
fonte