为什么transform搭配Map/mapply运行报错,搭配strsplit却能正常工作?
问题描述
我此前使用dplyr和tidyr回答了一个相关问题,根据评论建议,我改用Map重构了答案。
后续我尝试仅使用base R工具实现相同需求,但运行结果不符合预期:
transform( df, Begin_New = Map(seq, Begin, End - 6000, list(by = 1000)) # 或使用mapply(...) )
运行后抛出如下错误:
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : Arguments imply different number of rows: 25, 33, 84, 36, 85, 165
该报错逻辑我可以理解,但我不清楚为什么以下代码可以正常运行:
df2 <- data.frame(id = 1:4, nested = c("a, b, f", "c, d", "e", "e, f")) transform(df2, nested = strsplit(nested, ", "))
在我的认知中,Map(seq, Begin, End - 6000, list(by = 1000))和strsplit(nested, ", ")均返回由向量组成的list(),二者行为存在差异的原因是什么?我已查阅相关报错问题,但仍未找到两个示例表现不同的原因。
测试数据
df <- structure(list(ID = c("A01", "A01", "A01", "A01", "A01", "A01" ), Period = c("Baseline", "Run", "Recovery", "Baseline", "Run", "Recovery"), Begin = c(0, 30500, 68500, 2000, 45000, 135000), End = c(30500, 68500, 158000, 43000, 135000, 305000)), row.names = c(NA, -6L), class = "data.frame")
解答
二者行为差异来自transform函数对返回列表的隐式处理逻辑:
- 首先确认两者的返回值结构确实一致:
Map返回长度为6的列表(和df行数相同),strsplit返回长度为4的列表(和df2行数相同),每个元素都是对应行生成的向量。 - 触发报错的核心原因是:当列表内的元素都是数值型向量时,
transform会默认尝试把列表展开成普通的多列结构,此时会校验每个元素的长度是否一致,你返回的6个数值向量长度分别是25、33、84等,长度不一致,所以抛出行数不匹配的错误。 - 而
strsplit返回的列表元素是字符串向量,transform不会尝试展开这类列表,会直接将其识别为列表列存入数据框,所以不会报错。
如果要让你的代码正常运行,只需要用I()函数把Map的返回值标记为AsIs类,告诉transform不要尝试展开该列表,直接作为列表列处理即可:
transform( df, Begin_New = I(Map(seq, Begin, End - 6000, list(by = 1000))) )
内容的提问来源于stack exchange,提问作者Martin Gal
相关产品推荐
相关产品推荐

