Qual é a diferença entre as funções flatten e ravel no 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 as funções retornam a mesma lista. Então, qual é a necessidade de duas funções diferentes executando o mesmo trabalho.

criptomanico
fonte
14
Ravel geralmente retorna uma visão para a matriz existente (às vezes retorna uma cópia). Achatar retorna uma nova matriz.
8288 Alex
1
Aqui está uma demonstração prática da diferença sutil.
prosti
Então, alguém pode dar um exemplo de quando é melhor achatar uma matriz e quando usá-la?
Aleksandar

Respostas:

371

A API atual é a seguinte:

  • flatten sempre retorna uma cópia.
  • ravelretorna uma visão da matriz original sempre que possível. Isso não é visível na saída impressa, mas se você modificar a matriz retornada pelo ravel, poderá modificar as entradas na matriz original. Se você modificar as entradas em uma matriz retornada do achatamento, isso nunca acontecerá. O ravel geralmente será mais rápido, pois nenhuma memória é copiada, mas você precisa ter mais cuidado ao modificar a matriz que retorna.
  • reshape((-1,)) obtém uma visualização sempre que os avanços da matriz permitirem, mesmo que isso signifique que você nem sempre obtém uma matriz contígua.
IanH
fonte
30
Alguma idéia de por que os desenvolvedores do NumPy não aderiram a uma função com algum parâmetro copy = [True, False]?
Franck Dernoncourt
41
As garantias do Backcompat às vezes causam coisas estranhas como essa. Por exemplo: os desenvolvedores numpy recentemente (na 1.10) adicionaram uma garantia implícita anteriormente de que o ravel retornaria uma matriz contígua (uma propriedade que é muito importante ao escrever extensões C), então agora a API a.flatten()deve obter uma cópia com certeza, a.ravel()para evitar a maioria das cópias, mas ainda assim garante que a matriz retornada seja contígua e a.reshape((-1,))para realmente obter uma visualização sempre que os passos da matriz permitirem, mesmo que isso signifique que você nem sempre obtém uma matriz contígua.
21715 IanHarder
4
@Hossein IanH explicou: ravelgarante uma matriz contígua e, portanto, não é garantido que ele retorne uma visualização; reshapesempre retorna uma exibição e, portanto, não é garantido que ele retorne uma matriz contígua.
iled
4
@ Hossein Isso seria uma pergunta totalmente nova. Muito brevemente, é muito mais rápido ler e gravar em um espaço de memória contíguo. Existem várias perguntas e respostas sobre isso aqui no SO ( bom exemplo aqui ), sinta-se à vontade para abrir uma nova, se tiver mais alguma pergunta.
iled
2
reshape(-1)é equivalente areshape((-1,))
Tom Pohl
53

Como explicado aqui, a principal diferença é que:

  • flatten é um método de um objeto ndarray e, portanto, só pode ser chamado para matrizes numpy verdadeiras.

  • ravel é uma função no nível da biblioteca e, portanto, pode ser chamada em qualquer objeto que possa ser analisado com êxito.

Por exemplo ravel, funcionará em uma lista de ndarrays, enquanto flattennão estiver disponível para esse tipo de objeto.

O @IanH também aponta diferenças importantes na manipulação de memória em sua resposta.

Bryan P
fonte
4
thx por essa informação sobre o ravel () trabalhando em listas de ndarray's
javadba 28/10
Não só listas de matrizes, mas também listas de listas :)
timtody
15

Aqui está o espaço para nome correto para as funções:

Ambas as funções retornam matrizes 1D achatadas, apontando para as novas estruturas de memória.

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

No exemplo superior:

  • os locais de memória dos resultados são diferentes,
  • os resultados têm a mesma aparência
  • achatar retornaria uma cópia
  • Ravel retornaria uma visão.

Como verificamos se algo é uma cópia? Usando o .baseatributo do ndarray. Se for uma visualização, a base será a matriz original; se for uma cópia, a base será None.

prosti
fonte