我有一个由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]])
}
答案 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])))