tidyr 1.2.0中pivot_wider()需指定names_from参数导致健康数据处理代码失效的解决方案
解决tidyr 1.2.0中pivot_wider行为变更的问题
你遇到的问题其实是tidyr 1.2.0对pivot_wider()的参数逻辑做了严格规范——旧版本允许你不指定names_from就隐式按其他列分组聚合,但新版本要求必须明确说明哪些列是用来生成宽表列名的,这就导致你原来“歪打正着”的写法失效了。
不过好消息是,你的核心需求其实是分组聚合(把同一手术组的OPERTN合并成字符串,OPDATE取第一个值),完全不需要依赖pivot_wider的隐式行为。用更直接的分组聚合写法,不仅能完美复现旧版本的结果,还更稳定、更高效,适合你千万级的数据集。
推荐解决方案:显式分组聚合
直接用dplyr::group_by() + summarise(),逻辑清晰且版本兼容:
library(tidyverse) df %>% # 按唯一标识手术组的列分组 group_by(row, opdate_grp, side, opgrp) %>% summarise( # 合并同一组的OPERTN为逗号分隔字符串 OPERTN = toString(OPERTN), # 取同一组的第一个OPDATE OPDATE = first(OPDATE), # 取消分组,避免后续操作受分组影响 .groups = "drop" )
运行这段代码后,你会得到和旧版本tidyr完全一致的输出:
# A tibble: 8 × 6 row opdate_grp side opgrp OPERTN OPDATE <dbl> <dbl> <chr> <dbl> <chr> <chr> 1 1 1 bilateral 1 W373, Z941 2018-03-23 2 2 1 bilateral 1 W374, Z941 2018-10-12 3 3 1 left 1 W383, Z943 2020-12-08 4 4 2 none 2 O325 2013-03-31 5 5 1 none 1 G47 2012-01-22 6 5 2 none 2 C488 2012-01-25 7 6 1 none 1 X90 2018-12-25 8 6 2 none 2 T36 2018-12-28
为什么这个方案更好?
- 稳定性拉满:
group_by()和summarise()是dplyr的核心函数,API非常稳定,未来tidyr或dplyr版本更新都不会影响结果。 - 性能更优:对于1000万行的大数据,分组聚合的效率远高于
pivot_wider(后者本质是表重塑操作,额外开销更大)。 - 逻辑直观:一眼就能看懂你要按哪些列分组、对哪些列做什么聚合,维护起来比旧写法轻松太多。
针对超大数据量的优化
如果你的数据真的有1000万行,推荐用data.table实现,它的分组聚合速度比dplyr快数倍,内存占用也更低:
library(data.table) setDT(df)[, .(OPERTN = toString(OPERTN), OPDATE = first(OPDATE)), by = .(row, opdate_grp, side, opgrp)]
(可选)用pivot_wider适配新版本的写法
如果你非要坚持用pivot_wider,可以通过指定id_cols明确分组键,同时设置names_from = NULL来避免生成多列:
df %>% pivot_wider( id_cols = c(row, opdate_grp, side, opgrp), names_from = NULL, values_from = c(OPERTN, OPDATE), values_fill = NA, values_fn = list(OPERTN = toString, OPDATE = first) )
不过这种写法本质还是依赖pivot_wider的边缘特性,不如分组聚合稳定,不推荐长期使用。
内容的提问来源于stack exchange,提问作者JisL
相关产品推荐
相关产品推荐

