5

我是 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() )
}

谢谢你。

4

1 回答 1

14

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

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

x1,x2x3是协变量, 和y1, y2,y3是三个独立的响应。您正在尝试拟合三个线性模型:

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

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

你走错了路。 lm()是一项昂贵的手术。只要您的数据集不小,for循环的成本就可以忽略不计。for将循环替换为lapply不会带来性能提升。

由于所有三个模型都有相同的 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”类之外还有一个额外的“mlm”类。我创建了一个特殊的标签,收集了一些关于该主题的问题,并通过它的标签 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().


跟进:

我对概括感兴趣。我有一个数据框df,其中第一n列是因变量(y1,y2,y3,....),下一m列是自变量(x1+x2+x3+....)。因为n = 3m = 3fit <- lm(cbind(y1, y2, y3) ~ ., data = dat))。但是如何通过使用df. 我的意思是类似的东西(for i in (1:n)) fit <- lm(cbind(df[something] ~ df[something], data = dat))。我用pasteand创建的那个“东西” paste0。谢谢你。

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

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

我更喜欢reformulate它的简洁性,但是,它不支持公式中的多个 LHS。如果要对 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它会自动将其强制转换为公式类。formula或者您可以使用(或)自己进行强制as.formula

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

评论:

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

于 2016-09-01T19:25:50.150 回答