scipy 高效地将一个小的xarray.DataArray插入到一个大数组的坐标中?

x7rlezfr  于 2023-08-05  发布在  其他
关注(0)|答案(2)|浏览(135)

我有一个大的,高分辨率的3D(time: 200, y: 2000, x: 2000xarray.DataArray类似于这个:

import xarray as xr
import numpy as np
import pandas as pd

time = pd.date_range("2019-01-01", "2021-12-30", periods=200)
y_large = np.linspace(-1000000, -1032000, 2000)
x_large = np.linspace(-1968000, -2000000, 2000)
data_large = np.random.randint(low=0, high=10, size=(200, 2000, 2000))

da_large = xr.DataArray(
    data=data_large,
    coords={"time": time, "y": y_large, "x": x_large},
    dims=("time", "y", "x"),
)
da_large

字符串
x1c 0d1x的数据
我还有一个较小的低分辨率(time: 200, y: 100, x: 100xarray.DataArray,包含不同的数据,但覆盖相同的xy区段:

y_small = np.linspace(-1000000, -1032000, 100)
x_small = np.linspace(-1968000, -2000000, 100)
data_small = np.random.randint(low=100, high=110, size=(200, 100, 100))

da_small = xr.DataArray(
    data=data_small,
    coords={"time": time, "y": y_small, "x": x_small},
    dims=("time", "y", "x"),
)
da_small



我需要**将我的小的低分辨率数组(da_small)插入到我的大数组(da_large)的高分辨率网格中,**这样我就得到了一个time: 200, y: 2000, x: 2000数组,其中包含从da_small重新采样的值。
我想我可以使用xarray.interp()方法来实现这一点,通过传入我的高分辨率坐标来采样并将da_small的值插值到da_large的每个像素中:

da_small.interp(x=da_large.x, y=da_large.y, method="linear")


然而,我的挑战是,这个操作会导致内存中出现极大的峰值,这会使我的内核崩溃。这对我来说是一个障碍,因为我的实际数据可能比这个例子更大(高达几千像素高/宽和几百个时间步长深)。
我的问题是:如何以更有效的方式执行此类操作(重新缩放或将小数组插入较大数组的网格中),避免如此大的峰值内存使用?
(If如果可能的话,我更喜欢与xarray兼容的解决方案,这样它就可以插入到我现有的工作流程中。)

5lwkijsr

5lwkijsr1#

(If如果可能的话,我更喜欢与xarray兼容的解决方案,这样它就可以插入到我现有的工作流中
所以你可以考虑使用xarray with Dask
这比xarray 's .interp() method要好,后者试图将所有计算结果保存在内存中

暗沉

Xarray是一个开源项目和Python包,它将Pandas的标记数据功能扩展到N维数组类数据集。它与NumPyPandas共享类似的API,并在后台支持DaskNumPy阵列。
而且,如果您可以使用Dask,那么您就可以访问并行化或chunking
Dask数组由许多NumPy(或类似NumPy)数组组成。
这些阵列的排列方式会显著影响性能。例如,对于一个正方形数组,你可以沿着行、列或更像正方形的方式排列块。NumPy数组的不同排列对于不同的算法将更快或更慢。
在这里,我对原始性能不太感兴趣,而对使用分块的内存管理更感兴趣,分块将数据划分为更易于管理的小块。
您可以根据内存容量指定块大小:

import xarray as xr
import numpy as np
import pandas as pd

# Defining the large high-resolution DataArray
time = pd.date_range("2019-01-01", "2021-12-30", periods=200)
y_large = np.linspace(-1000000, -1032000, 2000)
x_large = np.linspace(-1968000, -2000000, 2000)
data_large = np.random.randint(low=0, high=10, size=(200, 2000, 2000))

da_large = xr.DataArray(
    data=data_large,
    coords={"time": time, "y": y_large, "x": x_large},
    dims=("time", "y", "x"),
)

# Defining the small low-resolution DataArray
y_small = np.linspace(-1000000, -1032000, 100)
x_small = np.linspace(-1968000, -2000000, 100)
data_small = np.random.randint(low=100, high=110, size=(200, 100, 100))

da_small = xr.DataArray(
    data=data_small,
    coords={"time": time, "y": y_small, "x": x_small},
    dims=("time", "y", "x"),
)

# Convert to Dask arrays using chunking
da_large_dask = da_large.chunk({'time': 10, 'y': 500, 'x': 500})
da_small_dask = da_small.chunk({'time': 10, 'y': 25, 'x': 25})

# Perform interpolation operation
da_interp_dask = da_small_dask.interp(x=da_large_dask.x, y=da_large_dask.y, method="linear")

# Compute the result using Dask
with dask.config.set(scheduler='threads'):  # or 'processes', depending on your needs
    da_interp = da_interp_dask.compute()

字符串
您可以使用Dask将数据划分为块,并对这些块执行计算,而不是一次对整个数组执行计算。
这将通过在任何给定时间仅在内存中保留必要的数据来减少内存使用。
块大小并不直接指定要使用的内存量,但它们确实会影响内存使用。块越大,每次计算需要的内存就越多,因为一次加载的数据越多。
您可以通过修改传递给.chunk()方法的字典中的数字来更改块大小。例如,如果你想将内存使用减半,你可以将块大小的每个维度减少大约sqrt(2)(因为内存使用与三个维度的乘积成正比):

da_large_dask = da_large.chunk({'time': 7, 'y': 350, 'x': 350})
da_small_dask = da_small.chunk({'time': 7, 'y': 18, 'x': 18})


或者,您可以使用dask.array.core.normalize_chunks尝试根据数组大小和内存限制计算块大小。

yduiuuwa

yduiuuwa2#

使用xarray的.interp()将一个小数组插值到一个更大的网格中确实会导致大量的内存消耗,特别是对于大型数据集。为了更有效地执行此操作并避免大内存峰值,您可以使用xarray的.reindex()方法沿着Dask进行延迟计算和分块。Dask允许您对较小的、可管理的数据块执行计算,从而减少内存开销。
以下是如何实现这一点的分步指南:
1.安装所需的库(如果尚未安装):

pip install xarray dask

字符串
1.导入必要的模块:

import xarray as xr
import dask.array as da


1.使用da.from_array()将DataArrays转换为Dask数组:

da_large = da.from_array(da_large)
da_small = da.from_array(da_small)


1.使用da.reindex()执行插值:

da_interp = da_small.reindex(y=da_large.y, x=da_large.x, method="linear")


1.将生成的Dask数组转换回xarray DataArray:

da_interp = xr.DataArray(da_interp, coords={"time": time, "y": da_large.y, "x": da_large.x}, dims=("time", "y", "x"))


现在,da_interp将是一个基于Dask的xarray DataArray,包含da_large网格中da_small的插值。此操作不会立即消耗大量内存,因为Dask在较小的块上延迟计算结果,使其更高效地使用内存。
如果需要在da_interp上执行进一步的计算,请记住使用Dask感知函数,因为它们可以通过将其分解为更小的任务来优化计算。
此外,您可以通过在da.from_array()中指定chunks参数来控制块大小。例如,设置chunks={"time": 1, "y": 100, "x": 100}将创建大小为1时间步长× 100行× 100列的块,这可以进一步减少内存开销。
通过同时利用Dask和xarray,您可以高效地处理大型数据集,同时保持与xarray功能和工作流的兼容性。

相关问题