我希望创建一个矩阵,该矩阵显示基于第二个变量的分组变量的重叠值实例的计数。具体来说,我希望通过元分析来确定初级研究重叠的程度,以便创建一个网络图。
所以,在这个例子中,我有三个元分析,包括三个主要研究的一部分。
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有两个共同的研究。
发布于 2020-03-22 05:07:42
我相信你在寻找一个交叉研究的对称矩阵。
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发布于 2020-03-22 06:08:26
与@r2evans相同的想法,也是Base (口才稍差一点)(根据需要编辑):
# 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)])))https://stackoverflow.com/questions/60795913
复制相似问题