🌐
NumPy
numpy.org › doc › 2.2 › reference › generated › numpy.ravel.html
numpy.ravel — NumPy v2.2 Manual
When a view is desired in as many cases as possible, arr.reshape(-1) may be preferable. However, ravel supports K in the optional order argument while reshape does not. ... It is equivalent to reshape(-1, order=order). >>> import numpy as np >>> x = np.array([[1, 2, 3], [4, 5, 6]]) >>> np.ravel(x) array([1, 2, 3, 4, 5, 6])
🌐
GeeksforGeeks
geeksforgeeks.org › python › numpy-ravel-python
numpy.ravel() in Python - GeeksforGeeks
December 23, 2024 - The numpy.ravel() functions returns contiguous flattened array(1D array with all the input-array elements and with the same type as it). A copy is made only if needed.
Discussions

ravel vs. flatten
Hi, I heard that if the values in the result were contiguous in the original array, ravel does not produce a copy of the underlying values. >>> import numpy as np >>> x = np.r_[:10].reshape((2, 5)) >>> x array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) >>> x.ctypes.data 93975275387840 >>> x.ravel().ctypes.data 93975275387840 # SAME MEMORY LOCATION >>> x.flatten().ctypes.data 93975280365840 # DIFFERENT LOCATION Looks that way, yeah. Let's try non-contiguous: >>> y = x[:, ::2] >>> y array([[0, 2, 4], [5, 7, 9]]) >>> y.flags.contiguous False # NOT CONTIGUOUS ANYMORE >>> y.ctypes.data 93975275387840 >>> y.ravel().ctypes.data 93975280484400 # DIFFERENT LOCATION >>> y.flatten().ctypes.data 93975280372960 # DIFFERENT LOCATION That tracks, too. What does that mean? It means if you edit the output of ndarray.ravel(), the original might change, too, because they can both point to the same data. How do I know if the values in the result were contagious in the original array not? Check the flags of the array, like I did above. In practice, is it recommended to use flattern or ravel all the time? flatten() if you're going to change the copy and you don't want the original to change; otherwise ravel(). More on reddit.com
🌐 r/learnpython
6
1
March 11, 2020
What to use- flatten() or ravel()- for an image array?
Ravel returns a view of the original array, flatten a copy. If you edit the result of ravel then the change is seen in the original array, and vice versa. If you are only reading the array then ravel is the better choice More on reddit.com
🌐 r/learnpython
1
1
July 18, 2021
python - What does the function name `ravel` stand for in `NumPy`? - Stack Overflow
What does ravel stand for in NumPy? Sometimes, it is a bit harder to remember a function name that the name has nothing to do with its description. More on stackoverflow.com
🌐 stackoverflow.com
python - Numpy ravel takes too long after a slight change to a ndarray - Stack Overflow
Is there any reason for the ravel to create a copy of the array? How can i reduce this time? Note: I also tested the inplace reshape method that's written on the notes of numpy.reshape documentation, but, as specified, an error was raised, meaning that the array need to be copied before in ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Vultr Docs
docs.vultr.com › python › third-party › numpy › ravel
Python Numpy ravel() - Flatten Array | Vultr Docs
November 14, 2024 - The ravel() function is a versatile tool in NumPy for flattening arrays into a one-dimensional structure. Whether dealing with simple two-dimensional arrays or more complex ones, utilizing this function ensures that data manipulation becomes ...
🌐
Programiz
programiz.com › python-programming › numpy › methods › ravel
NumPy ravel()
The ravel() method flattens a NumPy array without changing its data. The ravel() method flattens a NumPy array without changing its data. Example import numpy as np array1 = np.array([[0, 1], [2, 3]]) # flatten an array array2 = np.ravel(array1) print(array2) # Output : [0 1 2 3] ravel() Syntax ...
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.ravel.html
numpy.ravel — NumPy v2.5.dev0 Manual
numpy.ravel(a, order='C')[source]# Return a contiguous flattened array. A 1-D array, containing the elements of the input, is returned. A copy is made only if needed. As of NumPy 1.10, the returned array will have the same type as the input array. (for example, a masked array will be returned ...
🌐
Medium
medium.com › @whyamit101 › numpy-ravel-in-python-4da4f282986e
numpy.ravel() in Python. If you think you need to spend $2,000… | by why amit | Medium
February 26, 2025 - That’s where numpy.ravel() steps in—your trusty tool for flattening arrays effortlessly.
Find elsewhere
🌐
DataCamp
datacamp.com › doc › numpy › flatten-vs-ravel
NumPy Flatten vs Ravel
In this syntax, `flatten` creates a new array, while `ravel` tries to return a view of the original array, minimizing memory usage. A "view" in NumPy is an array that shares the same data buffer as the original array, allowing for efficient memory use.
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.unravel_index.html
numpy.unravel_index — NumPy v2.5.dev0 Manual
Converts a flat index or array of flat indices into a tuple of coordinate arrays · An integer array whose elements are indices into the flattened version of an array of dimensions shape. Before version 1.6.0, this function accepted just one index value
🌐
Reddit
reddit.com › r/learnpython › ravel vs. flatten
r/learnpython on Reddit: ravel vs. flatten
March 11, 2020 -

