2015-06-04 150 views
9

我想統計兩個元素的每個組合出現在同一個組中的次數。r個組中元素的組合數

例如,使用:

> 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) 

回答

9

這裏是一個data.table辦法(大致相同@ josilber從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 

你也可以考慮觀看的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所假設的那樣)。 @阿倫的回答是快還是:

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辦法很好地擴展到更大的連擊,而合併和@阿倫的回答,而更快的對,不(據我可以看到):

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

其實我最喜歡的最後一種方法。爲什麼不推薦? –

+0

@DavidArenburg我想像做這樣的笛卡爾連接是非常緩慢的。此外,它僅適用於特殊情況下的對,而'c(id = split(combn(id,3),1:3))'是第一種方法的直接擴展。最後,在這裏導航'i。*'符號有點繁瑣,導致結果中出現「錯誤」的名字。 – Frank

+1

我不認爲二進制連接會很慢,但由於是笛卡爾連接,可能會花費一些額外的內存。 –

6

你可以重塑你的數據,每個組中每對在一個單獨的行(我用分步應用合併),然後使用plyr包中的count來計算唯一行的頻率:

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 
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 
6

使用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 
+0

一般來說,數據集必須訂購'setorder(dat,group,id)' –