计数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

我希望它返回:

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(并且不那么雄辩((根据需要编辑(:

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

最新更新