In this article we will discuss main differences between numpy.ravel() and ndarray.flatten() functions.

Objective of both the numpy.ravel() and ndarray.flatten() functions is the same i.e. flatten a numpy array of any shape. But there are some basic differences in both of them. Before going into detail about differences, let’s have a basic overview of both the functions,

#### numpy.ravel()

`numpy.ravel(a, order='C')`

ravel() is a built-in function in numpy module that accepts an array-like element as parameter and returns a flatten 1D view of the input array.

#### numpy.ndarray.flatten()

`ndarray.flatten(order='C')`

flatten() is a member function of the numpy array and it returns a flatten 1D copy of the numpy array object.

Both the functions flattens in input array, now let’s discuss main differences between them

## Differences between ravel() & flatten()

First of all, import the numpy module,

`import numpy as np`

### Difference 1: Performance : Copy vs view

ndarray.flatten() function returns a flatten copy of the array object. Whereas, on the other side numpy.ravel() returns a flattened 1D view of the input array (if possible). Let’s understand this with an example,

Suppose we have a 2D Numpy array,

```# Create a 2D Numpy array
arr_2d = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])

print(arr_2d)```

Output:
```[[0 1 2]
[3 4 5]
[6 7 8]]```

Now let’s use ndarray.flatten() to convert it to a flatten 1D numpy array,
```# Convert the 2D array to 1D array
flat_array = arr_2d.flatten()

print(flat_array)```

Output:
`[0 1 2 3 4 5 6 7 8]`

flatten() returns a copy of the input numpy array. So, any modification done in it will not affect the original numpy array.
Let’s confirm this,
```# Modify the 2nd element  in flat array
flat_array = 222

# Changes will be reflected in only flat array and original 2D array will remain unaffected
print(flat_array)

print(arr_2d)
```

Output:
```[  0 222   2   3   4   5   6   7   8]
[[0 1 2]
[3 4 5]
[6 7 8]]```

We changed the value of the 2nd element in the flattened 1D numpy array, but the original 2D array remains unaffected with this. This confirms that flatten() returns a copy of the input numpy array.

Now let’s use numpy.ravel() to convert our 2D numpy array to a flatten 1D numpy array,

```# Get a flattened view of 2D Numpy array
flat_array = np.ravel(arr_2d)

print('Flattened view:')
print(flat_array)
```

Output:
```Flattened view:
[0 1 2 3 4 5 6 7 8]```

If possible, ravel() returns a view of the input numpy array. When it returns a view then any modification done in the view object will also be reflected in the original numpy array.
To check if the the ravel() function returned a view object or not we will use the base attribute of the returned object. If it is not None then it points the original numpy array and it means return flattened array is a view only,

Let’s confirm this,

```if flat_array.base is not None:
# Modify the 2nd element  in flat array
flat_array = 11

# Changes will be reflected in both flat array and original 2D array
print(flat_array)
print(arr_2d)
```

Output:
```[ 0 11  2  3  4  5  6  7  8]
[[ 0 11  2]
[ 3  4  5]
[ 6  7  8]]```

We changed the value of the 2nd element in the flattened 1D numpy array only but the change was reflected in the original 2D numpy array too. This confirms that ravel() returns a view of the input numpy array.

As ravel() returns a view if possible, whereas flatten() returns a copy always. So, the performance of ravel() is quite better than the flatten().

### Difference 2: Compatibility with other array like sequences (list etc)

ndarray.flatten() is a member function of the numpy array object, therefore it can be used to flatten a numpy array object only. Whereas numpy.ravel() is a builtin function of the numpy module that accepts an array-like element, therefore we can also pass a list to it.

For example,
Flatten a list of lists using numpy.ravel()

```# Create a list of lists
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]

# Create a flattened numpy array from list of lists
flat_array = np.ravel(list_of_lists)

print('Flattened Numpy Array:')
print(flat_array)
```

Output:
```Flattened Numpy Array:
[1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5]```

Whereas, this is not possible with ndarray.flatten() function.

So, to sum up in the end there are 2 main differences between the ndarray.flatten() and numpy.ravel() function,

1. ravel() function returns a view if possible, where flatten() always returns a copy. Therefore performance of ravel(0 is much better than flatten()
2. ravel() function can accept other array-like elements like lists etc. Whereas, flatten() can work with numpy arrays only.

The complete example is as follows,

```import numpy as np

def main():

print('*** ravel() vs flatten()  ***')

print('** Difference 1 -> Performance : Copy vs view **')

# Create a 2D Numpy array
arr_2d = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])

print('2D Numpy Array:')
print(arr_2d)

print('Get a flattened 1D copy of 2D numpy array using flatten()')

# Convert the 2D array to 1D array
flat_array = arr_2d.flatten()

print('Flattened 1D Numpy Array:')
print(flat_array)

# Modify the 2nd element  in flat array
flat_array = 222

# Changes will be reflected in only flat array and original 2D array will remain unaffected
print(flat_array)

print(arr_2d)

print('Get a flattened 1D View of 2D numpy array using ravel()')

# Get a flattened view of 2D Numpy array
flat_array = np.ravel(arr_2d)

print('Flattened view:')
print(flat_array)

print('numpy.ravel() returns a view of the input array ')

if flat_array.base is not None:
# Modify the 2nd element  in flat array
flat_array = 11

# Changes will be reflected in both flat array and original 2D array
print(flat_array)
print(arr_2d)

print('*** Difference 2 -> Compatibility with other array like sequences like list ***')

print('Flatten a list of lists using numpy.ravel()')

# Create a list of lists
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]

# Create a flattened numpy array from list of lists
flat_array = np.ravel(list_of_lists)

print('Flattened Numpy Array:')
print(flat_array)

if __name__ == '__main__':
main()
```

Output
```*** ravel() vs flatten()  ***
** Difference 1 -> Performance : Copy vs view **
2D Numpy Array:
[[0 1 2]
[3 4 5]
[6 7 8]]
Get a flattened 1D copy of 2D numpy array using flatten()
Flattened 1D Numpy Array:
[0 1 2 3 4 5 6 7 8]
[  0 222   2   3   4   5   6   7   8]
[[0 1 2]
[3 4 5]
[6 7 8]]
Get a flattened 1D View of 2D numpy array using ravel()
Flattened view:
[0 1 2 3 4 5 6 7 8]
numpy.ravel() returns a view of the input array
[ 0 11  2  3  4  5  6  7  8]
[[ 0 11  2]
[ 3  4  5]
[ 6  7  8]]
*** Difference 2 -> Compatibility with other array like sequences like list ***
Flatten a list of lists using numpy.ravel()
Flattened Numpy Array:
[1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5]```