Hi, I heard that if the values in the result were contiguous in the original array, ravel does not produce a copy of the underlying values. What does that mean? How do I know if the values in the result were contagious in the original array not? In practice, is it recommended to use flattern or ravel all the time?

🌐
Reddit
reddit.com › r/learnpython › what to use- flatten() or ravel()- for an image array?
r/learnpython on Reddit: What to use- flatten() or ravel()- for an image array?
July 18, 2021 -

For a component (H,S,V) array of an image, I want to plot a histogram and calculate some statistical parameters. For this, I need to flatten the array first, and then group the elements as required. For flattening the array, I read about those two functions, and I feel ravel() is better as it takes less memory and time.

I won’t have to modify the component array after flattening; I’ll only have to traverse through it. So, should I use ravel()? Or, should I use flatten() instead?

Thanks.

🌐
NumPy
numpy.org › doc › 2.1 › reference › generated › numpy.ravel_multi_index.html
numpy.ravel_multi_index — NumPy v2.1 Manual
raveled_indicesndarray · An array of indices into the flattened version of an array of dimensions dims. See also · unravel_index · Notes · New in version 1.6.0. Examples · >>> import numpy as np >>> arr = np.array([[3,6,6],[4,5,1]]) >>> np.ravel_multi_index(arr, (7,6)) array([22, 41, 37]) >>> np.ravel_multi_index(arr, (7,6), order='F') array([31, 41, 13]) >>> np.ravel_multi_index(arr, (4,6), mode='clip') array([22, 23, 19]) >>> np.ravel_multi_index(arr, (4,4), mode=('clip','wrap')) array([12, 13, 13]) >>> np.ravel_multi_index((3,1,4,1), (6,7,8,9)) 1621 ·
🌐
SciPy
docs.scipy.org › doc › numpy-1.8.1 › reference › generated › numpy.ravel.html
numpy.ravel — NumPy v1.8 Manual
March 26, 2014 - numpy.ravel(a, order='C')[source]¶ · Return a flattened array. A 1-D array, containing the elements of the input, is returned. A copy is made only if needed. See also · ndarray.flat · 1-D iterator over an array. ndarray.flatten · 1-D array copy of the elements of an array in row-major order.
Top answer
1 of 1
3

This is because all your operations above are producing views for the same data, but the last ravel is requires a copy.

An array in numpy array has an underlying memory, and shape & strides determining where each element lies.

Reshaping a contiguous array may be performed by simply changing shape and strides, without modifying the data. The same is true with slices here. But since your last array is not contiguous, when you use ravel it will make a copy of everything.

For instance in a 3d array accessing the element arr[i,j,k] means to access the memory at base + i * arr.strides[0] + j * arr.strides[1] + k * arr.strides[1] you can doo many things with this (even broadcasting if you use stride 0 in a given axis).

