查找所有重复行,包括“下标较小的元素”

R 的 duplicated返回一个向量,显示向量或数据帧的每个元素是否是下标较小的元素的副本。因此,如果5行数据帧中的3、4和5行是相同的,duplicated将给出向量

FALSE, FALSE, FALSE, TRUE, TRUE

但在这种情况下,我实际上想得到

FALSE, FALSE, TRUE, TRUE, TRUE

也就是说,我想知道一行是否也被一个带有 更大下标的行复制。

58466 次浏览

您需要组装一组 duplicated值,应用 unique,然后使用 %in%进行测试。像往常一样,一个示例问题将使这个过程生动起来。

> vec <- c("a", "b", "c","c","c")
> vec[ duplicated(vec)]
[1] "c" "c"
> unique(vec[ duplicated(vec)])
[1] "c"
>  vec %in% unique(vec[ duplicated(vec)])
[1] FALSE FALSE  TRUE  TRUE  TRUE

duplicated有一个 fromLast参数。?duplicated的“示例”部分向您展示了如何使用它。只需调用 duplicated两次,一次用 fromLast=FALSE,一次用 fromLast=TRUE,并取其中任一行为 TRUE


编辑: 您没有提供一个可重复的示例,因此这里有@jbaums 提供的一个插图

vec <- c("a", "b", "c","c","c")
vec[duplicated(vec) | duplicated(vec, fromLast=TRUE)]
## [1] "c" "c" "c"

编辑: 以数据框架为例:

df <- data.frame(rbind(c("a","a"),c("b","b"),c("c","c"),c("c","c")))
df[duplicated(df) | duplicated(df, fromLast=TRUE), ]
##   X1 X2
## 3  c  c
## 4  c  c

我已经有了 同样的问题,如果我没记错的话,这也是一个答案。

vec[col %in% vec[duplicated(vec$col),]$col]

不知道哪一个更快,但是,我目前使用的数据集不够大,不足以进行测试,产生重大的时间差。

如果您对某些列的哪些行是重复的感兴趣,您可以使用 皮尔方法:

ddply(df, .(col1, col2), function(df) if(nrow(df) > 1) df else c())

使用 Dplyr添加 count 变量:

df %>% add_count(col1, col2) %>% filter(n > 1)  # data frame
df %>% add_count(col1, col2) %>% select(n) > 1  # logical vector

对于重复的行(考虑所有列) :

df %>% group_by_all %>% add_tally %>% ungroup %>% filter(n > 1)
df %>% group_by_all %>% add_tally %>% ungroup %>% select(n) > 1

这些方法的好处是,您可以指定多少个重复项作为截止值。

通过执行以下操作,可以使用 dplyr获得数据帧中的重复行

library(tidyverse)
df = bind_rows(iris, head(iris, 20)) # build some test data
df %>% group_by_all() %>% filter(n()>1) %>% ungroup()

可以使用排除某些列 group_by_at(vars(-var1, -var2))来对数据进行分组。

如果实际上需要行索引而不仅仅是数据,那么您可以首先添加它们,如下所示:

df %>% add_rownames %>% group_by_at(vars(-rowname)) %>% filter(n()>1) %>% pull(rowname)

下面是@Joshua Ulrich 的函数解。这种格式允许您使用与重复()相同的方式来使用此代码:

allDuplicated <- function(vec){
front <- duplicated(vec)
back <- duplicated(vec, fromLast = TRUE)
all_dup <- front + back > 0
return(all_dup)
}

用同样的例子:

vec <- c("a", "b", "c","c","c")
allDuplicated(vec)
[1] FALSE FALSE  TRUE  TRUE  TRUE


我也遇到过类似的问题,但是我需要通过特定列中的值来识别重复的行。我想出了以下 Dplyr解决方案:

df <- df %>%
group_by(Column1, Column2, Column3) %>%
mutate(Duplicated = case_when(length(Column1)>1 ~ "Yes",
TRUE ~ "No")) %>%
ungroup()

代码按特定列对行进行分组。如果组的长度大于1,则代码将组中的所有行标记为重复。一旦这样做,你可以使用 Duplicated列过滤等。

这更新了@Holger Brandl 的回答,以反映最新版本的 dplyr (例如1.0.5) ,其中 group_by_all()group_by_at()已被取代。帮助文档建议使用 across()代替。

因此,要获取所有有副本的行,您可以这样做: iris %>% group_by(across()) %>% filter(n() > 1) %>% ungroup()

要包含这些行的索引,请添加一个“ rowid”列,但将其从分组中排除: iris %>% rowid_to_column() %>% group_by(across(!rowid)) %>% filter(n() > 1) %>% ungroup()

在上面的后面追加 %>% pull(rowid),您将得到索引的向量。

这就是 vctrs::vec_duplicate_detect()的工作原理

# on a vector
vctrs::vec_duplicate_detect(c(1, 2, 1))
#> [1]  TRUE FALSE  TRUE
# on a data frame
vctrs::vec_duplicate_detect(mtcars[c(1, 2, 1),])
#> [1]  TRUE FALSE  TRUE

Reprex 软件包于2022.07-19年度创作(v2.0.1)