Numpy: Solicitud: argmax2d

Creado en 21 jun. 2017  ·  13Comentarios  ·  Fuente: numpy/numpy

Sería realmente bueno si hubiera una función de conveniencia para realizar un argmax sobre una matriz 2D y devolver los índices de fila y columna del máximo.

A menudo me encuentro reutilizando el siguiente código

def argmax2d(X):
    n, m = X.shape
    x_ = np.ravel(X)
    k = np.argmax(x_)
    i, j = k // m, k % m
    return i, j

Si bien es simple, es lo suficientemente opaco donde tengo que buscar constantemente esta función.
Sería bueno si esto ya estuviera disponible en numpy.

¿Habría alguna objeción a la apertura de un PR en número para tener esta funcionalidad disponible?

Comentario más útil

¿Por qué no usar np.unravel_index ?

p.ej

np.unravel_index(X.argmax(), X.shape)

Como beneficio adicional, también funciona cuando X tiene más de 2 dimensiones.

Todos 13 comentarios

¿Por qué no usar np.unravel_index ?

p.ej

np.unravel_index(X.argmax(), X.shape)

Como beneficio adicional, también funciona cuando X tiene más de 2 dimensiones.

No soy fan de argmax2d , pero i, j = a.argmax(axis=(0, 1)) me podrían persuadir

@ eric-wieser ¿cómo dirías que debería comportarse? Actualmente a.argmax() devuelve un escalar y a.argmax(axis=0) devuelve una matriz con la forma de las dimensiones restantes. Esperaría que a.argmax(axis=(0,1)) para una matriz 3d devuelva una matriz de forma a.shape[2] .

Dejando de lado este problema, sería un poco extraño usar a.argmax(axis=range(n)) en el caso general para obtener una tupla de índice de longitud n lugar del índice lineal de enteros predeterminado. ¿Quizás una nueva palabra clave podría cambiar entre las representaciones de salida?

Por otra parte, ¿cómo funcionaría esta opción de resultado consciente de la forma junto con la palabra clave existente axis ya da como resultado un valor de retorno no escalar?

¿Qué pasa si una de las filas en su matriz 2D no tiene un máximo (es simplemente una matriz constante)? ​​¿Cómo argmax puede informar eso?
Por ejemplo:

# setup the problem
import numpy as np
x=np.arange(10).reshape([2,5])
x[1,3]=2
# x is this:
# [[0, 1, 2, 3, 4],
#  [5, 6, 7, 2, 9]]

# this will behave normally
np.argmax(x==2, axis=1)
# Out: [2,3]

# but this one returns 0 instead of NaN
np.argmax(x==3, axis=1)
# Out: [3,0]
# Expected: [3, nan]

Sería bueno tener un argumento adicional, por ejemplo, para permitir que el usuario controle qué hacer en el caso sin un máximo disponible: np.argmax(x,axis,no_ind=0) (0 es el valor predeterminado para preservar la compatibilidad con versiones anteriores).

@ thoth291 ¿no es esta una pregunta más genérica con respecto al comportamiento de argmax ? Lo mismo sucede sin el argumento de palabra clave axis en una matriz 1d:

>>> np.argmax([2,2,2])
0

Y este es el comportamiento habitual en caso de empates: elija el primero entre los valores empatados. De manera similar, cómo max de esa matriz no es nan : es 2. Y si tiene un máximo, debe tener un índice correspondiente. ¿O me perdí tu punto?

@adeak , ahora dijiste eso, estoy empezando a pensar que esta es una pregunta más general.
Estoy de acuerdo en que max([2,2,2]) es igual a 2 .
Pero piense en argmax ([2,2,2]) - según la definición en la documentación numpy devuelve the indices corresponding to the first occurrence . Esto parece estar bien desde el punto de vista de la implementación, pero en realidad es solo un arcaísmo del algoritmo y no tiene nada que ver con lo que realmente debería suceder. Efectivamente, CUALQUIER índice puede devolverse y debe tratarse como correcto. O se puede decir que argmax es ambiguo en el caso de una matriz de valores constantes.

