460
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]

Both function return the same list. Then what is the need of two different functions performing same job.

4
  • 30
    Ravel usually returns a view into the existing array (sometimes it returns a copy). Flatten returns a new array. Commented Mar 8, 2015 at 18:55
  • 5
    Possible duplicate of What is the difference between flatten and ravel in numpy? Commented Aug 22, 2016 at 2:32
  • 1
    Here is a practical demonstration of subtle difference. Commented Jan 22, 2019 at 17:12
  • 1
    So can someone give an example when it is better to flatten an array and when to ravel it ? Commented Mar 28, 2020 at 19:00

4 Answers 4

570

The current API is that:

  • flatten always returns a copy.
  • ravel returns a contiguous view of the original array whenever possible. This isn't visible in the printed output, but if you modify the array returned by ravel, it may modify the entries in the original array. If you modify the entries in an array returned from flatten this will never happen. ravel will often be faster since no memory is copied, but you have to be more careful about modifying the array it returns.
  • reshape((-1,)) gets a view whenever the strides of the array allow it even if that means you don't always get a contiguous array.
Sign up to request clarification or add additional context in comments.

14 Comments

Any idea why NumPy developers didn't stick to one function with some parameter copy=[True,False]?
Backcompat guarantees sometimes cause odd things like this to happen. For example: the numpy developers recently (in 1.10) added a previously implicit guarantee that ravel would return a contiguous array (a property that is very important when writing C extensions), so now the API is a.flatten() to get a copy for sure, a.ravel() to avoid most copies but still guarantee that the array returned is contiguous, and a.reshape((-1,)) to really get a view whenever the strides of the array allow it even if that means you don't always get a contiguous array.
@Hossein IanH explained it: ravelguarantees a contiguous array, and so it is not guaranteed that it returns a view; reshape always returns a view, and so it is not guaranteed that it returns a contiguous array.
@Hossein That would be a whole new question. Very briefly, it is much faster to read and write to a contiguous memory space. There are several questions and answers on that here on SO (nice example here), feel free to open a new one if you have any further questions.
Why is it called ravel? What is the idea behind the name?
|
93

As explained here a key difference is that:

  • flatten is a method of an ndarray object and hence can only be called for true numpy arrays.

  • ravel is a library-level function and hence can be called on any object that can successfully be parsed.

For example ravel will work on a list of ndarrays, while flatten is not available for that type of object.

@IanH also points out important differences with memory handling in his answer.

2 Comments

thx for that info about the ravel() working on lists of ndarray's
Not only lists of arrays but also lists of lists :)
34

Here is the correct namespace for the functions:

Both functions return flattened 1D arrays pointing to the new memory structures.

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

In the upper example:

  • the memory locations of the results are different,
  • the results look the same
  • flatten would return a copy
  • ravel would return a view.

How we check if something is a copy? Using the .base attribute of the ndarray. If it's a view, the base will be the original array; if it is a copy, the base will be None.


Check if a2 is copy of a1

import numpy
a1 = numpy.array([[1,2],[3,4]])
a2 = a1.copy()
id(a2.base), id(a1.base)

Out:

(140735713795296, 140735713795296)

2 Comments

id(a1.base) should be the same as id(a2.base)
a1.base and a2.base are both None, which is why the id of the base can/will be the same. But id(a1) and id(a2) are different due to copying. The bases will be different if a2 is a slice of a1 , in which case "a1.base is None" but "a2.base is a1"
0

Let me present a comparison between the three functions/methods in a little table I put together for my students:

Aspect y = x.flatten() y = np.ravel(x) y = x.reshape(-1)
Return value (y) copy view if possible view if possible
Original value (x) unchanged may change if view may change if view
Speed slower faster if view faster if view
Memory usage higher lower if view lower if view
Contiguous memory layout always only if view No guarantee

If this variety weren't enough: be reminded that the reshape() method takes the new shape either as a tuple (like (-1,) as in the code examples above) or as a parameter list. The latter saves you two parentheses. The module-level function np.reshape(arr, newshape, ...), however, accepts the new shape specified as a tuple only.

Which reminds me of one of the articles of faith in the Zen of Python (import this): "There should be one-- and preferably only one --obvious way to do it." :-)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.