计算 R 中两个向量重叠的实例

Count instances of overlap in two vectors in R

我希望创建一个矩阵来显示基于第二个变量的分组变量的重叠值实例的计数。具体来说,我希望确定主要研究在荟萃分析中的重叠程度,以便创建网络图。

所以,在这个例子中,我有三项荟萃分析,其中包括三项主要研究的一部分。

df <- data.frame(metas = c(1,1,1,2,3,3), studies = c(1,3,2,1,2,3))

   metas studies
1     1    1
2     1    3
3     1    2
4     2    1
5     3    2
6     3    3

我想 return:

  v1 v2 v3
1  3  1  2
2  1  1  0
3  2  0  2

第 1 行第 1 列中的值表示 Meta 分析 1 具有三项与其自身相同的研究(即,它包括三项研究)。第 1 列第 2 列表示 Meta 分析 1 与 Meta 分析 2 有一项共同研究。第 1 行第 3 列表示 Meta 分析 1 与 Meta 分析 3 有两项共同研究。

我相信您正在寻找交叉研究的对称矩阵。

dfspl <- split(df$studies, df$metas)
out <- outer(seq_along(dfspl), seq_along(dfspl),
             function(a, b) lengths(Map(intersect, dfspl[a], dfspl[b])))
out
#      [,1] [,2] [,3]
# [1,]    3    1    2
# [2,]    1    1    0
# [3,]    2    0    2

如果你需要他们的名字,你可以使用df$metas定义的名字:

rownames(out) <- colnames(out) <- names(dfspl)
out
#   1 2 3
# 1 3 1 2
# 2 1 1 0
# 3 2 0 2

如果您需要定义为 v 的名称加上元名称,请使用

rownames(out) <- colnames(out) <- paste0("v", names(dfspl))
out
#    v1 v2 v3
# v1  3  1  2
# v2  1  1  0
# v3  2  0  2

如果您需要了解它在做什么,outer 创建两个参数向量的展开,并将它们同时传递给函数。例如,

outer(seq_along(dfspl), seq_along(dfspl), function(a, b) { browser(); 1; })
# Called from: FUN(X, Y, ...)
debug at #1: [1] 1
# Browse[2]> 
a
# [1] 1 2 3 1 2 3 1 2 3
# Browse[2]> 
b
# [1] 1 1 1 2 2 2 3 3 3
# Browse[2]> 

我们最终要做的是找到每对研究的交集。

dfspl[[1]]
# [1] 1 3 2
dfspl[[3]]
# [1] 2 3
intersect(dfspl[[1]], dfspl[[3]])
# [1] 3 2
length(intersect(dfspl[[1]], dfspl[[3]]))
# [1] 2

当然,我们做了两次(一次用于 1 和 3,一​​次用于 3 和 1,这是相同的结果),所以这有点低效......最好将它们过滤为仅看上半部或下半部再转移到另一半


为更高效的过程进行了编辑(只计算每个交叉对 一次,从不计算自交叉。)

eg <- expand.grid(a = seq_along(dfspl), b = seq_along(dfspl))
eg <- eg[ eg$a < eg$b, ]
eg
#   a b
# 4 1 2
# 7 1 3
# 8 2 3
lens <- lengths(Map(intersect, dfspl[eg$a], dfspl[eg$b]))
lens
# 1 1 2       ## btw, these are just names, from eg$a
# 1 2 0 
out <- matrix(nrow = length(dfspl), ncol = length(dfspl))
out[ cbind(eg$a, eg$b) ] <- lens
out
#      [,1] [,2] [,3]
# [1,]   NA    1    2
# [2,]   NA   NA    0
# [3,]   NA   NA   NA
out[ lower.tri(out) ] <- out[ upper.tri(out) ]
diag(out) <- lengths(dfspl)
out
#      [,1] [,2] [,3]
# [1,]    3    1    2
# [2,]    1    1    0
# [3,]    2    0    2

与@r2evans 相同的想法,也是 Base R(少一点 eloquent)(根据需要进行编辑):

# Create df using sample data: 

df <- data.frame(metas = c(1,1,1,2,3,3), studies = c(1,7,2,1,2,3))

# Test for equality between the values in the metas vector and the rest of 
# of the values in the dataframe -- Construct symmetric matrix from vector: 

m1 <- diag(v1); m1[,1] <- m1[1,] <- v1 <- rowSums(data.frame(sapply(df$metas, `==`, 
                                                                    unique(unlist(df)))))

# Coerce matrix to dataframe setting the names as desired; dropping non matches:

df_2 <- setNames(data.frame(m1[which(rowSums(m1) > 0), which(colSums(m1) > 0)]),
                 paste0("v", 1:ncol(m1[which(rowSums(m1) > 0), which(colSums(m1) > 0)])))