生成多个邻接矩阵的更快方法
Faster way to generate multiple adjacency matrix
假设我有一个如下所示的任意概率矩阵 P
,
P = matrix(c(0.3,0.2,0.2,0.2,0.3,0.2,0.2,0.2,0.3),3,3)
P
[,1] [,2] [,3]
[1,] 0.3 0.2 0.2
[2,] 0.2 0.3 0.2
[3,] 0.2 0.2 0.3
对于单个邻接矩阵,它的生成方式类似于(未加权,无自环)
tem = matrix(runif(3^2), nrow = 3)
tmpG = 1 * (tmpmat < P)
tmpG[lower.tri(tmpG)] <- 0
tmpG <- t(tmpG) + tmpG - diag(diag(tmpG))
但是,如果我需要生成100个邻接矩阵怎么办,所以我记下下面的代码
G = list()
for (i in 1:rep) {
tmpmat = matrix(runif(n^2), nrow = n)
tmpG = 1 * (tmpmat < P)
tmpG[lower.tri(tmpG)] <- 0
tmpG <- t(tmpG) + tmpG - diag(diag(tmpG))
if (noloop) {
diag(tmpG) = 0
}
G[[i]] = tmpG
}
在我的例子中,n >10000
和 T = 1000
,所以它非常慢,有什么更好的改进方法吗?
我认为我们可以做得更好,方法是仅使用所需长度的向量,并在最后将其放入矩阵中。我没有仔细检查过这个,你的代码没有任何评论可供我比较意图,所以在信任它之前请确保这是正确的。
p_vec = P[upper.tri(P, diag = !noloop)]
nn = length(p_vec)
tmpG_vec = runif(nn) < p_vec
tmpG = matrix(0, n, n)
tmpG[upper.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG[lower.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG
然后我们可以将其包装在 replicate
中进行迭代。
对更多 dimensions/higher 次重复进行基准测试,我们获得了大约 25% 的加速,但速度仍然很慢(我中止了 n = 5000
的基准测试,因为我厌倦了等待)。通过 运行 并行,您可能会获得相当多的速度 - 如果您有 8 个内核,则可以说几乎是 8 倍的加速。参见,例如 ,尽管可能有更现代的方法来做到这一点。
rep = 5L
n = 2000
noloop = TRUE
P = matrix(runif(n^2), n)
P = P %*% t(P)
P = P / colSums(P)
p_vec = P[upper.tri(P, diag = !noloop)]
nn = length(p_vec)
microbenchmark::microbenchmark(
loop = {
G = list()
for (i in 1:rep) {
tmpmat = matrix(runif(n^2), nrow = n)
tmpG = 1 * (tmpmat < P)
tmpG[lower.tri(tmpG)] <- 0
tmpG <- t(tmpG) + tmpG - diag(diag(tmpG))
if (noloop) {
diag(tmpG) = 0
}
G[[i]] = tmpG
}
},
diagonal = replicate(rep, {
tmpG_vec = runif(nn) < p_vec
tmpG = matrix(0, n, n)
tmpG[upper.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG[lower.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG
}),
times = 5L
)
# Unit: seconds
# expr min lq mean median uq max neval
# loop 1.525028 1.614544 2.136637 2.148771 2.387423 3.007417 5
# diagonal 1.312022 1.360457 1.592914 1.444902 1.602536 2.244652 5
假设我有一个如下所示的任意概率矩阵 P
,
P = matrix(c(0.3,0.2,0.2,0.2,0.3,0.2,0.2,0.2,0.3),3,3)
P
[,1] [,2] [,3]
[1,] 0.3 0.2 0.2
[2,] 0.2 0.3 0.2
[3,] 0.2 0.2 0.3
对于单个邻接矩阵,它的生成方式类似于(未加权,无自环)
tem = matrix(runif(3^2), nrow = 3)
tmpG = 1 * (tmpmat < P)
tmpG[lower.tri(tmpG)] <- 0
tmpG <- t(tmpG) + tmpG - diag(diag(tmpG))
但是,如果我需要生成100个邻接矩阵怎么办,所以我记下下面的代码
G = list()
for (i in 1:rep) {
tmpmat = matrix(runif(n^2), nrow = n)
tmpG = 1 * (tmpmat < P)
tmpG[lower.tri(tmpG)] <- 0
tmpG <- t(tmpG) + tmpG - diag(diag(tmpG))
if (noloop) {
diag(tmpG) = 0
}
G[[i]] = tmpG
}
在我的例子中,n >10000
和 T = 1000
,所以它非常慢,有什么更好的改进方法吗?
我认为我们可以做得更好,方法是仅使用所需长度的向量,并在最后将其放入矩阵中。我没有仔细检查过这个,你的代码没有任何评论可供我比较意图,所以在信任它之前请确保这是正确的。
p_vec = P[upper.tri(P, diag = !noloop)]
nn = length(p_vec)
tmpG_vec = runif(nn) < p_vec
tmpG = matrix(0, n, n)
tmpG[upper.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG[lower.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG
然后我们可以将其包装在 replicate
中进行迭代。
对更多 dimensions/higher 次重复进行基准测试,我们获得了大约 25% 的加速,但速度仍然很慢(我中止了 n = 5000
的基准测试,因为我厌倦了等待)。通过 运行 并行,您可能会获得相当多的速度 - 如果您有 8 个内核,则可以说几乎是 8 倍的加速。参见,例如
rep = 5L
n = 2000
noloop = TRUE
P = matrix(runif(n^2), n)
P = P %*% t(P)
P = P / colSums(P)
p_vec = P[upper.tri(P, diag = !noloop)]
nn = length(p_vec)
microbenchmark::microbenchmark(
loop = {
G = list()
for (i in 1:rep) {
tmpmat = matrix(runif(n^2), nrow = n)
tmpG = 1 * (tmpmat < P)
tmpG[lower.tri(tmpG)] <- 0
tmpG <- t(tmpG) + tmpG - diag(diag(tmpG))
if (noloop) {
diag(tmpG) = 0
}
G[[i]] = tmpG
}
},
diagonal = replicate(rep, {
tmpG_vec = runif(nn) < p_vec
tmpG = matrix(0, n, n)
tmpG[upper.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG[lower.tri(tmpG, diag = !noloop)] = tmpG_vec
tmpG
}),
times = 5L
)
# Unit: seconds
# expr min lq mean median uq max neval
# loop 1.525028 1.614544 2.136637 2.148771 2.387423 3.007417 5
# diagonal 1.312022 1.360457 1.592914 1.444902 1.602536 2.244652 5