使用“ for循环”在R中运行一系列线性回归

时间:2019-02-22 02:58:31

标签: r

我有一个由2000行和三列组成的数据框。这些列用于主题ID#,IV和DV。数据中有50位参与者(受试者编号1:50),每个参与者都有40个独立的观察值(每个参与者40行)。

我想找到每个参与者的截距和斜率,但我不是想手动运行50 lm,而是想办法使用for循环来实现这一目标。

为简单起见,这是数据的精简版本(我只为3个参与者做5行,而不是产生完整的2000行)。

不知道在for循环时我在做什么,这是我最后尝试的方法。

注意:我重新创建了以下数据的较小版本。基本上,我想为示例数据帧中的四个参与者中的每个参与者创建一个在iv上运行lm的lm的for循环,以便我可以找到每个参与者的截距和斜率(而不是汇总所有内容)。

df <- data.frame(
  id = rep(1:4, each=5),
  iv = c(5.0, 3.6, 3.4, 4.5, 4.6, 7.8, 7.2, 10.8, 7.7, 8.7, 7.6, 6.8, 
         6.2, 5.6, 4.6, 6.7, 6.6, 6.3, 7.0, 5.1),
  dv = c(6.50, 8.50, 8.00, 10.00, 10.00, 3.50, 10.00, 7.25, 2.50, 6.50,
         10.00, 8.75, 10.00, 9.75, 10.00, 7.75, 7.75, 7.50, 8.75, 5.75)  
)


for (i in 1:4)
{
  m3 <- lm(df$dv ~ df$iv, data=df$id[[i]])
}

2 个答案:

答案 0 :(得分:2)

这不是for循环,而是绝对更简洁的以R为中心的处理方式。 broom::tidy()仅将lm()的输出放入一个易于处理的数据帧中。

编辑:如果要在一个data.frame中使用它并能够区分ID,则可以使用下面的更新代码。我相信do()已过时,或者不再受支持用于操作函数的方法。

library(tidyverse)
library(broom)

df <- data.frame(
  id = rep(1:4, each=5),
  iv = c(5.0, 3.6, 3.4, 4.5, 4.6, 7.8, 7.2, 10.8, 7.7, 8.7, 7.6, 6.8, 
         6.2, 5.6, 4.6, 6.7, 6.6, 6.3, 7.0, 5.1),
  dv = c(6.50, 8.50, 8.00, 10.00, 10.00, 3.50, 10.00, 7.25, 2.50, 6.50,
         10.00, 8.75, 10.00, 9.75, 10.00, 7.75, 7.75, 7.50, 8.75, 5.75)  
)

df %>% 
  group_split(id) %>% 
  map_df(~ lm(dv ~ iv, data = .) %>% 
           tidy() %>% 
           mutate(id = unique(.x$id))
         )
#> # A tibble: 8 x 6
#>   term        estimate std.error statistic p.value    id
#>   <chr>          <dbl>     <dbl>     <dbl>   <dbl> <int>
#> 1 (Intercept)   8.96       5.28     1.70   0.188       1
#> 2 iv           -0.0847     1.24    -0.0684 0.950       1
#> 3 (Intercept)   3.55      10.3      0.344  0.753       2
#> 4 iv            0.284      1.21     0.235  0.829       2
#> 5 (Intercept)  10.5        1.65     6.36   0.00786     3
#> 6 iv           -0.126      0.264   -0.478  0.665       3
#> 7 (Intercept)  -1.69       1.06    -1.59   0.210       4
#> 8 iv            1.45       0.167    8.69   0.00321     4

reprex package(v0.2.1)于2019-02-22创建

答案 1 :(得分:1)

我通过组合group_by()do()来进行这种分组回归。

虽然@dylanjm使用map()broom()提供了一个很好的简洁方法来生成包含模型输出的小标题列表,但是如果您想要一个具有两列全部内容的df的单个df,则这种选择可能会很方便截距和坡度。

library(dplyr)
df <- data.frame(id = rep(1:4, each=5),
             iv = c(5.0, 3.6, 3.4, 4.5, 4.6, 7.8, 7.2, 10.8, 7.7, 8.7, 7.6, 6.8, 
                    6.2, 5.6, 4.6, 6.7, 6.6, 6.3, 7.0, 5.1),
             dv = c(6.50, 8.50, 8.00, 10.00, 10.00, 3.50, 10.00, 7.25, 2.50, 6.50,
                    10.00, 8.75, 10.00, 9.75, 10.00, 7.75, 7.75, 7.50, 8.75, 5.75)) 

#This will segment obs by the `id` variable, & run a separate lm for each of the segments.
df_lms<- df %>% 
         group_by(id)%>% 
         do(mod = lm(dv ~ iv, data=.))

#This will give you a dataframe with a column for intercepts, and a column for slopes.
cbind(df_lms %>% do(data.frame(intc = coef(.$mod)[1])),
      df_lms %>% do(data.frame(slope = coef(.$mod)[2])))