Хотя использование замаскированных массивов может быть не самым эффективным решением в этом случае в этом случае, оно позволит вам выполнять замаскированные операции на определенных осях при более или менее сохранении формы, что является большим удобством. Имейте в виду, что во многих случаях замаскированные функции по-прежнему копируют замаскированные данные.
В текущем коде у вас в основном правильная идея, но вы пропустили несколько приемов, например, возможность отрицатьи комбинировать маски. Кроме того, тот факт, что распределение масок как булевых значений впереди более эффективно, и маленькие мелкие мелочи, такие как np.full(..., 0) -> np.zeros(..., dtype=bool)
.
Давайте рассмотрим это в обратном порядке. Допустим, у вас был хорошо себя ведущий 1-D массив с пиком, скажем a1
. Вы можете использовать маскирование, чтобы легко находить максимумы и минимумы (или индексы) следующим образом:
peak_index = np.nanargmax(a1)
mask = np.zeros(a1.size, dtype=np.bool)
mask[peak:] = True
trough_plus = np.nanargmin(np.ma.array(a1, mask=~mask))
trough_minus = np.nanargmin(np.ma.array(a1, mask=mask))
Это учитывает тот факт, что замаскированные массивы отражают смысл маски относительно обычного логического индексирования numpy. Также нормально, что максимальное значение появляется при расчете trough_plus
, поскольку оно гарантированно не будет минимальным (если у вас нет ситуации с полностью нан).
Теперь, если a1
был замаскированным массивомуже (но все еще 1D), вы можете сделать то же самое, но временно объединить маски. Например:
a1 = np.ma.array(a1, mask=np.isnan(a1))
peak_index = a1.argmax()
mask = np.zeros(a1.size, dtype=np.bool)
mask[peak:] = True
trough_plus = np.ma.masked_array(a1, mask=a.mask | ~mask).argmin()
trough_minus (np.ma.masked_array(a1, mask=a.mask | mask).argmin()
Опять же, поскольку маскированные массивы имеют обратные маски, важно комбинировать маски, используя |
вместо &
, как вы это делали бы для обычных булевых масок. В этом случае нет необходимости вызывать версию nan для argmax
и argmin
, поскольку все nans уже замаскированы.
Надеемся, что обобщение на несколько измерений станет понятным, еслираспространенность ключевого слова axis
в функциях numpy:
a = np.ma.array(a, mask=np.isnan(a))
peak_indices = a.argmax(axis=0).reshape(1, *a.shape[1:])
mask = np.arange(a.shape[0]).reshape(-1, *(1,) * (a.ndim - 1)) >= peak_indices
trough_plus = np.ma.masked_array(a, mask=~mask | a.mask).argmin(axis=0)
trough_minus = np.ma.masked_array(a, mask=mask | a.mask).argmin(axis=0)
Техника N-мерного маскирования исходит из Эффективно заполнить маску на основе стартовых индексов , которые запрашивались только для этой цели.