缘由
艺多不压身
碎碎念
我们继续飞行在云层和雾气之间,飞行在一个无光无影的空洞世界中。 ——《风沙星辰》
Ref
Correlation and regression fundamentals with tidy data principles – tidymodels
代码
用 nest 风格优雅地做批量计算
在数据分析中,我们经常需要 对不同分组做相同的统计检验或建模。
常见的实现思路有三种:
- 基础函数 + broom::tidy()
- group_by + rstatix(或直接 group_modify)
- 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 rowsPart 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)