查找所有重复行,包括“具有较小下标的元素”
Posted
技术标签:
【中文标题】查找所有重复行,包括“具有较小下标的元素”【英文标题】:Finding ALL duplicate rows, including "elements with smaller subscripts" 【发布时间】:2011-12-12 20:33:36 【问题描述】:R 的duplicated
返回一个向量,显示向量或数据框的每个元素是否是具有较小下标的元素的副本。所以如果 5 行数据帧的第 3、4 和 5 行相同,duplicated
会给我向量
FALSE, FALSE, FALSE, TRUE, TRUE
但在这种情况下,我实际上想要得到
FALSE, FALSE, TRUE, TRUE, TRUE
也就是说,我想知道一行是否也被带有更大下标的行所复制。
【问题讨论】:
【参考方案1】: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
【讨论】:
等一下,我刚刚进行了测试,发现我错了: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 的三个副本。为什么会这样?
因为无论你是从头开始还是从前面开始,都会捕获中间的。例如,duplicated(c(1,1,1))
与 duplicated(c(1,1,1,), fromLast = TRUE)
给出 c(FALSE,TRUE,TRUE)
和 c(TRUE,TRUE,FALSE)
。在这两种情况下,中间值为TRUE
。取两个向量的|
得到c(TRUE,TRUE,TRUE)
。【参考方案2】:
您需要组装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
【讨论】:
同意。甚至可能会减慢处理速度,但不太可能减慢速度。 非常正确。 OP 没有提供数据示例来测试数据框中的“曾经重复”的行。我认为我使用duplicated
、unique
和%in%
的建议可以很容易地推广到一个数据框,如果一个人首先paste
每一行都有一个不寻常的分隔符。 (接受的答案更好。)【参考方案3】:
可以使用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)
【讨论】:
很好地使用了n()
。不要忘记取消组合生成的数据框。
@qwr 我已调整答案以取消组合结果
@HolgerBrandl,@qwr,一般答案很有用,但我不明白如何选择要排除的列。 group_by_at(vars(-var1, -var2))
中的“vars”指的是什么? var1
和 var2
列名称是否在名为 vars
的数据表中?我认为负号表示排斥,对吗?所以剩下的过程(filter
和ungroup
)作用于数据表vars
中的其余列,但不包括var1
和var2
,对吗?很抱歉这么迂腐,但我经常在速记方面遇到问题!
vars
是 dplyr 中的一个方法,参见 dplyr.tidyverse.org/reference/vars.html 。 var1, var2 确实是指要从重复检查中排除的列名。对建议解决方案中的分组变量进行重复评估。事实上,否定意味着排斥。
group_by_all()
和 group_by_at()
在 dplyr 的最新版本中已被取代。现在你可以这样做了:iris %>% group_by(across()) %>% filter(n() > 1) %>% ungroup()
【参考方案4】:
我有same question,如果我没记错的话,这也是一个答案。
vec[col %in% vec[duplicated(vec$col),]$col]
不知道哪个更快,但我目前使用的数据集不够大,无法进行会产生显着时间间隔的测试。
【讨论】:
这个答案似乎使用vec
作为原子向量和数据框。我怀疑使用实际的 datframe 会失败。【参考方案5】:
这是@Joshua Ulrich 作为函数的解决方案。这种格式允许您以与使用 duplicated() 相同的方式使用此代码:
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
【讨论】:
【参考方案6】:我遇到了类似的问题,但我需要通过特定列中的值来识别重复的行。我想出了以下 dplyr 解决方案:
df <- df %>%
group_by(Column1, Column2, Column3) %>%
mutate(Duplicated = case_when(length(Column1)>1 ~ "Yes",
TRUE ~ "No")) %>%
ungroup()
代码按特定列对行进行分组。如果组的长度大于 1,则代码会将组中的所有行标记为重复。完成后,您可以使用Duplicated
列进行过滤等。
【讨论】:
【参考方案7】:如果您对某些列的重复行感兴趣,可以使用 plyr 方法:
ddply(df, .(col1, col2), function(df) if(nrow(df) > 1) df else c())
使用 dplyr 添加计数变量:
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
这些方法的好处是您可以指定多少重复作为截止值。
【讨论】:
【参考方案8】:这更新了@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)
,你会得到一个索引向量。
【讨论】:
以上是关于查找所有重复行,包括“具有较小下标的元素”的主要内容,如果未能解决你的问题,请参考以下文章