In [268]: X = np.random.randint(0,100,(200,200,1500))
Давайте проверим, как apply
работает только с np.mean
:
In [269]: res = np.apply_along_axis(np.mean, 2, X)
In [270]: res.shape
Out[270]: (200, 200)
In [271]: timeit res = np.apply_along_axis(np.mean, 2, X)
1.2 s ± 36.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Эквивалент, использующий итерацию по первым двум измерениям. Я использую reshape
, чтобы было легче писать; скорость должна быть примерно такой же с двойным l oop.
In [272]: res1 = np.reshape([np.mean(row) for row in X.reshape(-1,1500)],(200,200))
In [273]: np.allclose(res, res1)
Out[273]: True
In [274]: timeit res1 = np.reshape([np.mean(row) for row in X.reshape(-1,1500)],(200,200))
906 ms ± 13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Так что apply
может быть удобным, но это не инструмент скорости.
Для скорости в numpy
вам необходимо максимально использовать скомпилированный код и избегать ненужных python циклов уровней.
In [275]: res2 = np.mean(X,axis=2)
In [276]: np.allclose(res2,res)
Out[276]: True
In [277]: timeit res2 = np.mean(X,axis=2)
120 ms ± 619 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Если использование apply
в вашем новом случае сложно, вы не Не теряйте ничего, используя то, что вы понимаете.
masked
In [278]: mask = np.random.randint(0,2, X.shape).astype(bool)
Итерация [272] может быть адаптирована для работы с маской:
In [279]: resM1 = np.reshape([np.mean(row[m]) for row,m in zip(X.reshape(-1,1500),mask.reshape(-1,150
...: 0))],X.shape[:2])
In [280]: timeit resM1 = np.reshape([np.mean(row[m]) for row,m in zip(X.reshape(-1,1500),mask.reshape
...: (-1,1500))],X.shape[:2])
1.43 s ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Это может есть проблемы, если row[m]
пуст. np.mean([])
выдает предупреждение и nan
значение.
Применение маски к X
до того, как любая дальнейшая обработка приведет к потере информации о размерах.
In [282]: X[mask].shape
Out[282]: (30001416,)
apply
работает только с одним массивом , поэтому будет неудобно (хотя и возможно) использовать его для итерации как X
, так и mask
. Структурированный массив с полями данных и масок может подойти. Но предыдущие тайминги показывают, что нет преимущества в скорости.
маскированный массив
Обычно я не ожидаю, что маскированные массивы будут обеспечивать скорость, но в этом случае это помогает:
In [285]: xM = np.ma.masked_array(X, ~mask)
In [286]: resMM = np.ma.mean(xM, axis=2)
In [287]: np.allclose(resM1, resMM)
Out[287]: True
In [288]: timeit resMM = np.ma.mean(xM, axis=2)
849 ms ± 20.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
np.nanmean
Есть набор функций, которые используют np.nan
маскировку:
In [289]: Xfloat = X.astype(float)
In [290]: Xfloat[~mask] = np.nan
In [291]: resflt = np.nanmean(Xfloat, axis=2)
In [292]: np.allclose(resM1, resflt)
Out[292]: True
In [293]: %%timeit
...: Xfloat = X.astype(float)
...: Xfloat[~mask] = np.nan
...: resflt = np.nanmean(Xfloat, axis=2)
...:
...:
2.17 s ± 200 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Это не помогает: (