Numpy: ENH: Alternative zu `random.shuffle`, mit einem `axis`-Argument.

Erstellt am 11. Okt. 2014  ·  35Kommentare  ·  Quelle: numpy/numpy

Es wäre schön, eine Alternative zu numpy.random.shuffle , die ein axis Argument akzeptiert und die eindimensionalen Slices unabhängig voneinander mischt. Hier ist eine Implementierung, die ich disarrange nenne. Es funktioniert, aber es wäre schön, eine effizientere C-Implementierung zu haben.

def disarrange(a, axis=-1):
    """
    Shuffle `a` in-place along the given axis.

    Apply numpy.random.shuffle to the given axis of `a`.
    Each one-dimensional slice is shuffled independently.
    """
    b = a.swapaxes(axis, -1)
    # Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
    # so `a` is shuffled in place, too.
    shp = b.shape[:-1]
    for ndx in np.ndindex(shp):
        np.random.shuffle(b[ndx])
    return

Beispiel:

In [156]: a = np.arange(20).reshape(4,5)

In [157]: a
Out[157]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [158]: disarrange(a, axis=-1)

In [159]: a
Out[159]: 
array([[ 2,  0,  4,  3,  1],
       [ 8,  6,  7,  9,  5],
       [11, 14, 13, 10, 12],
       [19, 18, 16, 17, 15]])

In [160]: a = np.arange(20).reshape(4,5)

In [161]: disarrange(a, axis=0)

In [162]: a
Out[162]: 
array([[ 5, 11,  7, 13, 14],
       [ 0,  6,  2,  3,  4],
       [10,  1, 17, 18, 19],
       [15, 16, 12,  8,  9]])

Diese Anfrage wurde durch diese Frage zu Stackoverflow motiviert: http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/

01 - Enhancement numpy.random

Hilfreichster Kommentar

Gibt es Neuigkeiten zu diesem Thema? Ich war überrascht, dass es diese Funktion nicht gibt. Im Moment verwende ich np.apply_along_axis mit np.random.permutation als Problemumgehung.

Alle 35 Kommentare

Verstehe nicht, warum dies eine Alternative sein sollte – warum nicht einfach ein . hinzufügen
Achsenargument zum Mischen? Vorgabe auf Keine, wie np.sum.

Am Samstag, 11. Oktober 2014 um 21:36 Uhr, Warren Weckesser [email protected]
schrieb:

Es wäre schön, eine Alternative zu numpy.random.shuffle zu haben
akzeptiert ein Achsenargument, und das mischt unabhängig die
eindimensionale Scheiben. Hier ist eine Implementierung, die ich disarrange nenne.
Es funktioniert, aber es wäre schön, eine effizientere C-Implementierung zu haben.

def disarrange(a, Achse=-1):
"""
Verschieben Sie a direkt entlang der angegebenen Achse.

Apply numpy.random.shuffle to the given axis of `a`.
Each one-dimensional slice is shuffled independently.
"""
b = a.swapaxes(axis, -1)
# Shuffle `b` in-place along the last axis.  `b` is a view of `a`,
# so `a` is shuffled in place, too.
shp = b.shape[:-1]
for ndx in np.ndindex(shp):
    np.random.shuffle(b[ndx])
return

Beispiel:

In [156]: a = np.arange(20).reshape(4,5)

In [157]: a
Aus[157]:
Array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])

In [158]: disarrange(a, Achse=-1)

In [159]: a
Aus[159]:
Array([[ 2, 0, 4, 3, 1],
[ 8, 6, 7, 9, 5],
[11, 14, 13, 10, 12],
[19, 18, 16, 17, 15]])

In [160]: a = np.arange(20).reshape(4,5)

In [161]: disarrange(a, Achse=0)

In [162]: a
Aus[162]:
Array([[ 5, 11, 7, 13, 14],
[ 0, 6, 2, 3, 4],
[10, 1, 17, 18, 19],
[15, 16, 12, 8, 9]])

Diese Anfrage wurde durch diese Frage zum Stackoverflow motiviert:
http://stackoverflow.com/questions/26310346/quickly-calculate-randomized-3d-numpy-array-from-2d-numpy-array/


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/numpy/numpy/issues/5173.

Nathaniel J. Smith
Postdoktorand - Informatik - University of Edinburgh
http://vorpus.org

Das aktuelle Verhalten von shuffle ist nicht wirklich wie axis=None . Es behandelt sein Argument als eindimensionale Folge.

