【问题标题】:Optimize R nested loops with apply or similar使用 apply 或类似方法优化 R 嵌套循环
【发布时间】:2020-05-24 14:19:23
【问题描述】:

我在这里向您展示的代码准确地计算出我想要的,除了一个问题:对于大型数据集,它只需要 太长。因此,我想知道 是否有使用 apply() 系列或其他方式的替代解决方案

我总是很难将嵌套循环重新表达为矢量函数。你觉得你能帮我一把吗?我将不胜感激;)

所以,在应用这个嵌套循环之前,我已经有了:

  1. 2 个数据帧,分别称为 “DATA”“DATA_100_WELLS”。从他们那里,我只需要变量“WELL”(分类)和“DELTA”(数字)
  2. 3个全局变量,分别称为ti、ta和tb,会出现在嵌套循环中
  3. 一个“chosen_model”,我将在函数“predict”中使用它

到这里……如果很难理解,请见谅……

#loop for each WELL from "DATA_100_WELLS"
for (WELL_PROCESS in unique(DATA_100_WELLS$WELL)) {
  #----------------------------------------------------------------------------------
  #I take just 1 of the wells
  print("WELL------------------------------------------------------------")
  print(WELL_PROCESS)
  DATA_WELL <- DATA_100_WELLS[DATA_100_WELLS$WELL==WELL_PROCESS,] #select just the well I want

  #I calculate some stuff (Var_est0, sigma, linf, lsup, Za, Zb, n_ray and A)
  DATA_WELL$Var_est0 = predict(chosen_model,data.frame(predict=DATA_WELL$predict))
  DATA_WELL$sigma    = sqrt(DATA_WELL$Var_est0)
  DATA_WELL$linf     <- DATA_WELL$predict+DATA_WELL$sigma*ta
  DATA_WELL$lsup     <- DATA_WELL$predict+DATA_WELL$sigma*tb
  Za                 <- qnorm(alfa/2)
  Zb                 <- qnorm(1-alfa/2)
  n_ray              <- mean(DATA_WELL$predict)
  A                  =  sum(DATA_WELL$Var_est0)

  #Then i create an empty df called "TABLE", and slice off the heading
  TABLE<-data.frame(well="",d=0,p=0)
  TABLE<-TABLE[-1,]
  #After that, I iterate over each WELL from the second df, "DATA"
  for (well in unique(DATA$WELL)){
    print(paste("Process...: ",well,sep=""))
    #I calculate variable "large",based on max value of the existing variable "DELTA" (numeric)
    large = max(DATA[DATA$WELL==well,]$DELTA)
    #cicle from 1 max.distance (large-1)
    for (d in c(1:(large-1))){
      #cicle from position 1 to large-distance (look how this turns to be symmetric)
      for (pos in (1:(large-d))){
        #I did all of this to calculate variables ti and tj 
        ti = DATA[DATA$WELL==well & DATA$DELTA==pos,]$ti
        tj = DATA[DATA$WELL==well & DATA$DELTA==pos+d,]$ti
        #I append the results into the once empty df "TABLE", and calculate p based on ti*tj
        TABLE<-rbind(TABLE,data.frame(well=well,d=d,p=ti*tj))
      }
    }
  }

参考文献:

  1. “WELL”是一个分类变量,指定名称
  2. "DELTA" 是一个已经存在的变量,存在于两个df中
  3. 总共有 4 个循环:首先,针对 df1 中的每个 WELL。其次,对于 df2 中的每个 WELL。第三,对于向量 1:(large-1) 中的每个距离。最后,对于向量 1:(large-1) 中的每个位置,进行对称计算,并将其存储在 df "TABLE" 中。

就是这样。如有必要,也可以用 Python 编写解决方案。

说真的,谢谢!!

【问题讨论】:

  • 没有任何样本数据可供测试,我什至不会尝试这个!几个建议;不要在循环内绑定。 bind 命令在内存中进行复制,当数据帧的大小增加时会变成一个缓慢的过程。其次,不要通过DATA$WELL==well 不断检查/过滤,而是使用 split 函数创建要使用的较小数据帧的列表。较小的内存使用和减少比较次数会稍微提高性能。最后,尝试对内循环进行矢量化,这将是最大的性能提升。
  • 没有基准测试、分析或minimal reproducible example?我不确定人们应该如何提供帮助。
  • apply 系列函数比for 循环更快的假设通常是错误的。这样你不会看到太大的进步。

标签: python r loops optimization apply


【解决方案1】:

正如 cmets 中所提到的,如果没有可重现的示例,虽然我会尝试一下,但很难提供帮助。以下更改应该会加快速度:

1) 不要将对象重复绑定到自身,而是将元素插入列表并在循环之后调用 bind_rows。

2) 将 DATA df 子集到 wells_df 中,用于外循环中的每个井。

甚至比 #2 更好,但未实现,您可以在循环之前通过 WELL 将 DATA 拆分为一个列表,这样您只需遍历 DATA 一次。

我没有运行此代码。

table_agg <- list()

for (well in unique(DATA$WELL)){
  print(paste("Process...: ",well,sep=""))
  #I calculate variable "large",based on max value of the existing variable "DELTA" (numeric)
  wells_df <- DATA[DATA$WELL==well,]
  large = max(wells_df$DELTA)
  #cicle from 1 max.distance (large-1)
  for (d in c(1:(large-1))){
    #cicle from position 1 to large-distance (look how this turns to be symmetric)
    for (pos in (1:(large-d))){
      #I did all of this to calculate variables ti and tj 
      ti = wells_df[wells_df$DELTA==pos,]$ti
      tj = wells_df[wells_df$DELTA==pos+d,]$ti
      #I append the results into the once empty df "TABLE", and calculate p based on ti*tj
      table_agg[[length(table_agg)+1]]<-data.frame(well=well,d=d,p=ti*tj)
    }
  }
}

TABLE <- dplyr::bind_rows(table_agg)

【讨论】:

  • 太棒了!令人难以置信的是,现在节省了多少时间。谢谢帕特里克。并感谢大家的分享。下次我会遵循正统的。对此我深表歉意:)
猜你喜欢
  • 1970-01-01
  • 2018-03-09
  • 1970-01-01
  • 2019-10-11
  • 2018-04-06
  • 2021-01-21
  • 2016-06-23
  • 1970-01-01
相关资源
最近更新 更多