R: R Matrices and Arrays

Last updated: 2026-08-26

In the previous lesson, we learned about "one-dimensional" vectors. In this lesson, we’ll move on to "two-dimensional" and "multidimensional" concepts—matrices and arrays. Matrices are the foundation of data analysis (Excel spreadsheets, image pixels, and neural network weights are all matrices), so let’s make sure we fully understand them in this lesson.

The "heart" of matrices is the apply() function family—it allows us to perform operations by row, column, or dimension without writing loops. This is where R is more concise than Python.

1. What You'll Learn



2. The Story of a Transcript

(1) Pain Point: Compiling Grades Across Multiple Subjects

Xiao Zhao is an academic affairs officer. The transcripts for five students in three courses are as follows:

TEXT 📖 Display only
       Mathematics  Chinese Language  English
Alice     85    78    92
Bob     72    88    80
Charlie     90    85    87
Diana     65    70    75
Eve     95    92    88

Calculate: ① Each student’s total score; ② The average score for each subject; ③ Identify the student with the highest score in math.

If you were to write this using Excel formulas, it would take forever; if you were to write it in Python, you’d have to use nested loops—

(2) Solution using R

R
# 5x3 Matrix
scores <- matrix(c(85, 78, 92,
                   72, 88, 80,
                   90, 85, 87,
                   65, 70, 75,
                   95, 92, 88),
                 nrow = 5, byrow = TRUE)
colnames(scores) <- c("Mathematics", "Chinese Language", "English")
rownames(scores) <- c("Alice", "Bob", "Charlie", "Diana", "Eve")

# 1. Each Student's Total Score(Sum in One Line)
row_sums <- apply(scores, 1, sum)

# 2. Average per subject(Calculate the average for a column)
col_means <- apply(scores, 2, mean)

# 3. Find the highest score in math
top_math <- which.max(scores[, "Mathematics"])

Five lines of code to solve three tasks. That’s the power of matrices and the apply function.



3. The Essence of Matrices: Two-Dimensional Vectors

(1) Conversion from Vectors to Matrices

100%
graph LR
    A["One-dimensional vector c 1,2,3,4,5,6"] --> B["reshape into 2x3 Matrix"]
    B --> C["1 2 3 / 4 5 6"]
    B --> D["1 4 / 2 5 / 3 6"]
    
    style A fill:#cce5ff
    style B fill:#fff3cd
R
# One-dimensional vector
v <- 1:6
v
# [1] 1 2 3 4 5 6

# Convert to 2 row 3 List of Matrices
m <- matrix(v, nrow = 2, ncol = 3)
m
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

(2) The Four Key Properties of Matrices

Property Meaning Example
dim(m) dimensional vector dim(m)c(2, 3)
nrow(m) Line number nrow(m)2
ncol(m) Number of rows ncol(m)3
length(m) Total number of elements length(m)6
R
m <- matrix(1:6, nrow = 2)

dim(m)        # [1] 2 3
nrow(m)       # [1] 2
ncol(m)       # [1] 3
length(m)     # [1] 6  ← Total Number of Elements


4. matrix(): Create a matrix

(1) Basic Syntax

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

(2) 4 Ways to Create

R
# 1. Provide the data directly + Number of rows and columns
m1 <- matrix(1:6, nrow = 2)
#      [,1] [,2] [,3]
# [1,]    1    3    5   ← Fill by column by default
# [2,]    2    4    6

# 2. byrow = TRUE(Fill by Row)
m2 <- matrix(1:6, nrow = 2, byrow = TRUE)
#      [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    4    5    6

# 3. Add row and column names
m3 <- matrix(1:6, nrow = 2, byrow = TRUE,
            dimnames = list(c("row1", "row2"), c("colA", "colB", "colC")))
#     colA colB colC
# row1   1   2   3
# row2   4   5   6

# 4. Specify only nrow,ncol Automatic Inference
m4 <- matrix(1:6, nrow = 3)  # 3 row 2 col
#      [,1] [,2]
# [1,]    1    4
# [2,]    2    5
# [3,]    3    6
⚠️ Note: byrow = FALSE is the default (fill by column). In most cases, we want to fill by row (one student per row/one record), so you must explicitly specify byrow = TRUE.