Dicho todo esto, preferiría evitar esa decisión en primer lugar y devolver inf para indicar que depende del usuario decidir cómo tratar tal caso.

y no tiene nada que ver con lo que realmente sucede.

¿Quiere decir "no tiene nada que ver con la definición abstracta de argmax"? Seguro que espero que _ "el algoritmo" _ y _ "lo que realmente sucede" _ no solo sean lo mismo, sino que coincidan con los documentos.

@adeak : Lo siento por no responder nunca

Por otra parte, ¿cómo funcionaría esta opción de resultado consciente de la forma junto con la palabra clave de eje existente que ya da como resultado un valor de retorno no escalar?

Creo que hay una forma obvia de lidiar con esto. Como ejemplo:

>>> ret = argmax(np.empty((A, B, C, D, E)), axes=(0, 2))
>>> type(ret)
tuple
>>> len(ret)  # == len(axes)
2
>>> ret[0].shape
(B, D, E)
>>> ret[1].shape
(B, D, e)

Con eso y manteniendo atenuadas, obtendría arr[argmax(arr, axes, keepdims=True)] == max(arr, keepdims=True) por cualquier dimensionalidad, lo que me parece muy deseable

En pseudocódigo, esperaría:

def argmax(arr, axes, keepdims)
    was_tuple = isinstance(axes, tuple):
    if not was_tuple:
        axes = (axes,)

    shape = np.array(arr.shape)
    axis_mask = np.array([i in axes for i in range(arr.ndim)])
    shape[axis_mask] = 1
    ret = tuple(np.empty(shape) for _ in axes)

    # do the actual work

    if not keepdims:
        ret = tuple(r.reshape(shape[~axis_mask]) for r in ret)

    if not was_tuple:
        return ret[0]

@ eric-wieser - buen truco - lo escribí más rápido de lo que pude traducir correctamente. Tendré cuidado más tarde. Se actualizó el comentario a "debería suceder" en lugar de "sucede". Espero que ayude, de lo contrario - abierto a sugerencias para reformular.
El punto es que argmax ([2,2,2]) == 0 es tan bueno como argmax ([2,2,2]) == 1 o cualquier otra cosa y debe ser elegido por el usuario en lugar de la biblioteca. De lo contrario, debería proporcionarse un mecanismo de reserva en forma de (por ejemplo) palabra clave adicional default= o initial= que indicaría qué devolver en este caso.

@ thoth291 : dado que lo que está discutiendo no es específico de _2D_ argmax, le sugiero que cree un nuevo problema

@ eric-wieser no se preocupe, gracias por responderme. Creo que entiendo su sugerencia, y parece clara y práctica. El hecho de que el tipo del argumento axis determina si el valor de retorno es una matriz o una tupla de matrices me sorprende un poco (especialmente axes=0 vs axes=[0] ), pero estoy seguro de que existen muchos ejemplos del mismo comportamiento (además, la practicidad vence a la pureza).

~ Solo para estar seguro: en su ejemplo, si axes=(0,2) , las formas devueltas deberían ser (B,D,E) , ¿verdad?

Sólo para estar seguro

Ambos corregidos, buena atrapada

El hecho de que el tipo de argumento del eje determina si el valor de retorno es una matriz o una tupla de matrices me sorprende un poco.

Tenga en cuenta que la matriz real es la misma. Creo que esto afecta tanto la practicidad como la pureza: la regla es que axis=(a,)res = (arr,) y axis=ares = arr . Apis que las tuplas de casos especiales de tamaño 1 me parecen una mala idea, ya que esa carcasa especial tiene que volverse contagiosa en toda la pila de llamadas

Nunca hubiera pensado en tuplas de longitud 1 en casos especiales, eso suena mal. Me preguntaba sobre el caso escalar vs tupla. Se me ocurrió vagamente que los casos de tupla escalar y de longitud 1 se corresponden entre sí de la manera que mencionaste, pero ahora que lo deletreaste es obvio que los casos de tupla escalar -> 1-tupla -> general de tupla son generalizaciones sencillas. Así que gracias, apoyo plenamente tu sugerencia.

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