缘由

艺多不压身

碎碎念

我们继续飞行在云层和雾气之间,飞行在一个无光无影的空洞世界中。 ——《风沙星辰》

Ref

Correlation and regression fundamentals with tidy data principles – tidymodels

代码

用 nest 风格优雅地做批量计算

在数据分析中,我们经常需要 对不同分组做相同的统计检验或建模。
常见的实现思路有三种:

  1. 基础函数 + broom::tidy()
  2. group_by + rstatix(或直接 group_modify)
  3. nest + map

今天我们来对比一下它们的区别,并重点看看 nest 风格的优势。


加载数据

library(tidymodels)
 
data(Orange)
 
Orange <- as_tibble(Orange)
Orange
#> # A tibble: 35 × 3
#>    Tree    age circumference
#>    <ord> <dbl>         <dbl>
#>  1 1       118            30
#>  2 1       484            58
#>  3 1       664            87
#>  4 1      1004           115
#>  5 1      1231           120
#>  6 1      1372           142
#>  7 1      1582           145
#>  8 2       118            33
#>  9 2       484            69
#> 10 2       664           111
#> # ℹ 25 more rows

Part 1:相关性计算示例

方法 1:手工 cor.test + tidy

ct <- cor.test(Orange$age, Orange$circumference)
ct %>% tidy()

这里 cor.test() 返回的是一个 S3 对象(htest),必须再用 broom::tidy() 才能整齐化为 tibble。
适合单组数据,但不便于批量计算。


方法 2:group_by + rstatix

Orange %>% 
  group_by(Tree) %>% 
  rstatix::cor_test(age, circumference)

rstatix::cor_test() 已经返回了整齐化的 tibble。
这种写法简洁,但只能做 单一检验,无法方便地组织后续更多计算。


方法 3:group_by + group_modify

Orange %>% 
  group_by(Tree) %>% 
  group_modify(~ .x %>% rstatix::cor_test(age, circumference))

这里更灵活,可以在 ~{} 里写任意逻辑。
但输出结果依然是 直接拼接的长表,没有保留中间对象。


方法 4:nest + map

nested <- Orange %>% nest(data = c(age, circumference))
 
nested %>% 
  mutate(
    test   = map(data, ~ cor.test(.x$age, .x$circumference)),
    tidied = map(test, tidy)
  ) %>% 
  unnest(cols = tidied) %>% 
  select(-data, -test)

这里的优势是:

  • nest 把每个分组的数据收集成列表列(data)。
  • map 可以同时保存原始模型对象(test)和整齐化结果(tidied)。
  • 输出时我们可以选择要展开的列,非常灵活。

Part 2:批量建模示例

以 mtcars 数据集为例,我们想在不同 am(变速器类型)下建立回归模型:

regressions <- 
  mtcars %>%
  nest(data = c(-am)) %>% 
  mutate(
    fit      = map(data, ~ lm(wt ~ mpg + qsec + gear, data = .x)),
    tidied   = map(fit, tidy),
    glanced  = map(fit, glance),
    augmented= map(fit, augment)
  )

此时,一个 tibble 中同时保存了:

  • 原始数据(data)
  • 模型对象(fit)
  • 参数表(tidied)
  • 整体模型表现(glanced)
  • 带预测值与残差的增强数据(augmented)

需要哪一部分结果,就 unnest 哪一列:

regressions %>% 
  select(tidied) %>% 
  unnest(tidied)