如何避免我非常大的嵌套 for 循环?

bir*_*ird 1 loops for-loop r nested-loops

我必须使用物理公式来实现一些模拟。在一个公式中,有许多变量。我想用 100 个样本改变这些变量。对于每个样本,我必须使用所有组合进行计算。简化的 for 循环更好地解释了我想要做什么:

set.seed(3)
a = rnorm(100)
b = rnorm(100)
c = rnorm(100)
d = rnorm(100)
f = rnorm(100)

for (a in 1:length(a)) {
        
        for (b in 1:length(b)) {
                
                for (c in 1:length(c)) {
                        
                        for (d in 1:length(d)) {
                                
                                for (f in 1:length(f)) {
                                        
                                        value = a + b / c * d - f # for illustrative purposes only
                                        # .... 
                                        # ... then I append the value to a vector etc.
                                        
                                }
                                
                        }
                        
                }
                
        }
        
}
Run Code Online (Sandbox Code Playgroud)

如您所见,当要改变的参数数量(每个参数 100 个样本)增加时,模拟数量呈指数增加,计算时间也会增加。我必须改变 10-15 个参数并计算所有参数组合的“值”。有什么办法(完全)可以避免这些循环?在处理这样的大型计算时,良好的编程习惯是什么?

Kon*_*lph 6

您所做的本质上是使用一些给定的操作创建一个大型的多维排列数组,并将结果展平。

可以使用outer以下方法创建置换数组:例如,outer(a, b, `+`)是 的所有成对组合的数组a[i] + b[j]。整个数组由(注意运算符优先级!)给出:

array = outer(outer(a, outer(outer(b, c, `/`), d), `+`), f, `-`)
Run Code Online (Sandbox Code Playgroud)

(或者,outer(a, b)与 相同outer(a, b, `*`),也可以写为a %o% b。)

要展平数组,请使用as.vector

value = as.vector(array)
Run Code Online (Sandbox Code Playgroud)

结果与使用expand.grid. 不同之处在于 usingexpand.grid更具可读性:

value = with(expand.grid(a = a, b = b, c = c, d = d, f = f), a + b / c * d - f)
Run Code Online (Sandbox Code Playgroud)

...但慢得多,并且使用了大量的内存。

我们可以通过创建自定义运算符来提高数组排列的可读性:

make_outer = function (f) function (a, b) outer(a, b, f)
`%o+%` = make_outer(`+`)
`%o-%` = make_outer(`-`)
`%o/%` = make_outer(`/`)

value = as.vector(a %o+% ((b %o/% c) %o% d) %o-% f)
Run Code Online (Sandbox Code Playgroud)