Хотите верьте, хотите нет, но я думаю, что вы в основном там!Подробнее см. DataArrayGroupBy.reduce
.
da_ffdi_95th = ds['FFDI'].groupby('time.season').reduce(
np.percentile, dim='time', q=95)
Поскольку мы используем функцию NumPy, данные будут загружены с нетерпением.Чтобы сделать это совместимым с dask, функция, которую мы передаем reduce
, должна иметь возможность работать с массивами NumPy или dask.В то время как dask реализует функцию, которая делает это, dask.array.percentile
, он работает только с одномерными массивами, а не идеально подходит для функции NumPy .
К счастью, с dask.array.map_blocks
достаточно легко написать нашу собственную.При этом используется реализация NumPy percentile
и применяется к каждому фрагменту массива dask;единственное, к чему мы должны быть осторожны, - это убедиться, что массив, к которому мы его применяем, не разделен на части по измерению, по которому мы хотим вычислить процентиль.
import dask.array as dask_array
def dask_percentile(arr, axis=0, q=95):
if len(arr.chunks[axis]) > 1:
msg = ('Input array cannot be chunked along the percentile '
'dimension.')
raise ValueError(msg)
return dask_array.map_blocks(np.percentile, arr, axis=axis, q=q,
drop_axis=axis)
Затем мы можем написать функцию-обертку, котораявызывает соответствующую реализацию percentile
в зависимости от типа входного массива (NumPy или dask):
def percentile(arr, axis=0, q=95):
if isinstance(arr, dask_array.Array):
return dask_percentile(arr, axis=axis, q=q)
else:
return np.percentile(arr, axis=axis, q=q)
Теперь, если мы вызываем reduce
, убедитесь, что добавлен аргумент allow_lazy=True
, этоОперация возвращает массив dask (если базовые данные хранятся в массиве dask и соответствующим образом разделены):
da_ffdi_95th = ds['FFDI'].groupby('time.season').reduce(
percentile, dim='time', q=95, allow_lazy=True)