自定义函数结合dplyr across()报错问题排查
批量统计多列值为1时的唯一ID数量
数据与需求
给定数据框:
dat <- data.frame(ID=c("12345", "54321", "12345", "54321", "99999", "12345"), cat1 = c(1,0,0,0,0,0), cat2= c(1,1,1,1,1,1), cat3= c(1,0,1,0,1,0), cat4=c(0,0,0,0,0,0))
需要统计每一列值为1时对应的唯一ID数量,期望输出:
cat1 1 cat2 3 cat3 2 cat4 0
错误原因分析
你编写的自定义函数结合summarise(across())时出现报错,核心问题是:
across()在迭代每一列时,传递给.fns(即你的my_function)的.x是当前列的数值向量(比如cat1的c(1,0,0,0,0,0)),而不是整个数据框。- 你的
my_function第一个参数data期望接收数据框,却传入了单个数值向量,导致filter()无法处理向量类型的数据,触发报错:no applicable method for 'filter' applied to an object of class "c('double', 'numeric')"。
正确解法
解法1:直接在across()内实现逻辑(最简)
不需要自定义函数,直接利用.x指代当前列向量,筛选出该列值为1对应的ID后统计去重数量:
dat |> summarise(across(c(cat1, cat2, cat3, cat4), ~n_distinct(ID[.x == 1])))
运行后输出:
cat1 cat2 cat3 cat4 1 1 3 2 0
解法2:修改自定义函数适配across()
调整函数参数,让它接收列向量和ID向量,而非整个数据框:
my_function <- function(col_vec, id_vec) { n_distinct(id_vec[col_vec == 1]) } # 调用函数 dat |> summarise(across(c(cat1, cat2, cat3, cat4), ~my_function(.x, ID)))
解法3:重塑数据后统计(更直观)
通过pivot_longer将宽表转为长表,分组统计后补全缺失类别:
library(tidyr) dat |> pivot_longer(cols = starts_with("cat"), names_to = "category", values_to = "value") |> filter(value == 1) |> group_by(category) |> summarise(n = n_distinct(ID)) |> complete(category = paste0("cat", 1:4), fill = list(n = 0))
输出结果:
# A tibble: 4 × 2 category n <chr> <int> 1 cat1 1 2 cat2 3 3 cat3 2 4 cat4 0
内容的提问来源于stack exchange,提问作者lemnbalm
相关产品推荐
相关产品推荐

