为何purrr::pwalk在mutate中新增列时报错,而purrr::pmap可正常运行?
为何purrr::pwalk在mutate中新增列时报错,而purrr::pmap可正常运行?
嘿,这个问题问到点子上了,刚好戳中purrr包里map系列和walk系列函数的核心设计差异!我给你拆解得明明白白:
首先说pmap:它天生就是用来「生成并收集结果」的。你调用pmap的时候,它会把每一行对应参数的计算结果(也就是你用str_c拼接的字符串),一个个收集成一个长度为150的列表——这个长度刚好和iris的行数完全匹配,所以mutate可以直接把这个列表赋值给新列concated_cols,每一行对应列表里的一个元素,完美契合mutate的要求。
然后是pwalk:这货的本职工作根本不是生成结果,而是处理「副作用操作」——就是那些不需要返回值,只是“做事情”的操作,比如你提到的写文件、打印日志、生成图表这些。它完全不会去收集你在.f里写的返回值,反而会直接把你传入的.l参数(也就是那个包含Sepal.Length和Petal.Length的列表)原封不动地返回给你。
这就是报错的根源!当你在mutate里用pwalk时,它返回的是两个长度为150的向量组成的列表(也就是你的输入.l),而mutate新增列的规则是:新列要么是和数据框行数一致的单个向量(长度150),要么是单个标量(长度1)。现在你给它的是一个有2个元素的列表,R当然会报错说“concated_cols must be size 150 or 1, not 2”了!
你可以单独跑两行代码验证这个差异:
# pmap返回150个拼接后的字符串组成的列表,长度150 iris %>% pmap(list(Sepal.Length, Petal.Length), \(x,y) str_c(x,y)) %>% length() # pwalk返回传入的两个向量的列表,长度2 iris %>% pwalk(list(Sepal.Length, Petal.Length), \(x,y) str_c(x,y)) %>% length()
最后给你对应场景的正确用法:
- 如果是要生成新列、获取计算结果:就用pmap(或者更精准的pmap_chr/pmap_dbl,能直接返回指定类型的向量,比列表更顺手);
- 如果是要执行写文件这种副作用操作:别放到mutate里,直接在数据框上调用pwalk就行,比如:
# 用pwalk批量写文件的示例 iris %>% pwalk(function(Sepal.Length, Petal.Length, Species, ...) { # 按行生成文件名并写入内容 file_name <- str_c("iris_row_", row_number(), "_", Species, ".txt") write_lines(str_c(Sepal.Length, "-", Petal.Length), file = file_name) })
备注:内容来源于stack exchange,提问作者Aegis
相关产品推荐
相关产品推荐

