如何查找数据框中重复的数据

今天看到群里面有童鞋问了一个问题:如何查找数据框中的重复值?这个问题问的非常好,而且很有趣。查找重复值一般大家都会想到unique()函数,distinct()函数,duplicated()函数等等。但是这些函数一般只能找出每组重复数据中的一个,并不能指出哪些数据是重复的。怎么办?有个童鞋给出了一个非常有创意的解决方案。下面来看看代码:

1
2
3
4
5
6
7
# 模拟的数据框
dat <- data.frame(
id1 = c(1, 1, 1, 2, 2, 1),
id2 = c(2, 2, 3, 2, 2, 2),
id3 = c(4, 4, 6, 7, 7, 9)
)
dat
1
2
3
4
5
6
7
#> id1 id2 id3
#> 1 1 2 4
#> 2 1 2 4
#> 3 1 3 6
#> 4 2 2 7
#> 5 2 2 7
#> 6 1 2 9

可以看到,数据框中的第1,第2行是完全相同的,第4,第5行也是完全相同的。数据框小肉眼可以一眼看出来,但是一旦数据框有成千上万行,估计眼睛看瞎了也看出来,^_^。下面我们的任务就找出第1,2,4,5行数据。

该童鞋给出的解决方案是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
library(dplyr)
dat %>%
# 下面这一步非常巧妙,将每一列进行分组
# 很显然,分完组后,很容易求出哪些组有出现不止一次
group_by(id1, id2, id3) %>%
# 注意:这里是mutate(index = n()),不是summarize(index = n())
mutate(index = n()) %>%
# 选择那些出现不止一次的组
filter(index > 1) %>%
# 选择1前3列
select(1:3) %>%
# 去掉分组属性
ungroup()
1
2
3
4
5
6
7
#> # A tibble: 4 x 3
#> id1 id2 id3
#> <dbl> <dbl> <dbl>
#> 1 1 2 4
#> 2 1 2 4
#> 3 2 2 7
#> 4 2 2 7

上面代码中关键的步骤在于对所有的变量进行分组,以及用mutate()而不是summarize()。下面我们来看看为什么要这样做。

1
2
3
dat %>%
group_by(id1, id2, id3) %>%
mutate(index = n())
1
2
3
4
5
6
7
8
9
10
11
12
#> Source: local data frame [6 x 4]
#> Groups: id1, id2, id3 [4]
#>
#> # A tibble: 6 x 4
#> id1 id2 id3 index
#> <dbl> <dbl> <dbl> <int>
#> 1 1 2 4 2
#> 2 1 2 4 2
#> 3 1 3 6 1
#> 4 2 2 7 2
#> 5 2 2 7 2
#> 6 1 2 9 1
1
2
3
dat %>%
group_by(id1, id2, id3) %>%
summarize(index = n())
1
2
3
4
5
6
7
8
9
10
#> Source: local data frame [4 x 4]
#> Groups: id1, id2 [?]
#>
#> # A tibble: 4 x 4
#> id1 id2 id3 index
#> <dbl> <dbl> <dbl> <int>
#> 1 1 2 4 2
#> 2 1 2 9 1
#> 3 1 3 6 1
#> 4 2 2 7 2

看到两者的结果,豁然开朗了吧。原来聚合函数也能这么用!!

上面的解法非常巧妙,我自己是没有想到这么做的。我也给出了一种解决方案,只不过既没有上面代码的优雅,运行效率可能也不如上面的代码。

我的代码如下:

1
duplicated(dat)
1
#> [1] FALSE TRUE FALSE FALSE TRUE FALSE
1
2
dup_dat <- dat[duplicated(dat), ]
dup_dat
1
2
3
#> id1 id2 id3
#> 2 1 2 4
#> 5 2 2 7
1
2
3
4
5
6
7
n_dat <- nrow(dat)
n_dup <- nrow(dup_dat)
index <- integer(nrow(dat))
for (i in 1:n_dat) for (j in 1:n_dup) {
if (all(dat[i, ] == dup_dat[j, ]))
index[i] <- i
}
1
index
1
#> [1] 1 2 0 4 5 0
1
dat[index != 0, ]
1
2
3
4
5
#> id1 id2 id3
#> 1 1 2 4
#> 2 1 2 4
#> 4 2 2 7
#> 5 2 2 7

相比较而言,我的代码就要繁琐多了。