HOWTO · R
R 中按列删除重复行
这篇文章演示了如何在 R 中按列删除重复的行
本页内容
若要在 R 数据框中为每个所选键保留一行,当您需要其他列时,请使用 dplyr 的 distinct() 并设置 .keep_all = TRUE。以下每种方法都会按照数据当前的顺序保留最早的匹配行,因此当另一个记录应优先时,请先排序。这些示例使用一个具有 id、group 和 score 列的小型数据框。
使用 dplyr 包的 distinct 函数按列删除 R 中的重复行
当 id 定义了唯一记录,且您希望结果包含每个原始列时,请使用 distinct(df, id, .keep_all = TRUE)。distinct() 会比较所选的键列,并为每个键值保留第一行。使用 .keep_all = TRUE 时,其他列会被带入结果中,但不会影响两行是否匹配。若没有该参数,结果仅包含所选的列。
对于复合键,请列出每一列:distinct(df, id, group, .keep_all = TRUE)。这样,具有相同 id 但不同 group 值的行便会保持分离。下面的完整示例使用相同的示例数据,并展示了两种键的选择。它需要安装 dplyr;其结果在下文中说明,且此示例不附带运行时的输出。
df <- data.frame(
id = c(1, 2, 2, 3, 3),
group = c("A", "A", "B", "A", "B"),
score = c(8, 5, 9, 4, 7)
)
if (requireNamespace("dplyr", quietly = TRUE)) {
unique_by_id <- dplyr::distinct(df, id, .keep_all = TRUE)
unique_by_pair <- dplyr::distinct(df, id, group, .keep_all = TRUE)
print(unique_by_id)
print(unique_by_pair)
} else {
cat("Install dplyr to run these distinct() examples.\n")
}
单一键的结果保留了 (1, A, 8)、(2, A, 5) 和 (3, A, 4)。复合键的结果保留了这些行以及 (2, B, 9) 和 (3, B, 7),因为每个 id 与 group 的配对都是唯一的。下面的另一个 Base R 示例会打印这两个结果。
df <- data.frame(
id = c(1, 2, 2, 3, 3),
group = c("A", "A", "B", "A", "B"),
score = c(8, 5, 9, 4, 7)
)
unique_by_id <- df[!duplicated(df$id), ]
unique_by_pair <- df[!duplicated(df[c("id", "group")]), ]
cat("By id:\n")
cat(paste(unique_by_id$id, unique_by_id$group, unique_by_id$score, sep = ":"), sep = "\n")
cat("\nBy id and group:\n")
cat(paste(unique_by_pair$id, unique_by_pair$group, unique_by_pair$score, sep = ":"), sep = "\n")
By id:
1:A:8
2:A:5
3:A:4
By id and group:
1:A:8
2:A:5
2:B:9
3:A:4
3:B:7
在这里,!duplicated(df$id) 标记了每个 id 后续出现的位置;将键列的数据框传递给 duplicated() 会对其组合应用相同的首次出现规则。两种选择都保留了每个所选行的所有列。
使用 group_by、filter 和 duplicated 函数按列删除 R 中的重复行
对于单一全局 id 键,filter(!duplicated(id)) 会保留其首次出现。如果输入可能已经分组,请先调用 ungroup(),以便 filter() 对整个数据评估重复检查:
df %>% ungroup() %>% filter(!duplicated(id))
管道 %>% 将其左侧的值作为第一个参数传递给其右侧的函数。在 filter(!duplicated(id)) 之前按 id 分组不会删除后面的行:在每个 id 组内,该键是恒定的,因此 duplicated(id) 找不到后续出现。按另一列分组在 ID 可能在每个组内独立重复时非常有用;此时,duplicated(id) 会保留每个组中每个 ID 的首次出现。对于单一全局键,未分组的表达式与上面的 Base R 选择具有相同的首行行为。
例如,按 group 分组会在每个组内分别应用相同的检查:
df %>%
group_by(group) %>%
filter(!duplicated(id)) %>%
ungroup()
此管道按照当前的行顺序,保留每个 group 内每个 id 的第一行。在示例数据中,每个 id 与 group 的配对仅出现一次,因此每一行都是其在组内该 id 的首次出现,五行全部保留;若再有一行重复同一组中已出现过的 id,则会被丢弃。
使用 group_by 和 slice 函数按列删除 R 中的重复行
dplyr 管道 df %>% group_by(id) %>% slice(1) %>% ungroup() 从每个 id 组中选取位置 1。当前的行顺序决定了哪个记录排在第一位;slice(1) 不会自动选取最高分或最新记录。在分组和切片之前,请按照您希望的偏好排列数据,然后在后续操作应将结果视为普通数据框时取消分组。
对于示例数据,此方法保留了与单一键的 distinct() 和 duplicated() 方法相同的行:ID 1、2 和 3 的第一行。当任务是选取唯一的键组合时,请使用 distinct();当按每个组内的位置选取一行是更广泛的分组工作流程的一部分时,请使用 slice(1)。这些 dplyr 表达式仅供说明,且需要 dplyr 包;上面的 Base R 示例无需该依赖即可运行。