matrix()
matrix(data, nrow, ncol, byrow, dimnames) Matrices are two-dimensional data structures in R that hold elements of the same atomic type. They are fundamental to statistical computing and linear algebra.
Syntax
matrix(data, nrow, ncol, byrow, dimnames)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
data | any | , | An atomic vector (or scalar) to fill the matrix |
nrow | integer | , | Number of rows |
ncol | integer | , | Number of columns |
byrow | logical | FALSE | Fill matrix by rows if TRUE, by columns if FALSE |
dimnames | list | NULL | Optional row and column names |
Examples
Basic matrix creation
# Create a 3x2 matrix filled column-wise (default)
mat <- matrix(1:6, nrow = 3, ncol = 2)
mat
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
# Fill by rows instead
mat_by_row <- matrix(1:6, nrow = 3, ncol = 2, byrow = TRUE)
mat_by_row
# [,1] [,2]
# [1,] 1 2
# [2,] 3 4
# [3,] 5 6
Columns fill first by default, the same column-major layout FORTRAN uses. Set byrow = TRUE when your data arrives row by row, such as reading a table line by line into a matrix buffer. The dimnames argument attaches row and column names as a list of two character vectors, making printed output more readable and easier to index by name in subsequent operations.
Named rows and columns
# Add row and column names
mat <- matrix(1:6, nrow = 3, ncol = 2,
dimnames = list(c("r1", "r2", "r3"),
c("c1", "c2")))
mat
# c1 c2
# r1 1 4
# r2 2 5
# r3 3 6
Named dimensions improve readability but do not affect computation speed. Matrix arithmetic — multiplication with %*%, transposition with t(), and row or column summaries — works identically whether you assign dimnames or not. R delegates these operations to optimized BLAS/LAPACK libraries, so performance scales with the underlying hardware rather than R interpreter overhead.
Matrix operations
# Matrix multiplication
A <- matrix(1:4, nrow = 2)
B <- matrix(5:8, nrow = 2)
A %*% B
# [,1] [,2]
# [1,] 23 34
# [2,] 34 50
# Transpose
t(A)
# [,1] [,2]
# [1,] 1 3
# [2,] 2 4
# Row and column sums
rowSums(A)
# [1] 3 7
colSums(A)
# [1] 4 6
Matrix subsetting uses the same [row, col] syntax as data frames. Leaving one index blank selects all entries in that dimension. Unlike data frames, matrix subsetting does not drop the dimension attribute for single-row or single-column selections — you get a matrix back, not a vector. To extract a plain vector from one row, use mat[1, , drop = TRUE] or simply index with mat[1, ] and accept the dimensional result.
Common patterns
Matrix indexing
mat <- matrix(1:9, nrow = 3)
# Access element
mat[2, 3]
# [1] 8
# Access row
mat[1, ]
# [1] 1 4 7
# Access column
mat[, 2]
# [1] 4 5 6
Building matrices incrementally is common in simulation and data-processing loops. rbind() stacks vectors as rows, and cbind() stacks them as columns. Both functions coerce inputs to a common type — mixing numeric and character vectors produces a character matrix. For large data where you accumulate rows in a loop, pre-allocate the full matrix and fill by index rather than calling rbind() repeatedly, which copies the entire matrix each iteration.
Binding vectors
# Combine vectors as rows
rbind(1:3, 4:6)
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 4 5 6
# Combine vectors as columns
cbind(1:3, 4:6)
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
rbind() and cbind() produce matrices from vectors, but diag() is the go-to for creating structured square matrices. The identity matrix is the neutral element of matrix multiplication, and custom diagonal matrices encode independent scaling along each axis. Knowing diag() in all three modes — creation from a scalar, creation from a vector, and extraction from an existing matrix — covers most diagonal needs in statistical computing.
Diagonal matrices
# Identity matrix
diag(3)
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 1 0
# [3,] 0 0 1
# Custom diagonal
diag(c(1, 2, 3))
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 2 0
# [3,] 0 0 3
Diagonal matrices appear throughout linear algebra: identity matrices for initialization, covariance matrices for multivariate work, and regularization terms in optimization. diag(n) creates an n×n identity. diag(x) with a vector places those values on the diagonal of an otherwise-zero matrix. When x is already a matrix, diag(x) extracts the diagonal as a vector — the function shifts behavior based on input type, so double-check what you are passing.
When to use matrix vs data frame
Use a matrix when all values are the same type and you need efficient numeric computation — linear algebra, distance calculations, simulation output, or design matrices for statistical models. R’s linear algebra functions (%*%, solve(), t(), crossprod()) require matrix input and are implemented in optimized BLAS/LAPACK routines.
Use a data frame (or tibble) when columns represent different variables with potentially different types — the typical case for real-world datasets.
A matrix uses less memory than a data frame for the same numeric data because there is no overhead for per-column type tracking. For large simulation output where every cell is a double and you need column-wise summary statistics, apply(m, 2, mean) on a matrix is faster than colMeans(as.matrix(df)) on a data frame.
Converting between the two is straightforward: as.matrix(df) converts a data frame to matrix (coercing all columns to a common type), and as.data.frame(m) goes the other way.
Matrices in R are stored in column-major order (columns are contiguous in memory), the same layout as FORTRAN. This means column operations are faster than row operations at the hardware level. When writing code that loops over a matrix, iterating by column (for (j in 1:ncol(m))) is faster than iterating by row. Use t() to transpose the matrix if you need row-oriented access and performance matters. Transposing copies the data into a new layout, so it is a one-time cost rather than a per-operation overhead.
matrix() recycles the data argument if it is shorter than nrow * ncol: matrix(1:3, nrow = 2, ncol = 3) fills the six cells by cycling through 1, 2, 3, 1, 2, 3. A warning is issued only if the data length is not a multiple of the matrix size. This recycling behavior, while convenient for filling a matrix with a repeated pattern, is a common source of unintentional bugs — verify the dimensions match the data length when constructing matrices from computed vectors.