tl;博士:为什么 raster::sampleRandom 需要这么多时间?例如从 30k 个细胞中提取 3k 个细胞(超过 10k 个时间步)。我能做些什么来改善这种情况吗?
编辑:底部的解决方法。
考虑一个 R 脚本,我必须在其中读取一个大文件(通常超过 2-3GB)并对数据执行分位数计算。我使用 raster 包来读取 ( netCDF
) 文件。我在 64 位 GNU/Linux 下使用 R 3.1.2 和 4GB 的 RAM,大部分时间都有 3.5GB 可用。
由于文件通常太大而无法放入内存(由于某种原因,即使 2GB 的文件也无法放入 3GB 的可用内存:)unable to allocate vector of size 2GB
我不能总是这样做,如果我有 16GB 的 RAM,我会这样做:
pr <- brick(filename[i], varname=var[i], na.rm=T)
qs <- quantile(getValues(pr)*gain[i], probs=qprobs, na.rm=T, type=8, names=F)
sampleRaster()
但相反,我可以使用包中的函数对文件中的少量单元格进行采样raster
,仍然可以获得良好的统计数据。
例如:
pr <- brick(filename[i], varname=var[i], na.rm=T)
qs <- quantile(sampleRandom(pr, cnsample)*gain[i], probs=qprobs, na.rm=T, type=8, names=F)
我对 6 个不同的文件(i
从 1 到 6 个)执行此操作,这些文件都有大约 30k 个单元和 10k 个时间步长(所以 300M 值)。文件是:
- 1.4GB,1 个变量,文件系统 1
- 2.7GB,2 个变量,所以我读取的变量大约 1.35GB,文件系统 2
- 2.7GB,2 个变量,所以我读取的变量大约 1.35GB,文件系统 2
- 2.7GB,2 个变量,所以我读取的变量大约 1.35GB,文件系统 2
- 1.2GB,1 个变量,文件系统 3
- 1.2GB,1 个变量,文件系统 3
注意:
- 文件位于三个不同的 nfs 文件系统上,我不确定它们的性能。我不能排除这样一个事实,即 nfs 文件系统的性能从一个时刻到另一个时刻可能会有很大差异。
- 脚本运行时,RAM 使用率始终为 100%,但系统并未使用所有的交换空间。
sampleRandom(dataset, N)
从一层(=一个时间步长)获取 N 个非 NA 随机单元,并读取它们的内容。对每一层的相同 N 个单元执行此操作。如果将数据集可视化为 3D 矩阵,Z 为时间步长,则该函数采用 N 个随机非 NA 列。但是,我猜该函数不知道所有层的 NA 都位于相同的位置,因此它必须检查它选择的任何列中是否没有 NA。- 当对具有 8393 个单元(总共约 340MB)的文件使用相同的命令并读取所有单元时,计算时间是尝试从具有 30k 个单元的文件中读取 1000 个单元的一小部分。
产生下面输出的完整脚本在这里,带有注释等。
如果我尝试读取所有30k 个单元格:
cannot allocate vector of size 2.6 Gb
如果我阅读1000 个单元格:
- 5分钟
- 45米
- 30米
- 30米
- 20米
- 20米
如果我阅读3000 个单元格:
- 15分钟
- 18米
- 35米
- 34 米
- 60米
- 60米
如果我尝试读取5000 个单元格:
- 2.5 小时
- 22 小时
- 对于 >2 我不得不在 18 小时后停下来,我不得不将工作站用于其他任务
通过更多的测试,我已经能够发现它是sampleRandom()
占用大部分计算时间的函数,而不是分位数的计算(我可以使用其他分位数函数来加速,例如kuantile()
)。
- 为什么
sampleRandom()
要花这么长时间?为什么它的表现如此奇怪,有时很快有时很慢? - 最好的解决方法是什么?我想我可以为第一层手动生成 N 个随机单元,然后
raster::extract
为所有时间步手动生成。
编辑:工作解决方法是:
cells <- sampleRandom(pr[[1]], cnsample, cells=T) #Extract cnsample random cells from the first layer, exluding NAs
cells[,1]
prvals <- pr[cells[,1]] #Read those cells from all layers
qs <- quantile(prvals, probs=qprobs, na.rm=T, type=8, names=F) #Compute quantile
这很有效,而且速度非常快,因为所有层的 NA 都在相同的位置。我认为这应该是一个sampleRandom()
可以实施的选项。