BRAGA

02 Writing02-02 Notes02-02-152

Matrix definition

Published 16 Apr 20269 min read
Contents
  1. 01Deep Breakdown
  2. 02Flowchart
  3. 03Real-world use
  4. 04The formula, piece by piece
  5. 05The formula in words
  6. 06Critical Concepts
  7. 07Step-by-step calculation (tiny example)
  8. 08Code examples
A=[aij]A = [a_{ij}]
(1)

of size m×nm \times n

Deep Breakdown

What it tells me (Situation Awareness): A=[aij]A = [a_{ij}] is the defining notation for a matrix: a rectangular array of numbers arranged in mm rows and nn columns, where aija_{ij} denotes the entry in row ii, column jj. This is the data container that underpins all of linear algebra. In DA/DS, a matrix is the fundamental way to represent tabular data (NN observations × pp features), a linear transformation (weights mapping one vector space to another), covariance structure, adjacency in a graph, a convolution kernel, or any rectangular array of numbers that must be operated on collectively. Knowing how to read matrix notation — what mm, nn, ii, jj each mean — unlocks every formula in linear algebra.

Flowchart

Design matrixWeight matrixCovarianceSquare m=nTall m nWide mMatrix A of sizem x nm rows:observations,samples, outputdimensionsn columns:features, inputdimensions,variablesEntry a_ij: row i(1-indexed),column j(1-indexed)Shapeinterpretation inDA/DSX: N_obs xN_features --each row is onedata pointW: N_outputs xN_inputs --linear map frominputs to outputsSigma: p x p --symmetric,capturespairwise featurespreadDeterminant,inverse,eigenvaluesdefinedOverdeterminedsystem: moreequations thanunknowns (OLS)Underdetermined system: moreunknowns thanequations (L1/L2reg)

Real-world use

Where it is used

Every time you load a CSV into pandas or numpy, you are working with a matrix. The design matrix XX in regression, the weight matrices in neural networks, the covariance matrix in PCA, the adjacency matrix in graph analytics, the confusion matrix in classification evaluation, and the ratings matrix in collaborative filtering are all instances of A=[aij]A = [a_{ij}].

Problem it solves

Data and linear transformations are fundamentally 2D structures (or can be reshaped into 2D). Matrix notation provides a compact, algebraically manipulable representation: instead of tracking m×nm \times n separate numbers, you manipulate a single object AA using rules (addition, multiplication, transposition, inversion) that encode the collective behavior of all entries.

How it solves the problem

By indexing entries as aija_{ij} (row first, column second), matrix notation makes explicit the two-dimensional structure. Operations on AA translate to entry-level rules: [A+B]ij=aij+bij[A + B]_{ij} = a_{ij} + b_{ij}, [AB]ij=∑kaikbkj[AB]_{ij} = \sum_k a_{ik} b_{kj}, etc. Code maps directly to this notation: A[i, j] in NumPy is aija_{ij} (0-indexed).

Example in a business

A retail data scientist works with a sales dataset of N=5000N = 5000 weekly store-SKU combinations, each described by p=12p = 12 features (price, promotions, seasonality index, etc.). This is stored as a NumPy array XX of shape (5000,12)(5000, 12): 5000 rows (observations), 12 columns (features). The matrix notation X=[xij]X = [x_{ij}] tells them immediately: xi,3x_{i, 3} is the 4th feature of the ii-th observation. The normal equations XTXX^T X (shape 12×1212 \times 12) and XTyX^T y (shape 12×112 \times 1) are derived purely from this 2D structure.

The formula, piece by piece

  • AA: the matrix object; a rectangular array identified by its name
  • [aij][a_{ij}]: shorthand for "the matrix whose (i,j)(i,j) entry is aija_{ij}"; square brackets indicate the entry rule that defines the whole matrix
  • aija_{ij}: a single scalar (real number); ii is the row index (1≤i≤m1 \leq i \leq m), jj is the column index (1≤j≤n1 \leq j \leq n)
  • m×nm \times n: the shape or dimensions; mm = number of rows, nn = number of columns; read as "m by n"
  • m=nm = n: square matrix; m>nm > n: tall/skinny; m<nm < n: wide/fat Full notation: A=[aij]m×n=[a11a12⋯a1na21a22⋯a2n⋮⋮⋱⋮am1am2⋯amn]A = [a_{ij}]_{m \times n} = \begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{bmatrix}

