在 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.memory
和 ff
包的内容,试图声明 big.matrix 或 3D 数组 (1305 x 378 x 12784),但目前还没有成功。
面对问题的适当策略是什么?
- 提取单点时间序列以计算单个趋势并填充较小的数据框
- 将日常文件分片化以避免内存问题,但结尾有很多 dataframes/files
- 尝试用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
}
我遇到内存问题,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.memory
和 ff
包的内容,试图声明 big.matrix 或 3D 数组 (1305 x 378 x 12784),但目前还没有成功。
面对问题的适当策略是什么?
- 提取单点时间序列以计算单个趋势并填充较小的数据框
- 将日常文件分片化以避免内存问题,但结尾有很多 dataframes/files
- 尝试用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
}