Когда вы индексируете массив с помощью логической маски, элементы извлекаются и помещаются в одномерный массив.Это в значительной степени должно было иметь место, так как выбранные элементы маски не являются равномерно распределенными по нашему в любом измерении.Выражение results[mask] = value
эквивалентно results.__setitem__(mask, value)
: явно модификация на месте result
.Однако results[mask][index_keep] = value
эквивалентно result.__getitem__(mask).__setitem__(index_keep, value)
.Операция на месте происходит с временным массивом, который полностью отбрасывается.
Решение состоит в том, чтобы поиграть с индексом, чтобы получить один вызов __setitem__
для нужного объекта.Один из способов сделать это - применить index_keep
к mask
.Сначала вам нужно будет преобразовать mask
в линейные индексы, например, с помощью np.flatnonzero
:
result.ravel()[np.flatnonzero(mask)[index_keep]] = value
Это будет работать до тех пор, пока ravel
возвращаетвид, который он должен в большинстве случаев.Если result
является непрерывным массивом, это будет работать постоянно.Он не будет работать, если result
уже является подмножеством массива большего размера.
Преимущество этого подхода состоит в том, что он использует только один индексный массив и работает для любого числа измерений.Использование np.where
может быть адаптировано для того же, но требует большего временного хранения.Недостатком, конечно, является то, что этот подход ограничен непрерывными массивами.
PS Вам почти наверняка не нужно копировать value
.Его элементы не будут изменены, и назначение уже сделает копию в соответствующих местах result
.Создание копии просто создает ненужный временный массив, который будет немедленно отброшен.