In [181]: a = np.arange(20).reshape(4,5)

In [182]: np.random.shuffle(a)

In [183]: a
Out[183]: 
array([[ 0,  1,  2,  3,  4],
       [15, 16, 17, 18, 19],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

Sie können das als axis=0 interpretieren, aber die fehlende Funktion ist das unabhängige Mischen der 1-D-Slices.

Für ein 2D-Array können Sie a.T mischen, um axis=1 zu emulieren, aber das bringt Ihnen kein unabhängiges Mischen:

In [184]: a = np.arange(20).reshape(4,5)

In [185]: np.random.shuffle(a.T)

In [186]: a
Out[186]: 
array([[ 4,  1,  0,  3,  2],
       [ 9,  6,  5,  8,  7],
       [14, 11, 10, 13, 12],
       [19, 16, 15, 18, 17]])

In disarrange würde ich erwarten, dass sich axis=None wie np.random.shuffle(a.flat) .

Es wäre in Ordnung, wenn das alternative Mischen durch Hinzufügen geeigneter Argumente zu shuffle implementiert würde, die das Verhalten steuern, aber ich habe keinen Vorschlag für diese API.

Vielleicht könnten zwei Argumente zu shuffle hinzugefügt werden: axis und independent (oder etwas in diese Richtung). Die neue Signatur wäre:

def shuffle(a, independent=False, axis=0)

Wenn independent False ist, verhält es sich wie das aktuelle shuffle . Bei True verhält es sich wie disarrange .

Oh, äh, ich bin einfach davon ausgegangen, dass es eher mit Analogem übereinstimmt
Funktionen wie sort :-(. Es wäre schöner, wenn diese Art von
Shuffling-of-Slices wurden wie folgt geschrieben: idx = arange(...); mischen (idx);
multi_dim_array[idx, ...]; aber keiner hat mich gefragt :-)

Ich gebe +1 für eine Shuffle-Version mit übereinstimmenden Aufrufkonventionen
np.sort, wobei wir in der Regel die Liste überprüfen sollten. Vielleicht haben Sie
Vorschläge zu entscheidenden Themen wie dem besten Namen auch :-)

(Vielleicht "durcheinander"?)

Am Sa, 11. Oktober 2014 um 22:31 Uhr, Warren Weckesser < [email protected]

schrieb:

Das aktuelle Verhalten von Shuffle ist nicht wirklich wie axis=None. Es behandelt
sein Argument als eindimensionale Folge.

In [181]: a = np.arange(20).reshape(4,5)

In [182]: np.random.shuffle(a)

In [183]: a
Aus[183]:
Array([[ 0, 1, 2, 3, 4],
[15, 16, 17, 18, 19],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])

Sie können dies als Achse = 0 interpretieren, aber das fehlende Merkmal ist das
unabhängiges Mischen der 1-D-Scheiben.

Für ein 2D-Array können Sie aT mischen, um axis=1 zu emulieren, aber dies wird nicht
erhalten Sie unabhängiges Mischen:

In [184]: a = np.arange(20).reshape(4,5)

In [185]: np.random.shuffle(aT)

In [186]: a
Aus[186]:
Array([[ 4, 1, 0, 3, 2],
[ 9, 6, 5, 8, 7],
[14, 11, 10, 13, 12],
[19, 16, 15, 18, 17]])

In Unordnung würde ich erwarten, dass sich axis=None so verhält wie
np.random.shuffle(a.flat).

Es wäre in Ordnung, wenn das alternative Mischen durch Hinzufügen implementiert würde
geeignete Argumente, um diese Kontrolle über ihr Verhalten zu mischen, aber ich tue es nicht
einen Vorschlag für diese API haben.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/numpy/numpy/issues/5173#issuecomment -58765220.

Nathaniel J. Smith
Postdoktorand - Informatik - University of Edinburgh
http://vorpus.org

Ah, das gewünschte Verhalten als Analogon von sort ist eine gute Idee.

Oh, ähm, ich habe nur angenommen, dass es mit analogen Funktionen wie Sortieren konsistenter ist

Ich war auch überrascht, und aufgrund der Kommentare zur Stackoverflow-Frage waren mindestens zwei andere erfahrene, nüchterne Benutzer überrascht. Ich werde eine Diskussion auf der Mailingliste starten.

Ich denke, wenn der durchschnittliche Benutzer derzeit etwas falsch macht, dann ist es das wert
die andere Option erwähnen -- wir _könnten_ ein Argument hinzufügen, um zwischen zu wählen
die beiden Verhaltensweisen, die mit der Standardeinstellung auf das aktuelle Verhalten beginnen,
und irgendwann nach viel FutureWarning und Geschrei die Standardeinstellung wechseln
Menschen zu warnen. Aber das ist ein hässlicher Übergang...

Am Sa, 11. Okt 2014 um 23:00 Uhr, Warren Weckesser < [email protected]

schrieb:

Oh, äh, ich bin einfach davon ausgegangen, dass es eher mit Analogem übereinstimmt
Funktionen wie sortieren

Ich war auch überrascht und aufgrund der Kommentare zum Stackoverflow
Frage, waren mindestens zwei andere erfahrene, nüchterne Benutzer überrascht. Krank
Starten Sie eine Diskussion auf der Mailingliste.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/numpy/numpy/issues/5173#issuecomment -58766099.

Nathaniel J. Smith
Postdoktorand - Informatik - University of Edinburgh
http://vorpus.org

Sie könnten auch Vorschläge zu wichtigen Themen wie dem besten Namen haben.

Wir brauchen eine Funktion namens Sue.

Ich wollte diesem Feature nur +1 geben, da ich es auch erwartet hatte, analog zu sort(axis=N). Wurde eine Entscheidung über die Mailingliste getroffen?

Das wäre wirklich nützlich!

Das würde ich auch schätzen!

Gemäß https://stackoverflow.com/a/35647011/3401634 für mehrdimensionale Arrays X

np.random.shuffle(X)

ist das gleiche wie

np.take(X, np.random.permutation(X.shape[0]), axis=0, out=X)

Warum also nicht implementieren

np.random.shuffle(X, axis=axis)

wie

np.take(X, np.random.permutation(X.shape[axis]), axis=axis, out=X)

mit dem Standardwert axis=0 ?

Gibt es Neuigkeiten zu diesem Thema? Ich war überrascht, dass es diese Funktion nicht gibt. Im Moment verwende ich np.apply_along_axis mit np.random.permutation als Problemumgehung.

Kann das jetzt wegen #13829 geschlossen werden?

(Beachten Sie, dass ich bei der Arbeit an den Beispielen hier einen Fehler im neuen Shuffle-Code gefunden habe. Im Folgenden verwende ich den in https://github.com/numpy/numpy/pull/14662 vorgeschlagenen Fix, der bereits zusammengeführt.)

@wkschwartz , die Änderung in #13829 ist nützlich, aber es ist nicht die hier angeforderte Verbesserung. Die in #13829 hinzugefügte Achse behandelt das Array immer noch als eine 1-d-Sequenz, die gemischt werden soll. Mit dem neuen Achsenargument kann der Benutzer angeben, welche Achse als 1-d-Achse angesehen wird, aber es führt kein unabhängiges Mischen innerhalb der Achse durch.

Beispielsweise,

In [1]: import numpy as np                                                      

In [2]: rng = np.random.default_rng()                                           

In [3]: x = np.arange(20).reshape(2, 10)                                        

In [4]: x                                                                       
Out[4]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

In [5]: rng.shuffle(x, axis=1)                                                  

In [6]: x                                                                       
Out[6]: 
array([[ 5,  9,  6,  4,  7,  0,  3,  2,  1,  8],
       [15, 19, 16, 14, 17, 10, 13, 12, 11, 18]])

Sie können sehen, dass die Zeilen nicht unabhängig voneinander gemischt wurden. Die Spalten wurden neu angeordnet, aber die Werte in jeder Spalte sind gleich.

Das in dieser Ausgabe angeforderte Verhalten besteht darin, unabhängig zu mischen, wie in dem disarrange Code, den ich oben angegeben habe:

In [10]: x = np.arange(20).reshape(2, 10)                                       

In [11]: x                                                                      
Out[11]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])

