【问题标题】:Match/group duplicate rows (indices)匹配/分组重复行(索引)
【发布时间】:2015-12-16 23:46:23
【问题描述】:

如何有效地匹配/分组重复行的索引?

假设我有这个数据集:

set.seed(14)
dat <- data.frame(mtcars[sample(1:5, 14, TRUE), ])[sample.int(14), ]
rownames(dat) <- NULL
dat 

##     mpg cyl disp  hp drat    wt  qsec vs am gear carb
## 1  22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## 2  21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## 3  18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## 4  22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## 5  22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## 6  22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## 7  18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## 8  18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## 9  22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## 10 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## 11 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## 12 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## 13 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## 14 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4

我可以使用

找到所有重复项(包括第一个重复项)的索引
which_duplicated <- function(dat){
    which(duplicated(dat) | duplicated(dat[nrow(dat):1, ])[nrow(dat):1])
}

which_duplicated(dat)

## [1]  1  2  3  4  5  6  7  8  9 10 11 13

但我希望能够匹配这些索引,如下所示:

list(
    c(2, 13),
    c(1, 4, 5, 6, 9),
    c(3, 7, 8, 10, 11)
)

我怎样才能有效地做到这一点?

【问题讨论】:

  • 慢但是Filter(function(x) length(x) &gt; 1, by(dat, as.list(dat), rownames))

标签: r


【解决方案1】:

这是使用“data.table”的一种可能性:

library(data.table)
as.data.table(dat)[, c("GRP", "N") := .(.GRP, .N), by = names(dat)][
                   N > 1, list(list(.I)), by = GRP]
##    GRP             V1
## 1:   1      1,4,5,6,9
## 2:   2           2,13
## 3:   3  3, 7, 8,10,11

基本思想是创建一个“分组”其他列的列(使用.GRP)以及一个计算有多少重复行的列(使用.N),然后过滤任何包含更多的列多于一个重复项,并将“GRP”列放入list

【讨论】:

    【解决方案2】:

    我们可以使用dplyr。使用与@AnandaMahto 的帖子类似的方法,我们创建一个行索引列名(add_rownames(),按所有列分组,我们filter 数据集每个组中的行数大于1,summarise ' rowname' 到 list 并提取 list 列。

    library(dplyr)
    add_rownames(dat) %>% 
          group_by_(.dots= names(dat)) %>% 
          filter(n()>1) %>%
          summarise(rn= list(rowname))%>%
          .$rn
     #[[1]]
     #[1] "3"  "7"  "8"  "10" "11"
    
     #[[2]]
     #[1] "2"  "13"
    
     #[[3]]
     #[1] "1" "4" "5" "6" "9"
    

    【讨论】:

    • 两种解决方案都非常出色(与我自己不会想到的相同逻辑)且高效。我用绿色勾号标记了 Ananda 的解决方案,因为他首先使用逻辑。谢谢+1
    猜你喜欢
    • 2012-12-30
    • 2018-02-22
    • 2014-09-07
    • 2017-05-08
    • 2011-10-22
    • 1970-01-01
    • 2021-07-09
    • 2017-08-28
    • 1970-01-01
    相关资源
    最近更新 更多