Numpy: Erros de transmissão com máscaras booleanas multidimensionais

Criado em 3 abr. 2019  ·  3Comentários  ·  Fonte: numpy/numpy

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.

Reproduzindo exemplo de código:

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)

Mensagem de erro:

     (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,)

Informações sobre a versão Numpy / Python:

1.16.2 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34) 
[GCC 7.3.0]

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 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,) 

Todos 3 comentários

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).

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Levstyle picture Levstyle  ·  3Comentários

dmvianna picture dmvianna  ·  4Comentários

dcsaba89 picture dcsaba89  ·  3Comentários

marcocaccin picture marcocaccin  ·  4Comentários

manuels picture manuels  ·  3Comentários