Numpy: Anfrage: argmax2d

Erstellt am 21. Juni 2017  ·  13Kommentare  ·  Quelle: numpy/numpy

Es wäre wirklich schön, wenn es eine Komfortfunktion gäbe, um ein argmax über ein 2D-Array auszuführen und die Zeilen- und Spaltenindizes des Maximums zurückzugeben.

Ich ertappe mich oft dabei, dass ich den folgenden Code wiederverwende

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

Obwohl es einfach ist, ist es undurchsichtig genug, um diese Funktion ständig nachschlagen zu müssen.
Es wäre schön, wenn dies bereits in numpy verfügbar wäre.

Gibt es Einwände gegen die Eröffnung einer PR in numpy, um diese Funktionalität sofort verfügbar zu haben?

Hilfreichster Kommentar

Warum nicht np.unravel_index ?

z.B

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

Als Bonus funktioniert es auch, wenn X mehr als 2 Dimensionen hat.

Alle 13 Kommentare

Warum nicht np.unravel_index ?

z.B

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

Als Bonus funktioniert es auch, wenn X mehr als 2 Dimensionen hat.

Ich bin kein Fan von argmax2d , aber i, j = a.argmax(axis=(0, 1)) könnte mich überzeugen

@eric-wieser wie würdest du sagen, dass sich das verhalten sollte? Derzeit gibt a.argmax() einen Skalar zurück und a.argmax(axis=0) ein Array mit der Form der verbleibenden Dimensionen. Ich würde erwarten, dass a.argmax(axis=(0,1)) für ein 3D-Array ein Array der Form a.shape[2] .

Abgesehen von diesem Problem wäre es etwas seltsam, im allgemeinen Fall a.argmax(axis=range(n)) zu verwenden, um ein n -Längenindextupel anstelle des standardmäßigen ganzzahligen linearen Index zu erhalten. Vielleicht könnte ein neues Schlüsselwort zwischen Ausgabedarstellungen wechseln?

Andererseits, wie würde diese formbewusste Ergebnisoption mit dem vorhandenen axis Schlüsselwort zusammenarbeiten, das bereits zu einem nicht skalaren Rückgabewert führt?

Was ist, wenn eine der Zeilen in Ihrem 2D-Array kein Maximum hat (es ist einfach ein konstantes Array) - wie kann argmax das melden?
Zum Beispiel:

# 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]

Es wäre schön, ein zusätzliches Argument zu haben, um beispielsweise dem Benutzer die Kontrolle darüber zu geben, was zu tun ist, wenn kein Maximum verfügbar ist: np.argmax(x,axis,no_ind=0) (0 ist Standard, um die Abwärtskompatibilität zu wahren).

@thoth291 ist dies nicht eine allgemeinere Frage zum Verhalten von argmax ? Dasselbe passiert ohne axis Schlüsselwortargument in einem 1d-Array:

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

Und das ist das übliche Verhalten bei Gleichstand: Wählen Sie den ersten der gebundenen Werte. In ähnlicher Weise ist das max dieses Arrays nicht nan : es ist 2. Und wenn Sie ein Maximum haben, müssen Sie einen entsprechenden Index haben. Oder habe ich deinen Punkt übersehen?

@adeak , jetzt hast du das gesagt - ich fange an zu denken, dass dies tatsächlich eine allgemeinere Frage ist.
Ich kann zustimmen, dass max([2,2,2]) gleich 2 .
Aber denken Sie an argmax([2,2,2]) - laut Definition in der numpy-Dokumentation gibt es the indices corresponding to the first occurrence . Dies scheint aus Sicht der Implementierung in Ordnung zu sein - aber es ist wirklich nur ein Archaismus des Algorithmus und hat nichts damit zu tun, was eigentlich passieren sollte. Tatsächlich kann JEDER Index zurückgegeben werden und sollte als korrekt behandelt werden. Oder man kann sagen, dass argmax im Fall eines Arrays mit konstanten Werten mehrdeutig ist.

Abgesehen davon würde ich eine solche Entscheidung lieber von vornherein vermeiden und inf zu signalisieren, dass es an dem Benutzer liegt, zu entscheiden, wie ein solcher Fall behandelt wird.