In [12]: disarrange(x, axis=1)                                                  

In [13]: x                                                                      
Out[13]: 
array([[ 4,  3,  7,  8,  0,  6,  5,  2,  9,  1],
       [12, 15, 19, 17, 18, 14, 10, 13, 11, 16]])

Ich würde das gerne nochmal schweben lassen, vielleicht auch für das Mittwochstreffen. Wir haben gerade choice und permutation und in 1.18 sogar das Achsenargument hinzugefügt (es ist also brandneu).

All diese verwenden die aktuelle Shuffle- Logik, die shuffle the subarrays along this axis , anstelle von shuffle along (individual) axis was meiner Meinung nach wohl passieren sollte. Dh es mischt "über" statt "entlang" oder innerhalb der gegebenen Achse.

Aber in fast allen Fällen bedeutet axis entlang der Achse in NumPy, mit hoffentlich sehr wenigen Ausnahmen, wie apply_over_axes das das "Over" im Namen hat. Ich werde also so mutig sein und behaupten, dass sogar eine Umbenennung des Arguments in over_axis=0 besser wäre, um Verwirrung zu vermeiden! Insbesondere bei Zufallszahlen, bei denen ein falsches Mischen sehr schwer zu bemerken ist.

Wie im obigen Github-Querverweis erwähnt, habe ich eine in Arbeit befindliche PR unter https://github.com/numpy/numpy/pull/15121. Ich habe einige gute Rückmeldungen erhalten, nachdem ich die PR eingereicht hatte, aber ich habe mir nicht die Zeit genommen, alle angesprochenen Probleme anzusprechen.

