Skip to content

R - Matrices

Matrices are fundamental R objects that arrange elements in a two-dimensional rectangular grid. A key characteristic is that all elements within a matrix must be of the same atomic type (e.g., all numeric, all character). While you can create character or logical matrices, their primary use in data analysis is for storing numeric data for mathematical computations.

In modern R, especially within the tidyverse ecosystem, the tibble or data.frame is often preferred for general data storage because it allows columns of different types. Matrices remain essential for linear algebra, statistical modeling, and high-performance computing tasks.

A matrix is created using the matrix() function.

The basic syntax for creating a matrix in R is:

matrix(data, nrow, ncol, byrow = FALSE, dimnames = NULL)

Description of the parameters:

  • data: The input vector that populates the matrix.
  • nrow: The number of rows.
  • ncol: The number of columns.
  • byrow: A logical value. If TRUE, the matrix is filled row by row. If FALSE (the default), it’s filled column by column.
  • dimnames: An optional list of two vectors to name the rows and columns.

Let’s create a few matrices to see how the arguments work. We’ll use modern R styling, such as the <- assignment operator.

# By default, R fills matrices by column.
# Let's create a 4x3 matrix.
mat_by_col <- matrix(data = 3:14, nrow = 4)
print(mat_by_col)
# To fill by row, set byrow = TRUE.
mat_by_row <- matrix(data = 3:14, nrow = 4, byrow = TRUE)
print(mat_by_row)
# We can also add names for clarity.
row_names <- paste0("row_", 1:4)
col_names <- paste0("col_", 1:3)
named_mat <- matrix(
data = 3:14,
nrow = 4,
byrow = TRUE,
dimnames = list(row_names, col_names)
)
print(named_mat)

When we execute the above code, it produces the following result:

# Output for mat_by_col (filled by column)
[,1] [,2] [,3]
[1,] 3 7 11
[2,] 4 8 12
[3,] 5 9 13
[4,] 6 10 14
# Output for mat_by_row (filled by row)
[,1] [,2] [,3]
[1,] 3 4 5
[2,] 6 7 8
[3,] 9 10 11
[4,] 12 13 14
# Output for named_mat
col_1 col_2 col_3
row_1 3 4 5
row_2 6 7 8
row_3 9 10 11
row_4 12 13 14

You can access elements, rows, or columns using square bracket notation [row, column]. Leaving an index blank selects all elements in that dimension.

# Let's use our named_mat from the previous example
# Access the element at the 1st row, 3rd column
print(named_mat[1, 3])
# You can also use names if they exist
print(named_mat["row_1", "col_3"])
# Access the entire 4th row
print(named_mat[4, ])
# Access the entire 2nd column
print(named_mat[, 2])

Executing the above code produces:

[1] 5
[1] 5
col_1 col_2 col_3
12 13 14
row_1 row_2 row_3 row_4
4 7 10 13

Mathematical operations on matrices are a core strength of R. It’s crucial to understand the difference between element-wise operations and true matrix algebra.

Standard arithmetic operators perform calculations element by element. This requires both matrices to have the exact same dimensions.

# Create two 2x3 matrices
matrix1 <- matrix(c(3, 9, -1, 4, 2, 6), nrow = 2)
matrix2 <- matrix(c(5, 2, 0, 9, 3, 4), nrow = 2)
# Element-wise addition
add_result <- matrix1 + matrix2
cat("Result of addition:\n")
print(add_result)
# Element-wise multiplication
# THIS IS NOT MATRIX MULTIPLICATION!
mult_result <- matrix1 * matrix2
cat("\nResult of element-wise multiplication:\n")
print(mult_result)

The output clearly shows each corresponding element being operated on:

Result of addition:
[,1] [,2] [,3]
[1,] 8 -1 5
[2,] 11 13 10
Result of element-wise multiplication:
[,1] [,2] [,3]
[1,] 15 0 6
[2,] 18 36 24

For true matrix multiplication according to the rules of linear algebra, you must use the %*% operator. The inner dimensions must match (i.e., the number of columns in the first matrix must equal the number of rows in the second).

# Create compatible matrices for multiplication
# matrix_A is 2x3
matrix_A <- matrix(1:6, nrow = 2, byrow = TRUE)
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 4 5 6
# matrix_B is 3x2
matrix_B <- matrix(7:12, nrow = 3, byrow = TRUE)
# [,1] [,2]
# [1,] 7 8
# [2,] 9 10
# [3,] 11 12
# The result will be a 2x2 matrix
matrix_prod <- matrix_A %*% matrix_B
cat("Result of true matrix multiplication (2x3 %*% 3x2):\n")
print(matrix_prod)

Executing this demonstrates correct matrix multiplication:

Result of true matrix multiplication (2x3 %*% 3x2):
[,1] [,2]
[1,] 58 64
[2,] 139 154
  • Element-wise vs. Matrix Multiplication: Always remember to use %*% for linear algebra multiplication. Using * is a very common error that leads to incorrect results.
  • Dimension Mismatch: R will throw an error if you try to perform operations on matrices with incompatible dimensions. Always check dim() before operations.
  • Data Homogeneity: Remember that a matrix can only hold one data type. If you mix types (e.g., numbers and text), R will coerce all elements to the least restrictive type (usually character), which can prevent mathematical operations.
  • When to use a Matrix: Use matrices for mathematical tasks. For general data storage and manipulation (e.g., a table of customer data with names, ages, and IDs), use a tibble or data.frame.