Universal functions (ufuncs)

NumPy · Essentials · 10 min

Ufuncs are the vocabulary of vectorized maths, and their options let you control memory and edge cases.

A ufunc (universal function) is a function that operates element by element on arrays, implemented in C for each supported dtype. The arithmetic operators are ufuncs in disguise: a + b calls np.add(a, b).

Common unary ufuncs: np.sqrt, np.exp, np.log, np.log1p, np.abs, np.sin, np.floor, np.isnan. Binary ones: np.add, np.maximum, np.minimum, np.power, np.hypot, np.arctan2. Don't confuse np.maximum(a, b) (element-wise larger of two arrays) with np.max(a) (largest value in one array).

Use NumPy's ufuncs, not the math module: math.sqrt only accepts a single number, while np.sqrt maps over the whole array in C.

Every ufunc accepts the same keyword arguments:

  • out=: write the result into an existing array instead of allocating a new one
  • where=: compute only where a boolean mask is True; other positions of out are left untouched
  • dtype=: choose the computation type

Binary ufuncs also have methods that turn them into other operations: np.add.reduce(a) is a sum, np.multiply.accumulate(a) a running product, np.maximum.accumulate(a) a running max, and np.multiply.outer(x, y) builds a multiplication table.

Invalid inputs follow IEEE rules: np.log(0) is -inf, np.sqrt(-1) is nan, each with a RuntimeWarning. Wrap code in with np.errstate(...) to silence or escalate these warnings deliberately.

Example

import numpy as np

x = np.array([1.0, 4.0, 9.0])
print(np.sqrt(x))                     # [1. 2. 3.]
print(np.maximum(x, 5))               # [5. 5. 9.]
print(np.array_equal(np.add(x, 1), x + 1))   # True: + is np.add

out = np.empty_like(x)
np.multiply(x, 10, out=out)           # no new allocation
print(out)                            # [10. 40. 90.]

v = np.array([4.0, -1.0, 16.0])
res = np.zeros_like(v)
np.sqrt(v, out=res, where=v >= 0)     # skip negatives safely
print(res)                            # [2. 0. 4.]

print(np.add.reduce([1, 2, 3, 4]))            # 10
print(np.maximum.accumulate([3, 1, 4, 1, 5])) # [3 3 4 4 5]
print(np.multiply.outer([1, 2], [1, 2, 3]))   # [[1 2 3] [2 4 6]]

Remember

  • Ufuncs are compiled element-wise functions; operators call them
  • np.maximum compares element-wise, np.max reduces one array
  • out= and where= control allocation and which elements are computed
  • .reduce, .accumulate and .outer derive new operations from any binary ufunc

Watch out for

  • Using where= without out=: the skipped positions then contain uninitialised values.

Check yourself

  1. What does `np.maximum.accumulate(np.array([2, 5, 3, 7, 1]))` return?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: numpy.org/doc/stable/user/basics.ufuncs.html