Numpy: El comportamiento de indexación con puntos suspensivos no es intuitivo.

Creado en 27 jul. 2020  ·  6Comentarios  ·  Fuente: numpy/numpy

La indexación de matrices con puntos suspensivos puede ser extremadamente contradictoria. Por ejemplo, en el siguiente ejemplo, la introducción de elipses redundantes altera la forma de la salida:

a = np.array([[[False]]])
a[0:0, 0, ..., [0]]
Out[23]: array([], shape=(1, 0), dtype=bool)
a[0:0, 0,  [0]]
Out[24]: array([], shape=(0, 1), dtype=bool)

No creo que este sea el comportamiento deseado, pero parece provenir directamente de las decisiones de diseño con respecto a cómo se maneja la indexación compleja .

Información de la versión de Numpy / Python:

1.17.3 3.7.5 (predeterminado, 25 de octubre de 2019, 10:52:18)
[Clang 4.0.1 (etiquetas / RELEASE_401 / final)]

04 - Documentation 33 - Question 57 - Close?

Comentario más útil

Estoy de acuerdo en que todo esto es confuso, y ni siquiera habría estado seguro sin comprobar lo que sucede aquí. Pero me parece la elección correcta.

¿Por qué debería ser realmente "invisible"? ... debería comportarse de forma idéntica para cualquier número de dimensiones. Para hacer eso, tiene que activar la transposición en todos los casos. Es decir, imagina algo organizado como series, ..., color donde ... está definido por el usuario y puede ser 0-d. Si tuviera que escribir un programa para manejar esos datos, necesitaría que la indexación se transponga de manera predecible sin importar a qué se expanda (o no) ... .

Al final, esto es simplemente confuso, y tendríamos que recoger .oindex y .vindex etc. más seriamente para resolverlo: https://numpy.org/neps/nep- 0021-indexación-avanzada.html

Todos 6 comentarios

Esto parece un caso de esquina particularmente desagradable: supongo que consideramos que ... obliga a los dos índices avanzados, 0 y [0] , a considerarse no adyacentes, aunque los ejes que indexan _son_ adyacentes.

Nos encontramos con este problema al intentar replicar la indexación numpy. Creo que esta es una interacción extraña entre dos reglas:

  • La elipsis se expande a una tupla de cortes completos, cada uno de los cuales se considera un índice básico
  • Los índices básicos y avanzados de orden mixto desencadenan una operación de transposición.

Este caso especial se activa porque una tupla 0-d (cuando ... se usa con todos los índices presentes) todavía se considera un bloque de índice básico, cuando realmente debería ser invisible.

Estoy de acuerdo en que todo esto es confuso, y ni siquiera habría estado seguro sin comprobar lo que sucede aquí. Pero me parece la elección correcta.

¿Por qué debería ser realmente "invisible"? ... debería comportarse de forma idéntica para cualquier número de dimensiones. Para hacer eso, tiene que activar la transposición en todos los casos. Es decir, imagina algo organizado como series, ..., color donde ... está definido por el usuario y puede ser 0-d. Si tuviera que escribir un programa para manejar esos datos, necesitaría que la indexación se transponga de manera predecible sin importar a qué se expanda (o no) ... .

Al final, esto es simplemente confuso, y tendríamos que recoger .oindex y .vindex etc. más seriamente para resolverlo: https://numpy.org/neps/nep- 0021-indexación-avanzada.html

Estoy con el argumento de @seberg de que el comportamiento actual es la mejor generalización. Sin embargo, ciertamente podríamos asegurarnos de que los documentos sean más claros.

No conocía esa propuesta, ¡gracias por la referencia @seberg!

Déjame reformular solo para asegurarme de que entiendo tu argumento. Digamos que etiquetamos índices avanzados A e índices básicos B y, como antes, llamo al reordenamiento op una transposición (generalizada). En su ejemplo, tenemos cuatro casos:

  • [A1, ..., A2] y [B1, ... A1] : estos casos activan la transposición a [A1, A2, ....] y [A1, B1, ...] independientemente de cómo se expanda ... .
  • [A1, ..., B1] y [B1, ..., B2] : estos casos no.

Estas reglas son consistentes una vez que sepa a qué clase (A o B) pertenecen series y color , independientemente de cómo se expanda ... . Esto equivale a tratar el ... como un bloque (potencialmente 0-d) de índices básicos. Tratar el 0-d ... como un caso especial sería malo porque la transposición estaría condicionada a si el usuario pasa en una matriz 2-D o 3-o-más-D. Estoy de acuerdo, este es un mal lugar para estar.

Mi intuición de que los bloques 0-d deberían ser no operativos fue impulsada por cómo se comportan las tuplas, donde para cualquier i ,

i: int
M: Tuple[int, ...]
N = ()
assert M[:i] + N + M[i:] == M

Esto entra en conflicto con la convención de indexación numpy que da como resultado los cuatro casos anteriores dependiendo de lo que sea i . Esto tiene más que ver con la operación de transposición en sí, en lugar de cómo se trata ... , y es un argumento para la propuesta NEP21.

Durante el desarrollo, cambiaríamos la forma en que hicimos la indexación e insertaríamos ... para preparar el código para el futuro y nos confundiríamos mucho cuando las formas se transpusieran mágicamente. Simplemente se vio exacerbado por el caso vacío de ... que es particularmente contradictorio.

¡Gracias por echar un vistazo! Puedo enviar un documento de relaciones públicas si lo desea.

@antonl a doc PR es siempre bienvenido, hay muchas mejoras posibles aquí.

¿Fue útil esta página
0 / 5 - 0 calificaciones