dplyr中修改代码遇向量类型报错与计算结果异常问题排查
dplyr代码修改后的类型错误与结果不符问题
原始代码与预期输出
以下代码运行后能得到符合预期的结果:
library(dplyr) myData <- data.frame( Element = c("A","A","B","A","C","C"), Group = c(0,0,0,0,1,1) ) myDataGroups <- myData %>% mutate(origOrder = row_number()) %>% group_by(Element) %>% mutate(ElementCnt = row_number()) %>% ungroup() %>% mutate(Group = factor(Group, unique(Group))) %>% arrange(Group) %>% mutate(groupCt = cumsum(Group != lag(Group, 1, Group[[1]])) - 1L) %>% group_by(Group) %>% mutate(GroupRank = ElementCnt - groupCt, GroupRank = if_else( as.character(Group) == "0", ElementCnt, min(GroupRank)) ) %>% ungroup() %>% arrange(origOrder) myDataGroups
输出:
> myDataGroups # A tibble: 6 x 6 Element Group origOrder ElementCnt groupCt GroupRank <chr> <fct> <int> <int> <int> <int> 1 A 0 1 1 -1 1 2 A 0 2 2 -1 2 3 B 0 3 1 -1 1 4 A 0 4 3 -1 3 5 C 1 5 1 0 1 6 C 1 6 2 0 1
问题1:添加max(0, groupCt)后的类型错误
将语句mutate(GroupRank = ElementCnt - groupCt,...)修改为mutate(GroupRank = ElementCnt - max(0,groupCt),...)后,出现错误提示:
Error: Problem with mutate() column GroupRank.
i GroupRank = if_else(as.character(Group) == "0", ElementCnt, min(GroupRank)).
x false must be an integer vector, not a double vector
尝试用as.integer(...)转换类型但无效。
问题2:修改if_else外层加max(1, ...)后的结果不符合预期
不添加上述max函数,而是将语句GroupRank = if_else( as.character(Group) == "0", ElementCnt, min(GroupRank))修改为GroupRank = max(1,if_else( as.character(Group) == "0", ElementCnt, min(GroupRank))),得到的GroupRank结果不符合预期:
# A tibble: 6 x 6 Element Group origOrder ElementCnt groupCt GroupRank <chr> <fct> <int> <int> <int> <dbl> 1 A 0 1 1 -1 3 2 A 0 2 2 -1 3 3 B 0 3 1 -1 3 4 A 0 4 3 -1 3 5 C 1 5 1 0 1 6 C 1 6 2 0 1
错误原因与解决方法
问题1:类型不匹配的原因与修复
- 原因:
max(0, groupCt)中,0是默认的double类型,即使groupCt是integer,max返回的结果会转为double。此时ElementCnt - max(0, groupCt)得到的GroupRank是double类型,后续min(GroupRank)也会返回double;而if_else的第一个分支ElementCnt是integer类型,if_else要求两个分支的返回类型必须一致,因此触发类型错误。 - 修复方法:使用integer类型的
0L替代0,让max返回integer类型结果:
或者显式将mutate(GroupRank = ElementCnt - max(0L, groupCt), GroupRank = if_else( as.character(Group) == "0", ElementCnt, min(GroupRank)) )max结果转为integer:mutate(GroupRank = ElementCnt - as.integer(max(0, groupCt)), GroupRank = if_else( as.character(Group) == "0", ElementCnt, min(GroupRank)) )
问题2:max函数误用的原因与修复
- 原因:
max(1, ...)是对整个输入向量取全局最大值,而非逐元素比较。在group_by(Group)的分组中,Group=0组的if_else结果是c(1,2,1,3),max(1, c(1,2,1,3))会直接返回3,导致整个组的GroupRank都被设为3,不符合逐行取最大值的预期。 - 修复方法:使用
pmax函数(逐元素最大值)替代max,同时用1L保证integer类型:mutate(GroupRank = ElementCnt - groupCt, GroupRank = pmax(1L, if_else( as.character(Group) == "0", ElementCnt, min(GroupRank))) )
内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072
相关产品推荐
相关产品推荐

