05匹配、成员判断与集合运算

使用 match、%in%、union、intersect 和 setdiff 对齐 ID、检查成员关系并比较两个向量的唯一元素集合。

2026-04-06
RMatchingSetsVectorsData Alignment
本章目录 · 7

基因 ID、样本名和标签之间的比较常见于三个不同问题:某个值是否存在、它第一次出现在哪里,以及两个集合有哪些共有或特有元素。%in%match() 和集合函数分别回答这三个问题。

%in%:判断是否属于目标集合

x <- c("Hi", "Wor", "2", "1", "3")
table <- c("Hello", "World", "1", "2", "3")

x %in% table
# [1] FALSE FALSE TRUE TRUE TRUE

结果与左侧 x 等长,因此适合直接筛选:

x[x %in% table]

数据框中筛选指定分组:

keep_groups <- c("Control", "Treatment")

df[df$group %in% keep_groups, ]

判断“不属于”时,在整个表达式外取反:

!(x %in% table)

如果项目经常使用,可以定义语义化运算符:

`%nin%` <- function(x, table) {
  !(x %in% table)
}

x %nin% table

自定义运算符只是可读性封装,不会改变 %in% 的匹配规则。团队代码应确保定义位置明确,避免读者误以为 %nin% 是 Base R 自带运算符。

match():返回首次匹配位置

match(
  c("Hi", "Wor", "2", "1", "3"),
  c("Hello", "World", "1", "2", "3")
)
# [1] NA NA 4 3 5

match(x, table)x 中每个元素返回它在 table 中第一次出现的位置;找不到时返回 NA

这可以按目标 ID 顺序重排一张表:

desired_order <- c("S3", "S1", "S2")

sample_info <- data.frame(
  sample_id = c("S1", "S2", "S3"),
  group = c("A", "B", "A")
)

idx <- match(desired_order, sample_info$sample_id)
sample_info[idx, ]

正式对齐前必须检查缺失和重复:

anyNA(idx)
anyDuplicated(sample_info$sample_id)

如果 table 中同一个 ID 出现多次,match() 只返回第一次的位置。需要一对多或多对多关系时,应显式使用数据连接,而不是依赖 match() 猜测对应行。

%in%match() 的关系

%in% 可以理解为“是否得到有效匹配位置”:

x %in% table
!is.na(match(x, table))

两者用途不同:

目标 使用
判断是否存在 %in%
获取目标中的位置 match()
获取满足条件的左侧位置 which(x %in% table)

which() 把逻辑向量转换为其中 TRUE 的位置;它不能找回 match() 提供的目标表位置。

集合运算

Base R 提供三个最常用的二元集合操作:

A <- c(1, 2, 3, 4)
B <- c(3, 4, 5, 6)

union(A, B)
# [1] 1 2 3 4 5 6

intersect(A, B)
# [1] 3 4

setdiff(A, B)
# [1] 1 2
函数 回答的问题
union(A, B) A 或 B 中出现过哪些唯一元素?
intersect(A, B) 哪些唯一元素同时出现在 A 和 B?
setdiff(A, B) 哪些唯一元素在 A 中、但不在 B 中?

差集有方向:

setdiff(A, B)
setdiff(B, A)

判断两个向量是否代表同一集合,不考虑顺序和重复次数:

setequal(c(1, 2, 2), c(2, 1))
# [1] TRUE

集合不保留重复次数

集合函数关注唯一成员,不处理 multiplicity:

A <- c("gene1", "gene1", "gene2")
B <- c("gene1", "gene3")

intersect(A, B)
# [1] "gene1"

如果重复次数本身有意义,应先用 table()count() 或行级连接处理,不能把集合运算当作重复观测比较。

比较两批 ID

expected <- c("S1", "S2", "S3", "S4")
observed <- c("S1", "S2", "S4", "S5")

missing_ids <- setdiff(expected, observed)
unexpected_ids <- setdiff(observed, expected)
shared_ids <- intersect(expected, observed)

list(
  missing = missing_ids,
  unexpected = unexpected_ids,
  shared = shared_ids
)

这是导入样本表、表达矩阵或结果文件后的常用完整性检查。随后若要按 ID 合并多列信息,使用 join/merge,并显式验证 key 是否唯一。

缺失值与类型

比较前确认两边使用相同语义和兼容类型:

1 %in% "1"

R 可能发生类型转换,但代码能够运行不代表 ID 体系真的一致。基因 symbol、Ensembl ID、rsID 和样本条码不应只因字符看起来相似就直接比较。

缺失值也需要单独判断:

NA %in% c(1, NA)
# [1] TRUE

如果 NA 代表未知 ID,通常应在集合比较前明确统计或排除,而不是让它成为一个普通集合成员。