使用多个LHS拟合线性模型

bog*_*cis 5 regression r linear-regression lm mlm

我是R的新手,我想用一个*apply函数改进下面的脚本(我已经读过apply,但我无法使用它).我想lm在多个独立变量(数据框中的列)上使用函数.我用了

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

Formula(i) 被定义为

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

谢谢.

李哲源*_*李哲源 12

如果我没有弄错你,你正在使用这样的数据集:

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

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

y1 ~ x1 + x2 + x3
y2 ~ x1 + x2 + x3
y3 ~ x1 + x2 + x3
Run Code Online (Sandbox Code Playgroud)

目前您使用的是循环遍历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
Run Code Online (Sandbox Code Playgroud)

如果你检查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
Run Code Online (Sandbox Code Playgroud)

注意:不要写

y1 + y2 + y3 ~ x1 + x2 + x3
Run Code Online (Sandbox Code Playgroud)

这将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)).那个"东西"我与创建它pastepaste0.谢谢.

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

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

我更喜欢reformulate它的整洁,但它不支持配方中的多个LHS.如果你想改变LHS,它还需要一些特殊的处理.所以在下面我将使用paste解决方案.

对于您的数据框df,您可以这样做

paste0("cbind(", paste(names(df)[1:n], collapse = ", "), ")", " ~ .")
Run Code Online (Sandbox Code Playgroud)

一个更漂亮的方式是使用sprintftoString构建LHS:

sprintf("cbind(%s) ~ .", toString(names(df)[1:n]))
Run Code Online (Sandbox Code Playgroud)

以下是使用iris数据集的示例:

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

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

formula(string_formula)
# cbind(Sepal.Length, Sepal.Width) ~ .
Run Code Online (Sandbox Code Playgroud)

备注:

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