Frage r zählen Kombinationen von Elementen in Gruppen


Ich möchte zählen, wie oft jede Kombination von zwei Elementen in derselben Gruppe erscheint.

Zum Beispiel mit:

> 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

Das erwartete Ergebnis wäre:

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)

9
2018-06-04 20:41


Ursprung


Antworten:


Hier ist ein data.table Ansatz (ungefähr das gleiche wie @ Josilber's aus plyr):

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

Sie können auch die Ergebnisse in a betrachten table:

pairs[, table(id.1,id.2) ]
#     id.2
# id.1 11 12 13
#   10  2  1  1
#   11  0  1  2

Sie können Zusammenführungen anstelle von verwenden combn:

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

Benchmarks. Bei großen Daten können die Zusammenführungen ein wenig schneller sein (wie von @DavidArenburg angenommen). @ Aruns Antwort ist noch schneller:

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

(Ich habe die Gruppe ausgelassen, weil ich nicht glaube, dass es für die Zeitplanung wichtig sein wird.)


Zur Verteidigung von Combn. Das combn Ansatz erstreckt sich gut zu größeren Combos, während Merges und @ Aruns Antwort, während viel schneller für Paare, nicht (soweit ich sehe):

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

9
2018-06-04 20:51



Sie könnten Ihre Daten so umformen, dass jedes Paar in jeder Gruppe in einer separaten Zeile steht (ich habe für diesen Schritt Split-Apply-Combine verwendet) und dann verwendet count von dem plyr Paket, um die Häufigkeit eindeutiger Zeilen zu zählen:

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

6
2018-06-04 20:47



Ein anderer Weg mit 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

6
2018-06-04 21:48



Hier ist ein dplyr Annäherung, mit combn um die Kombinationen zu machen.

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

2
2018-06-04 21:09