如何简洁地从数据框中写出具有多个变量的公式?

161

假设我有一个响应变量和一组包含三个协变量的数据(作为玩具示例):

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 + 等等


6个回答

262

在公式中,有一个特殊的标识符可以用来表示所有变量,它就是 . 标识符。

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 作为参照,因为 x1x2 已经在公式中了。


数据框'd'有4列(y、x1、x2和x3)。因此,如果公式是"y ~ .",那么右侧的意思是除左侧列出的列之外的所有列吗? - stackoverflowuser2010
1
@stackoverflowuser2010 是的,. 在技术上意味着 data 中的所有变量 不包括公式中已有的变量 - Gavin Simpson
1
@theforestecologist 如果你的意思是data是一个列表,公式中的变量从该列表中查找,那么是的。数据框,列表或环境都是data参数的可接受选项。如果这不是你的意思,你需要再详细解释一下。 - Gavin Simpson
@Gavin。那就是我的意思。谢谢。如果我使用data[[x]]作为列出的变量而不是实际的变量名(例如,'x3'),我该如何使用这种方法?例如,我该如何使以下内容起作用:lm(d[[1]] ~ d[[3]] + ., data = d) - theforestecologist
它依赖于列表的names(名称); 假设你有ll <- list(y = rnorm(10), x = rnorm(10), z = rnorm(10), zz = runif(10)),那么以下代码可以运行:lm(y ~ x + ., data = ll)。因此,除非数据本来就是一个列表,否则没有太多理由将其组织成这种形式,但这样做也可以。公式中要求的元素具有相同的长度,这对列表中的内容施加了一些限制。更复杂的对象可能需要代码来提取所需的元素;如果d[[1]]是数据框/矩阵,则需要编写代码才能使其正常工作。 - Gavin Simpson
更多信息,请参见?formula - undefined

79

稍微有些不同的方法是从字符串创建公式。在 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
这对于从文件中读取这些值非常有效。谢谢! - Ben Sidhom
1
请注意,as.formula部分是必须的。 - Jinhua Wang

11

当然可以,只需在数据框的第一列中添加响应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语言中使用<-进行赋值比使用=更加推荐。


1
谢谢!是的,我知道每个人都说要使用<-,但没有人说为什么,而=更容易输入=)。 - grautur
5
一个原因是像 foo(bar <- 1:10) 这样的语句是可行的(并且 bar 被创建了),但 foo(bar = 1:10) 则会失败,因为 bar 不是 foo 的参数,也不会创建 bar - Gavin Simpson
4
为什么 x3 的系数是 NA - Ziyuan
1
@Ziyuan:因为我们只有3个数据点,却要估计4个参数(包括截距)。这个系统是不定的,lm函数通过舍弃一个变量来解决这个问题。 - undefined

10

juba方法的扩展是使用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)

注意,在 d <- cbind(y, d) 中添加因变量到数据框中是首选的,不仅因为它允许使用 reformulate,还因为它允许在诸如 predict 的函数中将来使用 lm 对象。


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()来进行模型选择。正如文档中所述: 通过穷举搜索、向前或向后逐步搜索或顺序替换进行模型选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接