我正在研究存储在 NetCDF 文件中的 NEE(网络生态系统交换数据),我将其称为 NEE_2022.nc 。该文件在我的 wd 中。 空间覆盖整个欧洲,分辨率约为1公里;时间范围为 2022 年,时间分辨率为每小时。 在这里我提供一些有关数据的更多信息:
**1 variables** (excluding dimension variables):
float NEE[lon,lat,time]
long_name: net ecosystem exchange
units: micromoles/m2/s
_FillValue: 1.00000001504747e+30
missing_value: 1.00000001504747e+30
**3 dimensions**:
time Size:8760 *** is unlimited ***
standard_name: time
long_name: time endpoint
units: hours since 2022-01-01 00:00:00
calendar: standard
axis: T
lon Size:400
standard_name: longitude
long_name: longitude
units: degrees_east
axis: X
lat Size:480
standard_name: latitude
long_name: latitude
units: degrees_north
axis: Y
这是我的目标: 我想每月对每个像素进行平均; 我还想为每个月 NEE 栅格创建一张地图。 不需要空间子集。
注意 R.version 命令返回以下文本:
platform x86_64-w64-mingw32
arch x86_64
os mingw32
crt ucrt
system x86_64, mingw32
status
major 4
minor 2.2
year 2022
month 10
day 31
svn rev 83211
language R
version.string R version 4.2.2 (2022-10-31 ucrt)
我在打开文件时遇到问题。 当我运行以下代码时:
library(ncdf4)
library(raster)
library(rgdal)
library(ggplot2)
library(terra)
NEE_2022 <- nc_open('NEE_2022.nc',readunlim=FALSE)
NEE.array <- ncvar_get(NEE_2022, "NEE")
我的记忆力有问题。我收到以下错误消息:
错误:无法分配大小为 12 GB 的向量
然后,我通过使用
ncvar_get()
函数中的“start”和“count”参数成功创建了数组。我尝试只选择第一天(24 小时)。我做了以下事情:
NEE.array <- ncvar_get(NEE_2022, "NEE", start = c(1,1,1), count = c(-1,-1,24))
我该如何继续?
由于 NEE 文件太大,无法装入内存,因此必须将其分段处理。
解决方案1:显而易见的方法
将每小时数据汇总为每日数据是最容易理解的方法,之后您必须将每日数据汇总为每月数据(在您的问题中,您提到“每月平均每个像素”,但我假设您想要总和为“每月 NEE”,而不是平均值为“每月平均每小时 NEE”)。执行此操作的基本循环如下所示:
library(ncdf4)
NEE_2022 <- nc_open('NEE_2022.nc')
# Number of days per month
days_in_month <- c(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
# First hour of every month in 2022
h1 <- c(1, 745, 1417, 2161, 2881, 3625, 4345, 5089, 5809, 6553, 7273, 8017)
# Array for the result
NEE_data <- array(0, dim = c(480, 400, 12))
for (m in 1:12) {
mon <- array(0, dim = c(480, 400))
for (d in 1:days_in_month[m]) {
data <- ncvar_get(NEE_2022, "NEE",
start = c(1, 1, h1[m]),
count = c(-1, -1, 24))
mon <- mon + rowSums(data, dims = 2) * 3600
}
NEE_data[, , m] <- mon
}
nc_close(NEE_2022)
您还可以将两个循环合并为一个,但代价是从文件中读取更大的数据,这可能会耗尽您的内存:
for (m in 1:12) {
data <- ncvar_get(NEE_2022, "NEE",
start = c(1, 1, h1[m]),
count = c(-1, -1, 24 * days_in_month[m]))
NEE_data[, , m] <- rowSums(data, dims = 2) * 3600
}
解决方案 2:R 方式
在R think中,你应该用向量来构建你的问题,尽可能避免循环。虽然由于文件较大而无法避免循环,但您仍然可以对处理逻辑进行矢量化。在这种情况下,这意味着在 time
维度上创建一个
factor,然后使用它在一次操作中根据文件大小逐像素提取所有每月总和:
# Create the factor
f <- as.factor(rep(rep(1:12, days_in_month), each = 24))
# Loop through every pixel
for (lat in 1:480) {
for (lon in 1:400) {
data <- ncvar_get(NEE_2022, "NEE", start = c(lat, lon, 1), count = c(1, 1, -1))
NEE_data[lon, lat, ] <- tapply(data, f, sum) * 3600
}
}
您可以通过读取和处理较大的块来减少循环数,例如10 x 10 纬度/经度块。
潜在的陷阱
上述代码通常应放置在函数内,以便可以轻松存储和重用。问题是上面的代码高度依赖于您正在处理的文件的具体情况。如果您想处理另一个文件并且该数据覆盖地球的另一个区域,则尺寸可能会发生变化。如果您处理 2020 年的数据,则必须考虑闰日。
CFtime
包,因为它可以自动处理时间序列,并将生成在第二个解决方案中使用的因子.