使用 xarray,如何在多维数据集上并行化一维操作?

LCT*_*LCT 6 python dask python-xarray

我有一个 4D xarray 数据集。我想在特定维度(这里是时间)上的两个变量之间进行线性回归,并将回归参数保留在 3D 数组中(其余维度)。我设法通过使用此串行代码获得了我想要的结果,但速度相当慢:

# add empty arrays to store results of the regression
res_shape = tuple(v for k,v in ds[x].sizes.items() if k != 'year')
res_dims = tuple(k for k,v in ds[x].sizes.items() if k != 'year')
ds[sl] = (res_dims, np.empty(res_shape, dtype='float32'))
ds[inter] = (res_dims, np.empty(res_shape, dtype='float32'))
# Iterate in kept dimensions
for lat in ds.coords['latitude']:
    for lon in ds.coords['longitude']:
        for duration in ds.coords['duration']:
            locator = {'longitude':lon, 'latitude':lat, 'duration':duration}
            sel = ds.loc[locator]
            res = scipy.stats.linregress(sel[x], sel[y])
            ds[sl].loc[locator] = res.slope
            ds[inter].loc[locator] = res.intercept
Run Code Online (Sandbox Code Playgroud)

我怎样才能加速和并行化这个操作?

我知道这apply_ufunc可能是一个选项(并且可以与 dask 并行化),但我没有设法使参数正确。

以下问题是相关的,但没有答案:

编辑 2:将上一个编辑移至答案

And*_*ams 6

LCT之前的回答涵盖了这里应该说的大部分内容,但是我认为可以将dask='parallelized'多个输出结合起来,就像您从scipy.stats.linregress.

这里的技巧是将多个输出堆叠到一个数组中,然后输出该数组,您还必须使用 kwargoutput_core_dims来指定调用的 DataArray 输出apply_ufunc()现在将具有额外的维度:

def new_linregress(x, y):
    # Wrapper around scipy linregress to use in apply_ufunc
    slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
    return np.array([slope, intercept, r_value, p_value, std_err])
Run Code Online (Sandbox Code Playgroud)
# return a new DataArray
stats = xr.apply_ufunc(new_linregress, ds[x], ds[y],
                       input_core_dims=[['year'], ['year']],
                       output_core_dims=[["parameter"]],
                       vectorize=True,
                       dask="parallelized",
                       output_dtypes=['float64'],
                       output_sizes={"parameter": 5},
                      )
Run Code Online (Sandbox Code Playgroud)

注意此方法目前仅适用于dask='parallelized'您有的情况dask<2.0,但如果您有其他类似的东西,它似乎适用于多个输出dask='allowed'。查看此Github 问题了解更多详细信息。

希望能帮助到你!

编辑:我已获悉该dask<2.0问题已得到纠正,只要您有xarray>=0.15.0!所以可以使用dask='parallelized'now 来加快速度。:)


LCT*_*LCT 5

可以通过像这样传递来应用scipy.stats.linregress(和其他非 ufunc)到 xarray 数据集:apply_ufunc()vectorize=True

# return a tuple of DataArrays
res = xr.apply_ufunc(scipy.stats.linregress, ds[x], ds[y],
        input_core_dims=[['year'], ['year']],
        output_core_dims=[[], [], [], [], []],
        vectorize=True)
# add the data to the existing dataset
for arr_name, arr in zip(array_names, res):
    ds[arr_name] = arr
Run Code Online (Sandbox Code Playgroud)

虽然还是连续剧 apply_ufunc但在这种特定情况下比循环实现快 36 倍左右。

然而,与 dask 的并行化仍然没有像来自 的多个输出那样实现scipy.stats.linregress

NotImplementedError:dask='parallelized' 尚不支持来自 apply_ufunc 的多个输出