Was ist der Unterschied zwischen Flatten- und Ravel-Funktionen in Numpy?

292
import numpy as np
y = np.array(((1,2,3),(4,5,6),(7,8,9)))
OUTPUT:
print(y.flatten())
[1   2   3   4   5   6   7   8   9]
print(y.ravel())
[1   2   3   4   5   6   7   8   9]

Beide Funktionen geben dieselbe Liste zurück. Was brauchen dann zwei verschiedene Funktionen, die denselben Job ausführen?

kryptoman
quelle
14
Ravel gibt normalerweise eine Ansicht in das vorhandene Array zurück (manchmal gibt es eine Kopie zurück). Flatten gibt ein neues Array zurück.
Alex
1
Hier ist eine praktische Demonstration subtiler Unterschiede.
Prosti
Kann jemand ein Beispiel geben, wann es besser ist, ein Array zu reduzieren und wann es zu ravelen?
Aleksandar

Antworten:

371

Die aktuelle API lautet:

  • flatten gibt immer eine Kopie zurück.
  • ravelGibt nach Möglichkeit eine Ansicht des ursprünglichen Arrays zurück. Dies ist in der gedruckten Ausgabe nicht sichtbar. Wenn Sie jedoch das von ravel zurückgegebene Array ändern, werden möglicherweise die Einträge im ursprünglichen Array geändert. Wenn Sie die Einträge in einem von flatten zurückgegebenen Array ändern, wird dies niemals passieren. Ravel ist oft schneller, da kein Speicher kopiert wird. Sie müssen jedoch vorsichtiger sein, wenn Sie das zurückgegebene Array ändern.
  • reshape((-1,)) Ruft eine Ansicht ab, wenn die Schritte des Arrays dies zulassen, auch wenn dies bedeutet, dass Sie nicht immer ein zusammenhängendes Array erhalten.
IanH
quelle
30
Irgendeine Idee, warum NumPy-Entwickler sich nicht an eine Funktion mit einem Parameter copy = [True, False] gehalten haben?
Franck Dernoncourt
41
Backcompat-Garantien führen manchmal dazu, dass seltsame Dinge wie diese passieren. Beispiel: Die Numpy-Entwickler haben kürzlich (in Version 1.10) eine zuvor implizite Garantie hinzugefügt, dass Ravel ein zusammenhängendes Array zurückgibt (eine Eigenschaft, die beim Schreiben von C-Erweiterungen sehr wichtig ist). Daher muss die API jetzt a.flatten()sicher eine Kopie abrufen, um dies a.ravel()zu vermeiden Die meisten Kopien garantieren jedoch, dass das zurückgegebene Array zusammenhängend ist, und a.reshape((-1,))um wirklich eine Ansicht zu erhalten, wann immer die Schritte des Arrays dies zulassen, auch wenn dies bedeutet, dass Sie nicht immer ein zusammenhängendes Array erhalten.
IanH
4
@Hossein IanH erklärte es: ravelGarantiert ein zusammenhängendes Array, und daher kann nicht garantiert werden, dass es eine Ansicht zurückgibt. reshapeGibt immer eine Ansicht zurück, sodass nicht garantiert werden kann, dass ein zusammenhängendes Array zurückgegeben wird.
iled
4
@Hossein Das wäre eine ganz neue Frage. Kurz gesagt, es ist viel schneller, in einen zusammenhängenden Speicherbereich zu lesen und zu schreiben. Hier auf SO gibt es mehrere Fragen und Antworten ( schönes Beispiel hier ). Wenn Sie weitere Fragen haben, können Sie gerne eine neue öffnen.
iled
2
reshape(-1)ist gleichbedeutend mitreshape((-1,))
Tom Pohl
53

Wie hier erklärt , besteht ein wesentlicher Unterschied darin, dass:

  • flatten ist eine Methode eines ndarray-Objekts und kann daher nur für echte Numpy-Arrays aufgerufen werden.

  • ravel ist eine Funktion auf Bibliotheksebene und kann daher für jedes Objekt aufgerufen werden, das erfolgreich analysiert werden kann.

Arbeitet beispielsweise ravelan einer Liste von ndarrays, während flattensie für diesen Objekttyp nicht verfügbar ist.

@IanH weist in seiner Antwort auch auf wichtige Unterschiede bei der Speicherbehandlung hin.

Bryan P.
quelle
4
Danke für diese Info über die ravel (), die an Listen von ndarray's
javadba
Nicht nur Listen von Arrays, sondern auch Listen von Listen :)
Timtody
15

Hier ist der richtige Namespace für die Funktionen:

Beide Funktionen geben abgeflachte 1D-Arrays zurück, die auf die neuen Speicherstrukturen verweisen.

import numpy
a = numpy.array([[1,2],[3,4]])

r = numpy.ravel(a)
f = numpy.ndarray.flatten(a)  

print(id(a))
print(id(r))
print(id(f))

print(r)
print(f)

print("\nbase r:", r.base)
print("\nbase f:", f.base)

---returns---
140541099429760
140541099471056
140541099473216

[1 2 3 4]
[1 2 3 4]

base r: [[1 2]
 [3 4]]

base f: None

Im oberen Beispiel:

  • Die Speicherorte der Ergebnisse sind unterschiedlich.
  • Die Ergebnisse sehen gleich aus
  • Abflachen würde eine Kopie zurückgeben
  • Ravel würde eine Ansicht zurückgeben.

Wie prüfen wir, ob etwas eine Kopie ist? Verwenden Sie das .baseAttribut des ndarray. Wenn es sich um eine Ansicht handelt, ist die Basis das ursprüngliche Array. Wenn es sich um eine Kopie handelt, ist die Basis None.

Prosti
quelle