@WarrenWeckesser , die kühl ist, was ich bin persönlich mehr über dringend besorgt ist , dass wir die über Sinn in der neuen API und vor kurzem an , dass erweitert.
Und ich frage mich, ob wir das nicht teilweise zurückziehen sollten, zB indem wir zumindest das Argument axis umbenennen. Oder gar das mehrdimensionale Verhalten vorerst wieder komplett loswerden...

Wahrscheinlich überreagiere ich gerade, weil ich mich ein bisschen ärgere, dass ich das übersehen habe oder vorher nicht zu Ende gedacht habe... Aber ich halte die aktuelle Logik ehrlich gesagt für sehr gefährlich. Es ist leicht zu übersehen , dass es nicht an Bedeutung des erwarteten liefert. Und es ist nicht die Bedeutung, die np.sort verwendet.

@seberg , danke, dass angestoßen hast . Ich denke, wir müssen noch einen Konsens über die API erzielen. Ich werde versuchen, hier eine kurze Zusammenfassung früherer Ideen zu geben. Ich werde Ihrer Konvention folgen, "over" und "along" für zwei Interpretationen von axis . Ich weiß nicht, ob wir an dieser Stelle die bestehende "Entlang"-Interpretation von axis für shuffle und permutation vollständig rückgängig machen können, aber ich denke, viele Leute würde mich freuen, wenn sich herausstellt, dass wir es können. :)

Am Ende der Mailinglistendiskussion vor einigen Jahren dachte ich, die Lösung bestehe darin, die APIs von shuffle und permutation nicht zu ändern und stattdessen zwei neue Methoden einzuführen, die entlang der Achse randomisiert sind statt darüber. Eine Methode würde direkt funktionieren und die andere würde eine Kopie zurückgeben. Damals bevorzugte ich die Namen permute und permuted , aber es gab einige Einwände gegen diese Namen. In der PR vom letzten Dezember habe ich sie randomly_permute und randomly_permuted , aber diese Namen sollten als Platzhalter betrachtet werden. Bevor wir versuchen, uns für diese Namen zu entscheiden, müssen wir entscheiden, ob das Hinzufügen von zwei neuen Funktionen der richtige Ansatz ist. Von hier an bezeichne ich die vorgeschlagenen neuen Methoden der Kürze halber als permute und permuted .

Mit den neuen Funktionen hätten wir die folgenden verwandten Generator Methoden:

meaning    operate     return
of axis    in-place     copy
-------    --------  -----------
"over"     shuffle   permutation
"along"    permute   permuted

(Die Methoden, die "über" der Achse arbeiten, shuffle und permutation , existieren bereits.)

Anstelle von zwei neuen Methoden wurde vorgeschlagen, dass wir nur eine haben, mit einem Parameter, der das Verhalten gegenüber dem Kopieren an Ort und Stelle steuert. Dazu wurden zwei Vorschläge gemacht:

(a) Fügen Sie einen Parameter out . Um direkt zu arbeiten, übergeben Sie das Eingabearray als out . Wenn out nicht angegeben wird, geben Sie eine gemischte Kopie zurück.
(b) Fügen Sie ein boolesches Flag wie copy oder inplace , das das gewünschte Verhalten angibt.

