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


111

R duplicated返回一个向量,该向量表示向量或数据帧的每个元素是否都是下标较小的元素的重复。因此,如果5行数据帧的第3、4和5行相同,请duplicated给我向量

FALSE, FALSE, FALSE, TRUE, TRUE

但是在这种情况下,我实际上想要

FALSE, FALSE, TRUE, TRUE, TRUE

也就是说,我想知道行是否也被下标较大的行重复。

Answers:


128

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

3
等等,我只是进行了测试,发现我错了:x <- c(1:9, 7:10, 5:22); y <- c(letters, letters[1:5]); test <- data.frame(x, y); test[duplicated(test$x) | duplicated(test$x, fromLast=TRUE), ]退还了他的所有三个副本,分别是7、8和9。为什么这样做有效?
JoeM05 '17

1
因为无论从头到尾还是从头开始,都将捕获中间的对象。例如,duplicated(c(1,1,1))vs duplicated(c(1,1,1,), fromLast = TRUE)给出c(FALSE,TRUE,TRUE)c(TRUE,TRUE,FALSE)TRUE在两种情况下都是中间值。取|两个向量都得出c(TRUE,TRUE,TRUE)
布兰登'18

34

您需要组装一组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

同意。甚至可能减慢处理速度,但不太可能减慢处理速度。
IRTFM

确实如此。OP没有提供数据示例来测试数据帧中的“重复”行。我认为,我的建议使用duplicatedunique并且%in%如果paste每个行都以不寻常的分隔符开头,则很容易将其推广到一个数据框。(可接受的答案更好。)
IRTFM,

3

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

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

但是,Dunno的速度更快,但我当前使用的数据集不足以进行测试,从而产生巨大的时间间隔。


1
这个答案似乎vec既用作原子向量又用作数据帧。我怀疑使用实际的datframe会失败。
IRTFM

3

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

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)

1
很好用n()。不要忘记对结果数据帧进行分组。
qwr

@qwr我已经调整了答案以将结果取消分组
Holger Brandl

2

这是@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

0

如果您对某些列中哪些行重复感兴趣,可以使用plyr方法:

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

这些方法的好处在于,您可以指定多少重复作为截止。


0

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

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

该代码按特定列对行进行分组。如果组的长度大于1,则代码会将组中的所有行标记为重复。完成后,您可以使用Duplicated列进行过滤等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.