如何在dplyr的mutate中提取嵌套tibble列表列元素并解决报错?
问题场景
- 测试tibble构造代码:
library(dplyr) my_tib <- tibble(names = c("blah", "blah2"), data = list(1, c(2, 3)))
- 数据默认打印结构:
names data <chr> <list> 1 blah <dbl [1]> 2 blah2 <dbl [2]>
- 值提取规则:对
data列每个列表元素按规则提取值,生成data_min列:- 若元素长度为2,取第一个元素
- 若元素长度为1且首元素大于10,返回
NA_integer_ - 若元素长度为1且首元素小于10,取首元素
- 原触发报错的实现代码:
my_tib %>% rowwise() %>% mutate(data_min = case_when(lengths(data) == 2 ~ data[[1]], lengths(data) == 1 & data[[1]] > 10 ~ NA_integer_, lengths(data) == 1 & data[[1]] < 10 ~ data[[1]]))
- 运行报错信息:
Error in `mutate()`: ! Problem while computing `data_min = case_when(...)`. ✖ `data_min` must be size 1, not 2. ℹ Did you mean: `data_min = list(case_when(...))` ? ℹ The error occurred in row 2. Run `rlang::last_error()` to see where the error occurred.
- 期望输出结果:
names data data_min <chr> <list> <int> 1 blah <dbl [1]> 1 2 blah2 <dbl [2]> 2
报错原因
rowwise()会按行切分数据集,此时每行的data是列表中存储的原子向量本身。代码中使用的lengths()是向量化函数,作用是遍历传入对象的每个最外层元素返回长度:处理第二行data = c(2,3)时,lengths(data)会返回长度为2的向量c(1,1)(原子向量的每个标量元素长度都是1),导致case_when输出长度为2,和单行计算要求的长度1不匹配,触发报错。
修复方案
将所有判断逻辑中的lengths()替换为单对象长度计算函数length()即可,length()会直接返回当前行向量的总长度,符合行级计算逻辑:
my_tib %>% rowwise() %>% mutate(data_min = case_when( length(data) == 2 ~ data[[1]], length(data) == 1 & data[[1]] > 10 ~ NA_integer_, length(data) == 1 & data[[1]] < 10 ~ data[[1]] )) %>% ungroup()
运行后输出与预期完全一致:
# A tibble: 2 × 3 names data data_min <chr> <list> <dbl> 1 blah <dbl [1]> 1 2 blah2 <dbl [2]> 2
如果需要data_min严格为整数类型,在返回值外套一层as.integer()即可。
内容的提问来源于stack exchange,提问作者Tea Tree
相关产品推荐
相关产品推荐