The formula in words

"A matrix is a grid of numbers with mm rows and nn columns. The entry aija_{ij} is the number in row ii and column jj. The two indices tell you exactly where in the grid to look: first go down ii rows, then go right jj columns." Tiny numeric example: A=[725103]A = \begin{bmatrix}7 & 2 & 5 \\ 1 & 0 & 3\end{bmatrix} has m=2m = 2 rows, n=3n = 3 columns. a11=7a_{11} = 7, a12=2a_{12} = 2, a13=5a_{13} = 5, a21=1a_{21} = 1, a22=0a_{22} = 0, a23=3a_{23} = 3. In NumPy (0-indexed): A[0, 0] = 7, A[1, 2] = 3.

Critical Concepts

  • Row-first indexing: aija_{ij} always means row ii, column jj. Never invert this.
  • 1-indexed vs 0-indexed: mathematical notation uses 1-based indexing (ii from 1 to mm); NumPy/Python use 0-based indexing. When translating formulas to code, subtract 1 from each index.
  • Shape vs size: "shape" is the pair (m,n)(m, n); "size" is m×nm \times n (total number of entries). A.shape in NumPy returns the tuple (m, n); A.size returns m*n.
  • Row vector: 1×n1 \times n matrix; column vector: m×1m \times 1 matrix. A 1D NumPy array is neither until you add a dimension.
  • Square matrix (m=nm = n): the only case where determinant, trace, eigenvalues, and inverse are defined in the classical sense.
  • Sparse vs dense: in practice, many matrices (adjacency, TF-IDF, one-hot encodings) are mostly zeros. Storing them as dense [aij][a_{ij}] arrays wastes memory; use scipy.sparse instead.
  • Data matrix convention: in statistics and ML, rows are observations and columns are features (N×pN \times p convention).

In pure linear algebra, a matrix often represents a linear map from Rn\mathbb{R}^n to Rm\mathbb{R}^m. Both are valid; be explicit about which convention you use.

Step-by-step calculation (tiny example)

Step 1: Read the matrix and extract its dimensions Given A=[3−10427]A = \begin{bmatrix}3 & -1 \\ 0 & 4 \\ 2 & 7\end{bmatrix}. Count rows: 3 (top to bottom). Count columns: 2 (left to right). So AA is 3×23 \times 2.

Step 2: Index individual entries using row-first notation a11=3a_{11} = 3 (row 1, column 1), a12=−1a_{12} = -1 (row 1, column 2). a21=0a_{21} = 0 (row 2, column 1), a22=4a_{22} = 4 (row 2, column 2). a31=2a_{31} = 2 (row 3, column 1), a32=7a_{32} = 7 (row 3, column 2).

Step 3: Translate to NumPy (0-indexed) and verify shape

python
import numpy as np
A_numpy = np.array([[3, -1], [0, 4], [2, 7]])
# a_{11} = A_numpy[0, 0], a_{32} = A_numpy[2, 1]

A_numpy.shape returns (3, 2): m=3m=3, n=2n=2.

Code examples

Beginner example (Python)

python
import numpy as np

# -- Defining a matrix and accessing entries ---------------------------
A = np.array([[7.0, 2.0, 5.0], [1.0, 0.0, 3.0]])
m, n = A.shape
print(f"Matrix A ({m} x {n}):")
print(A)
print(f"\nm = {m} rows, n = {n} columns, total entries = {A.size}")

# Access entries using 0-indexed NumPy syntax
# Mathematical a_11 = A[0, 0], a_23 = A[1, 2]
print(f"\na_11 (row 1, col 1) = {A[0, 0]:.1f}")
print(f"a_12 (row 1, col 2) = {A[0, 1]:.1f}")
print(f"a_23 (row 2, col 3) = {A[1, 2]:.1f}")

# Extract a full row and full column
row_2 = A[1, :]   # second row (index 1)
col_3 = A[:, 2]   # third column (index 2)
print(f"\nRow 2 (a_2j): {row_2}")
print(f"Col 3 (a_i3): {col_3}")

# Common shapes in DA/DS
print(f"\nShape {A.shape}: wide (m < n) -> more features than observations")
B = A.T
print(f"Transposed shape {B.shape}: tall (m > n) -> more observations than features")

Beginner example (R)