und hat nichts mit dem zu tun, was tatsächlich passiert.

Meinst du "hat nichts mit der abstrakten Definition von argmax zu tun"? Ich hoffe sehr, dass _"der Algorithmus"_ und _"was tatsächlich passiert"_ nicht nur dasselbe sind, sondern auch mit den Dokumenten übereinstimmen.

@adeak : Entschuldigung, dass

Andererseits, wie würde diese formabhängige Ergebnisoption mit dem vorhandenen Schlüsselwort Axis zusammenarbeiten, was bereits zu einem nicht skalaren Rückgabewert führt?

Ich denke, es gibt einen offensichtlichen Weg, damit umzugehen. Als Beispiel:

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

Damit und keepdims erhältst du arr[argmax(arr, axes, keepdims=True)] == max(arr, keepdims=True) für jede Dimensionalität, was mir sehr wünschenswert erscheint

In Pseudocode würde ich erwarten:

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 - schöner Fang - ich habe es schneller getippt, als es richtig übersetzen konnte. Werde später vorsichtig sein. Der Kommentar wurde auf "sollte passieren" statt "passiert" aktualisiert. Hoffe das hilft sonst - offen für Vorschläge zur Umformulierung.
Der Punkt ist, dass argmax([2,2,2])==0 genauso gut ist wie argmax([2,2,2])==1 oder etwas anderes und es sollte vom Benutzer und nicht von der Bibliothek ausgewählt werden. Andernfalls sollte ein Fallback-Mechanismus in Form eines (zum Beispiel) zusätzlichen Schlüsselworts default= oder initial= bereitgestellt werden, das anweist, was in diesem Fall zurückgegeben werden soll.

@thoth291 : Da das, was Sie besprechen, nicht spezifisch für _2D_ argmax ist, schlage ich vor, dass Sie ein neues Problem erstellen

@eric-wieser keine Sorge, danke, dass du dich bei mir gemeldet hast. Ich glaube, ich verstehe Ihren Vorschlag, und er erscheint eindeutig und praktisch. Die Tatsache, dass der Typ des axis Arguments bestimmt, ob der Rückgabewert ein Array oder ein Tupel von Arrays ist, überrascht mich etwas (insbesondere axes=0 vs axes=[0] ), aber ich bin mir sicher, dass es viele existierende Beispiele für das gleiche Verhalten gibt (auch, Praktikabilität schlägt Reinheit).

~Nur um sicher zu gehen: In Ihrem Beispiel, wenn axes=(0,2) dann sollten die zurückgegebenen Formen (B,D,E) , oder?

Nur um sicher zu gehen

Beides korrigiert, guter Fang

Die Tatsache, dass der Typ des Achsenarguments bestimmt, ob der Rückgabewert ein Array oder ein Tupel von Arrays ist, überrascht mich etwas

Beachten Sie, dass das tatsächliche Array identisch ist. Ich denke, dies trifft sowohl auf die Praktikabilität als auch auf die Reinheit zu - die Regel lautet, dass axis=(a,)res = (arr,) und axis=ares = arr . Apis, dass Spezialfalltupel der Größe 1 mir eine schlechte Idee erscheinen, da diese Spezialhülle die gesamte Aufrufliste ansteckend werden muss

Ich hätte nie daran gedacht, Tupel der Länge 1 im Sonderfall zu verwenden, das klingt falsch. Ich habe mich über den Fall Skalar vs. Tupel gewundert. Mir ist vage aufgefallen, dass die Fälle von Skalar- und Länge-1-Tupel in der von Ihnen erwähnten Weise einander entsprechen, aber jetzt, wo Sie es buchstabiert haben, ist es offensichtlich, dass Skalar -> 1-Tupel -> allgemeine Tupelfälle einfache Verallgemeinerungen sind. Also danke, ich unterstütze deinen Vorschlag voll und ganz.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

Foadsf picture Foadsf  ·  3Kommentare

kevinzhai80 picture kevinzhai80  ·  4Kommentare

keithbriggs picture keithbriggs  ·  3Kommentare

navytux picture navytux  ·  4Kommentare

astrofrog picture astrofrog  ·  4Kommentare