加速R中的循环

Ted*_*sby 1 loops memory-management r

这不是要求新代码,而是更多关于R如何进行这样的计算.当然,我会采取任何和所有建议来提高效率.

假设我有一个这样的脚本:

x=matrix(complex(1:10,1:10,imaginary = 1:10),ncol=2)
y=x+300
raw=list(x,y)
raw_complex = list(raw,raw,raw,raw)
Run Code Online (Sandbox Code Playgroud)

这是一个复杂矩阵列表.我正试图从中获得相角,这是:phase = atan(Im(x)/Re(x))

我目前的代码是:

for (m in 1:length(raw_complex)){
  for (n in 1:length(raw_complex[[m]])){
    for (i in 1:dim(raw_complex[[m]][[n]])[1]){
      for (j in 1:dim(raw_complex[[m]][[n]])[2]){
 raw_complex[[m]][[n]][i,j]=(atan(Im(raw_complex[[m]][[n]][i,j])/Re(raw_complex[[m]][[n]][i,j])))
      }}}}
Run Code Online (Sandbox Code Playgroud)

我知道,我知道,避免在R中使用循环.但从概念上讲,这使我更容易看到正在发生的事情,而不是lapply或sapply.

我的问题是,在循环的每次迭代中,R是在内存中复制整个列表或矩阵而不是一次拉出一个单独的元素?显然,我宁愿每次迭代都没有R制作完整的副本.

我的真实数据集有一个4的列表,在列表的每个元素中有95个矩阵.每个矩阵都是145x901,所以你可以看到我希望如何尽可能快.

哦,如果输出是实数而不是复数,那就太好了.我已尝试添加前面as.numeric()atan()但似乎没有帮助.

谢谢!

And*_*rie 5

利用R被矢量化的事实.具体来说,这意味着您可以直接在矢量或矩阵上应用许多计算.

例如,为阶段定义一个函数:

phase <- function(x)atan(Im(x)/Re(x))
phase(x)
Run Code Online (Sandbox Code Playgroud)

使用这个单一的简单函数,您可以计算矩阵中每个单元格的相位:

          [,1]      [,2]
[1,] 0.7853982 0.7853982
[2,] 0.7853982 0.7853982
[3,] 0.7853982 0.7853982
[4,] 0.7853982 0.7853982
[5,] 0.7853982 0.7853982
Run Code Online (Sandbox Code Playgroud)

现在,您只需一步即可phase在列表中应用此功能.为此,您可以使用lapply():

lapply(raw, phase)
[[1]]
          [,1]      [,2]
[1,] 0.7853982 0.7853982
[2,] 0.7853982 0.7853982
[3,] 0.7853982 0.7853982
[4,] 0.7853982 0.7853982
[5,] 0.7853982 0.7853982

[[2]]
            [,1]       [,2]
[1,] 0.003322247 0.01960533
[2,] 0.006622420 0.02279735
[3,] 0.009900667 0.02596819
[4,] 0.013157135 0.02911798
[5,] 0.016391974 0.03224688
Run Code Online (Sandbox Code Playgroud)

但是你真正想要的是将这个函数递归地应用到你的列表列表中.为此,函数rapply()存在 - r代表递归:

z <- rapply(raw_complex, phase, how = "list")
str(z)
List of 4
 $ :List of 2
  ..$ : num [1:5, 1:2] 0.785 0.785 0.785 0.785 0.785 ...
  ..$ : num [1:5, 1:2] 0.00332 0.00662 0.0099 0.01316 0.01639 ...
 $ :List of 2
  ..$ : num [1:5, 1:2] 0.785 0.785 0.785 0.785 0.785 ...
  ..$ : num [1:5, 1:2] 0.00332 0.00662 0.0099 0.01316 0.01639 ...
 $ :List of 2
  ..$ : num [1:5, 1:2] 0.785 0.785 0.785 0.785 0.785 ...
  ..$ : num [1:5, 1:2] 0.00332 0.00662 0.0099 0.01316 0.01639 ...
 $ :List of 2
  ..$ : num [1:5, 1:2] 0.785 0.785 0.785 0.785 0.785 ...
  ..$ : num [1:5, 1:2] 0.00332 0.00662 0.0099 0.01316 0.01639 ...
Run Code Online (Sandbox Code Playgroud)

这将是快速的 - 不是因为你避免了循环 - 而是因为你在矩阵而不是每个单元格上进行计算.

更重要的是,它简洁易读.