(3) Add column and row labels (for better readability)

R
m <- matrix(1:6, nrow = 2, byrow = TRUE)
rownames(m) <- c("Alice", "Bob")
colnames(m) <- c("Mathematics", "Chinese Language", "English")
m
#     Mathematics Chinese Language English
# Alice   1    2    3
# Bob   4    5    6


5. Accessing Matrix Elements

(1) 3 Ways to Access

Method Syntax Purpose
[i, j] Row i, Column j Single element
[i, ] Line i Entire line
[, j] Column j Entire column
[i, "col_name"] A column in row i By name
R
m <- matrix(1:9, nrow = 3, byrow = TRUE,
            dimnames = list(c("Alice", "Bob", "Charlie"),
                          c("Mathematics", "Chinese Language", "English")))
m
#     Mathematics Chinese Language English
# Alice   1    2    3
# Bob   4    5    6
# Charlie   7    8    9

# A single element
m[2, 3]            # [1] 6
m["Bob", "English"]  # [1] 6

# Entire row
m[1, ]             # Mathematics 1 Chinese Language 2 English 3
m["Alice", ]        # Ibid.

# Align
m[, 1]             # Alice 1 Bob 4 Charlie 7
m[, "Mathematics"]        # Ibid.

(2) Logical Index

R
# Find the math scores > 5 students
m[m[, "Mathematics"] > 5, ]
#     Mathematics Chinese Language English
# Bob   4 ...   ← Will not be selected
# Charlie   7    8    9


6. rbind/cbind: Merging Matrices

100%
graph TB
    A["Matrix A 3x2"] --> C["rbind Concatenate by row"]
    B["Matrix B 2x2"] --> C
    C --> D["New Matrix 5x2"]
    
    E["Matrix A 3x2"] --> F["cbind Concatenate by Column"]
    G["Matrix B 3x2"] --> F
    F --> H["New Matrix 3x4"]
    
    style A fill:#cce5ff
    style B fill:#cce5ff
    style E fill:#d4edda
    style G fill:#d4edda
R
a <- matrix(1:6, nrow = 3, byrow = TRUE)
b <- matrix(7:12, nrow = 3, byrow = TRUE)

# Concatenate by row(Sum of Rows)
rbind(a, b)
#      [,1] [,2]
# [1,]    1    2
# [2,]    3    4
# [3,]    5    6
# [4,]    7    8
# [5,]    9   10
# [6,]   11   12

# Concatenate by Column(Sum of a Series)
cbind(a, b)
#      [,1] [,2] [,3] [,4]
# [1,]    1    2    7    8
# [2,]    3    4    9   10
# [3,]    5    6   11   12
⚠️ Note: rbind(a, b) requires ncol(a) == ncol(b); cbind(a, b) requires nrow(a) == nrow(b), otherwise an error will occur.



7. The apply Series of Functions (The Essence)

(1) Why is apply needed?

Loops in R are very slow, but apply lets us perform operations row-by-row or column-by-column without writing loops:

R
m <- matrix(1:9, nrow = 3)

# Find the sum of each row(No need for a loop)
apply(m, 1, sum)
# [1] 12 15 18

# Find the sum of each column
apply(m, 2, sum)
# [1] 12 15 18

(2) The Core of apply()

R
apply(X, MARGIN, FUN)
Parameter Meaning Possible Values
X Matrix/Array matrix / array
MARGIN Dimension 1=row, 2=column, c(1,2)=row and column
FUN Function to be applied sum mean max function(x) ...
R
# 1=row(Process by row),2=col(Process by Column)
apply(m, 1, mean)   # Average per line
apply(m, 2, max)    # Maximum per column

# Custom Functions
apply(m, 1, function(x) max(x) - min(x))  # Range per row

(3) The 5 functions in the apply family

Function Input Output Typical Uses
apply() Matrices/Arrays Vectors/Matrices Row/Column Operations
lapply() Lists/Vectors Lists List Processing
sapply() Lists/Vectors Vectors/Matrices Simplified lapply
tapply() Vectors + Groups Arrays Group Statistics
mapply() Multivector List/Vector Multi-argument function

(4) lapply() vs sapply()

