在 R 中处理大数据集

Dealing with big datasets in R

我遇到内存问题,R 给出了 Can not allocate vector of size XX Gb 错误消息。我有一堆 netcdf 格式的每日文件(12784 天),在 1305x378(经度-纬度)网格中提供海面温度。这每天提供 493290 点,当移除 NA(超过陆地点)时减少到大约 245000。

我最后的 objective 是为每日文件中的 245000 个点中的任意一个构建一个时间序列,并找出每个点的时间趋势。我的想法是构建一个大数据框,每行一个点,每列一天 (2450000x12784),这样我就可以将趋势计算应用于任何点。但是随后,构建这样的数据框,如预期的那样出现了内存问题。

首先,我尝试了一个我以前用来读取数据并通过读取 nc 文件提取三列 (lon-lat-sst) 数据帧然后融化数据的脚本。这会导致在尝试一小段日子时计算时间过长,并导致内存问题。然后我尝试将每日文件子集化为纵向切片;这避免了内存问题,但 csv 输出文件太大,过程非常耗时。

另一种我尝试过但没有成功的策略是顺序读取所有 nc 文件,然后提取每个点的所有每日值并找到趋势。然后我只需要保存一个 245000 点数据帧。但我认为这会很耗时,而不是正确的 R 方式。

我一直在阅读有关 big.memoryff 包的内容,试图声明 big.matrix 或 3D 数组 (1305 x 378 x 12784),但目前还没有成功。

面对问题的适当策略是什么?

  1. 提取单点时间序列以计算单个趋势并填充较小的数据框
  2. 将日常文件分片化以避免内存问题,但结尾有很多 dataframes/files
  3. 尝试用bigmemory或ff包解决内存问题

提前感谢您的帮助

编辑 1 添加代码以填充矩阵

library(stringr)
library(ncdf4)
library(reshape2)
library(dplyr)

# paths
ruta_datos<-"/home/meteo/PROJECTES/VERSUS/CMEMS/DATA/SST/"
ruta_treball<-"/home/meteo/PROJECTES/VERSUS/CMEMS/TREBALL/"
setwd(ruta_treball)

sst_data_full <- function(inputfile) {

  sstFile <- nc_open(inputfile)
  sst_read <- list()

  sst_read$lon <- ncvar_get(sstFile, "lon")
  sst_read$lats <- ncvar_get(sstFile, "lat")
  sst_read$sst <- ncvar_get(sstFile, "analysed_sst")

  nc_close(sstFile)

  sst_read
}

melt_sst <- function(L) {
  dimnames(L$sst) <- list(lon = L$lon, lat = L$lats)
  sst_read <- melt(L$sst, value.name = "sst")
}

# One month list file: This ends with a df of 245855 rows x 33 columns
files <- list.files(path = ruta_datos, pattern = "SST-CMEMS-198201")

sst.out=data.frame()

for (i in 1:length(files) ) { 
  sst<-sst_data_full(paste0(ruta_datos,files[i],sep=""))
  msst <- melt_sst(sst)
  msst<-subset(msst, !is.na(msst$sst))

  if ( i == 1 ) {
  sst.out<-msst
  } else {
  sst.out<-cbind(sst.out,msst$sst)
  }

}

编辑 2 先前(较小的)数据框中用于计算时间趋势的代码。原始数据是时间序列矩阵,每一列都是一个序列。

library(forecast)

data<-read.csv(....)

for (i in 2:length(data)){

var<-paste("V",i,sep="")
ff<-data$fecha
valor<-data[,i]  
datos2<-as.data.frame(cbind(data$fecha,valor))
datos.ts<-ts(datos2$valor, frequency = 365)

datos.stl <- stl(datos.ts,s.window = 365)

datos.tslm<-tslm(datos.ts ~ trend)

summary(datos.tslm)

output[i-1]<-datos.tslm$coefficients[2]

}

fecha 是日期变量名

编辑 2 来自 F. Privé 答案的工作代码

library(bigmemory)

tmp <- sst_data_full(paste0(ruta_datos,files[1],sep=""))

library(bigstatsr)
mat <- FBM(length(tmp$sst), length(files),backingfile = "/home/meteo/PROJECTES/VERSUS/CMEMS/TREBALL" )

for (i in seq_along(files)) {
  mat[, i] <- sst_data_full(paste0(ruta_datos,files[i],sep=""))$sst
}

用这段代码创建了一个大矩阵

dim(mat)
[1] 493290  12783
mat[1,1]
[1] 293.05
mat[1,1:10]
[1] 293.05 293.06 292.98 292.96 292.96 293.00 292.97 292.99 292.89 292.97
ncol(mat)
[1] 12783
nrow(mat)
[1] 493290

因此,对于 Filebacked Big Matrix (FBM) 中的读取数据,您可以这样做

files <- list.files(path = "SST-CMEMS", pattern = "SST-CMEMS-198201*",
                    full.names = TRUE)

tmp <- sst_data_full(files[1])

library(bigstatsr)
mat <- FBM(length(tmp$sst), length(files))

for (i in seq_along(files)) {
  mat[, i] <- sst_data_full(files[i])$sst
}