Die Hauptalternative zum Erstellen neuer Methoden besteht darin, den vorhandenen Methoden einen neuen Parameter hinzuzufügen, der die Interpretation von axis ändert. Bevor ich diese aufzähle, werde ich einen Kommentar von Robert Kern im Mailinglisten-Thread wiederholen, wie das zusätzliche Argument in der Praxis wahrscheinlich verwendet wird (hier in Bezug auf den unten gezeigten Parameter independent ):

Es scheint mir ein vollkommen guter Grund zu sein, statt zwei Methoden zu haben
eins. Ich kann mir nicht vorstellen, dass ich kein wörtliches Wahr oder Falsch verwenden würde
dafür sollten es also wirklich zwei verschiedene Methoden sein.

( Redaktioneller Exkurs : In einer Diskussion wie dieser Generator Namensraum) zu vergrößern (manchmal als "Namensraumverschmutzung" bezeichnet). Wenn die Dinge gleich sind, ist ein kleinerer Namespace besser. Aber wie bei den meisten API-Entwurfsentscheidungen sind Kompromisse zu berücksichtigen. Wenn wir den Namespace kleiner halten, aber Methoden mit umständlichen oder übermäßig komplizierten APIs erstellen, gewinnen wir nicht.)

Nachdem dies alles gesagt wurde, sind hier zwei Ergänzungen zur bestehenden Signatur von shuffle vorgeschlagen worden.

(1) shuffle(x, axis=0, independent=False) : Das boolesche Flag independent bestimmt, wie axis interpretiert wird: False -> "over", True -> "along". (Es gibt wahrscheinlich bessere Namen als independent .)
(2) shuffle(x, axis=0, iaxis=???) : Ein zweites Argument, iaxis , gibt die Achse für das "Entlang"-Verhalten an. (Wie dies mit axis interagiert, erfordert eine klare Spezifikation. Vermutlich wird die Angabe eines Werts für iaxis dass axis ignoriert wird.)

Ich glaube, ich habe alle verschiedenen API-Ideen abgedeckt, die aufgekommen sind. Wenn jemand andere kennt, lass es uns wissen.

Ich freue mich über die Erweiterung der API hier. Ich bin mir nicht sicher, ob es viele Gründe gibt, dagegen zu sein:

  • Wir können wahrscheinlich zustimmen, dass es nützlich ist
  • Es gibt keinen guten Weg, dies mit bestehenden Funktionen zu erreichen
  • Die Verwendung eines kwarg für einen totalen Verhaltenswechsel scheint kein normales Muster zu sein, ich denke, Rober Kern war vollkommen richtig.

Ich nehme an, was hier vor sich geht ist, dass shuffle und permutation (und vielleicht choice ) mit einer Indexierungsoperation verglichen werden können (dh take ), die verwendet dieselbe Bedeutung für axis . Und der Grund, warum es sich für mich ein bisschen seltsam anfühlt, ist wahrscheinlich der Nachteil dieser Definition, dass sie im Gegensatz zu typischen Array-fähigen Funktionen nie auf ND verallgemeinert werden kann (sogar die Indizierung selbst tut es, wenn Sie arr[..., index] . Das war es zu Stapeln von Arrays verallgemeinern und dieselbe Operation wie zuvor für jedes einzelne ausführen).
Beachten Sie, dass take_along_axis die ND-verallgemeinerbare Bedeutung "entlang" für take korrekt an ND liefert (auch wenn es kompliziert erscheint). apply_along_axis und apply_over_axis ich das "über" bekommen, obwohl ich mir nicht sicher bin, ob "über" das richtige Wort ist...

Ich finde, dass permutation (was nicht leicht zu ändern ist, aber shuffled ) hier der wahre Ausreißer ist. Es war shuffle - shuffled , permute - permuted dann denke ich, dass die Dinge ziemlich klar und vernünftig aussehen. Ist jemand bereit, shuffled hinzuzufügen und eine Einstellung für permutation starten? permutation ist auch nicht sehr konsistent in seinem Verhalten mit itertools.permutations , FWIW.

Ich denke, permutation , permute , permuted ist ein verwirrendes Tripel von ähnlich klingenden Namen mit unterschiedlichen Verhaltensweisen. Es wäre gut (möglicherweise auf lange Sicht), dies zu vermeiden.

