R ::我有一个向量列表,如何计算两个向量在所有组合中共有的元素数量?

时间:2018-07-30 10:19:17

标签: r

我有一个向量列表...

A <- c("a", "b", "c", "d", "e")

B <- c("b", "e", "f", "g")

C <- c("c", "f", "g", "h", "i")

listofvectors <- list(A, B, C)

如何检查每个组合共有的元素数量? 因此,它将是比较的矩阵,并且具有相同的数字。这将给出代码指定的格式

output <- matrix(c(5, 2, 1, 2, 4, 2, 1, 2, 5), nrow = 3, ncol = 3)

dimnames(output) = list(c("A", "B", "C"), c("A", "B", "C"))
#  A B C
#A 5 2 1
#B 2 4 2
#C 1 2 5

对于单个向量,我可以使用A[A %in% B],但是我的实际列表中有300多个向量,因此对每种组合进行此操作都需要一段时间。

理想情况下,我想避免使用循环。我还看到函数combn()对于完成每个排列可能很有用。

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:0)

我不确定我是否能100%理解,但这也许对您有用:

l <- list(A,B,C)
sl_ <- seq_along(l)
eg_ <- expand.grid(sl_, sl_)

matrix(mapply(function(x,y) length(intersect(l[[x]],l[[y]])),eg_$Var1, eg_$Var2 ),nrow=length(l))
#      [,1] [,2] [,3]
# [1,]    5    2    1
# [2,]    2    4    2
# [3,]    1    2    5

尚未优化,因此,如果您遇到速度或内存问题,请告诉我。

答案 1 :(得分:0)

只要combn不会太大,您确实可以使用choose(n, 2)

common_elements <- combn(listofvectors, 2, 
                         FUN = function(x) intersect(x[[1]], x[[2]]), simplify = FALSE)
names(common_elements) <- vapply(combn(seq_along(listofvectors), 2, simplify = FALSE), 
                                 paste, collapse = "vs", FUN.VALUE = character(1))
#$`1vs2`
#[1] "b" "e"
#
#$`1vs3`
#[1] "c"
#
#$`2vs3`
#[1] "f" "g"
common_num <- lengths(common_elements)
#1vs2 1vs3 2vs3 
#   2    1    2 

library(Matrix)
#https://stackoverflow.com/a/51421029/1412059
fun <- function(x) {
  n <- 0.5 + sqrt(0.25 + 2 * length(x)) #calculate dimension
  i <- sequence(seq_len(n - 1)) #row indices
  j <- rep(seq_len(n - 1), seq_len(n - 1)) + 1 # column indices
  sparseMatrix(i = i, j = j, x = x, triangular = TRUE, dims = c(n, n))
}

output <- fun(common_num)
diag(output) <- lengths(listofvectors)
dimnames(output) <- rep(list(seq_along(listofvectors)), 2)
#3 x 3 sparse Matrix of class "dtCMatrix"
#  1 2 3
#1 5 2 1
#2 . 4 2
#3 . . 5

答案 2 :(得分:0)

最终与Roland的方法有些相似。

m = matrix(NA,nrow=length(listofvectors),ncol=length(listofvectors))

diag(m) = sapply(listofvectors,length)
m[lower.tri(m)] = apply(combn(1:3,2),2,function(x){length(intersect(listofvectors[[x[1]]],listofvectors[[x[2]]]))})
m[upper.tri(m)] = m[lower.tri(m)]

#     [,1] [,2] [,3]
#[1,]    5    2    1
#[2,]    2    4    2
#[3,]    1    2    5