通过替换双循环来加快矩阵乘法
Faster matrix multiplication by replacing a double loop
我有一个数据框,看起来有点像以下代码生成的(但更大)
set.seed(10)
mat <- matrix(rbinom(200, size=1, prob = .5), ncol = 10)
列中是问题,1 表示观察对特定问题感兴趣。我想生成一个比较所有观察结果的网络,并计算每个二人共同感兴趣的问题。
我生成了以下代码,看起来运行良好:
mat2 <- matrix(NA,20,20)
for(i in 1:nrow(mat)){
for(j in 1:nrow(mat)){
mat2[i,j] <- sum(as.numeric(mat[i,]==1) + as.numeric(mat[j,]==1) == 2)
}
}
所以我将每个条目与其他每个条目进行比较,只有当两个条目都有 1 个条目(即他们感兴趣)时,这总和为 2 并且将被计为对一个主题的共同兴趣。
我的问题是我的数据集非常大,循环现在已经运行了几个小时。
有谁知道如何在避免循环的同时做到这一点?
这应该会更快:
tmat <- t(mat==1)
mat4 <- apply(tmat, 2, function(x) colSums(tmat & x))
继续推广@jogo 的评论,因为它是迄今为止最快的(感谢提示,我也会在生产中使用它)。
set.seed(10)
mat <- matrix(rbinom(200, size=1, prob = .5), ncol = 10)
mat2 <- matrix(NA,20,20)
binary_mat <- mat == 1
tmat <- t(mat==1)
microbenchmark::microbenchmark(
"loop" = for(i in 1:nrow(mat)){
for(j in 1:nrow(mat)){
mat2[i,j] <- sum(as.numeric(mat[i,]==1) + as.numeric(mat[j,]==1) == 2)
}
},
"apply" = mat4 <- apply(tmat, 2, function(x) colSums(tmat & x)),
"matrix multiplication" = mat5 <- mat %*% t(mat),
"tcrossprod" = tcrossprod(mat),
"tcrossprod binary" = tcrossprod(binary_mat)
)
在我的机器上,这个基准测试的结果是
Unit: microseconds
expr min lq mean median uq max neval cld
loop 16699.634 16972.271 17931.82535 17180.397 17546.1545 31502.706 100 b
apply 322.942 330.046 395.69045 357.886 368.8300 4299.228 100 a
matrix multiplication 21.889 28.801 36.76869 39.360 43.9685 50.689 100 a
tcrossprod 7.297 8.449 11.20218 9.984 14.4005 18.433 100 a
tcrossprod binary 7.680 8.833 11.08316 9.601 12.0970 35.713 100 a
我有一个数据框,看起来有点像以下代码生成的(但更大)
set.seed(10)
mat <- matrix(rbinom(200, size=1, prob = .5), ncol = 10)
列中是问题,1 表示观察对特定问题感兴趣。我想生成一个比较所有观察结果的网络,并计算每个二人共同感兴趣的问题。
我生成了以下代码,看起来运行良好:
mat2 <- matrix(NA,20,20)
for(i in 1:nrow(mat)){
for(j in 1:nrow(mat)){
mat2[i,j] <- sum(as.numeric(mat[i,]==1) + as.numeric(mat[j,]==1) == 2)
}
}
所以我将每个条目与其他每个条目进行比较,只有当两个条目都有 1 个条目(即他们感兴趣)时,这总和为 2 并且将被计为对一个主题的共同兴趣。
我的问题是我的数据集非常大,循环现在已经运行了几个小时。
有谁知道如何在避免循环的同时做到这一点?
这应该会更快:
tmat <- t(mat==1)
mat4 <- apply(tmat, 2, function(x) colSums(tmat & x))
继续推广@jogo 的评论,因为它是迄今为止最快的(感谢提示,我也会在生产中使用它)。
set.seed(10)
mat <- matrix(rbinom(200, size=1, prob = .5), ncol = 10)
mat2 <- matrix(NA,20,20)
binary_mat <- mat == 1
tmat <- t(mat==1)
microbenchmark::microbenchmark(
"loop" = for(i in 1:nrow(mat)){
for(j in 1:nrow(mat)){
mat2[i,j] <- sum(as.numeric(mat[i,]==1) + as.numeric(mat[j,]==1) == 2)
}
},
"apply" = mat4 <- apply(tmat, 2, function(x) colSums(tmat & x)),
"matrix multiplication" = mat5 <- mat %*% t(mat),
"tcrossprod" = tcrossprod(mat),
"tcrossprod binary" = tcrossprod(binary_mat)
)
在我的机器上,这个基准测试的结果是
Unit: microseconds
expr min lq mean median uq max neval cld
loop 16699.634 16972.271 17931.82535 17180.397 17546.1545 31502.706 100 b
apply 322.942 330.046 395.69045 357.886 368.8300 4299.228 100 a
matrix multiplication 21.889 28.801 36.76869 39.360 43.9685 50.689 100 a
tcrossprod 7.297 8.449 11.20218 9.984 14.4005 18.433 100 a
tcrossprod binary 7.680 8.833 11.08316 9.601 12.0970 35.713 100 a