Universal functions & aggregation along axes

A universal function (ufunc) is a NumPy function that works element by element on whole arrays in compiled code. np.add, np.sqrt, np.exp, np.maximum and the operators + - * / ** are all ufuncs. Combined with the axis argument, they let you summarise data without a single Python loop.

Element-wise ufuncs

import numpy as np

prices = np.array([120.0, 450.0, 80.0, 999.0])
with_gst = np.round(prices * 1.18, 2)        # 18% GST
log_p = np.log(prices)                        # natural log
capped = np.minimum(prices, 500)              # cap each value at 500
floor_ceiling = np.clip(prices, 100, 800)     # keep within [100, 800]
Category Examples
Arithmetic np.add, np.subtract, np.multiply, np.divide, np.power
Maths np.sqrt, np.exp, np.log, np.log1p, np.abs
Comparison np.greater, np.equal, np.maximum, np.minimum
Rounding np.round, np.floor, np.ceil

Understanding axis

For a 2-D array, axis=0 collapses the rows (giving one result per column) and axis=1 collapses the columns (giving one result per row).

# rows = 3 stores, columns = 4 quarters (₹ lakh)
sales = np.array([[12, 15, 11, 20],
                  [ 9, 10, 14, 13],
                  [18, 17, 16, 25]])

sales.sum(axis=0)     # per quarter: [39 42 41 58]
sales.sum(axis=1)     # per store:   [58 46 76]
sales.max(axis=1)     # best quarter value for each store
sales.argmax(axis=1)  # index of best quarter: [3 2 3]
sales.mean()          # overall mean (no axis)

A memory aid: the axis you pass is the axis that disappears from the shape. (3, 4) summed over axis 0 becomes (4,).

keepdims for broadcasting

To divide each store's quarters by that store's total, keep the reduced axis so the shapes line up:

share = sales / sales.sum(axis=1, keepdims=True)   # (3, 4) / (3, 1)
print(share.round(2))

Without keepdims=True, the totals would have shape (3,), which broadcasts against columns and gives a wrong answer or a shape error.

reduce and accumulate

Every binary ufunc has methods for reductions:

np.add.reduce([1, 2, 3, 4])          # 10, same as sum
np.add.accumulate([1, 2, 3, 4])      # [1 3 6 10], same as cumsum
np.maximum.accumulate([3, 1, 4, 2])  # running maximum: [3 3 4 4]

A running maximum is useful for "best sales so far" or drawdown calculations on stock prices.

Handling missing values

np.sum of an array containing np.nan returns nan. Use the nan-aware versions: np.nansum, np.nanmean, np.nanmax, np.nanstd.

Common mistakes

  • Mixing up axis 0 and axis 1; check the output shape every time.
  • Forgetting keepdims=True when normalising rows.
  • Using Python's built-in sum() or max() on large arrays, which is far slower than the NumPy method.
  • Getting nan results because one missing value slipped in.

Practice

Build a 5 x 12 array of monthly sales for five branches. Find each branch's best month (index), each month's total, every branch's share of its annual sales per month (rows should sum to 1), and each branch's cumulative sales through the year.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India