基因 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,通常应在集合比较前明确统计或排除,而不是让它成为一个普通集合成员。