删除所有重复的行,除非有“相似”行

时间:2019-05-23 21:13:45

标签: r data.table

我有以下data.table

library(data.table)
dt = data.table(c(1, 1, 1, 2, 2, 2, 2, 3, 4),
                c(4, 4, 4, 5, 5, 6, 7, 4, 5))
   V1 V2
1:  1  4
2:  1  4
3:  1  4
4:  2  5
5:  2  5
6:  2  6
7:  2  7
8:  3  4
9:  4  5

我想研究给定V2的{​​{1}}的不同值。但是,如果给定V1的{​​{1}}的所有值都相同,那我就不感兴趣,因此我想删除这样的行。

查看上面的示例,前三行完全相同(V2V1),因此我希望将其删除。

但是,接下来的四行包括两行相同的行,其他行具有不同的V1=1。在这种情况下,我想显示给定V2=4的{​​{1}}的三个可能值:V2V2V1 = 2

最后两行具有唯一的(2, 5):属于“所有行都完全相同”类别,因此也应将其删除。

我能想到的最好的是this answer

(2, 6)

这显然不令人满意:它删除了(2, 7)对,因为它们是重复的,并且保留了V1dt[!duplicated(dt) & !duplicated(dt, fromLast = TRUE), ] V1 V2 1: 2 6 2: 2 7 3: 3 4 4: 4 5 对,因为它们是唯一的,因此没有标记(2,5)通过。

另一个选择就是简单地调用

(3,4)

但是它保留了我要删除的(4,5)duplicated()unique(dt) V1 V2 1: 1 4 2: 2 5 3: 2 6 4: 2 7 5: 3 4 6: 4 5 对。

最后,我要寻找的结果是:

(1,4)

其他任何格式也可以接受,例如:

(3,4)

(显示每个“有趣的” (4,5)的{​​{1}}可能的值)

我不知道如何区分 V1 V2 1: 2 5 2: 2 6 3: 2 7 情况(所有行都相同)和 V1 V2.1 V2.2 V2.3 1: 2 5 6 7 情况(有重复项,但是还有其他行具有相同的{{ 1}},因此我们必须删除重复的V2,但要保留一个副本)。

至于唯一行,我写了一个非常丑陋的电话,但只有在唯一行的情况下,它才有效。如果有两个,例如上面的示例,它将失败。

4 个答案:

答案 0 :(得分:5)

一种选择是按'V1'进行分组,获得唯一元素长度大于1的分组的索引,然后采用unique

unique(dt[dt[, .(i1 = .I[uniqueN(V2) > 1]), V1]$i1])
#   V1 V2
#1:  2  5
#2:  2  6
#3:  2  7

或者如@ r2evans所述

unique(dt[, .SD[(uniqueN(V2) > 1)], by = "V1"])

注意:OP的数据集是data.table,而data.table方法是很自然的方法


如果我们需要一个tidyverse选项,则可以与上述data.table选项相提并论

library(dplyr)
dt %>%
   group_by(V1) %>% 
   filter(n_distinct(V2) > 1) %>% 
   distinct()

答案 1 :(得分:2)

还有一种dplyr可能性:

dt %>%
 group_by(V1) %>%
 filter(n_distinct(V2) != 1 & !duplicated(V2))

     V1    V2
  <dbl> <dbl>
1     2     5
2     2     6
3     2     7

或者:

dt %>%
 group_by(V1) %>%
 filter(n_distinct(V2) != 1) %>%
 group_by(V1, V2) %>%
 slice(1)

答案 2 :(得分:2)

对于您的情况,以R为基础

dt[ave(dt$V2,dt$V1,FUN=function(x) length(unique(x)))>1&!duplicated(dt)]
   V1 V2
1:  2  5
2:  2  6
3:  2  7

答案 3 :(得分:2)

使用if语句可以使代码更简洁,并且可以说data.table'更多:

dt[, if (uniqueN(V2) > 1) unique(V2), by = V1]

#    V1 V1
# 1:  2  5
# 2:  2  6
# 3:  2  7

但是无法正确获取列名...

简洁一些的解决方案:

dt[, .(V2 = if (uniqueN(V2) > 1) unique(V2) else numeric(0)), by = V1]

dt[, .SD[if (uniqueN(V2) > 1) !duplicated(V2)], by = V1]

#    V1 V2
# 1:  2  5
# 2:  2  6
# 3:  2  7