【发布时间】:2018-02-09 10:30:15
【问题描述】:
问题的小介绍:
我正在开发一个生态生理模型,并使用一个名为 S 的参考类列表,它存储模型输入/输出所需的每个对象(例如气象、生理参数等)。
此列表包含 5 个对象(请参见下面的示例):
- 两个数据框,S$Table_Day(模型的输出)和S$Met_c(输入中的气象),它们都在列中具有变量,在行中具有观察值(输入或输出)。
- 参数列表S$Parameters.
- 矩阵
- 一个向量
该模型以每日时间步长运行许多函数。每一天都在从第一天 i=1 到最后一天 i=n 的 for 循环中计算。这个列表被传递给函数,这些函数通常在输入中从S$Met_c 和/或S$Parameters 获取数据,并使用索引(第 i 天)计算存储在S$Table_Day 中的内容。 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)
另外,如果有人在编程此类模型方面有任何经验,我对模型开发的任何建议都非常感兴趣。
【问题讨论】:
-
如果您对有关数据帧的性能感兴趣,您应该看看库
data.table -
@JulienNavarre 是的,我已经使用它在
S$Table_Day数据帧上执行复杂任务的计算,但是您是否认为使用 data.table 而不是 data.frame 通过索引来修改值更快? (我不是在谈论执行计算,而是将结果存储在表中)。 -
哦,是的!在这件事上查看data.table vignettes,你应该确保以最好的方式去做,但它快155倍
-
您在示例中给出的 10,000 行范围是否代表您的实际数据大小?最快的方法可能会因大小而异。
-
@MattSummersgill 绝对是的。它有 10,000 到 15,000 长。 S$Table_Day 有 157 列,S$Met_c 有 48 列(行数相同)。
标签: r performance data.table