Obwohl es einfach erscheint, die vorhandene API zu erweitern, denke ich, dass @rkerns Argument , keine Schlüsselwörter zu haben, die das Verhalten radikal ändern, der beste Weg ist.

Ich nehme an, für In-Place vs. Nicht-In-Place haben wir die alternative Schreibweise out= in NumPy. Aber da Shuffle vorhanden ist, ist das keine Lösung und Shuffle ist schön. Es könnte für permuted (dh permuted(arr, out=arr) bedeutet dasselbe wie permute(arr) , außer – anders als Shuffle – wird es in ndarray ).
Auf jeden Fall gefällt mir der Plan, permutation zugunsten von shuffled abzuschaffen, um den neuen Namespace aufzuräumen!

Ich komme auf dieses Problem zurück (und die zugehörige PR unter https://github.com/numpy/numpy/pull/15121).

Als ich das ursprüngliche Problem erstellte und versuchte, das Problem mit der aktuellen shuffle API zu beschreiben, wurde darauf hingewiesen, dass eine Möglichkeit zur Erklärung des Problems darin besteht, dass die meisten Leute das axis Argument erwarten von shuffle , um dasselbe wie das Argument axis von sort . Die Analogie zu sort ist ziemlich gut, daher könnte es nützlich sein, auch zu betrachten, wie wir mit dem Problem der direkten Operation im Vergleich zum Kopieren zum Sortieren umgehen. Die Funktion numpy.sort() akzeptiert ein Array-ähnliches Argument und gibt eine sortierte Kopie zurück. Für die direkte Sortierung verwendet man die muss ein ndarray, und nicht willkürlich sein Array-like. Andernfalls muss die Funktion die gesamte Formerkennung durchführen, die np.array tut, und auch Eingaben zurückweisen, die sich als unveränderlich erweisen (z. B. können wir kein direktes Mischen von [(1, 2, 3, 4), (5, 6, 7, 8)] ).

Es wäre großartig, wenn wir die sort API wirklich replizieren könnten, mit einer Funktion , die eine gemischte Kopie zurückgibt, und einer ndarray Methode , die an Ort und Stelle gemischt wird, aber ich glaube nicht, dass eine solche hinzugefügt wird eine Methode der Klasse ndarray hat eine Chance, akzeptiert zu werden.

und eine ndarray _method_, die an Ort und Stelle gemischt wird, aber ich glaube nicht, dass das Hinzufügen einer solchen Methode zur ndarray Klasse eine Chance hat, akzeptiert zu werden.

Ohne einen Singleton-Generator wäre dies meiner Meinung nach unmöglich zu erreichen.

@bashtage hat geschrieben

Ich finde, dass permutation (was nicht leicht zu ändern ist, aber shuffled ) hier der wahre Ausreißer ist. [Wenn es] shuffle-shuffled , permute-permuted dann denke ich, dass die Dinge ziemlich klar und vernünftig aussehen. Ist jemand bereit, shuffled hinzuzufügen und eine Einstellung für permutation starten?

Dies ist, was die Mailinglisten-Diskussion (irgendwie) im Jahr 2014 zusammenlief. Hier ist ein Link zu Nathaniels Vorschlag: https://mail.python.org/pipermail/numpy-discussion/2014-October/071364.html

Sein scramble[d] ist das, was ich randomly_permute[d] in https://github.com/numpy/numpy/pull/15121 genannt habe.

Wenn wir shuffled als Ersatz für permutation hinzufügen und die neuen Methoden aufrufen, die entlang einer Achse arbeiten permute[d] , lautet die Tabelle der zugehörigen Funktionen

meaning    operate
of axis    in-place   return copy
-------    ---------  -----------
"over"     shuffle    shuffled
"along"    permute    permuted

was eine schöne Konsistenz hat. In dieser API-Version hat keine der Methoden einen out Parameter.

Drüben in https://github.com/numpy/numpy/pull/15121 habe ich kürzlich eine weitere Methode hinzugefügt, mit dem plumpen und offensichtlich temporären Namen permuted_with_out , der zeigt, wie das Argument out könnte Gebraucht. Wenn wir einen Parameter out und bei den Namen der vorhandenen Methoden shuffle und permutation bleiben, sieht die Tabelle wie folgt aus:

meaning    operate
of axis    in-place                           return copy
-------    ---------------------------------  --------------------
"over"     shuffle(x, axis)                   permutation(x, axis)
"along"    permuted_with_out(x, axis, out=x)  permuted_with_out(x, axis)

Aber wenn wir einen Parameter out einführen, sollten wir konsequent sein und ihn auch in permutation . Und wir können immer noch in Erwägung ziehen, permutation durch shuffled ersetzen. Und da die neue Methode shuffled einen Parameter out , der eine direkte Operation ermöglicht, wird shuffle überflüssig und kann zusammen mit permutation veraltet sein. Wenn Sie dann zu den "schönen" Namen shuffled und permuted wechseln, ist die Tabelle

    meaning    operate
    of axis    in-place                  return copy
    -------    ------------------------  -----------------
    "over"     shuffled(x, axis, out=x)  shuffled(x, axis)
    "along"    permuted(x, axis, out=x)  permuted(x, axis)

Beachten Sie, dass der Parameter out nicht nur für den direkten Betrieb gedacht ist. Es ermöglicht die Wiederverwendung eines Ausgabearrays, wodurch möglicherweise die Erstellung eines temporären Arrays vermieden wird. Dies ist ein Vorteil dieser API gegenüber der shuffle/shuffled/permute/permuted API, aber ich bin mir nicht sicher, wie groß dieser Vorteil wirklich ist. Der Nachteil dieser API besteht darin, dass zwei Methoden veraltet sind, shuffle und permutation . Dies können für eine Weile "weiche" Verwerfungen sein (dh ihre Verwendung in den Dokumenten weniger betonen, aber für eine Weile keine wirkliche Veraltungswarnung hinzufügen), um die unmittelbaren Auswirkungen zu verringern.

Das ist meine Zusammenfassung der beiden Hauptanwärter auf den Wechsel. Wir haben die shuffle/shuffled/permute/permuted Version oder die Version mit shuffled/permuted mit einem out Parameter. Wenn im Jahr 2014 jemand eingesprungen wäre, um die besprochenen Änderungen zu implementieren, hätten wir wahrscheinlich bereits die shuffle/shuffled/permute/permuted Version. Aber die Version, die out hat ein paar (kleine? unbedeutende?) Vorteile: zwei Namen statt vier, und out ermöglicht einem Benutzer möglicherweise weniger temporäre Variablen. Ich würde mich über beides freuen.

Was denken die Leute?

Von den drei Szenarien, die Sie aufgelistet haben, würde ich sie der Reihe nach auf 1, 3 und ziemlich weit hinter 2 ordnen. Die 2 Permutationen, die ziemlich radikal unterschiedliche Dinge bewirken, scheinen eine große Quelle der Verwirrung zu sein. Meine persönliche Präferenz ist es, die obligatorische Verwendung von out für den Zugriff auf eine Funktion zu vermeiden; Ich denke immer an eine Leistungswahl, die in einigen Szenarien sinnvoll sein kann. Ich möchte den Schülern nicht wirklich beibringen, nur auf eine Funktion zuzugreifen. Ich würde auch annehmen, dass in Fall 3 x = shuffled(x, axis, out=x) auch return x anstelle von return None , so dass man, während es an Ort und Stelle ist, mit x enden könnte 3 mal erscheinen.

Meine persönliche Präferenz ist es, die obligatorische Verwendung von out für den Zugriff auf eine Funktion zu vermeiden; Ich denke immer an eine Leistungswahl, die in einigen Szenarien sinnvoll sein kann.

Aber das Mischen an Ort und Stelle _ist_ eine Leistungsentscheidung, nicht wahr?

Aber das Mischen an Ort und Stelle _ist_ eine Leistungsentscheidung, nicht wahr?

In-Place kann auch eine Codierungsstilauswahl sein, sofern verfügbar. Vielleicht ein verwirrendes und vielleicht fehleranfälliges.

Meine persönliche Meinung ist, dass sich f(x, out=x) immer etwas magisch anfühlt, da es manchmal als sehr nicht offensichtlicher Weg verwendet wird, um schnell etwas zu erreichen. f(x, inplace=True), obwohl es nicht wie etwas anderes aussieht, scheint viel klarer zu sein (sieht ein bisschen aus wie ein altes Panda-Muster, das größtenteils entfernt wurde).

Stimmt, aber es ist eine Wahl des Codierungsstils, die in NumPy normalerweise mit out=... geschrieben zu sein scheint (es sei denn, Sie verwenden einen In-Place-Operator oder eine Methode). Oder vielleicht ist es eine Wahl des Programmierstils, die NumPy derzeit in den meisten Fällen nicht aktiv versucht, einfach zu machen ...

Ich gebe zu, es ist ein bisschen magisch und ein inplace= Kwarg mag weniger magisch sein, aber auch ohne wirklichen Vorrang? Und ich bin mir nicht sicher, ob der Hauptgrund dafür, dass es weniger magisch erscheint, darin besteht, dass das In-Place-Shuffle das Herzstück des Algorithmus ist. Algorithmische Details sollten den meisten Schülern nicht viel ausmachen und am Ende spart die Verwendung von out= auch ungefähr eine einzige Kopie + die zugehörige Speicherbandbreite und ist vergleichbar mit ufuncs. (Fair genug, auch für Ufuncs ist out=input vielleicht etwas magisch, aber seine übliche Magie und ein bekanntes Muster – für fortgeschrittene Benutzer.)

Obwohl das Schreiben möglicherweise etwas mühsam und etwas weniger schnell zu lesen ist, scheint np.shuffled(x, out=x) sehr klar zu sein, was das Verhalten ist. Der nicht offensichtliche Teil scheint nur die Auswirkung auf die Leistung zu sein, die mir wie ein Problem vorkommt, das erfahrenen Benutzern vorbehalten ist.

Eine hypothetische Frage für diejenigen, die die Verwendung von out befürworten: Wenn wir die vorhandenen Funktionen numpy.sort und ndarray.sort und wir jetzt eine Sortierfunktion hinzufügen würden, wäre die die bevorzugte API ist numpy.sorted(a, axis=-1, kind=None, order=None, out=None) (ohne dass die Methode ndarray.sort für die direkte Sortierung implementiert werden muss)?

ndarray.sort ist nach list.sort modelliert, daher ist es wahrscheinlich unabhängig davon eine vernünftige API-Wahl. Allerdings wäre ich dafür gewesen, dass np.sort nicht existiert und stattdessen np.sorted(..., out=...) .

Ja, ich denke, np.sort sollte np.sorted heißen (genauso wie sorted() Python). Da nur die Methode das In-Place-Verhalten aufweist, sehe ich jedoch keine großen Bedenken.

Ich bin mir nicht sicher, ob "die Methode ndarray.sort nicht implementiert werden muss". Ich sehe nichts Falsches an der Methode (oder ihrem Verhalten vor Ort). Die Frage nach der Methode ist nur, wenn wir es für wichtig genug halten, eine bequeme Methodenkurzschrift bereitzustellen.
Ich nehme an, es ist auch nichts falsch daran, eine In-Place-Funktionsversion zu haben. Die Not-in-Place-Version scheint neuen Benutzern einfach besser zu sein und das out= Muster ist für mich so verbreitet, dass fortgeschrittene Benutzer ausreichend gut bedient sind.

Ich bin mir nicht sicher, ob "die Methode ndarray.sort nicht implementiert werden muss". Ich sehe nichts Falsches an der Methode (oder ihrem Verhalten vor Ort).

Das war Teil meines API-Gedankenexperiments. Ich wollte nicht andeuten, dass an dem, was wir jetzt haben, etwas nicht stimmt. Ich habe gerade gesagt, dass, wenn wir bei Null anfangen würden – und ich füge meinen hypothetischen Prämissen hinzu, dass wir uns nicht darum kümmern, die Python-API für Listen abzugleichen – dann wäre die bevorzugte API zum Sortieren numpy.sorted(..., out=...) , und wir würden nichts anderes brauchen.

Eine andere, nicht so hypothetische Frage: Wenn die Verwendung von out hier die bevorzugte Option ist, sollten wir aus Gründen der API-Konsistenz in NumPy planen, out zu numpy.sort hinzuzufügen, numpy.partition , numpy.argsort , und, na ja , was es derzeit nicht gibt?

Ja, meiner Meinung nach ist das Hinzufügen eines out= kwargs mit derselben Semantik wie für ufuncs eine gute Wahl für praktisch alle NumPy-API-Funktionen. Jedes Fehlen eines out Arguments ist im Allgemeinen eine Verbesserung, die darauf wartet, vorgenommen zu werden (obwohl es in der Praxis meiner Meinung nach eine kleine Verbesserung sein kann und in seltenen Fällen möglicherweise nicht allzu viel zusätzliche Codekomplexität wert ist).

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen