列出所有可能的组合并取交集

12

我有一个向量列表:

> l <- list(A=c("one", "two", "three", "four"), B=c("one", "two"), C=c("two", "four", "five", "six"), D=c("six", "seven"))

> l
$A
[1] "one"   "two"   "three" "four"

$B
[1] "one" "two"

$C
[1] "two"  "four" "five" "six"

$D
[1] "six"   "seven"

我希望能够计算列表元素所有可能的两两组合之间重叠的长度,格式不限。

AintB 2
AintC 2
AintD 0
BintC 1
BintD 0
CintD 1

我知道可以使用combn(x, 2)来获取向量中所有可能的成对组合的矩阵,而length(intersect(a, b))将给出两个向量重叠部分的长度,但我无法想出如何将这两个东西结合起来。

非常感谢任何帮助!谢谢。


3个回答

25

如果我理解正确,你可以查看crossprodstack

crossprod(table(stack(l)))
#    ind
# ind A B C D
#   A 4 2 2 0
#   B 2 2 1 0
#   C 2 1 4 1
#   D 0 0 1 2
你可以按照以下方式扩展这个想法,以获得只包含相关值的data.frame

  1. 编写一个漂亮的函数

  2. listIntersect <- function(inList) {
      X <- crossprod(table(stack(inList)))
      X[lower.tri(X)] <- NA
      diag(X) <- NA
      out <- na.omit(data.frame(as.table(X)))
      out[order(out$ind), ]
    }
    
  3. 应用它

  4. listIntersect(l)
    #    ind ind.1 Freq
    # 5    A     B    2
    # 9    A     C    2
    # 13   A     D    0
    # 10   B     C    1
    # 14   B     D    0
    # 15   C     D    1
    

性能似乎相当不错。

扩展列表

L <- unlist(replicate(100, l, FALSE), recursive=FALSE)
names(L) <- make.unique(names(L))

设置一些函数进行测试:

fun1 <- function(l) listIntersect(l)
fun2 <- function(l) apply( combn( l , 2 ) , 2 , function(x) length( intersect( unlist( x[1]) , unlist(x[2]) ) ) )
fun3 <- function(l) {
  m1 <- combn(names(l),2)
  val <- sapply(split(m1, col(m1)),function(x) {x1 <- l[[x[1]]]; x2 <- l[[x[2]]]; length(intersect(x1, x2))})
  Ind <- apply(m1,2,paste,collapse="int")
  data.frame(Ind, val, stringsAsFactors=F) 
}

看看时间安排:

system.time(F1 <- fun1(L))
#    user  system elapsed 
#    0.33    0.00    0.33
system.time(F2 <- fun2(L))
#    user  system elapsed 
#    4.32    0.00    4.31 
system.time(F3 <- fun3(L))
#    user  system elapsed 
#    6.33    0.00    6.33 

每个人似乎都在以不同的方式排序结果,但数字匹配:

table(F1$Freq)
# 
#     0     1     2     4 
# 20000 20000 29900  9900 
table(F2)
# F2
#     0     1     2     4 
# 20000 20000 29900  9900 
table(F3$val)
# 
#     0     1     2     4 
# 20000 20000 29900  9900 

1
读者注意:如果您想将“stack”与“list”一起使用,它需要名称。 - A5C1D2H2I1M1N2O1R2T1
这是一个非常高效的解决方案! - Helix123
这太优雅了!! - 林鼎棋
这太棒了,节省了我大量的循环计算交集! - Ahdee

19

combn 也可以与列表结构一起使用,您只需要对结果进行一些 unlist 操作即可使用 intersect...

# Get the combinations of names of list elements
nms <- combn( names(l) , 2 , FUN = paste0 , collapse = "" , simplify = FALSE )

# Make the combinations of list elements
ll <- combn( l , 2 , simplify = FALSE )

# Intersect the list elements
out <- lapply( ll , function(x) length( intersect( x[[1]] , x[[2]] ) ) )

# Output with names
setNames( out , nms )
#$AB
#[1] 2

#$AC
#[1] 2

#$AD
#[1] 0

#$BC
#[1] 1

#$BD
#[1] 0

#$CD
#[1] 1

如何获取任何集合中共同或相交的元素。就像您所解释和展示的那样,它显示了与任何交集相同的元素总数。 - PesKchan

3

尝试:

m1 <- combn(names(l),2)
val <- sapply(split(m1, col(m1)),function(x) {x1 <- l[[x[1]]]; x2 <- l[[x[2]]]; length(intersect(x1, x2))})
Ind <- apply(m1,2,paste,collapse="int")
data.frame(Ind, val, stringsAsFactors=F)   
#      Ind val
# 1 AntB   2
# 2 AntC   2
# 3 AntD   0
# 4 BntC   1
# 5 BntD   0
# 6 CntD   1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接