我希望对以下循环进行矢量化:
for (i in 1:n) {
for (j in 1:m) {
temp_mat[i,j]=min(temp_mat[i,j],1);
}
}
我以为我可以做temp_mat=min(temp_mat,1)
,但这并没有给我预期的结果。有没有办法对这个循环进行矢量化以使其更快?
答案 0 :(得分:10)
只需使用temp_mat <- pmin(temp_mat, 1)
即可。有关并行最小值的更多用法,请参阅?pmin
。
示例:
set.seed(0); A <- matrix(sample(1:3, 25, replace = T), 5)
#> A
# [,1] [,2] [,3] [,4] [,5]
#[1,] 3 1 1 3 3
#[2,] 1 3 1 2 3
#[3,] 2 3 1 3 1
#[4,] 2 2 3 3 2
#[5,] 3 2 2 2 1
B <- pmin(A, 2)
#> B
# [,1] [,2] [,3] [,4] [,5]
#[1,] 2 1 1 2 2
#[2,] 1 2 1 2 2
#[3,] 2 2 1 2 1
#[4,] 2 2 2 2 2
#[5,] 2 2 2 2 1
由于您具有计算科学的背景,我想提供更多信息。
pmin
很快,但远没有达到高绩效。它的前缀“parallel”仅表示element-wise
。 R中“矢量化”的含义与HPC中的“SIMD矢量化”不同。 R是一种解释型语言,因此R中的“向量化”意味着选择C级循环而不是R级循环。因此,pmin
只是用一个简单的C循环编码。
真正的高性能计算应该受益于SIMD矢量化。我相信你了解SSE / AVX内在函数。因此,如果您使用_mm_min_pd
中的SSE2
编写一个简单的C代码,您将从pmin
获得~2倍的加速;如果您从AVX看到_mm256_min_pd
,您将从pmin
获得~4倍的加速。
不幸的是,R本身无法执行任何SIMD。我对Does R leverage SIMD when doing vectorized calculations?关于此问题的帖子有答案。对于您的问题,即使您将R链接到HPC BLAS,pmin
也不会从SIMD中受益,因为pmin
不涉及任何BLAS操作。所以更好的选择是自己编写编译代码。
答案 1 :(得分:4)
问题稍微有些混乱,因为min()
已经过矢量化。为了在这种特定情况下获得所需的结果,不必使用该功能。 逻辑子集提供了一种可能更有效(当然也更紧凑)的替代方案。
如果我正确理解了您想要的输出,可以使用一个命令实现代码中嵌套循环执行的矩阵修改:
temp_mat[temp_mat > 1] <- 1
希望这有帮助。
set.seed(123)
temp_mat <- matrix(2*runif(50),10)
#> temp_mat
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0.5751550 1.91366669 1.7790786 1.92604847 0.2856000
# [2,] 1.5766103 0.90666831 1.3856068 1.80459809 0.8290927
# [3,] 0.8179538 1.35514127 1.2810136 1.38141056 0.8274487
# [4,] 1.7660348 1.14526680 1.9885396 1.59093484 0.7376909
# [5,] 1.8809346 0.20584937 1.3114116 0.04922737 0.3048895
# [6,] 0.0911130 1.79964994 1.4170609 0.95559194 0.2776121
# [7,] 1.0562110 0.49217547 1.0881320 1.51691908 0.4660682
# [8,] 1.7848381 0.08411907 1.1882840 0.43281587 0.9319249
# [9,] 1.1028700 0.65584144 0.5783195 0.63636202 0.5319453
#[10,] 0.9132295 1.90900730 0.2942273 0.46325157 1.7156554
temp_mat[temp_mat > 1] <- 1
#> temp_mat
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0.5751550 1.00000000 1.0000000 1.00000000 0.2856000
# [2,] 1.0000000 0.90666831 1.0000000 1.00000000 0.8290927
# [3,] 0.8179538 1.00000000 1.0000000 1.00000000 0.8274487
# [4,] 1.0000000 1.00000000 1.0000000 1.00000000 0.7376909
# [5,] 1.0000000 0.20584937 1.0000000 0.04922737 0.3048895
# [6,] 0.0911130 1.00000000 1.0000000 0.95559194 0.2776121
# [7,] 1.0000000 0.49217547 1.0000000 1.00000000 0.4660682
# [8,] 1.0000000 0.08411907 1.0000000 0.43281587 0.9319249
# [9,] 1.0000000 0.65584144 0.5783195 0.63636202 0.5319453
#[10,] 0.9132295 1.00000000 0.2942273 0.46325157 1.0000000