Matrices
Reviewed & published by Brayan K
A matrix is a two-dimensional grid of values of a single type — rows and columns of numbers that R can index, summarise, and run linear-algebra operations on.
Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll create matrices with matrix(), index them by [row, col], name dimensions, and use built-in row/column summaries and matrix multiplication.
What You'll Learn in This Lesson
- How to build a matrix with matrix() and byrow
- How dim(), nrow(), and ncol() describe shape
- How to index with [row, col] and whole rows/cols
- How to name rows and columns for clarity
- How rowSums(), colMeans(), and friends summarise
- How %*% does true matrix multiplication
1️⃣ Building a Matrix
Pass a vector to matrix() with nrow and/or ncol. By default R fills column by column; use byrow = TRUE to fill across rows. dim() reports the shape.
# A matrix is a 2-D grid of values of ONE type. Build it with matrix().
# byrow = TRUE fills row by row (the default fills column by column).
m <- matrix(1:6, nrow = 2, ncol = 3, byrow = TRUE)
m
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 4 5 6
dim(m) # rows, cols -> [1] 2 3
nrow(m); ncol(m) # -> [1] 2 ... [1] 32️⃣ Indexing by Row and Column
Index with m[row, col]. Leave a side blank to grab a whole row or column. Naming the dimensions with rownames() and colnames() lets you index by label.
# Index a matrix with [row, col]. Leave one side blank for a whole row/col.
m <- matrix(1:6, nrow = 2, byrow = TRUE)
m[1, 2] # row 1, col 2 -> [1] 2
m[1, ] # whole first row -> [1] 1 2 3
m[, 3] # whole third col -> [1] 3 6
# Name the dimensions for readable access:
rownames(m) <- c("a", "b")
colnames(m) <- c("x", "y", "z")
m["a", "z"] # -> [1] 33️⃣ Matrix Math
Element-wise math works just like vectors. R also gives you fast summaries — rowSums(), colMeans() — plus t() to transpose and %*% for genuine matrix multiplication.
# Element-wise math just like vectors, plus true matrix operations.
a <- matrix(c(1, 2, 3, 4), nrow = 2)
a * 2 # every element doubled
# Row and column summaries are built in:
rowSums(a) # -> [1] 4 6 (1+3, 2+4)
colMeans(a) # -> [1] 1.5 3.5
# t() transposes; %*% is real matrix multiplication:
t(a) # swap rows and cols
a %*% a # matrix productYour turn. Fill in the ___ blank, run it, and compare with the expected output.
# 🎯 YOUR TURN — replace each ___ then run it.
# 1) Build a 2x2 matrix of sales for two shops over two days
sales <- matrix(c(100, 150, 200, 120), nrow = 2, byrow = TRUE)
# 2) Print the total sales per row (each shop) with rowSums()
print(___(sales)) # 👉 replace ___ with rowSums
# 3) Print the average per column (each day) with colMeans()
print(colMeans(sales))
# ✅ Expected output:
# [1] 250 320
# [1] 150 135Mini-Challenge: A Times-Table Grid
Write it from the outline, run it, and check it against the example output. outer() is a neat way to build a grid from two vectors.
# 🎯 MINI-CHALLENGE: a 3x3 multiplication grid.
#
# 1. Use outer(1:3, 1:3) to build a 3x3 times-table matrix.
# (outer applies * to every pair, giving a grid)
# 2. Print the matrix.
# 3. Print the sum of ALL its values with sum().
# 4. Print the largest value with max().
#
# ✅ Example output:
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 2 4 6
# [3,] 3 6 9
# Total: 36
# Max: 9
# your code hereCommon Errors (and the fix)
- Matrix looks transposed — R filled by column. Add byrow = TRUE to fill in the order you typed values.
- "non-conformable arguments" — your matrices' dimensions don't line up for %*%. The first's columns must equal the second's rows.
- A row collapses to a vector — m[1, ] drops to a vector. Add drop = FALSE to keep it a matrix.
- Mixing types — putting text in a numeric matrix coerces everything to character. Matrices hold one type only; use a data frame for mixed columns.
Pro Tips
- 💡 Combine vectors fast: cbind() binds columns and rbind() binds rows into a matrix.
- 💡 Name dimensions: labelled rows/cols make indexing and output far easier to read.
- 💡 apply over a margin: apply(m, 1, max) gives the max of each row — preview of the apply lesson.
📋 Quick Reference — Matrices
| Task | R Syntax |
|---|---|
| Create | matrix(1:6, nrow = 2) |
| Shape | dim(m) |
| Element / row / col | m[i, j] ; m[i, ] ; m[, j] |
| Row/col summary | rowSums(m) ; colMeans(m) |
| Transpose | t(m) |
| Matrix multiply | a %*% b |
🎉 Lesson Complete!
- ✅ A matrix is a 2-D grid of one type
- ✅ matrix(..., byrow = TRUE) controls fill order
- ✅ Index with m[row, col]; blanks grab whole rows/cols
- ✅ rowSums() and colMeans() summarise fast
- ✅ %*% is true matrix multiplication
Practice quiz
What kind of values can a single matrix hold?
- Values of one type only
- Any mix of types
- Only character strings
- Only whole numbers
Answer: Values of one type only. A matrix is a 2-D grid where every cell must be the same type.
What does byrow = TRUE do in matrix()?
- Sorts the rows
- Fills the matrix row by row
- Transposes the matrix
- Removes empty rows
Answer: Fills the matrix row by row. By default R fills by column; byrow = TRUE fills across rows in input order.
How does R fill a matrix by default?
- Randomly
- Row by row
- Diagonally
- Column by column
Answer: Column by column. Without byrow, R is column-major and fills down the first column first.
What does dim(m) return for a matrix?
- The total number of cells
- The rownames
- The number of rows and columns
- The largest value
Answer: The number of rows and columns. dim() reports the shape as c(rows, cols).
How do you select the whole first row of a matrix m?
- m[1, ]
- m[, 1]
- m[1]
- m(1)
Answer: m[1, ]. Leaving the column index blank, m[1, ], grabs the entire first row.
Which operator does true matrix multiplication?
- *
- %*%
- %/%
- x()
Answer: %*%. %*% performs real matrix multiplication; plain * is element-wise.
What does rowSums(a) compute?
- The sum of all cells
- The product of each row
- The sum of each row
- The mean of each column
Answer: The sum of each row. rowSums() adds up the values in each row.
What does t(a) do to a matrix?
- Totals it
- Trims it
- Transposes rows and columns
- Truncates decimals
Answer: Transposes rows and columns. t() transposes the matrix, swapping its rows and columns.
Why might your matrix look 'transposed' from what you typed?
- R filled by column instead of by row
- matrix() reverses input
- dim() reordered it
- It used byrow = TRUE
Answer: R filled by column instead of by row. Default column-major fill surprises many beginners; add byrow = TRUE.
What causes a 'non-conformable arguments' error with %*%?
- Too many rows
- The dimensions don't line up for multiplication
- Using named dimensions
- A negative value
Answer: The dimensions don't line up for multiplication. For A %*% B, the first matrix's columns must equal the second's rows.
Continue this course
- Previous: Lists
- Next: Data Frames — R's spreadsheet-like table — the workhorse of data analysis
- Quick reference: R cheat sheet
Frequently asked questions
What is the difference between a matrix and a data frame?
A matrix is a 2-D grid where every cell must be the same type (all numbers, say) — it's ideal for mathematical work like linear algebra. A data frame is also table-shaped but each column can be a different type (a text column, a numeric column, a factor column), which makes it the right tool for real-world datasets. Use matrices for numeric computation; use data frames (the next lesson) for mixed-type tabular data.
How does matrix() decide where each value goes?
By default R fills a matrix column by column — the first values go down the first column, then the next column, and so on. If you'd rather fill across rows in the order you typed them, set byrow = TRUE. This trips up many beginners whose matrix looks 'transposed' from what they expected. Always be explicit with byrow when the input order matters.
What does %*% do, and how is it different from *?
The plain * multiplies matrices element by element (cell-by-cell), which requires them to be the same shape. The %*% operator performs true matrix multiplication from linear algebra, where rows of the first matrix combine with columns of the second, and the inner dimensions must match. If you're doing statistics or linear algebra you usually want %*%; for scaling every cell by a factor you want *.
How do I summarise rows and columns quickly?
R provides fast built-ins: rowSums() and colSums() add up each row or column, and rowMeans() and colMeans() average them. These are much faster and clearer than writing loops. For other summaries, apply(m, 1, FUN) runs a function over each row and apply(m, 2, FUN) over each column — you'll meet the apply family in detail later in this track.