Universal Functions, or ufuncs, are the secret behind NumPy's incredible speed. They perform element-wise operations on arrays — fast, clean, and without any Python loops. 🧩
Every time you write arr + 10 or np.sin(arr), you're using a ufunc.
What Makes ufuncs Special?
ufuncs are functions that:
- Operate element-by-element
- Support broadcasting
- Are implemented in fast C code
- Preserve array shape (usually)
Analogy: Think of a ufunc as a factory machine that processes every item on a conveyor belt (your array) simultaneously — no manual handling needed!
Basic Arithmetic ufuncs
Common operators are actually ufuncs.
import numpy as np
arr = np.array([1, 2, 3, 4])
print("Add:", np.add(arr, 10)) # or arr + 10
print("Subtract:", np.subtract(arr, 1)) # or arr - 1
print("Multiply:", np.multiply(arr, 2)) # or arr * 2
print("Divide:", np.divide(arr, 2)) # or arr / 2
print("Power:", np.power(arr, 3))
Add: [11 12 13 14]
Subtract: [0 1 2 3]
Multiply: [2 4 6 8]
Divide: [0.5 1. 1.5 2. ]
Power: [ 1 8 27 64]
Mathematical ufuncs
Trig, exponential, logarithmic — all vectorized.
angles = np.array([0, 30, 45, 60, 90]) * np.pi / 180
print("Sin:", np.sin(angles))
print("Cos:", np.cos(angles))
print("Exp:", np.exp([0, 1, 2]))
print("Log:", np.log([1, np.e, np.e**2]))
print("Square root:", np.sqrt([1, 4, 9, 16]))
Sin: [0. 0.5 0.71 0.87 1. ]
Cos: [1. 0.87 0.71 0.5 0. ]
Exp: [ 1. 2.718 7.389]
Log: [0. 1. 2.]
Square root: [1. 2. 3. 4.]
Comparison and Logical ufuncs
a = np.array([1, 2, 3])
b = np.array([2, 2, 1])
print("Greater:", np.greater(a, b))
print("Equal:", np.equal(a, b))
print("Logical AND:", np.logical_and(a > 1, b > 1))
Greater: [False False True]
Equal: [False True False]
Logical AND: [False True False]
Real-World Example: Student Grade Calculations
Let's use ufuncs on our familiar student marks.
marks = np.array([
[85, 88, 92],
[90, 76, 85],
[78, 92, 88],
[92, 85, 79],
[88, 90, 94]
])
# Total marks using reduce
total = np.add.reduce(marks, axis=1)
print("Totals:", total)
# Average (mean is a ufunc too)
average = np.mean(marks, axis=1)
print("Averages:", np.round(average, 1))
# Scaled scores (e.g., out of 150)
scaled = np.multiply(marks, 1.5)
print("Scaled first student:", scaled[0])
Totals: [265 251 258 256 272]
Averages: [88.3 83.7 86. 85.3 90.7]
Scaled first student: [127.5 132. 138. ]
Advanced ufunc Features
reduce() - Cumulative Operation
Applies operation sequentially along an axis.
# Cumulative sum per student
cumulative = np.add.reduce(marks, axis=1)
print("Same as sum:", cumulative)
# Cumulative product
cum_prod = np.multiply.reduce(marks, axis=1)
print("Cumulative product:", cum_prod)
accumulate() - Running Total
# Running sum across subjects
running_sum = np.add.accumulate(marks, axis=1)
print("Running totals:\n", running_sum)
Running totals:
[[ 85 173 265]
[ 90 166 251]
[ 78 170 258]
[ 92 177 256]
[ 88 178 272]]
outer() - All Pairs
small = np.array([1, 2, 3])
# All pairwise additions
outer_sum = np.add.outer(small, small)
print("Outer add:\n", outer_sum)
Outer add:
[[2 3 4]
[3 4 5]
[4 5 6]]
at() - In-Place Operations on Indices
data = np.array([10, 20, 30, 40])
indices = np.array([0, 2])
# Add 100 only at specified indices
np.add.at(data, indices, 100)
print("Modified in-place:", data) # Unrolled: adds multiple times if duplicates
Modified in-place: [110 20 130 40]
Creating Custom ufuncs
def my_func(a, b):
return a + b * 2
vectorized_func = np.frompyfunc(my_func, 2, 1)
result = vectorized_func([1, 2], [3, 4])
print("Custom:", result)
Custom: [7 10]
frompyfunc is slow — for performance, use Numba or write in Cython when needed.
Common ufuncs Quick Reference
- Arithmetic: add, subtract, multiply, divide, power, mod
- Trig: sin, cos, tan, arcsin, hypot
- Exponential: exp, exp2, log, log10, log1p
- Bitwise: bitwise_and, bitwise_or, left_shift
- Comparison: greater, less, equal, logical_xor
Beginner Mistakes - Common Errors and How to Avoid Them
axis in reduce/accumulate — wrong axis gives wrong results.
math module functions on arrays — they fail or process only one element.
Optimization Tips
np.sin(np.exp(arr)) — NumPy optimizes efficiently.
out parameter: np.sin(arr, out=result) to avoid copies.
Real-World Use Cases
- Signal Processing: Filtering with sin/cos waves
- Finance: Compound interest with exp/power
- Machine Learning: Activation functions (sigmoid, relu via ufuncs)
- Physics: Vector calculations with trig functions
Quick Summary 📝
- ufuncs: Fast element-wise operations
- Arithmetic, math, comparison all covered
- Methods: reduce, accumulate, outer, at
- Broadcasting works automatically
- Foundation of NumPy's performance
ufuncs are the engine driving NumPy's power. Master them, and your numerical code will fly! Happy computing! ✨
Comments
Post a Comment