Array Operations

Difficulty: Beginner

One of the most powerful features of NumPy is vectorized operations. Instead of writing explicit loops to perform element-by-element calculations, you apply operations to entire arrays at once. Under the hood, NumPy delegates these operations to optimized C code that processes the data in bulk. This is not just more concise to write; it is typically 10 to 100 times faster than an equivalent Python for loop, especially for large arrays.

Element-wise arithmetic works naturally with NumPy arrays. When you write arr1 + arr2, NumPy adds the corresponding elements of both arrays and returns a new array with the results. The same applies to subtraction (-), multiplication (*), division (/), floor division (//), modulo (%), and exponentiation (**). If the arrays have the same shape, the operation is performed element by element. You can also perform operations between an array and a scalar: arr * 3 multiplies every element by 3.

Comparison operators also work element-wise on NumPy arrays, returning boolean arrays. For example, arr > 5 produces an array of True and False values indicating which elements satisfy the condition. These boolean arrays are extremely useful for filtering data, as you can use them as indices to select only the elements that meet your criteria. You can combine conditions using the bitwise operators & (and), | (or), and ~ (not), but you must wrap each condition in parentheses.

NumPy provides a wide collection of universal functions (ufuncs) that operate element-wise on arrays. Mathematical ufuncs include np.sqrt(), np.exp(), np.log(), np.sin(), np.cos(), np.abs(), and np.power(). These functions are optimized and much faster than applying Python's built-in math functions in a loop. Each ufunc returns a new array with the results, leaving the original unchanged unless you use the out parameter to write results in place.

Aggregation functions like np.sum(), np.mean(), np.std(), np.min(), and np.max() reduce an array to a single summary value. They can also be called as methods on the array itself (arr.sum(), arr.mean()). A critical parameter is axis: by default, aggregations compute over the entire array, but specifying axis=0 aggregates along rows (column-wise) and axis=1 aggregates along columns (row-wise). Understanding the axis parameter is essential for working with multi-dimensional data.

Code examples

Element-wise arithmetic operations

import numpy as np

a = np.array([10, 20, 30, 40])
b = np.array([1, 2, 3, 4])

print("Add:", a + b)
print("Subtract:", a - b)
print("Multiply:", a * b)
print("Divide:", a / b)
print("Scalar multiply:", a * 2)

Each arithmetic operator applies element by element across both arrays. Division always returns float64 results. Scalar operations broadcast the scalar to match the array shape.

Universal functions (ufuncs)

import numpy as np

arr = np.array([1, 4, 9, 16, 25])

print("Sqrt:", np.sqrt(arr))
print("Square:", np.square(arr))
print("Sum:", np.sum(arr))
print("Mean:", np.mean(arr))

np.sqrt() and np.square() operate element-wise, returning new arrays. np.sum() and np.mean() are aggregation functions that reduce the array to a single value.

Comparison operators and boolean arrays

import numpy as np

arr = np.array([15, 8, 22, 3, 17, 10])

print("Greater than 10:", arr > 10)
print("Equal to 8:", arr == 8)

# Combined conditions
mask = (arr > 5) & (arr < 20)
print("Between 5 and 20:", mask)
print("Filtered:", arr[mask])

Comparisons return boolean arrays of the same shape. Combining conditions requires bitwise operators (& for and, | for or) with parentheses around each condition. Boolean indexing selects elements where the mask is True.

Vectorized vs loop performance concept

import numpy as np

# Vectorized operation
arr = np.arange(1, 6)
result = arr ** 2 + 2 * arr + 1
print("Vectorized result:", result)

# Equivalent loop (slow for large arrays)
loop_result = []
for x in arr:
    loop_result.append(x ** 2 + 2 * x + 1)
print("Loop result:", loop_result)

Both approaches produce the same values, but the vectorized version executes entirely in compiled C code while the loop runs in interpreted Python. For an array of 1 million elements, the vectorized version can be 100x faster.

Key points

Concepts covered

vectorized operations, element-wise math, comparison operators, universal functions, aggregation functions