A tentativa de indexar um array 2D de forma [N, M] com duas máscaras booleanas 1D, formas N e M, certas combinações de Verdadeiro e Falso levam a um erro de transmissão (particularmente quando um é totalmente falso). Não tenho certeza se esse comportamento é esperado, mas parece altamente surpreendente e indesejável.
No exemplo abaixo, x[[False, True, True], [True, True, True]]
erros, enquanto x[[False, True, True], True]
e x[[False, True, True]]
têm o comportamento esperado.
import numpy as np
from itertools import product
x = np.zeros((3,3))
mask_1d = [*product([True, False], repeat=3)]
for row_mask, col_mask in product(mask_1d, mask_1d):
try:
x[row_mask, col_mask]
except IndexError as e:
print(row_mask, col_mask)
print(e)
(True, True, True) (True, True, False)
shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (2,)
(True, True, True) (True, False, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (2,)
(True, True, True) (False, True, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (2,)
(True, True, True) (False, False, False)
shape mismatch: indexing arrays could not be broadcast together with shapes (3,) (0,)
(True, True, False) (True, True, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
(True, True, False) (False, False, False)
shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (0,)
(True, False, True) (True, True, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
(True, False, True) (False, False, False)
shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (0,)
(False, True, True) (True, True, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
(False, True, True) (False, False, False)
shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (0,)
(False, False, False) (True, True, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (0,) (3,)
(False, False, False) (True, True, False)
shape mismatch: indexing arrays could not be broadcast together with shapes (0,) (2,)
(False, False, False) (True, False, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (0,) (2,)
(False, False, False) (False, True, True)
shape mismatch: indexing arrays could not be broadcast together with shapes (0,) (2,)
1.16.2 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34)
[GCC 7.3.0]
Com matrizes booleanas, o código assume que você está tentando indexar uma única dimensão ou todos os elementos ao mesmo tempo - com a escolha, infelizmente, adivinhada de uma forma que permite que um único True
seja removido. Ou seja, ele transforma seu row_mask, col_mask
em um array booleano (2,3) e então descobre que não pode indexar o array (3,3).
Parte do problema é que tuplas e listas são tratadas como equivalentes, algo do qual estamos tentando nos afastar. Eventualmente, você lidaria com o índice de matriz booleana garantindo que a máscara fosse uma lista dupla.
Por enquanto, porém, temo que a única solução seja x[row_mask][:, col_mask]
.
cc @ eric-wieser, que está trabalhando para descontinuar o uso de "tratar tupla como lista" para operações de indexação.
PS Mais irritante, acho essa diferença:
x = np.arange(9).reshape(3, 3)
# x[[False, True, True], True]
# array([[3, 4, 5],
# [6, 7, 8]])
x[[False, True, True], False]
# IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (0,)
Sim, x[row_mask][:, col_mask]
é o que acabei fazendo. Obrigado pela explicação, estou feliz que seja algo que está sendo investigado.
Eu acho que arr[np.ix_(index)]
é o que você quer / está esperando aqui, ou em outras palavras na lógica de indexação externa como no NEP 21: https://github.com/numpy/numpy/blob/master/doc/neps /nep-0021-advanced-indexing.rst
Talvez isso seja retomado em algum momento. O NEP também diz que, pelo menos para a indexação atual, vários índices booleanos devem ser descontinuados (acho que permitir esse caso de uso específico ainda pode ter sido contestado - é consistente, mas pode não ter muito caso de uso e ser bastante confuso em qualquer caso).
Comentários muito úteis
Com matrizes booleanas, o código assume que você está tentando indexar uma única dimensão ou todos os elementos ao mesmo tempo - com a escolha, infelizmente, adivinhada de uma forma que permite que um único
True
seja removido. Ou seja, ele transforma seurow_mask, col_mask
em um array booleano (2,3) e então descobre que não pode indexar o array (3,3).Parte do problema é que tuplas e listas são tratadas como equivalentes, algo do qual estamos tentando nos afastar. Eventualmente, você lidaria com o índice de matriz booleana garantindo que a máscara fosse uma lista dupla.
Por enquanto, porém, temo que a única solução seja
x[row_mask][:, col_mask]
.cc @ eric-wieser, que está trabalhando para descontinuar o uso de "tratar tupla como lista" para operações de indexação.
PS Mais irritante, acho essa diferença: