R中dplyr报错Error: length(rows) ==1 is not TRUE的排查求助
让我来帮你拆解这个问题的根源,以及给出适配你需求的解决方案:
问题场景回顾
你需要统计变量前三排名数据中,各列1、2、3及NA(未进入前三的人数)的数量。当用dplyr::filter(year ==1, status ==2)得到LikelyRenew_ReasonB后,执行以下统计代码时抛出错误:
LikelyRenew_ReasonB %>% summarize( costC = count(cost), productsC = count(products), communC = count(commun), reimburseC = count(reimburse), policyC = count(policy), discountC = count(discount))
错误信息:Error: length(rows) == 1 is not TRUE
但当过滤条件改为year ==3, status ==1,或者改用plyr::summarize时,代码能正常运行并得到预期结果。
核心原因解析
这个问题本质是dplyr和plyr函数的逻辑差异,以及dplyr::summarize的运行规则导致的:
dplyr::summarize的硬性要求:
dplyr::summarize的每个汇总表达式必须返回单个值(长度为1的向量),而dplyr::count是用来对数据框分组计数的函数,它返回的是一个包含分组列和计数列的数据框——这就直接违反了dplyr::summarize的要求,所以会触发报错。为什么部分过滤条件能正常运行?
当你用year ==3, status ==1过滤后,数据中每一列(cost、products等)的取值可能只有一种(比如全是NA,或者全是某个单一数值),这时候dplyr::count返回的数据框只有1行,刚好满足length(rows) ==1的隐性校验,所以没触发错误;而year ==1, status ==2过滤后的数据中,至少有一列存在多种取值(比如同时有1、2、3和NA),dplyr::count返回多行数据框,就直接触发了报错。plyr::summarize的兼容性差异
plyr::summarize和dplyr::summarize的设计逻辑不同,它允许将数据框作为汇总结果返回,所以当你改用plyr::summarize时,即使count返回多行数据框,也能正常运行。不过这里要注意:你可能混用了dplyr::count和plyr::count,两者的行为也有细微差别,但在这个场景下刚好兼容。
适配需求的解决方案
根据你统计各列1、2、3及NA数量的需求,推荐以下几种更规范的实现方式:
方法1:用dplyr的across+table(最简洁)
table函数可以直接统计向量中各值的出现次数(包括NA,需设置useNA="always"),结合dplyr::summarize(across(...))可以批量处理所有目标列:
LikelyRenew_ReasonB %>% summarize(across(c(cost, products, commun, reimburse, policy, discount), ~list(table(., useNA = "always"))))
运行后每一列会返回一个包含各取值计数的表格,你可以根据需要转换为更易读的格式。
方法2:分组计数后整理成长格式结果
如果想得到每列的计数明细(比如单独列出1、2、3、NA的数量),可以定义一个小函数批量处理:
# 定义统计单列计数的函数 count_single_col <- function(df, col) { df %>% count({{col}}, name = "count", useNA = "always") %>% mutate(column_name = deparse(substitute(col))) } # 批量处理所有列并合并结果 dplyr::bind_rows( count_single_col(LikelyRenew_ReasonB, cost), count_single_col(LikelyRenew_ReasonB, products), count_single_col(LikelyRenew_ReasonB, commun), count_single_col(LikelyRenew_ReasonB, reimburse), count_single_col(LikelyRenew_ReasonB, policy), count_single_col(LikelyRenew_ReasonB, discount) )
这种方式会得到长格式的结果,方便后续的分析或可视化。
方法3:统一使用plyr函数(不推荐长期混用)
如果一定要沿用你原来的写法,要确保统一使用plyr的函数(避免和dplyr的同名函数冲突):
library(plyr) LikelyRenew_ReasonB %>% plyr::summarize( costC = plyr::count(cost), productsC = plyr::count(products), communC = plyr::count(commun), reimburseC = plyr::count(reimburse), policyC = plyr::count(policy), discountC = plyr::count(discount) )
不过不建议同时加载dplyr和plyr,因为大量同名函数会导致逻辑混淆,后续排查问题会很麻烦。
内容的提问来源于stack exchange,提问作者Ellie

