¿Cuál es la diferencia entre aplanar y ravel funciones en 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]

Ambas funciones devuelven la misma lista. Entonces, ¿cuál es la necesidad de dos funciones diferentes que realicen el mismo trabajo?

criptomanía
fuente
14
Ravel generalmente devuelve una vista en la matriz existente (a veces devuelve una copia). Flatten devuelve una nueva matriz.
Alex
1
Aquí hay una demostración práctica de la sutil diferencia.
prosti
Entonces, ¿alguien puede dar un ejemplo cuando es mejor aplanar una matriz y cuándo descifrarla?
Aleksandar

Respuestas:

371

La API actual es que:

  • flatten siempre devuelve una copia.
  • raveldevuelve una vista de la matriz original siempre que sea posible. Esto no es visible en la salida impresa, pero si modifica la matriz devuelta por ravel, puede modificar las entradas en la matriz original. Si modifica las entradas en una matriz devuelta de flatten, esto nunca sucederá. ravel a menudo será más rápido ya que no se copia memoria, pero debe tener más cuidado al modificar la matriz que devuelve.
  • reshape((-1,)) obtiene una vista cada vez que los pasos de la matriz lo permiten, incluso si eso significa que no siempre obtiene una matriz contigua.
IanH
fuente
30
¿Alguna idea de por qué los desarrolladores de NumPy no se adhirieron a una función con algún parámetro copy = [True, False]?
Franck Dernoncourt
41
Las garantías de Backcompat a veces hacen que sucedan cosas extrañas como esta. Por ejemplo: los desarrolladores numpy recientemente (en 1.10) agregaron una garantía previamente implícita de que ravel devolvería una matriz contigua (una propiedad que es muy importante al escribir extensiones C), por lo que ahora la API a.flatten()debe obtener una copia segura, a.ravel()para evitar la mayoría de las copias, pero aún así garantizan que la matriz devuelta sea contigua, y a.reshape((-1,))para obtener realmente una vista siempre que los pasos de la matriz lo permitan, incluso si eso significa que no siempre obtiene una matriz contigua.
IanH
44
@Hossein IanH lo explicó: ravelgarantiza una matriz contigua, por lo que no se garantiza que devuelva una vista; reshapesiempre devuelve una vista, por lo que no se garantiza que devuelva una matriz contigua.
iled
44
@Hossein Esa sería una pregunta completamente nueva. Muy brevemente, es mucho más rápido leer y escribir en un espacio de memoria contiguo. Hay varias preguntas y respuestas sobre eso aquí en SO ( buen ejemplo aquí ), siéntase libre de abrir una nueva si tiene más preguntas.
iled
2
reshape(-1)es equivalente areshape((-1,))
Tom Pohl el
53

Como se explica aquí, una diferencia clave es que:

  • flatten es un método de un objeto ndarray y, por lo tanto, solo se puede llamar para matrices numpy verdaderas.

  • ravel es una función de nivel de biblioteca y, por lo tanto, se puede invocar en cualquier objeto que se pueda analizar correctamente.

Por ejemplo ravel, funcionará en una lista de ndarrays, mientras flattenno esté disponible para ese tipo de objeto.

@IanH también señala diferencias importantes con el manejo de la memoria en su respuesta.

Bryan P
fuente
44
gracias por esa información sobre el ravel () trabajando en listas de ndarray's
javadba
No solo listas de matrices, sino también listas de listas :)
timtody
15

Aquí está el espacio de nombres correcto para las funciones:

Ambas funciones devuelven matrices 1D aplanadas que apuntan a las nuevas estructuras de memoria.

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

En el ejemplo superior:

  • las ubicaciones de memoria de los resultados son diferentes,
  • los resultados se ven iguales
  • aplanar devolvería una copia
  • Ravel devolvería una vista.

¿Cómo verificamos si algo es una copia? Usando el .baseatributo de la ndarray. Si es una vista, la base será la matriz original; si es una copia, la base lo será None.

prosti
fuente