Python, numpy boolean array: отрицание в where statement

с:

import numpy as np
array = get_array()

Мне нужно сделать следующее:

for i in range(len(array)):
    if random.uniform(0, 1) < prob:
        array[i] = not array[i]

с массивом numpy.array.

Мне хотелось бы сделать что-то похожее на:

array = np.where(np.random.rand(len(array)) < prob, not array, array)

но я получаю следующий результат (ссылаясь на "not array" ):

Значение истинности массива с более чем одним элементом неоднозначно. Используйте a.any() или a.all()

Почему я могу принимать значение массива, но не его отрицание?

В настоящее время я решил с помощью:

array = np.where(np.random.rand(len(array)) < prob, - array + 1, array)

но это выглядит действительно неуклюжим для меня.

Спасибо за помощь

p.s.: Меня не волнует, изменяет ли оператор массив или нет. Мне просто нужен результат операции.

Еще один вопрос: я хочу сделать это изменение по двум причинам: читаемость и эффективность. Есть ли реальное улучшение производительности? Еще раз спасибо

Ответ 1

Я предлагаю использовать

array ^= numpy.random.rand(len(array)) < prob

Это, вероятно, самый эффективный способ получить желаемый результат. Он изменит массив на месте, используя "xor", чтобы инвертировать записи, которые случайное условие оценивает до True для.

Почему я могу принимать значение массива, но не его отрицание?

Вы не можете взять значение истинности массива:

>>> bool(array)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Оператор not неявно пытается преобразовать свой операнд в bool, а затем возвращает противоположное значение истины. Невозможно перегрузить not, чтобы выполнить любое другое поведение. Чтобы отменить массив NumPy bool s, вы можете использовать

~array

или

numpy.logical_not(array)

или

numpy.invert(array)

хотя.

Ответ 2

Возможно, это поможет вам двигаться дальше.

Ответ 3

putmask очень эффективен, если вы хотите заменить выбранные элементы:

import numpy as np

np.putmask(array, numpy.random.rand(array.shape) < prob, np.logical_not(array))