拟合具有多个 LHS 的线性模型

Fitting a linear model with multiple LHS

我是 R 的新手,我想用 *apply 函数改进以下脚本(我读过 apply,但我无法使用它)。我想对多个自变量(数据框中的列)使用 lm 函数。我用了

for (i in (1:3) {
  assign(paste0('lm.',names(data[i])), lm(formula=formula(i),data=data))
  } 

Formula(i) 定义为

formula=function(x)
{
  as.formula ( paste(names(data[x]),'~', paste0(names(data[-1:-3]), collapse = '+')), env=parent.frame() )
}

谢谢。

如果我没有误会你的意思,你正在使用这样的数据集:

set.seed(0)
dat <- data.frame(y1 = rnorm(30), y2 = rnorm(30), y3 = rnorm(30),
                  x1 = rnorm(30), x2 = rnorm(30), x3 = rnorm(30))

x1x2x3是协变量,y1y2y3是三个独立的响应。您正在尝试拟合三个线性模型:

y1 ~ x1 + x2 + x3
y2 ~ x1 + x2 + x3
y3 ~ x1 + x2 + x3

目前您正在使用 y1y2y3 的循环,每次拟合一个模型。您希望通过将 for 循环替换为 lapply.

来加快该过程

你走错路了。 lm() 是一个昂贵的操作。只要你的数据集不小,for 循环的成本可以忽略不计。用 lapply 替换 for 循环不会提高性能。

由于所有三个模型的 RHS(~ 的右侧)相同,因此三个模型的模型矩阵相同。因此,所有模型的 QR 分解只需要进行一次。 lm 允许这样做,您可以使用:

fit <- lm(cbind(y1, y2, y3) ~ x1 + x2 + x3, data = dat)
#Coefficients:
#             y1         y2         y3       
#(Intercept)  -0.081155   0.042049   0.007261
#x1           -0.037556   0.181407  -0.070109
#x2           -0.334067   0.223742   0.015100
#x3            0.057861  -0.075975  -0.099762

如果你检查str(fit),你会发现这不是三个线性模型的列表;相反,它是具有单个 $qr 对象但具有多个 LHS 的单个线性模型。所以 $coefficients$residuals$fitted.values 是矩阵。生成的线性模型除了通常的“lm”class 之外还有一个额外的“mlm”class。我创建了一个特殊的 tag collecting some questions on the theme, summarized by its tag wiki.

如果您有更多的协变量,您可以使用 .:

避免键入或粘贴公式
fit <- lm(cbind(y1, y2, y3) ~ ., data = dat)
#Coefficients:
#             y1         y2         y3       
#(Intercept)  -0.081155   0.042049   0.007261
#x1           -0.037556   0.181407  -0.070109
#x2           -0.334067   0.223742   0.015100
#x3            0.057861  -0.075975  -0.099762

注意:不要写

y1 + y2 + y3 ~ x1 + x2 + x3

这会将 y = y1 + y2 + y3 视为单个响应。使用 cbind().


跟进:

I am interested in a generalization. I have a data frame df, where first n columns are dependent variables (y1,y2,y3,....) and next m columns are independent variables (x1+x2+x3+....). For n = 3 and m = 3 it is fit <- lm(cbind(y1, y2, y3) ~ ., data = dat)). But how to do this automatically, by using the structure of the df. I mean something like (for i in (1:n)) fit <- lm(cbind(df[something] ~ df[something], data = dat)). That "something" I have created it with paste and paste0. Thank you.

所以您正在对公式进行编程,或者想要在循环中动态生成/构造模型公式。有很多方法可以做到这一点,许多 Stack Overflow 问题都与此有关。通常有两种方法:

  1. use reformulate;
  2. 使用 paste / paste0formula / as.formula

我更喜欢reformulate因为它简洁,但是它不支持公式中的多个LHS。 It also needs some special treatment if you want to transform the LHS。所以在下面我会使用 paste 解决方案。

对于你的数据框df,你可以

paste0("cbind(", paste(names(df)[1:n], collapse = ", "), ")", " ~ .")

比较好看的方法是用sprintftoString构造LHS:

sprintf("cbind(%s) ~ .", toString(names(df)[1:n]))

这是一个使用 iris 数据集的示例:

string_formula <- sprintf("cbind(%s) ~ .", toString(names(iris)[1:2]))
# "cbind(Sepal.Length, Sepal.Width) ~ ."

您可以将此字符串公式传递给 lm,因为 lm 会自动将其强制转换为公式 class。或者您可以使用 formula(或 as.formula)自己进行强制转换:

formula(string_formula)
# cbind(Sepal.Length, Sepal.Width) ~ .

备注:

R 核心的其他地方也支持这个多 LHS 公式:

  • ;
  • .