r计算组中元素的组合

时间:2015-06-04 20:41:36

标签: r data.table

我希望计算两个元素的每个组合出现在同一组中的次数。

例如,使用:

> dat = data.table(group = c(1,1,1,2,2,2,3,3), id=c(10,11,12,10,11,13,11,13))
> dat
   group id
1:     1 10
2:     1 11
3:     1 12
4:     2 10
5:     2 11
6:     2 13
7:     3 11
8:     3 13

预期结果将是:

id.1  id.2  nb_common_appearances
10    11    2                      (in group 1 and 2)
10    12    1                      (in group 1)
11    12    1                      (in group 1)
10    13    1                      (in group 2)
11    13    2                      (in group 2 and 3)

4 个答案:

答案 0 :(得分:10)

这是data.table方法(与来自plyr的@ josilber大致相同):

pairs <- dat[, c(id=split(combn(id,2),1:2)), by=group ]
pairs[, .N, by=.(id.1,id.2) ]
#    id.1 id.2 N
# 1:   10   11 2
# 2:   10   12 1
# 3:   11   12 1
# 4:   10   13 1
# 5:   11   13 2

您也可以考虑在table

中查看结果
pairs[, table(id.1,id.2) ]
#     id.2
# id.1 11 12 13
#   10  2  1  1
#   11  0  1  2

您可以使用合并而不是combn

setkey(dat, group)
dat[ dat, allow.cartesian=TRUE ][ id<i.id, .N, by=.(id,i.id) ]

基准。对于大数据,合并可以更快一点(正如@DavidArenburg所假设的那样)。 @ Arun的回答更快:

DT <- data.table(g=1,id=1:(1.5e3),key="id")
system.time({a <- combn(DT$id,2)})
#    user  system elapsed
#    0.81    0.00    0.81
system.time({b <- DT[DT,allow.cartesian=TRUE][id<i.id]})
#    user  system elapsed
#    0.13    0.00    0.12
system.time({d <- DT[,.(rep(id,(.N-1L):0L),id[indices(.N-1L)])]})
#    user  system elapsed
#    0.01    0.00    0.02

(我忽略了分组操作,因为我觉得这对时间不重要。)

保护combn。 combn方法可以很好地扩展到更大的组合,而合并和@ Arun的答案虽然快得多,但却没有(据我所见) ):

DT2        <- data.table(g=rep(1:2,each=5),id=1:5)  
tuple_size <- 4

tuples <- DT2[, c(id=split(combn(id,tuple_size),1:tuple_size)), by=g ]
tuples[, .N, by=setdiff(names(tuples),"g")]    
#    id.1 id.2 id.3 id.4 N
# 1:    1    2    3    4 2
# 2:    1    2    3    5 2
# 3:    1    2    4    5 2
# 4:    1    3    4    5 2
# 5:    2    3    4    5 2

答案 1 :(得分:7)

使用data.table的另一种方式:

require(data.table)
indices <- function(n) sequence(n:1L) + rep(1:n, n:1)
dat[, .(id1 = rep(id, (.N-1L):0L), 
        id2 = id[indices(.N-1L)]), 
        by=group
  ][, .N, by=.(id1, id2)]
#    id1 id2 N
# 1:  10  11 2
# 2:  10  12 1
# 3:  11  12 1
# 4:  10  13 1
# 5:  11  13 2

答案 2 :(得分:6)

您可以重塑数据,使每个组中的每一对都在一个单独的行中(我已经使用了split-apply-combine进行该步骤),然后使用count中的plyr package计算唯一行的频率:

library(plyr)
count(do.call(rbind, lapply(split(dat, dat$group), function(x) t(combn(x$id, 2)))))
#   x.1 x.2 freq
# 1  10  11    2
# 2  10  12    1
# 3  10  13    1
# 4  11  12    1
# 5  11  13    2

答案 3 :(得分:2)

以下是dplyr方法,使用combn进行组合。

dat %>% 
    group_by(group) %>% 
    do(as.data.frame(t(combn(.[["id"]], 2)))) %>%
    group_by(V1, V2) %>% 
    summarise(n( ))

Source: local data frame [5 x 3]
Groups: V1

  V1 V2 n()
1 10 11   2
2 10 12   1
3 10 13   1
4 11 12   1
5 11 13   2