Применение scipy.ndimage.convolve к трехмерному массиву данных DataArray - PullRequest
0 голосов
/ 27 сентября 2018

У меня есть 3D xarray DataArray с размерами x, y, z, и я пытаюсь применить scipy.ndimage.convolve к каждой плоскости xy, сохраняя вывод в виде DataArray.Естественно, я пытаюсь использовать xr.apply_ufunc для этого.Если я делаю это только для одного самолета, он отлично работает:

da=xr.DataArray(np.random.rand(5,5,5), dims=("x", "y", "z"))
kernel=np.ones((3,3))
from scipy.ndimage import convolve
conv1 = lambda x: convolve(x, kernel, mode="wrap")
print(xr.apply_ufunc(conv1, da[:,:,0])) # works successfully

Я сейчас пытаюсь найти способ сделать то же самое для каждого самолета xy.Я думал, что сработает с использованием np.apply_along_axis или np.apply_over_axes, но ни один из них не работает.

Я мог бы выполнить итерацию по оси, поместить все в список и объединить, но я пытаюсь использовать xr.apply_ufunc, чтобы избежать проблем с атрибутами.Есть ли способ сделать это?

Вот пример того, что, как я думал, должно работать, но это не так:

np.apply_over_axes(conv1, c, axes=(0,1))

, но это не удается с

TypeError: <lambda>() takes 1 positional argument but 2 were given

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Как насчет использования ядра с формой (3, 3, 1) вместо (3, 3)?

kernel2d = np.ones((3, 3))
conv2d = lambda x: convolve(x, kernel2d, mode="wrap")
result2d = xr.apply_ufunc(conv2d, da[:, :, 0])

kernel3d = np.ones((3, 3, 1))
conv3d = lambda x: convolve(x, kernel3d, mode="wrap")
result3d = xr.apply_ufunc(conv3d, da)

(result2d == result3d[:, :, 0]).all()  # -> True

Другой вариант - использовать логику векторизации в xr.apply_ufunc, которая может быть ближе кчто вы пытались сделать

kernel = np.ones((3, 3))
conv = lambda x: convolve(x, kernel, mode="wrap")
result = xr.apply_ufunc(conv, da, input_core_dims=[['x', 'y']], 
                        output_core_dims=[['x', 'y']],
                        vectorize=True)
(result2d == result.transpose('x', 'y', 'z')).all()  # --> True

Этот параметр подготовлен только для удобства, и поэтому он может быть намного медленнее, чем первый, где вычисление векторизовано.

0 голосов
/ 28 сентября 2018

Возможный ответ, который я придумал, состоит в том, чтобы вручную сделать это:

def conv_rx(da, axis="z"):
    planes = [ xr.apply_ufunc(conv1, da.sel(z=z)) for z in da.z ]
    new = xr.concat(planes, dim=axis)
    return new.transpose(*da.dims)

, что дает правильный результат.Тем не менее, я не очень доволен этим, поскольку он не элегантный и довольно медленный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...