R语言统计分号分隔多值列内指定字符串的出现次数
问题根因
原代码使用Refer == id做整值精确匹配,仅能识别Refer单元格内容和目标ID完全相等的行,无法识别分号分隔的多值单元格中包含的目标ID,因此会漏统计符合要求的行。
方案1:最小改动原有循环代码
仅需替换匹配逻辑即可,不需要重构原有代码结构。为了避免ID存在子串包含关系时出现误匹配(比如ID为A1时误匹配A11这类值),使用带边界的正则规则做匹配:
library(dplyr) df0 <- data.frame (ID = c("A1", "A2", "A3", "A4", "B1", "C1", "D1"), Refer = c(" ", " ", "A1", "A1;A2", "A3;A1", "A2","A2;C1") ) n1 <- nrow(df0) df1 = data.frame(matrix( vector(), 0, 2, dimnames=list(c(), c("ID","Count"))), stringsAsFactors=F) for (i in 1:n1){ id <- df0$ID[i] # 构造正则匹配规则:id前后只能是字符串开头/结尾,或者分号分隔符 match_rule <- paste0("(^|;)", id, "($|;)") df2 <- filter(df0, grepl(match_rule, Refer)) n2 <- nrow(df2) df1[i,1] <- id df1[i,2] <- n2 }
运行后A1的计数为3,和预期结果一致。
方案2:无循环的简洁向量化实现
如果数据量较大,循环效率偏低,可以直接拆分多值单元格后计数,代码更简洁、运行速度更快:
library(dplyr) library(tidyr) df1 <- df0 %>% # 按分号拆分Refer列的多值,拆分为独立行 separate_rows(Refer, sep = ";") %>% # 过滤掉空格、空值 filter(trimws(Refer) != "") %>% # 统计每个ID的出现次数 count(Refer, name = "Count") %>% # 和原始ID列表做连接,未出现的ID计数补0 right_join(df0 %>% distinct(ID), by = c("Refer" = "ID")) %>% mutate(Count = tidyr::replace_na(Count, 0)) %>% select(ID = Refer, Count)
关键注意点
- 不要直接用简单的无边界字符串包含逻辑(比如裸写
grepl(id, Refer))做匹配,否则当ID存在命名包含关系时(比如同时存在A1和A11两个ID),会出现误计数,必须加分隔符/首尾边界限制。 separate_rows是tidyr包中专门处理分隔符多值单元格的函数,不需要手写字符串拆分、遍历的逻辑,适配绝大多数多值列统计场景。
内容的提问来源于stack exchange,提问作者PhD Student
相关产品推荐
相关产品推荐

