Как отмечается в комментариях @ Divakar , булевы расширенные индексы ведут себя так, как если бы они сначала передавались через np.nonzero
, а затем передавались вместе, см. Соответствующую документацию объяснения . Цитируя документы,
Как правило, если индекс включает в себя логический массив, результат будет идентичен вставке obj.nonzero()
в ту же позицию и использованию механизма индексации целочисленного массива, описанного выше. x[ind_1, boolean_array, ind_2]
эквивалентно x[(ind_1,) + boolean_array.nonzero() + (ind_2,)]
.
[...]
Объединение нескольких массивов логического индексирования или логического массива с массивом целочисленного индексирования лучше всего понять по аналогии obj.nonzero()
. Функция ix_
также поддерживает логические массивы и будет работать без сюрпризов.
В вашем случае вещание не обязательно будет проблемой, поскольку оба массива имеют только два ненулевых элемента. Проблема заключается в количестве измерений в результате:
>>> len(b1[:,None].nonzero())
2
>>> len(b2.nonzero())
1
Следовательно, индексное выражение a[b1[:,None], b2]
будет эквивалентно a[b1[:,None].nonzero() + b2.nonzero()]
, что поместит кортеж длины 3 внутрь a
, что соответствует индексу трехмерного массива. Отсюда и ошибка, которую вы видите по поводу «слишком много индексов».
Сюрпризы, упомянутые в документах, очень близки вашему примеру: что, если вы не внедрили это одноэлементное измерение? Начиная с логического массива длины 3 и длины 4 вы получите расширенный индекс длины 2, то есть массив 1d размером (2,)
. Это никогда не то, что вы хотели бы, что приводит нас к еще одной мелочи в теме.
Было много дискуссий о планировании модернизации расширенной индексации, см. Незавершенный проект NEP 21 . Суть проблемы заключается в том, что причудливое индексирование в numpy, хотя и четко задокументировано, имеет некоторые очень причудливые функции, которые практически ни к чему не полезны, но которые могут укусить вас, если вы совершите ошибку, выдавая удивительные результаты, а не ошибки.
Соответствующая цитата из нэпа:
Смешанные случаи, включающие несколько индексов массива, также удивительны,
только менее проблематично, потому что текущее поведение настолько бесполезно, что
это редко встречается на практике. Когда индекс логического массива
смешанный с другим логическим или целочисленным массивом, логический массив
преобразуются в индексы целочисленных массивов (эквивалентные np.nonzero()
) и
потом вещание. Например, индексирование двумерного массива размером (2, 2)
, например
x[[True, False], [True, False]]
создает 1D вектор с формой (1,)
,
не 2D подматрица с формой (1, 1)
.
Теперь я подчеркиваю, что NEP находится в стадии разработки, но одно из предложений в текущем состоянии NEP состоит в том, чтобы запретить логические массивы в случаях расширенного индексирования, таких как приведенные выше, и разрешать их только в сценарии «внешнего индексирования», т. е. именно то, что np.ix_
поможет вам с вашим логическим массивом:
Логическое индексирование - это концептуально внешнее индексирование. Вещание вместе с другими передовыми индексами в виде унаследованной индексации [т.е. текущее поведение], как правило, не является полезным или четко определенным. Таким образом, можно ожидать, что пользователь, который желает, чтобы поведение «отличное от нуля» и «широковещание» делало это вручную.
Моя точка зрения заключается в том, что поведение булевых расширенных индексов и их устаревший статус (или их отсутствие) могут измениться в не столь отдаленном будущем.