R
# lapply Back to List
numbers <- list(a = 1:3, b = 4:6, c = 7:9)
result_l <- lapply(numbers, sum)
# $a 6
# $b 15
# $c 24

# sapply Return Vector(More commonly used)
result_s <- sapply(numbers, sum)
#  a  b  c
#  6 15 24
💡 Tip: Use sapply() first—it’s more convenient for returning vectors. lapply() is more commonly used in functional programming pipelines.

(5) tapply() Grouped Statistics

R
# 5 Students 3 Course Grades, grouped by "Gender"
scores <- c(85, 78, 92, 72, 88, 80, 90, 85, 87, 65, 70, 75, 95, 92, 88)
gender <- c("M", "F", "M", "M", "F", "F", "M", "M", "F", "M", "F", "M", "F", "M", "F")

# Calculate the average by gender
tapply(scores, gender, mean)
#   F   M 
# 84.6 81.5
💡 Tip: tapply() is extremely commonly used when performing "group statistics"—but using dplyr::group_by() | summarise() in the next phase would be more elegant.

(6) mapply()—A Multi-Argument Function

R
# Sum the corresponding elements of two vectors
mapply(function(a, b) a + b, 1:3, 10:12)
# [1] 11 13 15


8. Arrays: Multidimensional Extensions

R
# 2x3x4 a three-dimensional array
arr <- array(1:24, dim = c(2, 3, 4))

# 1st 2x3 Matrix
arr[, , 1]
#      [,1] [,2] [,3]
# [1,]    1    3    5
# [2,]    2    4    6

# apply Supports multidimensional operations
apply(arr, c(1, 2), mean)  # Regarding No. 3 Find the average
💡 Tip: Arrays are rarely used in actual developmentdata.frame (Next Stage) and array (Images/Physics) are the mainstream approaches for multidimensional data.



9. Matrix Operations (Linear Algebra)

Operation Syntax Description
Transpose t(m) Row-to-Column
Matrix Multiplication m1 %*% m2 Linear Algebra Multiplication
Element-wise Multiplication m1 * m2 Corresponding Element-wise Multiplication
Inverse solve(m) Inverse Matrix
Sum (Rows/Columns) rowSums(m) / colSums(m) Quick Sum
R
m <- matrix(1:4, nrow = 2)
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4

# Transpose
t(m)
#      [,1] [,2]
# [1,]    1    2
# [2,]    3    4

# Matrix Multiplication (use m %*% m)
m %*% m
#      [,1] [,2]
# [1,]    7   15
# [2,]   10   22

# Inverse
solve(m)
#      [,1] [,2]
# [1,]   -2  1.5
# [2,]    1 -0.5


10. Complete Example: Comprehensive Analysis of a Transcript

Below is an example of a complete workflow that combines all the matrices and apply functions from this lesson.

▶ Example: Comprehensive Analysis of Class Grades

R 📖 Display only
# ============================================
# Comprehensive Analysis of Class Performance
# Features:5 Student 3 A Comprehensive Analysis of the Course Grade Matrix
# ============================================

# 1. Create a Grade Matrix(Fill by Row:One student per line)
scores <- matrix(c(
  85, 78, 92,   # Alice
  72, 88, 80,   # Bob
  90, 85, 87,   # Charlie
  65, 70, 75,   # Diana
  95, 92, 88    # Eve
), nrow = 5, byrow = TRUE)

# Add row and column names
rownames(scores) <- c("Alice", "Bob", "Charlie", "Diana", "Eve")
colnames(scores) <- c("Mathematics", "Chinese Language", "English")

cat("=== Grade Matrix ===\n")
print(scores)

# 2. Each Student's Total Score(Sum by Row)
cat("\n=== Student's Total Score ===\n")
row_totals <- apply(scores, 1, sum)
print(row_totals)

# 3. Average per subject/Highest/Lowest(Tally by Column)
cat("\n=== Statistics by Subject ===\n")
col_stats <- apply(scores, 2, function(x) {
  c(mean = round(mean(x), 2),
    max = max(x),
    min = min(x),
    sd = round(sd(x), 2))
})
print(col_stats)

# 4. Average score per student(Calculate the average by row)
cat("\n=== Average Student Score ===\n")
row_means <- apply(scores, 1, mean)
print(round(row_means, 2))

