gpt4 book ai didi

r - 使用索引修改 data.frame 的最有效方式(最快)

转载 作者:行者123 更新时间:2023-12-02 02:57:09 26 4
gpt4 key购买 nike

问题简介:

我正在开发一个生态生理模型,我使用了一个名为 S 的引用类列表。存储模型需要输入/输出的每个对象(例如气象、生理参数等)。
此列表包含 5 个对象(请参见下面的示例):
- 两个数据帧,S$Table_Day (模型的输出)和 S$Met_c (输入中的气象),它们都在列中有变量,在行中有观察(输入或输出)。
- 参数列表 S$Parameters .
- 一个矩阵
- 一个向量

该模型以每日时间步长运行许多函数。每一天都在 for 循环中计算,该循环从第一天 i=1 运行到最后一天 i=n。这个列表被传递给经常从 S$Met_c 获取数据的函数。和/或 S$Parameters在输入中并计算存储在 S$Table_Day 中的内容,使用索引(第 i 天)。 S是一个引用类列表,因为它们避免了修改时的复制,考虑到计算数量,这非常重要。

问题本身:

由于模型非常慢,我试图通过对不同解决方案进行微基准测试来减少计算时间。
今天,在比较两种存储数据的解决方案时,我发现了一些令人惊讶的事情。通过在预分配的数据帧之一中建立索引来存储数据比将其存储到未声明的向量中要长。阅读后this ,我认为预分配内存总是更快,但似乎R在按索引修改时执行更多操作(可能比较长度,类型等......)。

我的问题是 : 有没有更好的方法来执行此类操作?换句话说,有没有办法让我更有效地使用/存储输入/输出(在 data.frame、向量列表或其他中)来跟踪每天的所有计算?例如,使用多个向量(每个变量一个)并在结束时将它们重新组合到更复杂的对象(例如数据框列表)中会更好吗?

顺便说一句,我使用引用类来避免复制 S 中的大对象是否正确?将它传递给函数并从它们内部修改它?

用于比较的可重现示例:

SimulationClass <- setRefClass("Simulation",
fields = list(Table_Day = "data.frame",
Met_c= "data.frame",
PerCohortFruitDemand_c="matrix",
Parameters= "list",
Zero_then_One="vector"))
S= SimulationClass$new()
# Initializing the table with dummy numbers :
S$Table_Day= data.frame(one= 1:10000, two= rnorm(n = 10000), three= runif(n = 10000),Bud_dd= rep(0,10000))
S$Met_c= data.frame(DegreeDays= rnorm(n=10000, mean = 10, sd = 1))


f1= function(i){
a= cumsum(S$Met_c$DegreeDays[i:(i-1000)])
}

f2= function(i){
S$Table_Day$Bud_dd[(i-1000):i]= cumsum(S$Met_c$DegreeDays[i:(i-1000)])
}

res= microbenchmark(f1(1000),f2(1000),times = 10000)
autoplot(res)

结果:
Autoplot from Microbenchmark

此外,如果有人在编程此类模型方面有任何经验,我对模型开发的任何建议都非常感兴趣。

最佳答案

我阅读了更多关于这个问题的信息,为了繁荣,我会在这里写一些在其他帖子中提出的解决方案。

显然,正在阅读 在尝试通过索引减少分配给 data.frame 的计算时间时,写入都是值得考虑的。
来源都可以在其他讨论中找到:

  • How to optimize Read and Write to subsections of a matrix in R (possibly using data.table)
  • Faster i, j matrix cell fill
  • Time in getting single elements from data.table and data.frame objects

  • 几个解决方案似乎相关:
  • 使用 matrix如果可能的话,而不是 data.frame 来利用就地修改 (Advanced R) .
  • 使用 list而不是 data.frame,因为 [<-.data.frame不是原始函数 (Advanced R) .
  • 用 C++ 编写函数并使用 Rcpp ( from this source )
  • 使用 .subset2阅读而不是 [ ( third source )
  • 使用 data.table按照@JulienNavarre 和@Emmanuel-Lin 以及不同来源的建议,使用 setdata.frame:=如果使用 data.table不是问题。
  • 使用 [[而不是 [如果可能(仅按一个值索引)。这个不是很有效,而且限制性很强,所以我从下面的比较中去掉了它。


  • 以下是使用不同解决方案的性能分析:

    编码 :
    # Loading packages :
    library(data.table)
    library(microbenchmark)
    library(ggplot2)

    # Creating dummy data :
    SimulationClass <- setRefClass("Simulation",
    fields = list(Table_Day = "data.frame",
    Met_c= "data.frame",
    PerCohortFruitDemand_c="matrix",
    Parameters= "list",
    Zero_then_One="vector"))
    S= SimulationClass$new()
    S$Table_Day= data.frame(one= 1:10000, two= rnorm(n = 10000), three= runif(n = 10000),Bud_dd= rep(0,10000))
    S$Met_c= data.frame(DegreeDays= rnorm(n=10000, mean = 10, sd = 1))

    # Transforming data objects into simpler forms :
    mat= as.matrix(S$Table_Day)
    Slist= as.list(S$Table_Day)
    Metlist= as.list(S$Met_c)
    MetDT= as.data.table(S$Met_c)
    SDT= as.data.table(S$Table_Day)

    # Setting up the functions for the tests :
    f1= function(i){
    S$Table_Day$Bud_dd[i]= cumsum(S$Met_c$DegreeDays[i])
    }
    f2= function(i){
    mat[i,4]= cumsum(S$Met_c$DegreeDays[i])
    }
    f3= function(i){
    mat[i,4]= cumsum(.subset2(S$Met_c, "DegreeDays")[i])
    }
    f4= function(i){
    Slist$Bud_dd[i]= cumsum(.subset2(S$Met_c, "DegreeDays")[i])
    }
    f5= function(i){
    Slist$Bud_dd[i]= cumsum(Metlist$DegreeDays[i])
    }
    f6= function(i){
    set(S$Table_Day, i=as.integer(i), j="Bud_dd", cumsum(S$Met_c$DegreeDays[i]))
    }
    f7= function(i){
    set(S$Table_Day, i=as.integer(i), j="Bud_dd", MetDT[i,cumsum(DegreeDays)])
    }
    f8= function(i){
    SDT[i,Bud_dd := MetDT[i,cumsum(DegreeDays)]]
    }


    i= 6000:6500
    res= microbenchmark(f1(i),f3(i),f4(i),f5(i),f7(i),f8(i), times = 10000)
    autoplot(res)

    以及由此产生的自动绘图:

    Autoplot

    f1引用基赋值, f2使用 matrix而不是 data.frame , f3使用 .subset2 的组合和 matrix , f4使用 list.subset2 , f5使用两个 list s(阅读和写作), f6使用 data.table::set , f7使用 data.table::setdata.table对于累积和,和 f8使用 data.table := .

    如我们所见 最好的解决方案是使用列表 用于阅读和写作。看到 data.table 真是令人惊讶是最糟糕的解决方案。我相信我做错了什么,因为它应该是最好的。如果你能改进它,请告诉我。

    关于r - 使用索引修改 data.frame 的最有效方式(最快),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48703802/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com