R:用线性回归进行总结

goucqfw6  于 2023-02-01  发布在  其他
关注(0)|答案(5)|浏览(236)

我有一个数据集,其中有几个项目的年平均值。

数据有:

df <- data.frame(item  = c(1, 1, 1, 1,  2, 2, 2, 2,  3, 3, 3, 3,  4, 4, 4, 4),
                 year  = c(1, 2, 3, 4,  1, 2, 3, 4,  1, 2, 3, 4,  1, 2, 3, 4)
                 value = c(1, 2, 3, 3,  2, 3, 4, 0,  1, 1, 3, 2,  2, 1, 1, 2))

我需要为每个项目分别在年份和平均值之间建立一个简单的线性回归模型。

需要的数据:

| year |  slope |  intercept |
|:----:|:------:|:----------:|
|    1 |   0.7  |        0.5 |
|    2 |  -0.2  |        3.0 |    
|    3 |   0.5  |        0.5 |  
|    4 |   0.0  |        1.5 |

我的尝试:

我相信可以通过group_by()、summarise()和lm()的某种组合来完成。
所以我试着这么做

library(dplyr)
df %>%
  group_by(item) %>%
  summarise(slope     = unname(lm(value ~ year, data=df)[[1]])[2],
            intercept = unname(lm(value ~ year, data=df)[[1]])[1])

但是它对所有直线返回相同的斜率和截距。换句话说,group_by没有被应用。
因此,我的问题是:

  • 如何实现分组?
  • 如何将计算分别应用于每个项目?
rjee0c15

rjee0c151#

另一种方法是使用tidy并使用pivot_wider将结果转换为更宽的格式,如下所示(您可以添加更多结果,如p值):

library(dplyr)
library(tidyr)
library(broom)
df %>%
  group_by(item) %>%
  do(tidy(lm(value ~ year, data = .))) %>%
  select(item, term, estimate) %>%
  pivot_wider(names_from = term, values_from = estimate) %>%
  rename(slope = year, intercept = `(Intercept)`)
#> # A tibble: 4 × 3
#> # Groups:   item [4]
#>    item intercept slope
#>   <dbl>     <dbl> <dbl>
#> 1     1       0.5   0.7
#> 2     2       3.5  -0.5
#> 3     3       0.5   0.5
#> 4     4       1.5   0

创建于2023年1月29日,使用reprex v2.0.2

1u4esq0p

1u4esq0p2#

下面是另一个解决方案(相当冗长),使用group_split创建列表,然后使用map_dfr迭代每个列表,使用broom s tidy()获得整洁的输出,最后生成shape:

library(broom)
library(tidyverse)
df %>% 
  mutate(item = factor(item)) %>% 
  group_split(item) %>% 
  map_dfr(.f = function(df){
    lm(value ~ year, data = df) %>% 
      tidy() %>% 
      add_column(item = unique(df$item), .before = 1)
  }) %>% 
  mutate(term = str_replace_all(term, "[^[:alnum:]]", "")) %>% 
  select(item, term, estimate) %>% 
  pivot_wider(names_from = term,
              values_from = estimate)
item  Intercept  year
  <fct>     <dbl> <dbl>
1 1           0.5   0.7
2 2           3.5  -0.5
3 3           0.5   0.5
4 4           1.5   0
gtlvzcf8

gtlvzcf83#

lm( ..., data=df)中,你仍然使用你开始时使用的相同df对象,为了使你自己的方法工作,你需要用感知上下文的东西(即分组)来替换它,并返回当前组的当前数据:cur_data()

library(dplyr)
df <- data.frame(item  = c(1, 1, 1, 1,  2, 2, 2, 2,  3, 3, 3, 3,  4, 4, 4, 4),
                 year  = c(1, 2, 3, 4,  1, 2, 3, 4,  1, 2, 3, 4,  1, 2, 3, 4),
                 value = c(1, 2, 3, 3,  2, 3, 4, 0,  1, 1, 3, 2,  2, 1, 1, 2))

df %>%
  group_by(item) %>%
  summarise(slope     = unname(lm(value ~ year, data=cur_data())[[1]])[2],
            intercept = unname(lm(value ~ year, data=cur_data())[[1]])[1])
#> # A tibble: 4 × 3
#>    item slope intercept
#>   <dbl> <dbl>     <dbl>
#> 1     1   0.7       0.5
#> 2     2  -0.5       3.5
#> 3     3   0.5       0.5
#> 4     4   0         1.5

创建于2023年1月29日,使用reprex v2.0.2

qfe3c7zg

qfe3c7zg4#

您可以试试by

data.frame(unique(df$item), t(sapply(by(df, df$item, lm, fo=value ~ year), coef))) |>
  `colnames<-`(c('year', 'intercept', 'slope'))
#   year intercept slope
# 1    1       0.5   0.7
# 2    2       3.5  -0.5
# 3    3       0.5   0.5
# 4    4       1.5   0.0

也许更容易理解,但结果是一样的:

by(df, df$item, lm, fo = value ~ year) |>
  sapply(coef) |>
  t() |>
  data.frame(unique(df$item)) |>
  `colnames<-`(c('intercept', 'slope', 'year'))
rkttyhzu

rkttyhzu5#

library(tidyverse)

df %>% group_by(item) %>% 
do(reg = lm(value ~ year, data = .)$coefficients) %>%
unnest_wider(reg)

给出,

#   item `(Intercept)`   year
#  <dbl>         <dbl>  <dbl>
#1     1         0.500  0.7  
#2     2         3.50  -0.500
#3     3         0.5    0.5  
#4     4         1.5    0

相关问题