使用'dplyr'保存残差`

使用'dplyr'保存残差`,r,dplyr,R,Dplyr,我想使用dplyr对data.frame进行分组,拟合线性回归,并将残差保存为原始未分组data.frame中的一列 这里有一个例子 > iris %>% select(Sepal.Length, Sepal.Width) %>% group_by(Species) %>% do(mod = lm(Sepal.Length ~ Sepal.Width, data=.)) %>% 返回: Species mod 1 set

我想使用dplyr对data.frame进行分组,拟合线性回归,并将残差保存为原始未分组data.frame中的一列

这里有一个例子

> iris %>%
   select(Sepal.Length, Sepal.Width) %>%
   group_by(Species) %>%
   do(mod = lm(Sepal.Length ~ Sepal.Width, data=.)) %>%
返回:

     Species     mod
1     setosa <S3:lm>
2 versicolor <S3:lm>
3  virginica <S3:lm>
我从中改编了一个例子

返回:

Source: local data frame [150 x 10]
Groups: Species

   Species Sepal.Length Sepal.Width  .fitted    .se.fit      .resid       .hat
1   setosa          5.1         3.5 5.055715 0.03435031  0.04428474 0.02073628
2   setosa          4.9         3.0 4.710470 0.05117134  0.18952960 0.04601750
3   setosa          4.7         3.2 4.848568 0.03947370 -0.14856834 0.02738325
4   setosa          4.6         3.1 4.779519 0.04480537 -0.17951937 0.03528008
5   setosa          5.0         3.6 5.124764 0.03710984 -0.12476423 0.02420180
...

由于您要为每个组运行完全相同的回归,您可能会发现只需事先将回归模型定义为
函数()
,然后使用
mutate
为每个组执行它就更简单了

model<- function(y,x){ 
  a<- y + x 
  if( length(which(!is.na(a))) <= 2  ){
    return( rep(NA, length(a)))
  } else {
    m<- lm( y ~ x, na.action = na.exclude)
    return( residuals(m))
    } 
}
这将产生:

   Species Sepal.Length Sepal.Width       resid
    <fctr>        <dbl>       <dbl>       <dbl>
1   setosa          5.1         3.5  0.04428474
2   setosa          4.9         3.0  0.18952960
3   setosa          4.7         3.2 -0.14856834
4   setosa          4.6         3.1 -0.17951937
5   setosa          5.0         3.6 -0.12476423
6   setosa          5.4         3.9  0.06808885
种萼片。长度萼片。宽度剩余
1 setosa 5.1 3.5 0.04428474
2 setosa 4.9 3.0 0.18952960
3 setosa 4.7 3.2-0.14856834
4 setosa 4.6 3.1-0.17951937
5 setosa 5.0 3.6-0.12476423
6 setosa 5.4 3.9 0.06808885
这种方法在计算上应该与使用
augment()
的方法没有太大区别(我不得不在包含数亿个观察值的数据集上使用这两种方法,并且相信与使用
do()
函数相比,在速度上没有显著差异)


另外,请注意,省略
na.action=na.exclude
,或使用
m$residuals
而不是
residuals(m)
,将导致从残差的输出向量中排除具有NAs(在估计之前丢弃)的行。因此,相应的向量将没有足够的
length()
,无法与数据集合并,并且可能会出现一些错误消息。

一个解决方案似乎比目前提出的解决方案更简单,更接近原始问题的代码:

iris %>%
   group_by(Species) %>%
   do(data.frame(., resid = residuals(lm(Sepal.Length ~ Sepal.Width, data=.))))
结果:

# A tibble: 150 x 6
# Groups:   Species [3]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   resid
          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>
 1          5.1         3.5          1.4         0.2 setosa   0.0443
 2          4.9         3            1.4         0.2 setosa   0.190 
 3          4.7         3.2          1.3         0.2 setosa  -0.149 
 4          4.6         3.1          1.5         0.2 setosa  -0.180 
 5          5           3.6          1.4         0.2 setosa  -0.125 
 6          5.4         3.9          1.7         0.4 setosa   0.0681
 7          4.6         3.4          1.4         0.3 setosa  -0.387 
 8          5           3.4          1.5         0.2 setosa   0.0133
 9          4.4         2.9          1.4         0.2 setosa  -0.241 
10          4.9         3.1          1.5         0.1 setosa   0.120 
#一个tible:150 x 6
#类群:种[3]
萼片。长萼片。宽花瓣。长花瓣。宽种残余
1 5.1 3.5 1.4 0.2 setosa 0.0443
2 4.9 3 1.4 0.2 setosa 0.190
3 4.7 3.2 1.3 0.2刚毛-0.149
4.6 3.1 1.5 0.2刚毛-0.180
5 3.6 1.4 0.2刚毛-0.125
6 5.4 3.9 1.7 0.4刚毛0.0681
7 4.6 3.4 1.4 0.3刚毛-0.387
8 5 3.4 1.5 0.2 setosa 0.0133
9 4.4 2.9 1.4 0.2刚毛-0.241
10 4.9 3.1 1.5 0.1 setosa 0.120

(我知道发生了什么,但我自己永远也不会明白这一点。例如,为什么我需要在第二个
do
中使用匿名函数,而不是第一个?)
iris %>% group_by(Species) %>% 
  mutate(resid = model(Sepal.Length,Sepal.Width) ) %>% 
  select(Sepal.Length,Sepal.Width,resid)
   Species Sepal.Length Sepal.Width       resid
    <fctr>        <dbl>       <dbl>       <dbl>
1   setosa          5.1         3.5  0.04428474
2   setosa          4.9         3.0  0.18952960
3   setosa          4.7         3.2 -0.14856834
4   setosa          4.6         3.1 -0.17951937
5   setosa          5.0         3.6 -0.12476423
6   setosa          5.4         3.9  0.06808885
iris %>%
   group_by(Species) %>%
   do(data.frame(., resid = residuals(lm(Sepal.Length ~ Sepal.Width, data=.))))
# A tibble: 150 x 6
# Groups:   Species [3]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   resid
          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>
 1          5.1         3.5          1.4         0.2 setosa   0.0443
 2          4.9         3            1.4         0.2 setosa   0.190 
 3          4.7         3.2          1.3         0.2 setosa  -0.149 
 4          4.6         3.1          1.5         0.2 setosa  -0.180 
 5          5           3.6          1.4         0.2 setosa  -0.125 
 6          5.4         3.9          1.7         0.4 setosa   0.0681
 7          4.6         3.4          1.4         0.3 setosa  -0.387 
 8          5           3.4          1.5         0.2 setosa   0.0133
 9          4.4         2.9          1.4         0.2 setosa  -0.241 
10          4.9         3.1          1.5         0.1 setosa   0.120