使嵌套循环更有效?

时间:2012-02-16 22:01:40

标签: r r-faq

我正在使用以下脚本分析大量数据:

M <- c_alignment 
c_check <- function(x){
    if (x == c_1) {
        1
    }else{
        0
    }
}
both_c_check <- function(x){
    if (x[res_1] == c_1 && x[res_2] == c_1) {
        1
    }else{
        0
    }
}
variance_function <- function(x,y){
    sqrt(x*(1-x))*sqrt(y*(1-y))
}
frames_total <- nrow(M)
cols <- ncol(M)
c_vector <- apply(M, 2, max)
freq_vector <- matrix(nrow = sum(c_vector))
co_freq_matrix <- matrix(nrow = sum(c_vector), ncol = sum(c_vector))
insertion <- 0
res_1_insertion <- 0
for (res_1 in 1:cols){
    for (c_1 in 1:conf_vector[res_1]){
        res_1_insertion <- res_1_insertion + 1
        insertion <- insertion + 1
        res_1_subset <- sapply(M[,res_1], c_check)
        freq_vector[insertion] <- sum(res_1_subset)/frames_total
        res_2_insertion <- 0
        for (res_2 in 1:cols){
            if (is.na(co_freq_matrix[res_1_insertion, res_2_insertion + 1])){
                for (c_2 in 1:max(c_vector[res_2])){
                    res_2_insertion <- res_2_insertion + 1
                    both_res_subset <- apply(M, 1, both_c_check)
                    co_freq_matrix[res_1_insertion, res_2_insertion] <- sum(both_res_subset)/frames_total
                    co_freq_matrix[res_2_insertion, res_1_insertion] <- sum(both_res_subset)/frames_total
                }
            }
        }
    }
}
covariance_matrix <- (co_freq_matrix - crossprod(t(freq_vector)))
variance_matrix <- matrix(outer(freq_vector, freq_vector, variance_function), ncol = length(freq_vector))
correlation_coefficient_matrix <- covariance_matrix/variance_matrix

模型输入将是这样的:

1 2 1 4 3
1 3 4 2 1
2 3 3 3 1
1 1 2 1 2
2 3 4 4 2

我正在计算的是M[,i]中找到的每个州的二项式协方差,M[,j]中找到每个州。每行都是为该试验找到的状态,我想看看列的状态如何共同变化。

澄清:我找到了两个多项分布的协方差,但我是通过二项式比较来做的。

输入是4200 x 510矩阵,每列的c值平均约为15。我知道for循环在R中非常慢,但我不知道如何在这里使用apply函数。如果有人建议在这里正确使用apply,我真的很感激。现在脚本需要几个小时。谢谢!

2 个答案:

答案 0 :(得分:15)

我想写评论,但我有太多话要说。

首先,如果您认为申请更快,请查看Is R's apply family more than syntactic sugar?。它可能是,但它远未得到保证。

接下来,请不要在浏览代码时增加矩阵,这会让您的代码变得非常糟糕。预分配矩阵并将其填满,这可以将代码速度提高十倍以上。您通过代码生长不同的向量和矩阵,这是疯狂的(请原谅我强烈的演讲)

然后,查看?subset的帮助页面及其中的警告:

  

这是一种便于交互使用的便利功能。对于   编程最好使用标准的子集函数   [,特别是论证子集的非标准评估   可能会产生意想不到的后果。

始终。使用。指数。

此外,您一遍又一遍地重新计算相同的值。例如,fre_res_2为每个res_2和state_2计算res_1state_1组合的次数。这只是浪费资源。从循环中取出您不需要重新计算的内容,并将其保存在您可以再次访问的矩阵中。

哎呀,现在我来了:请使用矢量化函数。再想一想,看看你能从循环中拖出什么:这就是我所看到的计算核心:

cov <- (freq_both - (freq_res_1)*(freq_res_2)) /
(sqrt(freq_res_1*(1-freq_res_1))*sqrt(freq_res_2*(1-freq_res_2))) 

在我看来,你可以构造一个矩阵freq_both,freq_res_1和freq_res_2,并将它们用作那一行的输入。这将是整个协方差矩阵(不要将其称为covcov是一个函数)。退出循环。输入快速代码。

鉴于我不知道c_alignment中的内容,我不会为你重写你的代码,但你绝对应该摆脱C思维方式并开始思考R. / p>

让这成为一个开始:The R Inferno

答案 1 :(得分:3)

这不是4路嵌套循环,而是代码在每次迭代中增加内存的方式。这已经发生了4次我将# **放在cbindrbind行上。在这种情况下,R(和Matlab和Python)中的标准建议是提前分配然后填写。这就是apply函数的作用。只要已知结果数量,它们就会分配list,将每个结果分配给每个槽,然后在结束时将所有结果合并在一起。在您的情况下,您可以提前分配正确的大小矩阵,并在这4个点(粗略地说)分配。这应该与apply系列一样快,您可能会发现编码更容易。