r
# -- Defining a matrix and accessing entries ---------------------------
A <- matrix(c(7, 2, 5, 1, 0, 3), nrow = 2, byrow = TRUE)
cat(sprintf("Matrix A (%d x %d):\n", nrow(A), ncol(A)))
print(A)

# R uses 1-based indexing, same as math notation
cat(sprintf("\na_11 = %.1f\n", A[1, 1]))  # row 1, col 1
cat(sprintf("a_12 = %.1f\n", A[1, 2]))  # row 1, col 2
cat(sprintf("a_23 = %.1f\n", A[2, 3]))  # row 2, col 3

# Extract row and column
row_2 <- A[2, ]
col_3 <- A[, 3]
cat(sprintf("Row 2: %s\n", paste(row_2, collapse = ", ")))
cat(sprintf("Col 3: %s\n", paste(col_3, collapse = ", ")))

Professional example (Python)

python
import numpy as np
import pandas as pd
np.random.seed(42)

# -- Business scenario: inspect and validate a design matrix for regression
# Sales dataset: N observations, p features. Verify shape, sparsity, range.
N_OBS = 500
N_FEATURES = 8
FEATURE_NAMES = [
    "price_index", "promo_flag", "seasonality", "store_size_sqm",
    "competitor_dist_km", "foot_traffic", "online_share", "weather_index",
]

# Simulate realistic feature matrix
X = np.column_stack([
    np.random.uniform(0.8, 1.2, N_OBS),                  # price_index
    np.random.binomial(1, 0.3, N_OBS),                   # promo_flag (sparse: ~70% zeros)
    np.sin(2 * np.pi * np.arange(N_OBS) / 52),           # seasonality (weekly cycle)
    np.random.normal(1200, 300, N_OBS),                  # store_size_sqm
    np.random.exponential(2.0, N_OBS),                   # competitor_dist_km
    np.random.poisson(500, N_OBS).astype(float),         # foot_traffic
    np.random.beta(2, 5, N_OBS),                         # online_share (0-1)
    np.random.normal(0, 1, N_OBS),                       # weather_index
])
df = pd.DataFrame(X, columns=FEATURE_NAMES)

# Matrix-level diagnostics
m, n = X.shape
sparsity = float(np.sum(X == 0)) / X.size
cond_num = float(np.linalg.cond(X))
print(f"Design matrix X: {m} observations x {n} features (m x n = {m} x {n})")
print(f"Shape type: {'tall (overdetermined)' if m > n else 'wide (underdetermined)'}")
print(f"Sparsity (fraction of zeros): {sparsity:.3f}")
print(f"Condition number: {cond_num:.1f} ({'well-conditioned' if cond_num < 1000 else 'ill-conditioned'})")
print(f"\nSummary statistics per feature (columns = a_ij for each j):")
print(df.describe().round(3).to_string())
print(f"\nInterpretation: a_ij is the {n}-feature value for observation i. The tall shape (m={m} >> n={n}) makes OLS well-defined.")

Professional example (R)

r
# Design matrix X (m x n): columns = features, rows = observations
set.seed(42)
N_OBS <- 500
N_FEATURES <- 8
X <- cbind(
  runif(N_OBS, 0.8, 1.2),
  rbinom(N_OBS, 1, 0.3),
  sin(2 * pi * (1:N_OBS) / 52),
  rnorm(N_OBS, 1200, 300),
  rexp(N_OBS, 0.5),
  rpois(N_OBS, 500) + 0,
  rbeta(N_OBS, 2, 5),
  rnorm(N_OBS)
)
m <- nrow(X)
n <- ncol(X)
sparsity <- sum(X == 0) / length(X)
cond_num <- kappa(X)
cat(sprintf("X: %d x %d Sparsity: %.3f Condition number: %.1f\n", m, n, sparsity, cond_num))
cat("Summary per column:\n")
print(summary(as.data.frame(X)))

Source: 1300 p. 118

#linear-algebra#matrices-and-determinants#basic-principles-and-operations

Keyboard shortcuts

Single keys, ignored while typing in a field or with Cmd, Ctrl or Alt held.

0
Home
1 2 3 4
Work, Writing, Tools, About
j / k
Next / previous section on this page
n / p
Next / previous project or essay
u
Up one level
l
Deutsch
t
Light or dark theme
?
This list
Esc
Close