R Matrices: Fast Linear Algebra Operations That Data Frames Can't Do
A matrix is a 2D array where every element has the same type — typically numeric. Matrices are faster than data frames for math-heavy operations like linear algebra, statistics, and machine learning algorithms.
Data frames are great for mixed data (numbers + text + logical). But when all your data is numeric and you need matrix math — multiplication, transposition, decomposition, solving equations — matrices are the right tool. They're faster, use less memory, and support operations that data frames don't.
Introduction
A matrix in R is a 2D collection of values with rows and columns, where every element has the same type. Think of it as a vector arranged in a grid:
A vector is 1D: [1, 2, 3, 4, 5, 6]
A matrix is 2D: the same 6 values arranged as 2 rows × 3 columns (or 3×2, etc.)
# Create a matrix from a vector
m <- matrix(1:12, nrow = 3, ncol = 4)
print(m)
cat("\nDimensions:", nrow(m), "rows x", ncol(m), "columns\n")
cat("Total elements:", length(m), "\n")
Notice R fills the matrix column by column (column-major order) by default. The first column gets 1, 2, 3, then the second column gets 4, 5, 6, etc.
Standard operators apply element by element — just like vector math:
A <- matrix(c(1, 2, 3, 4), nrow = 2)
B <- matrix(c(5, 6, 7, 8), nrow = 2)
cat("A:\n"); print(A)
cat("\nB:\n"); print(B)
cat("\nA + B (element-wise addition):\n"); print(A + B)
cat("\nA * B (element-wise multiplication):\n"); print(A * B)
cat("\nA^2 (element-wise square):\n"); print(A^2)
cat("\nA / B (element-wise division):\n"); print(round(A / B, 3))
Important:A * B is element-wise multiplication, not matrix multiplication. For matrix multiplication, use %*%.
Matrix multiplication
# Matrix multiplication uses %*%
A <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 2) # 2x3
B <- matrix(c(7, 8, 9, 10, 11, 12), nrow = 3) # 3x2
cat("A (2x3):\n"); print(A)
cat("\nB (3x2):\n"); print(B)
# A %*% B produces a 2x2 matrix
C <- A %*% B
cat("\nA %*% B (2x2):\n"); print(C)
# Dimensions must match: A's columns = B's rows
cat("\nA:", nrow(A), "x", ncol(A), "\n")
cat("B:", nrow(B), "x", ncol(B), "\n")
cat("Result:", nrow(C), "x", ncol(C), "\n")
Matrix multiplication is the foundation of linear regression, PCA, neural networks, and most statistical algorithms.
Transpose
A <- matrix(1:6, nrow = 2)
cat("A (2x3):\n"); print(A)
# t() transposes — swaps rows and columns
At <- t(A)
cat("\nt(A) (3x2):\n"); print(At)
# Transpose + multiply: A'A (common in statistics)
AtA <- t(A) %*% A
cat("\nt(A) %*% A (3x3):\n"); print(AtA)
t(A) %*% A appears everywhere in statistics — it's the basis of least squares regression.
Matrix Functions
M <- matrix(c(4, 2, 7, 6), nrow = 2)
cat("M:\n"); print(M)
# Determinant
cat("\nDeterminant:", det(M), "\n")
# Inverse (M^-1 such that M %*% M^-1 = I)
M_inv <- solve(M)
cat("\nInverse of M:\n"); print(M_inv)
# Verify: M %*% M_inv should be identity
cat("\nM %*% M_inv (should be identity):\n")
print(round(M %*% M_inv, 10))
# Solving linear equations: Ax = b
# 2x + 3y = 8
# 4x + 1y = 10
A <- matrix(c(2, 4, 3, 1), nrow = 2)
b <- c(8, 10)
x <- solve(A, b)
cat("Solution: x =", x[1], ", y =", x[2], "\n")
# Verify: A %*% x should equal b
cat("Verification:", A %*% x, "\n")
Explanation:rowSums() adds across columns for each row. which.max() finds the position of the maximum, and rownames() converts that position to a product name.
Exercise 2: Solve a System of Equations
# Exercise: Solve this system of 3 equations:
# 2x + y - z = 8
# -3x - y + 2z = -11
# -2x + y + 2z = -3
#
# Set up as Ax = b and use solve()
# Write your code below:
Click to reveal solution
# Solution
A <- matrix(c(2, -3, -2, 1, -1, 1, -1, 2, 2), nrow = 3)
b <- c(8, -11, -3)
cat("A:\n"); print(A)
cat("b:", b, "\n")
x <- solve(A, b)
cat("\nSolution: x =", x[1], ", y =", x[2], ", z =", x[3], "\n")
# Verify
cat("Verification (A %*% x):", A %*% x, "\n")
cat("Should equal b:", b, "\n")
Explanation: The matrix A contains the coefficients (filled column-by-column: first column is x coefficients, second is y, third is z). solve(A, b) finds the vector x such that A %*% x = b.
Exercise 3: Correlation Matrix
# Exercise: Using mtcars, create a correlation matrix for
# mpg, hp, wt, and qsec. Then find which pair has the
# strongest correlation (positive or negative).
# Hint: cor() creates a correlation matrix
# Write your code below:
Explanation:cor() computes pairwise correlations for all columns. We zero the diagonal (self-correlation = 1.0) then find the maximum absolute value. The strongest correlation is between wt and mpg (about -0.87) — heavier cars get worse fuel economy.
Summary
Operation
Code
Notes
Create
matrix(data, nrow, ncol)
Fills column-by-column by default
By row
matrix(data, nrow, byrow = TRUE)
Fills row-by-row
From vectors
rbind() / cbind()
Stack rows or columns
Access
m[row, col]
Leave blank for all: m[1,], m[,2]
Element-wise
+, -, *, /
Applied to matching positions
Matrix multiply
A %*% B
Columns of A must = rows of B
Transpose
t(A)
Swap rows and columns
Inverse
solve(A)
Only for square, non-singular matrices
Solve Ax=b
solve(A, b)
Linear system of equations
Determinant
det(A)
0 means singular (no inverse)
Row/col stats
rowSums(), colMeans(), etc.
Very fast
Apply function
apply(m, MARGIN, fun)
1=rows, 2=columns
FAQ
When does R use matrices internally?
All the time. Linear regression (lm()) builds a design matrix internally. PCA uses eigen decomposition of a covariance matrix. Distance calculations (dist()) produce matrices. Most statistical algorithms work with matrices under the hood.
Can a matrix hold text?
Technically yes — matrix(c("a","b","c","d"), nrow=2) works. But text matrices are rare and slow. If you need mixed types, use a data frame. If you need fast text operations, use character vectors.
What's the difference between * and %*%?
* is element-wise: A[i,j] * B[i,j]. %*% is matrix multiplication: each element of the result is a dot product of a row of A with a column of B. For 2×2 matrices: (A %*% B)[1,1] = A[1,1]*B[1,1] + A[1,2]*B[2,1].
What happens if I multiply matrices with wrong dimensions?
R throws an error: "non-conformable arguments." For A %*% B, the number of columns in A must equal the number of rows in B.
What's Next?
Now you understand both data frames (mixed data) and matrices (numeric data). Explore further:
R Subsetting — advanced indexing for all data structures
R Type Coercion — how R converts between types
Linear Regression — see matrices in action for statistical modeling