另一个适用问题

时间:2014-11-09 21:13:13

标签: r apply

我完全相信高效的R程序应该尽可能避免使用循环,而应该使用apply函数的大系列。 但如果没有痛苦,这是不可能的。 例如,我面临一个问题,其解决方案涉及应用函数中的总和,因此结果列表减少到单个值,这不是我想要的。 具体来说,我会尽量简化我的问题 假设N =100

sapply(list(1:N), function(n) (
    choose(n,(floor(n/2)+1):n) * 
    eps^((floor(n/2)+1):n) * 
    (1- eps)^(n-((floor(n/2)+1):n))))

正如您所看到的,内部函数会导致构建向量的长度爆炸 而使用里面的和将把所有东西都折成单值

sapply(list(1:N), function(n) (
    choose(n,(floor(n/2)+1):n) * 
    eps^((floor(n/2)+1):n) * 
    (1- eps)^(n-((floor(n/2)+1):n))))

我想要的是N的程度列表。 所以你怎么看?我怎么修理它?

1 个答案:

答案 0 :(得分:7)

您的问题不包含可重现的代码(什么是“eps”?),但关于for循环和优化代码的一般观点:

For循环并不是非常慢。由于内存分配给对象的方式不正确,因此循环速度极慢。对于原始对象(如向量),修改字段中的值的成本很小 - 但扩展向量的长度/成本相当昂贵,因为您实际上正在创建一个全新的对象,为该对象寻找空间,复制名称,删除旧对象等。对于非原始对象(比如数据帧),它甚至更昂贵,因为每次修改,即使它不改变data.frame的长度,也会触发这个过程

但是:有一些方法可以优化for循环并使它们快速运行。最简单的指导方针是:

  1. 不要运行写入data.frame的for循环。请使用plyr或dplyr或data.table,具体取决于您的偏好。
  2. 如果您正在使用矢量并且可以提前知道输出的长度,它将更快地工作。在写入之前指定输出对象的大小。
  3. 不要把自己扭成结,避免循环。
  4. 所以在这种情况下 - 如果你只为N中的每个东西生成一个单独的值,你可以用向量完美地完成它的工作:

    #Create output object. We're specifying the length in advance so that writing to
    #it is cheap
    output <- numeric(length = length(N))
    
    #Start the for loop
    for(i in seq_along(output)){
        output[i] <- your_computations_go_here(N[i])
    }
    

    这实际上并不是特别慢 - 因为你正在写一个向量而你已经预先指定了长度。而且由于data.frames实际上是同等大小的向量列表,你甚至可以解决使用这个在data.frames上运行for循环的一些问题。如果您只是写入data.frame中的单个列,只需将其创建为向量,然后通过df$new_col <- output将其写入data.frame。你将得到相同的输出,就好像你已经遍历data.frame,但它会更快地工作,因为你只需要修改它一次。