You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用tidyverse实现向量与多值数据框列的交集计数?

用tidyverse统计每行字符串中指定元素的数量

初始变量与需求

给定R语言变量:

vals <- c("b", "c")
foo <- data.frame(x=c("a|b", "b|c", "c|d", "e|f|g"))

需要为foo新增一列y,统计每行x中包含vals内元素的个数,期望结果如下:

> foo2
      x y
1   a|b 1
2   b|c 2
3   c|d 1
4 e|f|g 0

失败的尝试及原因

尝试1:直接对列表列使用intersect

library(dplyr)
library(magrittr)

foo2 <- foo %>% mutate(x1=str_split(x, "\\|"), y=intersect(vals, x1))

报错信息:

Error in `mutate()`:
ℹ In argument: `y = intersect(vals, x1)`.
Caused by error:
! `y` must be size 4 or 1, not 0.

原因:str_split返回的是列表列,intersect无法直接处理列表结构,需要逐行对列表元素操作。

尝试2:固定取第一行的拆分结果

foo2 <- foo %>% mutate(x1=str_split(x, "\\|"), y=intersect(vals, x1[[1]]))

不符合预期的结果:

> foo2
      x      x1 y
1   a|b    a, b b
2   b|c    b, c b
3   c|d    c, d b
4 e|f|g e, f, g b

原因:x1[[1]]仅提取了第一行的拆分向量,所有行都基于这个值计算,导致结果错误。

正确的tidyverse实现

解法1:分步实现(清晰易懂)

library(dplyr)
library(stringr)
library(purrr)

foo2 <- foo %>%
  # 将每行x按|拆分为列表列
  mutate(x_split = str_split(x, "\\|")) %>%
  # 逐行计算拆分结果与vals的交集长度
  mutate(y = map_int(x_split, ~ length(intersect(vals, .x)))) %>%
  # 可选:移除中间辅助列x_split
  select(-x_split)

# 查看最终结果
foo2

输出符合预期:

x y
1   a|b 1
2   b|c 2
3   c|d 1
4 e|f|g 0

解法2:简化版(无中间列)

将拆分与计算合并为一步,代码更简洁:

foo2 <- foo %>%
  mutate(y = map_int(str_split(x, "\\|"), ~ length(intersect(vals, .x))))

核心原理

  • str_split(x, "\\|"):将每行字符串按|拆分,返回列表列,每个元素是该行拆分后的字符串向量。
  • map_int(...):遍历列表列的每个元素,对每个拆分后的向量计算与vals的交集长度,返回整数向量作为新列y的值。

内容的提问来源于stack exchange,提问作者dfrankow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:55:17