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/
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 Siea
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 sortierenIch 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?
Der Mailinglisten-Thread ist hier:
http://thread.gmane.org/gmane.comp.python.numeric.general/59014
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:
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 zurndarray
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, abershuffled
) 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ürpermutation
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).
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
mitnp.random.permutation
als Problemumgehung.