Unit 7: Operations on NumPy arrays
I. Orientation — The ndarray Model
NumPy (Numerical Python, first released as NumPy in 2006) organizes numerical data in homogeneous, multidimensional arrays called ndarray objects. Operations generally act on complete arrays rather than requiring explicit Python loops, making numerical programs concise and computationally efficient.
- Homogeneous storage: Every element normally has the same NumPy data type, or
dtype, such asint64,float32, orbool. - Dimensions and axes: An array’s
ndimis its number of dimensions; axes are numbered from0.- In shape
(r, c), axis0hasrrows and axis1hasccolumns. - For shape
(d, r, c), axis0indexesdtwo-dimensional layers.
- In shape
- Shape: The tuple
a.shaperecords the length of each axis. An array of shape(2, 3)has two rows and three columns. - Size:
a.sizegives the total number of elements:
TEXTsize = s₀ × s₁ × ... × sₙ₋₁
Here,sᵢis the length of axisi, andnis the number of dimensions. - Vectorization: Arithmetic and many functions operate element by element in compiled NumPy code, avoiding slower explicit Python iteration.
- Views and copies: Some manipulations return a view sharing memory with the original array, while others allocate an independent copy.
- Element-wise default: Operators such as
+,-,*,/, and comparisons usually pair corresponding elements; matrix multiplication instead uses@. - Broadcast compatibility: Arrays with unequal shapes may still interact when their trailing dimensions are equal or one of them is
1. - Conventional import: NumPy is ordinarily imported using:
PYTHONimport numpy as np
II. Array Manipulation — Changing Shape, Order, and Structure
A. Array manipulation
Array manipulation changes how array data is shaped, indexed, arranged, joined, or divided, usually without changing the underlying numerical meaning of its elements.
-
Reshaping:
reshape()changes dimensions while preserving the total number of elements.
PYTHONa = np.arange(12) b = a.reshape(3, 4)a.shapeis(12,), whileb.shapeis(3, 4).- A reshape from shape
Sto shapeTis valid only whenproduct(S) = product(T). - One dimension may be
-1, allowing NumPy to infer it:a.reshape(3, -1)produces shape(3, 4).
-
Flattening: Multidimensional data can be converted into one dimension.
a.flatten()returns an independent copy.a.ravel()returns a flattened view when memory layout permits, though it may return a copy.
PYTHONm = np.array([[1, 2], [3, 4]]) x = m.flatten() # array([1, 2, 3, 4])
-
Transposition:
a.Treverses the order of axes;np.transpose(a, axes)permits an explicit axis order.
PYTHONa = np.array([[1, 2, 3], [4, 5, 6]]) b = a.T
Here,a.shapeis(2, 3)andb.shapeis(3, 2). For a one-dimensional array,.Tdoes not create a column vector;a.reshape(-1, 1)is required. -
Axis movement: Functions rearrange dimensions without altering element values.
np.swapaxes(a, i, j)exchanges axesiandj.np.moveaxis(a, source, destination)moves a selected axis.- For image batches shaped
(batch, height, width, channels), moving channels to axis1gives(batch, channels, height, width).
-
Adding and removing dimensions: Dimensions of length
1help prepare data for broadcasting.
PYTHONx = np.array([10, 20, 30]) row = x[np.newaxis, :] # shape (1, 3) col = x[:, np.newaxis] # shape (3, 1)np.expand_dims(x, axis=k)inserts a new axis at positionk.np.squeeze(a, axis=k)removes an axis of length1; attempting to squeeze a longer axis raises an error.
-
Joining arrays: Concatenation combines arrays along an existing axis.
PYTHONa = np.array([[1, 2]]) b = np.array([[3, 4]]) np.concatenate((a, b), axis=0) # array([[1, 2], # [3, 4]])
Arrays must have matching dimensions except along the joining axis.np.stack()differs by creating a new axis;vstack(),hstack(), andcolumn_stack()are convenient specialized forms. -
Splitting arrays:
np.split(a, sections, axis)separates an array into equal parts, whilenp.array_split()permits unequal part sizes.np.hsplit()divides by columns for a two-dimensional array.np.vsplit()divides by rows.- Exact
split()raises an error if the selected axis cannot be divided evenly.
-
Repetition and rearrangement:
np.repeat()repeats individual elements, whereasnp.tile()repeats an entire pattern.
PYTHONnp.repeat([1, 2], 2) # array([1, 1, 2, 2]) np.tile([1, 2], 2) # array([1, 2, 1, 2])
B. Applications and limitations
Manipulation operations prepare arrays for computation, but correct shape and memory behavior must be checked explicitly.
- Data preparation: Reshaping converts a flat sequence of
12sensor values into, for example,3observations with4features each. - Memory sharing: Modifying a view may modify its source.
PYTHONa = np.arange(4) b = a.reshape(2, 2) b[0, 0] = 99
Becausebcommonly shares storage witha,a[0]becomes99;b = a.reshape(2, 2).copy()prevents this coupling. - Shape safety: Arrays can contain the same number of elements yet represent different structures; shape
(2, 6)is not semantically interchangeable with(3, 4). - Performance: Views are generally cheap because they reuse memory, while copying, concatenating, and repeatedly appending arrays allocate storage.
- Append limitation:
np.append()returns a new array rather than extending an array in place; collecting values in a list and converting once is often more efficient.
III. Broadcasting — Operating Across Compatible Shapes
A. Broadcasting
Broadcasting is NumPy’s rule for performing element-wise operations on arrays of different but compatible shapes without explicitly copying repeated values.
-
Comparison rule: Shapes are compared from their rightmost dimensions toward the left. Two dimensions are compatible when:
- their lengths are equal; or
- one length is
1.
-
Missing dimensions: If one shape has fewer axes, leading dimensions of length
1are conceptually inserted. Thus(3,)is treated like(1, 3)when paired with(2, 3). -
Result shape: Each result dimension takes the larger compatible length. Combining
(4, 1, 3)with(1, 5, 3)produces(4, 5, 3). -
Scalar broadcasting: A scalar behaves as though it had the same shape as the array.
PYTHONa = np.array([2, 4, 6]) a * 10 # array([20, 40, 60])
The scalar10is conceptually paired with every element; NumPy does not need to construct[10, 10, 10]. -
Worked example: A column vector and row vector broadcast to form a grid.
PYTHONcol = np.array([[1], [2], [3]]) # shape (3, 1) row = np.array([10, 20, 30, 40]) # shape (4,) result = col + row # shape (3, 4)TEXT[[11, 21, 31, 41], [12, 22, 32, 42], [13, 23, 33, 43]]
The column expands across four columns, while the row is treated as shape(1, 4)and expands across three rows. -
Incompatibility: Shapes
(2, 3)and(2,)fail because their rightmost dimensions are3and2; neither is1. Reshaping the second array to(2, 1)makes row-wise broadcasting possible. -
No physical tiling: Broadcasting conceptually stretches dimensions of length
1, ordinarily avoiding the memory cost ofnp.tile().
B. Applications and limitations
Broadcasting supports concise numerical formulas, but accidental compatibility can also produce unintended results.
-
Feature scaling: For data
Xof shape(m, n), subtracting a mean vectorμof shape(n,)centers every feature:
PYTHONcentered = X - mu
Here,mis the number of observations,nis the number of features, andμ[j]is the mean of featurej. -
Pairwise computation: Reshaping one vector as
(m, 1)and another as(1, n)creates allm × npairwise combinations. -
Efficiency: Broadcasting avoids explicit Python loops and unnecessary repeated arrays, typically improving speed and memory usage.
-
Memory risk: Although operands are not tiled, the result is materialized. Broadcasting shapes
(100000, 1)and(1, 100000)would request a result containing10¹⁰elements. -
Intent clarity:
np.newaxisorreshape()should make the intended axis explicit. A vector of shape(3,)may represent rows, columns, or features depending on context. -
Assignment restriction: An in-place operation cannot change the left operand’s shape. An array of shape
(3, 1)cannot store an in-place result of shape(3, 4).
IV. Binary Operators — Combining Two Operands
A. Binary operators
Binary operators combine two operands—arrays, array-like objects, or scalars—and generally produce an element-wise result governed by broadcasting.
-
Arithmetic operators: NumPy supports
+,-,*,/,//,%, and**.
PYTHONa = np.array([5, 8, 11]) b = np.array([2, 3, 4])a + bgives[7, 11, 15].a * bgives[10, 24, 44].a / bperforms true division.a // bperforms floor division, rounding toward negative infinity.a % bgives remainders, anda ** bperforms element-wise exponentiation.
-
Operator-function equivalents: Operators correspond to NumPy universal functions, or ufuncs.
a + bcorresponds tonp.add(a, b).a * bcorresponds tonp.multiply(a, b).a ** bcorresponds tonp.power(a, b).
These functions may support parameters such aswhere=andout=.
-
Comparison operators:
==,!=,<,<=,>, and>=return Boolean arrays.
PYTHONa >= 8 # array([False, True, True])
Whole-array conditions usenp.all(condition)ornp.any(condition); directly using a multi-element Boolean array inifis ambiguous and raises an error. -
Logical operators:
np.logical_and,np.logical_or,np.logical_not, andnp.logical_xoroperate on truth values.
PYTHONmask = (a >= 8) & (a < 11)
Parentheses are necessary because&has different precedence from comparisons. Python’sandandordo not perform element-wise array logic. -
Bitwise operators: Integer and Boolean arrays support
&,|,^,~,<<, and>>.&,|, and^combine corresponding bits.<< kand>> kshift each integer bykbit positions.- For Boolean arrays,
&,|, and^act as element-wise logical combinations.
-
Matrix multiplication versus multiplication:
- Element-wise multiplication:
A * Bmultiplies corresponding broadcast-compatible elements. - Matrix multiplication:
A @ B, equivalent tonp.matmul(A, B), contracts matching inner dimensions.
If
Ahas shape(m, n)andBhas shape(n, p), thenA @ Bhas shape(m, p):
TEXTCᵢⱼ = Σₖ AᵢₖBₖⱼ
Here,iindexes rows ofA,jindexes columns ofB,kspans the shared dimensionn, andCis the product. - Element-wise multiplication:
B. Applications and limitations
Binary operations provide vectorized numerical and conditional processing, while data types and exceptional values influence their results.
- Boolean selection: A comparison creates a mask for filtering:
PYTHONvalues = np.array([3, -1, 7, -4]) positive = values[values > 0] # array([3, 7]) - Type promotion: Combining different dtypes produces a common result dtype; adding an integer array to a floating-point array ordinarily yields floating-point values.
- In-place casting:
a += battempts to store the result ina’s existing dtype. Adding floating-point values to an integer array in place may raise a casting error rather than silently discard decimals. - Exceptional arithmetic: Division by zero and invalid floating-point operations can produce
inf,-inf, ornanwith warnings.np.isfinite(),np.isinf(), andnp.isnan()detect these values. - Floating-point equality: Rounding error makes
a == bunsuitable for many computed decimal values;np.isclose(a, b)andnp.allclose(a, b)compare within tolerances. - Precedence: Parenthesized expressions such as
(a > 0) & (a < 10)prevent operators from being grouped incorrectly and clearly communicate the intended element-wise condition.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →