循环次序对R的速度是否重要

时间:2016-03-24 18:37:17

标签: r

我有一个问题,我想进行模拟研究,模拟取决于两个变量xy。在我的模拟研究中,xy是我想要评估的潜在值的向量(如此不同的组合)。此外,对于xy的每个组合,我想要多次重复(因为那里有一个随机项,xy的每次运行都会有所不同。

举一个我正在处理的例子,我有以下简化的例子:

x = 1:10
y = 11:20

iterations = 2000
iter = 1

solution = array(NA,c(length(x),3,iterations))
for(i in x){
    for(j in y){
        for(k in 1:iterations){ 
            z = rnorm(3) + c(i,j,1) 
            solution[i,,k] = z
        }
    }
}

然而,在我的实际问题中,在for循环中得到的代码评估起来要小得多。但是,输入结构和输出结构相同。

所以我想知道,使用上面的例子说,按顺序设置循环是最有效的,还是让k in 1:iterations成为最外层的循环并尝试使用一些更好因为我将在网格outer()z上评估函数(在此示例中为x),所以在该1循环中排序y命令?

此外,我对完全不同的设置和设计非常开放。在一天结束时,我希望能够获得基于xy的解决方案,并对所有迭代进行平均,即apply(solution, c(1,2),mean)

编辑:

正如我所建议的,这是我正在使用的实际代码。

library(survival)

iter = 2000
n = 120
base = 2
hr = 0.5
m.x = 3
m.y = m.x/hr

ANS = NULL
for (vecX in c(0.3, 0.5, 0.6, 0.7)){
out = NULL

    for (vecY in c(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95)){
        m.x.p = m.x/vecX
        m.y.p = m.y/vecX
        m.x.n = m.x
        m.y.n = m.y

        n.t = round(n*base/(base+1))
        n.c = n - n.t

        for (ii in 1:iter){
            n.t.p = rbinom(1, n.t, vecY)
            n.t.n = n.t - n.t.p
            n.c.p = rbinom(1, n.c, vecY)
            n.c.n = n.c - n.c.p

            S = c(rexp(n.t.p, log(2)/m.y.p), rexp(n.t.n, log(2)/m.y.n), rexp(n.c.p, log(2)/m.x.p), rexp(n.c.n, log(2)/m.x.n))

            data1 = data.frame(Group = c(rep("T", n.t), rep("C", n.c)), dx = c(rep("P", n.t.p), rep("N", n.t.n), rep("P", n.c.p), rep("N", n.c.n)), S)

            fit = survfit(Surv(data1$S)~data1$Group)
            coxfit = coxph(Surv(data1$S)~data1$Group)

            HR = exp(coxfit$coefficients)
            p.val=summary(coxfit)$logtest["pvalue"]

            out = rbind(out, c(vecX, vecY, n.t.p, n.t.n, n.c.p, n.c.n, HR, p.val))
        }

    }
    colnames(out) = c("vecX", "vecY", "n.t.p", "n.t.n", "n.c.p", "n.c.n", "HR", "p.val")

    ans = as.data.frame(out)
ANS = rbind(ANS, ans)

}

2 个答案:

答案 0 :(得分:7)

是的,我相信理论上应该有所作为(见下面的例子)。

R使用像Fortran这样的列主要排序(与C不同),因此为了最大限度地减少缓存未命中,您希望遍历列。因此,对于填充矩阵,最佳方法是外循环具有列索引的方法。

对于n维数组,您也要记住这一点。在n = 3的情况下,我想这意味着让图层成为最外面的循环,然后是列,然后是行。不过,我可能会在这里弄错。

我通过5000矩阵用5000运行了这个快速示例。我们看到差异大约50秒,fill_matrix2()更快。

    n <- 5000
    A <- matrix(NA, n, n)
    B <- matrix(NA, n, n)

    fill_matrix1 <- function(X, val) {
        for (i in 1:nrow(X)) {
            for (j in 1:ncol(X)) {
                X[i, j] <- val
            }
        }
        return(X)
    }

    fill_matrix2 <- function(X, val) {
        for (j in 1:ncol(X)) {
            for (i in 1:nrow(X)) {
                X[i, j] <- val
            }
        }
        return(X)
    }

    system.time(fill_matrix1(A, 0))
    system.time(fill_matrix2(B, 0))

答案 1 :(得分:4)

循环的顺序实际上与此无关。如果您对代码进行了分析(请参阅help("Rprof")),您会发现CPU时间花费在survfitcoxph等功能上。当然在增长out,你应该避免。预先分配out到它的最终大小并填充它而不是增长它。