I have a view of a NumPy array. I want to apply a function to each of its elements and save the result into said view (essentially, I want to do an in-place map). I do not want to use for loops, because they do not benefit from any NumPy optimizations/parallelization. I also cannot do something like arr = map(fn, arr)
, since it creates a new object.

- 131
- 6
-
3what sort of function? If it only accepts scalar elements and returns a scalar value (same dtype), there's no 'efficient' apply. If the function has to be called once for each element the array, that is the main time consumer, and the iteration/map details don't make much difference. – hpaulj May 27 '23 at 16:03
-
`numpy` parallelization' is achieved by using compiled numpy methods. They still loop, but it's in C code on simple C arrays. – hpaulj May 27 '23 at 16:09
-
Just like you said, the function takes a scalar and returns another scalar. It's a neural network activation function. I actually plan to run the whole thing with CuPy, but I'm asking about NumPy since their APIs are supposed to be mostly compatible. – sajmon May 27 '23 at 16:14
-
@sajmon: There is no general answer. Give us your use case, maybe we can help, but this is too vague to be answerable; without specifics, or any way to modify the function in question, the answer is "you have to run it once for each element and reassign with the result". – ShadowRanger May 27 '23 at 23:21
2 Answers
You aren't the first to ask about applying a scalar function to all elements of an array. That comes up often. Just search for the use of "vectorize" in SO questions.
By stressing that this is a view
, I assume you want to make sure that the changes apply to the corresponding elements of the base array. Others stress in-place because they think this will save memory or be faster.
If array is 2d then the old-fashioned nested loop
for i in range ...:
for j in range ...:
arr[i,j] = func(arr[i,j])
takes care of the in-place requirement.
If you can rework func
to work with a 1d array, you can do
for i in range...:
arr[i,:] = func(arr[i,:])
func
will produce a new array, but those values can be copied back into arr[i,:]
(and arr.base
) without problem.
The ideal, speed wise, is a function that can work with the whole nd array, with operators and numpy functions. That's fastest, but will always produce a tempoary buffer that you have to copy. That has to be copied back to the view
(though the out
parameter of ufunc
can help).
arr[:] = func(arr)
Even arr[indx] += 1
uses a temporary buffer, when can be problem if the indx
has duplicate indicies. For that, ufunc
may have an at
method to perform unbuffered iteration.
https://numpy.org/doc/stable/reference/generated/numpy.ufunc.at.html
There aren't many numpy operations that work in-place. Most produce a new array. It's easier to create a building-block language that way.
There are some tools that "streamline" iterating on an array, but they don't offer any real performance enhancement. But questions come up often about them - np.vectorize
, np.frompyfunc
, np.nditer
, and (my least favorite) np.apply_along_axis
. In-place is trickier with the functions.
But for real performance you have to use a tool that compiles your function, such as numba
or cython
. There are lots of SO about those.
Python map
just sets up an iteration, which is 'run' with a for
or list()
. I prefer the list-comprehension notation. None of that is special to numpy
.
Other SO deal with multithreading and processing.

- 221,503
- 14
- 230
- 353
It seems you function is designed to execute individually on individual elements. The best way to go efficient is to edit and vectorize the function. Alternatively, a quick and dirty solution is to ask NumPy to do it for you, see numpy.vectorize.
But be aware, depending on the set of operation executed inside the function, you may go more efficient if vectorize your function manually.

- 34
- 4
-
Thank you for your response. Unfortunately, this does not address the main issue of doing assigning the results in-place. – sajmon May 27 '23 at 17:06