我正在处理一个大型全球降水数据集(具有非常精细的空间分辨率),以使用R中的SPEI package来计算标准化降水指数。
我的一般问题是指使用非常大的数据优化数据处理。我在其他帖子(here,here和here实例)中找到了一些讨论,但似乎与我的情况类似。
我的输入是具有超过20年的每月观察(> 20 * 12行)的降水时间序列的矩阵。 1,000,000点(列)。 SPI的计算为每个时间序列执行一系列步骤,并将指数计算为与中值的标准偏差。 输出是一个列表,结果矩阵($ fit)具有相同的输入矩阵大小。
这是代码示例:
require(SPEI)
#generating a random values matrix
data<-replicate(200, rnorm(240))
# erasing negative values
data[data<=0]=0
spi6 <- spi(data, 6, kernel = list(type = 'rectangular', shift = 0), distribution = 'PearsonIII', fit = 'ub-pwm', na.rm = FALSE, ref.start=NULL, ref.end=NULL, x=FALSE, params=NULL)
#testing the results
plot(spi6$fitted[,67])
#taking my results out
results <- t(spi6$fitted)
此脚本运行正常,但如果我增加点数(在这种情况下为列),则处理时间会呈指数增长。直到内存不足问题:
Warning messages:
1: In std[ff, s] <- qnorm(cdfpe3(acu.pred[ff], p3par)) :
Reached total allocation of 16253Mb: see help(memory.size)
2: In std[ff, s] <- qnorm(cdfpe3(acu.pred[ff], p3par)) :
Reached total allocation of 16253Mb: see help(memory.size)
3: In NextMethod("[<-") :
Reached total allocation of 16253Mb: see help(memory.size)
4: In NextMethod("[<-") :
Reached total allocation of 16253Mb: see help(memory.size)
5: In std[ff, s] <- qnorm(pze + (1 - pze) * pnorm(std[ff, s])) :
Reached total allocation of 16253Mb: see help(memory.size)
6: In std[ff, s] <- qnorm(pze + (1 - pze) * pnorm(std[ff, s])) :
Reached total allocation of 16253Mb: see help(memory.size)
7: In NextMethod("[<-") :
Reached total allocation of 16253Mb: see help(memory.size)
8: In NextMethod("[<-") :
Reached total allocation of 16253Mb: see help(memory.size)
如何拆分输入矩阵(或将过程拆分到输入矩阵上),以便并行处理列向量组(每个列向量都是特定点的全时序列),而不会丢失信息(或混乱)我的数据)? 感谢。
答案 0 :(得分:3)
我发现一个非常线性的,而不是指数的处理时间:
system.time(spi(data[,1], 6))
system.time(spi(data[,1:10], 6))
system.time(spi(data[,1:100], 6))
如果您看到指数增长,则可能是由于RAM分配过多的问题造成的。
一个简单的解决方案是将计算分解为矩阵:
spi6 <- data*NA
system.time(
for (i in 1:100) spi6[,i] <- spi(data[,i], 6)$fitted
)
或者,具有类似的效率:
system.time(
spi6 <- apply(data[,1:100], 2, function(x) spi(x, 6)$fitted)
)
如您所见,计算时间与原始选项非常相似,在该选项中您将整个矩阵作为spi()
函数的输入提供。 但,如果您遇到内存问题,可能会解决这些问题。
另一方面,如果您可以访问多核计算机(现在很可能就是这种情况),您可以通过并行计算看到计算时间的改进:
library(snowfall)
sfInit(parallel=TRUE, cpus=2)
sfLibrary(SPEI)
system.time(
spi6 <- sfApply(data[,1:100], 2, function(x) spi(x, 6)$fitted)
)
sfStop()
您可能需要将更高的值设置为ncpu
以获得更高的速度增益,具体取决于您的计算机支持的线程数。 然而,sfApply
,无法解决大型数据集的内存问题。这是因为该函数在分配的cpus数之间拆分数据集。由于系统的总内存不会发生变化,因此内存耗尽也是如此。
解决方案是合并两种方法:拆分数据集然后并行化。像这样:
data <- replicate(10000, rnorm(240))
sfInit(parallel=TRUE, cpus=10)
sfLibrary(SPEI)
spi6 <- data*NA
for (i in 0:9) {
chunk <- (i*1000)+(1:1000)
spi6[,chunk] <- sfApply(data[,chunk], 2, function(x) spi(x, 6)$fitted)
}
sfStop()
现在,您只需要找到块的最大大小,即传递给sfApply
的数据原始数量,以便不会溢出可用的RAM。一些尝试和错误,这很容易。