Quelle est la différence entre les fonctions d'aplatissement et de défilement dans 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]

Les deux fonctions renvoient la même liste. Alors, quel est le besoin de deux fonctions différentes effectuant le même travail.

cryptomaniaque
la source
14
Ravel renvoie généralement une vue dans le tableau existant (parfois il renvoie une copie). Flatten renvoie un nouveau tableau.
Alex
1
Voici une démonstration pratique de la différence subtile.
prosti
Alors, quelqu'un peut-il donner un exemple quand il vaut mieux aplatir un tableau et quand le défiler?
Aleksandar

Réponses:

371

L'API actuelle est la suivante:

  • flatten renvoie toujours une copie.
  • ravelrenvoie une vue du tableau d'origine autant que possible. Ce n'est pas visible dans la sortie imprimée, mais si vous modifiez le tableau retourné par ravel, cela peut modifier les entrées du tableau d'origine. Si vous modifiez les entrées dans un tableau renvoyé d'aplatir, cela ne se produira jamais. ravel sera souvent plus rapide car aucune mémoire n'est copiée, mais vous devez être plus prudent lorsque vous modifiez le tableau qu'il renvoie.
  • reshape((-1,)) obtient une vue chaque fois que les enjambées du tableau le permettent même si cela signifie que vous n'obtenez pas toujours un tableau contigu.
IanH
la source
30
Une idée pourquoi les développeurs de NumPy ne se sont pas tenus à une fonction avec une copie de paramètre = [Vrai, Faux]?
Franck Dernoncourt
41
Les garanties de rétrocompatibilité provoquent parfois des choses étranges comme celle-ci. Par exemple: les développeurs numpy ont récemment (en 1.10) ajouté une garantie précédemment implicite que ravel retournerait un tableau contigu (une propriété qui est très importante lors de l'écriture d'extensions C), donc maintenant l'API est a.flatten()d'obtenir une copie à coup sûr, a.ravel()pour éviter la plupart des copies, mais garantissent toujours que le tableau renvoyé est contigu et a.reshape((-1,))pour obtenir une vue réelle chaque fois que les pas du tableau le permettent, même si cela signifie que vous n'obtenez pas toujours un tableau contigu.
IanH
4
@Hossein IanH l'a expliqué: ravelgarantit un tableau contigu, et il n'est donc pas garanti qu'il renvoie une vue; reshaperenvoie toujours une vue, et il n'est donc pas garanti qu'il renvoie un tableau contigu.
iled
4
@Hossein Ce serait une toute nouvelle question. Très brièvement, il est beaucoup plus rapide de lire et d'écrire dans un espace mémoire contigu. Il y a plusieurs questions et réponses à ce sujet ici sur SO ( bel exemple ici ), n'hésitez pas à en ouvrir une nouvelle si vous avez d'autres questions.
iled
2
reshape(-1)est équivalent àreshape((-1,))
Tom Pohl
53

Comme expliqué ici, une différence clé est que:

  • flatten est une méthode d'un objet ndarray et ne peut donc être appelée que pour de vrais tableaux numpy.

  • ravel est une fonction au niveau de la bibliothèque et peut donc être appelée sur n'importe quel objet qui peut être analysé avec succès.

Par exemple ravel, fonctionnera sur une liste de ndarrays, alors qu'il flattenn'est pas disponible pour ce type d'objet.

@IanH souligne également des différences importantes avec la gestion de la mémoire dans sa réponse.

Bryan P
la source
4
merci pour ces informations sur le ravel () travaillant sur les listes de ndarray's
javadba
Non seulement des listes de tableaux mais aussi des listes de listes :)
timtody
15

Voici l'espace de noms correct pour les fonctions:

Les deux fonctions renvoient des tableaux 1D aplatis pointant vers les nouvelles structures de mémoire.

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

Dans l'exemple supérieur:

  • les emplacements mémoire des résultats sont différents,
  • les résultats se ressemblent
  • aplatir retournerait une copie
  • ravel retournerait une vue.

Comment vérifions-nous si quelque chose est une copie? Utilisation de l' .baseattribut du ndarray. S'il s'agit d'une vue, la base sera le tableau d'origine; s'il s'agit d'une copie, la base le sera None.

prosti
la source