arr_original = np.ones((1920*1080*4), dtype=np.uint8)
arr = arr_original
print(arr.shape, arr.strides)
arr = arr.reshape(1920,1080,4)
print(arr.shape, arr.strides)
arr = arr[:,:,:3] # keep strides only reduces the length of the last axis
print(arr.shape, arr.strides)
arr = arr[:,:,::-1] # change strides of last axis to -1
print(arr.shape, arr.strides)
arr[0,0,:] = [3,4,5] # operations here are using the memory allocated
arr[0,1,:] = [6,7,8] # for arr_original
arr = arr.ravel()
arr[:] = 0 # this won't affect the original because the data was copied
print(arr_original[:8])

Improving your solution

This is the situation where you have to experiment or dive in the library code. I prefer to test different ways of writing the code.

The original approach is the best approach in general, but in this specific case what we have is unaligned memory since you are writing to a uint8 with stride 3.

When judging performance it is important to be aware of what is reasonable to expect, in this case we can compare the format conversion with a pure copy

arr = arr_original.copy()

1.89 ms ± 43.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

arr = arr_original
arr = arr.reshape(1920,1080,4)
arr = arr[:,:,:3] 
arr = arr[:,:,::-1]
arr[0,0,:] = [3,4,5] 
arr[0,1,:] = [6,7,8] 
arr = arr.ravel()

12.3 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) (About 6x times slower than a copy)

arr = arr_original
arr = arr.reshape(1920,1080,4)
arr_aux = np.empty(arr.shape[:-1] + (3,), dtype=np.uint8)
arr_aux[:,:,0] = arr[:,:,2]
arr_aux[:,:,1] = arr[:,:,1]
arr_aux[:,:,2] = arr[:,:,0]
arr = arr_aux.ravel()

4.16 ms ± 25 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) (about 2x slower than a copy)

Analysis

In the first case the last axis has very small dimension as well, so maybe this is leading to a small loop. Let's see how this operation can be projected to C++

for(int i = 0; i < height; ++i){
  for(int j = 0; j < width; ++j){
    // this part would be the bottleneck
    for(int k = 0; k < 3; ++k){
      dst[(width * i + j)*3 + k] = src[(width * i + j)*4 + k];
    }
  }
}

Of course numpy is doing more things than this, and the indexes may be computed more efficiently by moving precomputing the part independent of the loop variable outside the loop. The idea here is to be didactic.

Let's count the number of branches executed, each for loop will perform N+1 branches for N iteration (N that enter the loop and the last jump that breaks it). So the above code runs 1 + height * (1 + 1 + width * (1 + 3)) ~ 4 * width * height branches.

If we unroll the innermost loop as

for(int i = 0; i < height; ++i){
  for(int j = 0; j < width; ++j){
    // this part would be the bottleneck
    dst[(width * i + j)*3 + 0] = src[(width * i + j)*4 + 0];
    dst[(width * i + j)*3 + 1] = src[(width * i + j)*4 + 1];
    dst[(width * i + j)*3 + 2] = src[(width * i + j)*4 + 2];
  }
}

The number of branches becomes 1 + height * (1 + 1 + width) ~ height * width, 4 times less. We cannot do this in python because we don't have access to the inner loop. But with the second code we implement something like

for(int i = 0; i < height; ++i){
  for(int j = 0; j < width; ++j){
    // this part would be the bottleneck
    dst[(width * i + j)*3 + 0] = src[(width * i + j)*4 + 0];
  }
}

for(int i = 0; i < height; ++i){
  for(int j = 0; j < width; ++j){
    dst[(width * i + j)*3 + 1] = src[(width * i + j)*4 + 1];
  }
}

for(int i = 0; i < height; ++i){
  for(int j = 0; j < width; ++j){
    dst[(width * i + j)*3 + 2] = src[(width * i + j)*4 + 2];
  }
}

That would still have less branches than the first.

By the improvement observed I imagine the last loop must be calling a function like memcpy or something else with more overhead in an attempt to be faster for bigger slices, maybe checking memory alignment and that will fail since we are using bytes with stride 3.

🌐
Medium
medium.com › @megha.natarajan › ravel-vs-values-navigating-the-nuances-in-python-9d92868fd094
.ravel() vs .values: Navigating the Nuances in Python | by Megha Natarajan | Medium
October 31, 2023 - For instance, if you have a pandas DataFrame and you wish to convert it into a flat, one-dimensional numpy array, you'd use .values to get a numpy representation and then .ravel() to flatten it.