For AI agents: use /llms.txt for the Nakafa content index.
Broadcasting is NumPy's rule system for combining arrays with different but compatible shapes. It expands dimensions of size one conceptually, without copying the values into a larger array. The NumPy broadcasting guide covers additional examples.
Vectorization lets one expression operate over an entire array. NumPy executes the underlying loop in optimized compiled code, which is often faster than an explicit Python loop.
import numpy as np
# Create two arrays
a = np.array([0, 1, 2])
b = np.array([2, 2, 2])
# Vectorization operation (element-wise)
result = a + b
print(result)
# Output: [2 3 4]In the example above, NumPy adds elements at corresponding positions. We describe the operation once instead of indexing every element in a Python loop.
To decide whether two shapes are compatible, NumPy compares their dimensions from right to left.
There are three main rules in broadcasting:
ValueErrorimport numpy as np
# 1D array with scalar
a = np.arange(3) # [0, 1, 2]
b = 5
result = a + b
print(f"Array a: {a}")
print(f"Scalar b: {b}")
print(f"Result a + b: {result}")
# Shape explanation:
# a has shape (3,)
# b has shape () - scalar
# After broadcasting: b becomes [5, 5, 5]
# Output: [5 6 7]When you work with arrays that have different dimensions, NumPy will try to automatically adjust their shapes. This process is very useful when you want to apply the same operation to each row or column of a matrix.
import numpy as np
# 2D array with 1D array
a = np.ones((3, 3)) # 3x3 matrix filled with 1s
b = np.arange(3) # [0, 1, 2]
result = a + b
print("Array a (3x3):")
print(a)
print(f"Array b (1D): {b}")
print("Result a + b:")
print(result)
# Broadcasting occurs:
# a: shape (3, 3)
# b: shape (3,) -> expanded to (1, 3) -> (3, 3)
# b is added to each row of aimport numpy as np
try:
# Arrays with incompatible shapes
a = np.arange(6).reshape(2, 3) # shape (2, 3)
b = np.arange(2) # shape (2,)
print(f"Array a shape: {a.shape}")
print(f"Array b shape: {b.shape}")
# This will produce an error
result = a + b
except ValueError as e:
print(f"Error: {e}")
print("Array shapes are incompatible for broadcasting")NumPy arithmetic operators work element by element unless an operation explicitly has different semantics, such as matrix multiplication.
When an array is combined with a scalar, broadcasting applies that scalar to every element. No manual indexing loop is required.
import numpy as np
a = np.array([0, 1, 2, 3, 4])
# Addition with scalar
print("Addition:")
print(f"a + 1 = {a + 1}")
# Output: [1 2 3 4 5]
# Multiplication with scalar
print("Multiplication:")
a *= 2
print(f"a *= 2: {a}")
# Output: [0 2 4 6 8]
# Power
print("Power:")
print(f"2**a = {2**a}")
# Output: [ 1 4 16 64 256]import numpy as np
a = np.array([0, 1, 2, 3, 4])
b = np.array([4, 3, 2, 1, 0])
# Element-wise subtraction
print("Subtraction:")
print(f"a - b = {a - b}")
# Output: [-4 -2 0 2 4]
# Element-wise multiplication
print("Element-wise multiplication:")
print(f"a * b = {a * b}")
# Output: [0 3 4 3 0]
# Matrix multiplication (dot product)
print("Matrix multiplication:")
print(f"a @ b = {a @ b}")
# Output: 10 (dot product result)It's important to understand the difference between element-wise multiplication (*) and matrix multiplication (@ or np.dot()). Element-wise multiplication multiplies elements at the same position, while matrix multiplication follows linear algebra rules.
NumPy also supports comparison operations that produce boolean arrays. These operations are very useful for data filtering or creating complex conditions.
import numpy as np
a = np.array([0, 1, 2, 3, 4])
b = np.array([0, 0, 2, 4, 4])
# Comparison operations
print("Greater than comparison:")
print(f"a > 2: {a > 2}")
# Output: [False False False True True]
print("Equal comparison:")
print(f"a == b: {a == b}")
# Output: [ True False True False True]
# Logical operations
print("Logical OR operation:")
print(f"(a > 2) | (a == b): {(a > 2) | (a == b)}")
# Output: [ True False True True True]For element-wise boolean logic, use ~ for NOT, & for AND, and | for OR, or use the corresponding np.logical_* functions. Put each comparison in parentheses because the operators have different precedence from comparisons. Python's scalar operators not, and, and or do not perform element-wise array logic.
Reduction functions combine many elements into fewer values. Without an axis they can reduce the whole array to one value; with an axis they reduce only that dimension. For a table of exam scores, this can produce an average for each subject or each student.
NumPy provides various statistical functions that are very useful for data analysis. These functions can be applied to the entire array or only to specific axes.
import numpy as np
# Create 2D array for example
data = np.array([[3, 0, -1, 1],
[2, -1, -2, 4],
[1, 7, 0, 4]])
print("Data array:")
print(data)
# Statistics on entire array
print(f"Total sum: {np.sum(data)}")
print(f"Mean: {np.mean(data):.2f}")
print(f"Minimum value: {np.min(data)}")
print(f"Maximum value: {np.max(data)}")
print(f"Standard deviation: {np.std(data):.2f}")
# Output:
# Total sum: 18
# Mean: 1.50
# Minimum value: -2
# Maximum value: 7
# Standard deviation: 2.50For a two-dimensional array, axis=0 collapses the row dimension and produces one value per column. axis=1 collapses the column dimension and produces one value per row.
Understanding axes helps you control how statistical functions work on multidimensional data. For example, if you have monthly sales data for various products, you can calculate total sales per product or per month.
import numpy as np
data = np.array([[3, 0, -1, 1],
[2, -1, -2, 4],
[1, 7, 0, 4]])
# Operations along axis=0 (for each column)
print("Maximum of each column (axis=0):")
print(f"max(axis=0): {np.max(data, axis=0)}")
# Output: [3 7 0 4]
print("Index of maximum in each column:")
print(f"argmax(axis=0): {np.argmax(data, axis=0)}")
# Output: [0 2 2 1]
# Operations along axis=1 (for each row)
print("Maximum of each row (axis=1):")
print(f"max(axis=1): {np.max(data, axis=1)}")
# Output: [3 4 7]
print("Index of maximum in each row:")
print(f"argmax(axis=1): {np.argmax(data, axis=1)}")
# Output: [0 3 1]Shape operations reorganize how the same elements are indexed. A reshape keeps the number of elements unchanged while assigning them to different dimensions.
New NumPy arrays are commonly C-contiguous, meaning the last index changes fastest in memory. Views created by slicing or transposing can have different strides, so an array is not always stored in one simple row-major layout. The order and stride rules matter when reshaping or flattening.
import numpy as np
# Create 2D array
a = np.array([[0, 1], [2, 3]])
print("2D Array:")
print(a)
print(f"Shape: {a.shape}")
# See how it's stored in memory
print(f"Stored in memory as: {a.ravel()}")
# Output: [0 1 2 3] (row-major order)Both flatten() and ravel() return a one-dimensional array. flatten() always creates a copy, while ravel() returns a view when possible and a copy when the memory layout requires it.
import numpy as np
# Create diagonal array
a = np.diag([1, 2, 3])
print("Diagonal array:")
print(a)
# Flatten - creates independent copy
b_flatten = a.flatten()
print(f"Flatten result: {b_flatten}")
# Changing flatten values doesn't affect original array
b_flatten[0] = 9
print(f"After changing flatten: {b_flatten}")
print("Original array remains the same:")
print(a)
print()
# Ravel - tries to create view (more efficient)
b_ravel = a.ravel()
print(f"Ravel result: {b_ravel}")
# Changing ravel values affects original array
b_ravel[0] = 9
print(f"After changing ravel: {b_ravel}")
print("Original array changed:")
print(a)reshape() changes the shape as long as the number of elements stays the same and returns a view when possible. The ndarray.resize() method used below changes the original array in place.
import numpy as np
# Create diagonal array and flatten
a = np.diag([1, 2, 3])
a_flat = a.flatten()
print(f"Flat array: {a_flat}")
# Reshape - change shape with same number of elements
b = a_flat.reshape(3, 3)
print("Reshape result to (3,3):")
print(b)
# Changing values in reshape
b[0, 0] = 9
print("After changing value:")
print(b)
print(f"Original flat array: {a_flat}") # Changes because reshape creates view
# Resize - change shape in-place (no return value)
a_flat.resize(3, 3)
print("After resize:")
print(a_flat) # Now a_flat is 2DA transpose permutes an array's axes. For a two-dimensional array it swaps rows and columns. NumPy provides the transpose() method and the shorter .T attribute.
import numpy as np
# Create 2x4 array
a = np.linspace(1, 8, 8).reshape(2, 4)
print("Original array (2x4):")
print(a)
# Transpose using method
b = a.transpose()
print("Transpose result (4x2):")
print(b)
# Transpose using .T attribute (shorter)
c = a.T
print("Using .T:")
print(c)
# Verify that transpose is a view
print("Is transpose a view?", np.shares_memory(a, b))Z-score standardization centers each feature at a mean of and scales it to a standard deviation of . It is defined only for features with nonzero standard deviation and puts features on comparable numerical scales.
The Z-Transform formula is , where:
import numpy as np
# Create sample data (5 observations, 3 features)
np.random.seed(42)
X = np.random.randn(5, 3) * 10 + 50 # Data with mean~50, std~10
print("Original data:")
print(X)
print(f"Data shape: {X.shape}")
# Calculate mean and standard deviation for each column
mu = np.mean(X, axis=0) # Mean of each column
sigma = np.std(X, axis=0) # Standard deviation of each column
print(f"Mean of each feature: {mu}")
print(f"Standard deviation of each feature: {sigma}")
# Perform Z-Transform
Z = (X - mu) / sigma
print("Data after Z-Transform:")
print(Z)
# Verify standardization results
print("Standardization verification:")
print(f"New mean: {np.mean(Z, axis=0)}") # Should be close to 0
print(f"New standard deviation: {np.std(Z, axis=0)}") # Should be close to 1
# New mean output: [ 1.24344979e-15 8.88178420e-17 -1.77635684e-16] (close to 0)
# New standard deviation output: [1. 1. 1.]Standardization prevents units alone from creating large scale differences. It does not guarantee equal importance or influence: the model and the data still determine that. For example, height in centimeters and weight in kilograms become numerically comparable after standardization.
For more details about NumPy array operations, you can visit the official NumPy documentation, which provides guides and practical examples.
Published: . Updated: .