如何在 R 中逐项匹配两列条目并提取对应行的值?
可以用 R 自带的 match() 找到每个条目在查找列中的位置,再据此提取对应的值,赋给新列。整个过程按条目匹配,不需要自己写 for 循环。
为什么 match() 适合这个问题?
你描述的两列都包含相同的 40 个条目,只是顺序不同。可以先找到每个条目在查找列中的行位置,再从该行的指定列取值。
match(x, table)
其中,x 是待查找的条目向量,table 是供查找的条目向量。返回结果与 x 等长,每个位置记录对应条目第一次出现在 table 中的位置;找不到时返回 NA。
传入整列时,match() 会逐个查找列中的条目。
在数据框中提取对应值
原问题没有提供实际数据和列名,下面用 4 个条目举例。假设数据框包含:
previous_item:供查找的条目列。source_value:与previous_item同行、需要提取的值。current_item:需要逐项查找的条目列。
df <- data.frame(
previous_item = c("A", "B", "C", "D"),
source_value = c(10, 20, 30, 40),
current_item = c("C", "A", "D", "B"),
stringsAsFactors = FALSE
)
# 找到每个 current_item 在 previous_item 中的位置
idx <- match(df$current_item, df$previous_item)
# 提取匹配行的值,并按 current_item 的顺序写入新列
df$matched_value <- df$source_value[idx]
df
结果为:
previous_item source_value current_item matched_value
1 A 10 C 30
2 B 20 A 10
3 C 30 D 40
4 D 40 B 20
第一行的 current_item 是 C,它位于 previous_item 的第三行。因此,新列第一行取到第三行的 source_value,即 30。其他条目也按同样的方式匹配,原有行顺序不变。
实际使用时,把列名换成自己的列名,也可以将步骤合并为一条语句:
df$matched_value <- df$source_value[
match(df$current_item, df$previous_item)
]
如果数据来自两个数据框
如果“之前的列表”和“当前的列表”分别存放在两个数据框中,写法类似。假设 previous 包含 item 和 value,current 包含待查找的 item:
current$matched_value <- previous$value[
match(current$item, previous$item)
]
位置来自 previous$item,因此要从与它逐行对应的 previous$value 中取值。
重复条目和未匹配条目怎么处理?
match() 遇到重复条目时,只返回第一次匹配的位置。如果查找列可能包含同名条目,而且这些行的值不同,需要先确定应该取哪一行。可以先检查查找列是否存在重复值:
anyDuplicated(df$previous_item)
返回 0 表示没有重复值;非零值表示存在重复值。
找不到匹配项时,idx 中相应位置为 NA,提取后的新列通常也会得到 NA。可以单独检查哪些条目没有匹配成功:
idx <- match(df$current_item, df$previous_item)
df$current_item[is.na(idx)]
应通过 idx 判断是否匹配成功,因为 source_value 本身也可能包含 NA。字符匹配区分大小写,前后空格也会影响结果;只有确认这些差异没有业务含义时,才应先统一清理。
如果条目列包含缺失值,还要留意:match() 可以让 NA 匹配到查找列中的 NA。若缺失条目不应参与匹配,可以明确排除:
idx <- match(df$current_item, df$previous_item)
idx[is.na(df$current_item)] <- NA_integer_
df$matched_value <- df$source_value[idx]
备注:内容仅供参考。
