使用dplyr查找重复元素

119

我尝试使用这里提供的代码来用dplyr查找所有重复元素,如下:

library(dplyr)

mtcars %>%
mutate(cyl.dup = cyl[duplicated(cyl) | duplicated(cyl, from.last = TRUE)])

我该如何将此处提供的代码转换为使用 dplyr 找到所有重复元素的方式?我的代码会报错。或者,是否有其他更简洁的函数可以比使用复杂的 x[duplicated(x) | duplicated(x, from.last = TRUE)] 更好地实现这一目标?

9个回答

215
我猜你可以使用filter来实现这个目的:
mtcars %>% 
  group_by(carb) %>% 
  filter(n()>1)

以下是一个小例子(请注意我添加了summarize()以证明结果数据集不包含重复的“carb”行。我使用了“carb”而非“cyl”,因为“carb”具有唯一的值,而“cyl”则没有):

summarize()被添加到该示例中,以证明最终数据集不包含具有重复“carb”的行。使用“carb”而不是“cyl”,因为“carb”具有唯一值,而“cyl”不具备其特点。

mtcars %>% group_by(carb) %>% summarize(n=n())
#Source: local data frame [6 x 2]
#
#  carb  n
#1    1  7
#2    2 10
#3    3  3
#4    4 10
#5    6  1
#6    8  1

mtcars %>% group_by(carb) %>% filter(n()>1) %>% summarize(n=n())
#Source: local data frame [4 x 2]
#
#  carb  n
#1    1  7
#2    2 10
#3    3  3
#4    4 10

15
我提到了add_count函数,它会添加一个名为n的列,方便我们进行筛选操作:mtcars %>% add_count(carb) %>% filter(n>1) 将会得到与之前相同的结果,但是多了一个n列。 - Pascal Martin
请注意,这将生成一个分组的数据框;使用像“distinct”这样的动词将产生与未分组的数据框不同的结果;要将其转换回仅包含重复记录的未分组数据,请使用ungroup()(https://dplyr.tidyverse.org/articles/grouping.html)。 - adam.r
在较新的dplyr版本中,你可以只使用filter.by参数,而无需使用group_bymtcars |> filter(n() > 1, .by = carb)。这样做的好处是不需要再进行任何ungroup操作。 - undefined

57

另一种解决方案是使用janitor软件包

mtcars %>% get_dupes(wt)

请注意,此操作的结果会显示所有数据中重复出现的实例。例如,如果您运行get_dupes(data.frame(x=c(1,1,1))),则会得到整个df。get_dupes还会添加一个计数列。请参阅 这里 - Levi Baguley

23

我们可以使用dplyr按如下方式查找重复元素。

library(dplyr)

# Only duplicated elements
mtcars %>%
  filter(duplicated(.[["carb"]])

# All duplicated elements
mtcars %>%
  filter(carb %in% unique(.[["carb"]][duplicated(.[["carb"]])]))

1
同时,以下是多列筛选的语法:mtcars %>% filter(duplicated(.[c("carb", "cyl")]) - RDavey

23
原始帖子在使用相关答案的解决方案时存在错误。在给出的示例中,当您在mutate内使用该解决方案时,它会尝试对cyl向量进行子集操作,该向量的长度与mtcars数据帧不同。

相反,您可以使用以下示例通过filter返回所有重复元素或使用ifelse创建一个虚拟变量,在稍后可以对其进行过滤:

 library(dplyr)

 # Return all duplicated elements
 mtcars %>%
   filter(duplicated(cyl) | duplicated(cyl, fromLast = TRUE))
 # Or for making dummy variable of all duplicated
 mtcars %>%
   mutate(cyl.dup =ifelse(duplicated(cyl) | duplicated(cyl, fromLast = TRUE), 1,0))

6
# Adding a shortcut to the answer above
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
mtcars %>% count(carb)
#> # A tibble: 6 x 2
#>    carb     n
#>   <dbl> <int>
#> 1    1.     7
#> 2    2.    10
#> 3    3.     3
#> 4    4.    10
#> 5    6.     1
#> 6    8.     1
mtcars %>% count(carb) %>% filter(n > 1)
#> # A tibble: 4 x 2
#>    carb     n
#>   <dbl> <int>
#> 1    1.     7
#> 2    2.    10
#> 3    3.     3
#> 4    4.    10

# Showing an alternative that follows the apparent intention if the asker
duplicated_carb <- mtcars %>% 
  mutate(dup_carb = duplicated(carb)) %>% 
  filter(dup_carb)
duplicated_carb
#>     mpg cyl  disp  hp drat    wt  qsec vs am gear carb dup_carb
#> 1  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4     TRUE
#> 2  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1     TRUE
#> 3  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1     TRUE
#> 4  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4     TRUE
#> 5  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2     TRUE
#> 6  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2     TRUE
#> 7  19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4     TRUE
#> 8  17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4     TRUE
#> 9  17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3     TRUE
#> 10 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3     TRUE
#> 11 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4     TRUE
#> 12 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4     TRUE
#> 13 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4     TRUE
#> 14 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1     TRUE
#> 15 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2     TRUE
#> 16 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1     TRUE
#> 17 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1     TRUE
#> 18 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2     TRUE
#> 19 15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2     TRUE
#> 20 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4     TRUE
#> 21 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2     TRUE
#> 22 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1     TRUE
#> 23 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2     TRUE
#> 24 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2     TRUE
#> 25 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4     TRUE
#> 26 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2     TRUE

2
关于“替代方案”,Marat的答案有30行,而你的只有26行。我猜你可以在原来的管道中添加一步:mtcars %>% count(carb) %>% filter(n > 1) %>% left_join(mtcars),也许需要先使用select(-n) - Frank

0

如果您想使用多个列来分组重复项,以下是一种更通用的解决方案

df%>%
  select(ID,COL1,COL2,all_of(vector_of_columns))%>%
  distinct%>%
  ungroup%>%rowwise%>%
  mutate(ID_GROUPS=paste0(ID,"_",cur_group_rows()))%>%
  ungroup%>%
  full_join(.,df,by=c("INFO_ID","COL1","COL2",vector_of_columns))->chk

0
在带有列的数据框中查找重复值
df<-dataset[duplicated(dataset$columnname),]

0

你可以使用duplicated()函数创建一个布尔掩码:

iris %>% duplicated()
  [1] FALSE FALSE FALSE .... TRUE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE

并通过方括号索引:

iris[iris %>% duplicated(),]
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
143          5.8         2.7          5.1         1.9 virginica

注意:这种方法是使用R和dplyr实现最接近Pandas的方法。
iris[iris %>% duplicated(), c("Petal.Length","Petal.Width","Species")]
    Petal.Length Petal.Width   Species
143          5.1         1.9 virginica

0
在包xlr中有一个名为repeated的函数。
请参阅:https://rpubs.com/Eauleaf/xlr
library(dplyr)
library(xlr)

mtcars |> filter(repeated(cyl))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接