# 5. Identify the student with the highest math score
top_math <- which.max(scores[, "Mathematics"])
cat("\nHighest Score in Math:", rownames(scores)[top_math], "(", max(scores[, "Mathematics"]), "min)\n")

# 6. Identify the student with the highest total score
top_total <- which.max(row_totals)
cat("Highest Total Score:", rownames(scores)[top_total], "(", max(row_totals), "min)\n")

# 7. Find a single subject < 70 students(Using Logical Indexes)
fail <- scores < 70
cat("\nFailed Courses(< 70):\n")
print(scores)
cat("\nDid I fail?(TRUE = Fail):\n")
print(fail)

# 8. Overall Ranking
cat("\n=== Overall Ranking(Sort by total score in descending order)===\n")
ranking <- order(row_totals, decreasing = TRUE)
result <- data.frame(
  Ranking = 1:5,
  Name = rownames(scores)[ranking],
  Total Score = row_totals[ranking],
  Average = round(row_totals[ranking] / 3, 2)
)
print(result)
43 logic lines (exceeds 40-line limit, display only)

Expected Output (Excerpt):

TEXT 📖 Display only
=== Grade Matrix ===
    Mathematics Chinese Language English
Alice   85   78   92
Bob   72   88   80
Charlie   90   85   87
Diana   65   70   75
Eve   95   92   88

=== Student's Total Score ===
Alice Bob Charlie Diana Eve
255  240  262  210  275

=== Average Student Score ===
Alice   Bob   Charlie   Diana   Eve
85.00  80.00  87.33  70.00  91.67

=== Overall Ranking(Sort by total score in descending order)===
  Ranking Name Total Score Average
1   1 Eve  275 91.67
2   2 Charlie  262 87.33
3   3 Alice  255 85.00
4   4 Bob  240 80.00
5   5 Diana  210 70.00

❓ FAQ

Q What is the difference between byrow = TRUE and FALSE?
A matrix(1:6, nrow=2, byrow=FALSE) (default) fills by column: 1 3 5 / 2 4 6; byrow=TRUE fills by row: 1 2 3 / 4 5 6. In data science scenarios, data is almost always filled by row (one row per sample).
Q How do I choose between apply() and a for loop?
A Use apply() whenever possible—R loops are 10 to 100 times slower. Use apply(m, 1, fun) instead of "looping by row," and apply(m, 2, fun) instead of "looping by column."
Q How do I choose between lapply() and sapply()?
A The return types are different—lapply returns a list, while sapply simplifies the result to a vector or matrix whenever possible. For everyday use, sapply is sufficient (the result is more concise).
Q What is the difference between %*% and *?
A %*% is matrix multiplication (following the rules of linear algebra), while * is element-wise multiplication (multiplying corresponding elements). Linear regression, neural networks, and other applications require %*%.
Q tapply() How is this used in real-world projects?
A tapply(x, group, fun) To quickly perform "grouped statistics"—grouping by gender, region, month, etc. However, in the next phase, using dplyr::group_by() \| summarise() is a more elegant approach; tapply serves as the foundation.

📖 Summary


📝 Exercises

  1. Basic Problem: Create a 4×4 matrix with elements ranging from 1 to 16, filled row by row, with row and column labels c("A","B","C","D") and c("X","Y","Z","W"), respectively. Print the matrix and verify that the row and column labels are correct.

  2. Basic Problem: Use apply() to calculate the row sums, column sums, row averages, and column maximums for the matrix from the previous problem.

  3. Basic Exercise: Use rbind() and cbind() to merge two 3×3 matrices (which you construct yourself), and verify how the number of rows and columns changes.

  4. Advanced Problem: Simulate the grades of 6 students in 4 courses: ① Use apply() to calculate each student’s total score; ② Use apply() to calculate the average score for each course; ③ Use which.max() to find the name of the student with the highest score in each course; ④ Use order() to rank the students.

  5. Challenge: Write a script to perform a "tiered analysis" of the grades for 100 students across 5 courses: ① Use tapply() to calculate the overall average by grouping by "gender"; ② Determine the number of students who scored 90 or higher in math but failed English (scored < 60); ③ Calculate the standard deviation for each student’s 5 courses (using apply() + a custom function).

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