# python – Most efficient way to map function over numpy array

## python – Most efficient way to map function over numpy array

Ive tested all suggested methods plus `np.array(map(f, x))` with `perfplot` (a small project of mine).

Message #1: If you can use numpys native functions, do that.

If the function youre trying to vectorize already is vectorized (like the `x**2` example in the original post), using that is much faster than anything else (note the log scale):

If you actually need vectorization, it doesnt really matter much which variant you use.

Code to reproduce the plots:

``````import numpy as np
import perfplot
import math

def f(x):
# return math.sqrt(x)
return np.sqrt(x)

vf = np.vectorize(f)

def array_for(x):
return np.array([f(xi) for xi in x])

def array_map(x):
return np.array(list(map(f, x)))

def fromiter(x):
return np.fromiter((f(xi) for xi in x), x.dtype)

def vectorize(x):
return np.vectorize(f)(x)

def vectorize_without_init(x):
return vf(x)

b = perfplot.bench(
setup=np.random.rand,
n_range=[2 ** k for k in range(20)],
kernels=[
f,
array_for,
array_map,
fromiter,
vectorize,
vectorize_without_init,
],
xlabel=len(x),
)
b.save(out1.svg)
b.show()
``````

How about using `numpy.vectorize`.

``````import numpy as np
x = np.array([1, 2, 3, 4, 5])
squarer = lambda t: t ** 2
vfunc = np.vectorize(squarer)
vfunc(x)
# Output : array([ 1,  4,  9, 16, 25])
``````

# TL;DR

As noted by @user2357112, a direct method of applying the function is always the fastest and simplest way to map a function over Numpy arrays:

``````import numpy as np
x = np.array([1, 2, 3, 4, 5])
f = lambda x: x ** 2
squares = f(x)
``````

Generally avoid `np.vectorize`, as it does not perform well, and has (or had) a number of issues. If you are handling other data types, you may want to investigate the other methods shown below.

# Comparison of methods

Here are some simple tests to compare three methods to map a function, this example using with Python 3.6 and NumPy 1.15.4. First, the set-up functions for testing:

``````import timeit
import numpy as np

f = lambda x: x ** 2
vf = np.vectorize(f)

def test_array(x, n):
t = timeit.timeit(
np.array([f(xi) for xi in x]),
from __main__ import np, x, f, number=n)
print(array: {0:.3f}.format(t))

def test_fromiter(x, n):
t = timeit.timeit(
np.fromiter((f(xi) for xi in x), x.dtype, count=len(x)),
from __main__ import np, x, f, number=n)
print(fromiter: {0:.3f}.format(t))

def test_direct(x, n):
t = timeit.timeit(
f(x),
from __main__ import x, f, number=n)
print(direct: {0:.3f}.format(t))

def test_vectorized(x, n):
t = timeit.timeit(
vf(x),
from __main__ import x, vf, number=n)
print(vectorized: {0:.3f}.format(t))
``````

Testing with five elements (sorted from fastest to slowest):

``````x = np.array([1, 2, 3, 4, 5])
n = 100000
test_direct(x, n)      # 0.265
test_fromiter(x, n)    # 0.479
test_array(x, n)       # 0.865
test_vectorized(x, n)  # 2.906
``````

With 100s of elements:

``````x = np.arange(100)
n = 10000
test_direct(x, n)      # 0.030
test_array(x, n)       # 0.501
test_vectorized(x, n)  # 0.670
test_fromiter(x, n)    # 0.883
``````

And with 1000s of array elements or more:

``````x = np.arange(1000)
n = 1000
test_direct(x, n)      # 0.007
test_fromiter(x, n)    # 0.479
test_array(x, n)       # 0.516
test_vectorized(x, n)  # 0.945
``````

Different versions of Python/NumPy and compiler optimization will have different results, so do a similar test for your environment.