Table of contents:

  • 1 Basic Definitions and Functions

    • 1.1 The matrix() Function

    • 1.2 The Dimension of a Matrix

    • 1.3 The cbind() and rbind() Functions

    • 1.4 Matrices Are Two-Dimensional Vectors

  • 2 Naming Rows and Columns of Two-Dimensional Objects

  • 3 Extracting Data From Two-Dimensional Objects

    • 3.1 Numeric Indices

    • 3.2 Logical Indices

    • 3.3 Named (Character) Indices

  • 4 Matrix Operations

    • 4.1 Entrywise Arithmetic Operations

    • 4.2 Matrix Multiplication

    • 4.3 The Identity Matrix

    • 4.4 The Inverse of a Matrix

  • 5 Operations on Matrix Columns and Rows

    • 5.1 The apply() Function

Learning Objectives

  • Create matrices with matrix(), rbind(), and cbind().

  • Understand how R stores and performs operations on matrices.

  • Add row and column names to two-dimensional objects.

  • Extract and assign values to two-dimensional objects.

  • Differentiate between * and %*% for matrices.

  • Compute the inverse of a square matrix

1: Basic Definitions and Functions

1.1: The matrix() Function:

matrix() function: creates a two-dimensional (rectangular) array of values. Every value in a matrix must be of the same variable_type

#takes in a vector and arranges it in nrow, ncol

one_to_six <- seq(1,6) # data 
matrix(one_to_six, nrow = 3, ncol = 2)
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

byrow = FALSE, which means R will fill the matrix by column

#takes in a vector and arranges it in nrow, ncol

one_to_six <- seq(1,6) # data 
matrix(one_to_six, nrow = 2, ncol = 3,  byrow = TRUE) # fills matrix by row first
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
matrix(one_to_six, nrow = 2, ncol = 3,  byrow = FALSE) # fills matrix by col first
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

Side note: The default values are nrow = 1 and ncol = 1, furthermore : recycling occurs:

matrix(1:4, nrow = 2, ncol = 6) # Complete recycling: no warning thrown (amount recycled is intiger divisible)
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    3    1    3    1    3
## [2,]    2    4    2    4    2    4
matrix(1:4, nrow = 2, ncol = 5) # Incomplete recycling: warning thrown (amount recycled is decimal divisible)
## Warning in matrix(1:4, nrow = 2, ncol = 5): data length [4] is not a
## sub-multiple or multiple of the number of columns [5]
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    1    3    1
## [2,]    2    4    2    4    2

1.2: The Dimension of a Matrix:

Dimension of a Matrix: dim() : the number of rows and the number of columns, often written as nrow × ncol, read aloud as “nrow by ncol”.

A <- matrix(1:6, nrow = 3, ncol = 2)
print("This Matrix has:")
## [1] "This Matrix has:"
dim(A)[1]
## [1] 3
print("rows and, this many col: ")
## [1] "rows and, this many col: "
dim(A)[2]
## [1] 2
print("here is the matrix: ")
## [1] "here is the matrix: "
A
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

Side note: rows = height, col = width

nrow() & ncol() function: input a two-dimensional object and output the number of rows or columns, respectively.

A <- matrix(1:6, nrow = 3, ncol = 2)
nrow(A)
## [1] 3
ncol(A)
## [1] 2

1.3: The cbind() and rbind() Functions:

#create matrix by each col entry. 
a <- c(1,2)
b <- c(2,3)
c <- c(4,5)
cbind(a,b,c)
##      a b c
## [1,] 1 2 4
## [2,] 2 3 5
#create matrix by each row entry. 
d <- c(1,2)
e <- c(3,4)
f <- c(5,6)
rbind(d,e,f)
##   [,1] [,2]
## d    1    2
## e    3    4
## f    5    6

Side note:

If the number of columns or rows match in a way that makes sense, i.e., they are conformable. Meaning, you can combine matrices.

  • Recall that conformable means to be able to conform to or comply with certain conditions, standards, or requirements–and in the context of maths and programming, that means you can do arithmetic operations on conformable matrices. ; the requirements of a conformable matrix

Condition of Conformable Matrices:

  • Dimensions are the same
# Test function: 
conformable_matrix <- function(matrix_1, matrix_2){
  if (is.null(dim(matrix_1))| is.null(dim(matrix_2))){
    print("One or more of these are not Matrices! Please Try Again")
  } else {
    if (nrow(matrix_1) == nrow(matrix_2) & ncol(matrix_1) == ncol(matrix_2)){
      print("Conformable Matrices!")
      print("Therefore, you CAN use cbind() or rbind() to combine those matrices")
    } else {
      print("Non-Conformable Matrices!")
      print("Therefore, you CANNOT use cbind() or rbind() to combine those matrices")
    }
  }
}

#Matrices
A <- matrix(1:6, nrow = 2, ncol = 3)
B <- matrix(1:6,  nrow = 2, ncol = 3)
C <- matrix(1:6,  nrow = 3, ncol = 2)

# Test for conformability: 
conformable_matrix(A,B)
## [1] "Conformable Matrices!"
## [1] "Therefore, you CAN use cbind() or rbind() to combine those matrices"
conformable_matrix(A,C)
## [1] "Non-Conformable Matrices!"
## [1] "Therefore, you CANNOT use cbind() or rbind() to combine those matrices"
conformable_matrix(A,c(1,2,3))
## [1] "One or more of these are not Matrices! Please Try Again"

1.4: Matrices Are Two-Dimensional Vectors:

  • All matrix objects are actually internally stored as vectors
  • Matrices type determines their ability to interact with one another.
  • Matrices are vectors with an additional attribute: dim()

list() function:

  • Allows you to create a list of different object types.
my_list <- list(name = "Alice", age = 25, scores = c(90, 85, 88))
my_list
## $name
## [1] "Alice"
## 
## $age
## [1] 25
## 
## $scores
## [1] 90 85 88

attributes () function:

  • Used to access or modify objects attributes. Therefore allowing you to understand and manipulate the structure of the object.
my_list <- list(name = "Alice", age = 25, scores = c(90, 85, 88))
attributes(my_list)
## $names
## [1] "name"   "age"    "scores"
Taking away all attributes: matrix to vector:
#recall that all matrices are just vectors with a dimension attribute: 
A <- matrix(1:6, ncol = 3, nrow = 2)
A
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
# Converted back to vector by saying attributes dont exist (NULL)
attributes(A) <- NULL
A
## [1] 1 2 3 4 5 6
Adding to all attribute: vector to matrix:
# Vector: 
A <- seq(1,6)
A
## [1] 1 2 3 4 5 6
# Matrix:  
attributes(A) <- list("dim" = c(3,2)) # 3 rows by 2 col
A
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
Accessing specific attributes: attr() function:
A <- matrix(1:6, nrow = 3, ncol = 2)
A
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
attr(A, "dim") <- NULL
A
## [1] 1 2 3 4 5 6

2: Naming Rows and Columns of Two-Dimensional Objects

rownames() & colnames function:

Name Height (inches) Weight (pounds) Income ($/month)
Leslie 62 115 4000
Ron 71 201 NA
April 66 119 2000

How would we format this data in R to maintain the row and col names?

SLOW WAY:

#matrix values
numeric_values <- cbind(c(62,71,66), c(115, 201, 119), c(4000, NA, 2000))

#row names
rownames(numeric_values) <- c("leslie", "Ron", "April")


#col names
colnames(numeric_values) <- c("Height", "Weight", "Income")
labeled_matrix <- numeric_values

labeled_matrix
##        Height Weight Income
## leslie     62    115   4000
## Ron        71    201     NA
## April      66    119   2000
#notice: 
attributes(labeled_matrix)
## $dim
## [1] 3 3
## 
## $dimnames
## $dimnames[[1]]
## [1] "leslie" "Ron"    "April" 
## 
## $dimnames[[2]]
## [1] "Height" "Weight" "Income"

QUICK WAY:

numeric_values <- cbind(c(62,71,66), c(115, 201, 119), c(4000, NA, 2000))
dimnames(numeric_values) <- list(c("leslie", "Ron", "April"), c("Height", "Weight", "Income"))
numeric_values
##        Height Weight Income
## leslie     62    115   4000
## Ron        71    201     NA
## April      66    119   2000

Fun Fact:

one_line <- matrix(c(62, 71, 66, 115, 201, 119, 4000, NA, 2000), nrow = 3, byrow = FALSE, 
                   dimnames = list(c("Leslie", "Ron", "April"), 
                                   c("Height", "Weight", "Income")))
one_line
##        Height Weight Income
## Leslie     62    115   4000
## Ron        71    201     NA
## April      66    119   2000

rbind() & cbind : naming respectively:

rbind("row 1" = 1:3, "row 2" = 4:6, "row 3" = 7:9) 
##       [,1] [,2] [,3]
## row 1    1    2    3
## row 2    4    5    6
## row 3    7    8    9
cbind("col 1" = 1:3, "col 2" = 4:6, "col 3" = 7:9)
##      col 1 col 2 col 3
## [1,]     1     4     7
## [2,]     2     5     8
## [3,]     3     6     9

3: Extracting Data From Two-Dimensional Objects

  • note that matrixes are 2 dimensional and so are their indices as a result.

3.1: Numeric Indices:

B <- matrix(1:9, nrow = 3, ncol = 3)
B
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
row = 1
col = 3
B[row,col]
## [1] 7
B[row,]
## [1] 1 4 7
B[,col]
## [1] 7 8 9
identical(B[,], B)
## [1] TRUE
  • Operations of indices are exactly the same as before except for seen above^

3.2: Logical Indices:

B <- matrix(1:9, nrow = 3, ncol = 3)
#logical indexing: 
B[B > 4]
## [1] 5 6 7 8 9
# Logical Indexing for specific index:
one_line <- matrix(c(62, 71, 66, 115, 201, 119, 4000, NA, 2000), nrow = 3, byrow = FALSE, 
                   dimnames = list(c("Leslie", "Ron", "April"), 
                                   c("Height", "Weight", "Income")))

one_line
##        Height Weight Income
## Leslie     62    115   4000
## Ron        71    201     NA
## April      66    119   2000
taller_than_leslie <- one_line[1,] > 62
one_line[taller_than_leslie, ]
##       Height Weight Income
## Ron       71    201     NA
## April     66    119   2000

3.3: Character Indices:

h_w_i_data <- matrix(c(62, 71, 66, 115, 201, 119, 4000, NA, 2000), nrow = 3, byrow = FALSE, 
                   dimnames = list(c("Leslie", "Ron", "April"), 
                                   c("Height", "Weight", "Income")))
#only Leslie
h_w_i_data["Leslie", ]
## Height Weight Income 
##     62    115   4000
# Everyone except Leslie
everyone_except_leslie <- h_w_i_data[rownames(h_w_i_data) != "Leslie", ]
everyone_except_leslie
##       Height Weight Income
## Ron       71    201     NA
## April     66    119   2000
#How tall is leslie? 
h_w_i_data["Leslie", "Height"]
## [1] 62

4 : Matrix operations:

4.1 : Entry-wise Arithmetic Operations:

  • You can entry-wise Arithmetic Operations on conformable matrixes (equal dimensions).
A <- matrix(c(1), nrow = 3, ncol = 3)
# Any normal arithmatic operations can occur to each
A + 1
##      [,1] [,2] [,3]
## [1,]    2    2    2
## [2,]    2    2    2
## [3,]    2    2    2
# Adding matrixes: 
B <- matrix(c(4), nrow = 3, ncol = 3)
# Entry wise addition between matrices: 
C <- B + A
C
##      [,1] [,2] [,3]
## [1,]    5    5    5
## [2,]    5    5    5
## [3,]    5    5    5

4.2 : Matrix Multiplication:

  • for an M by N matrix A to matrix multiply with B, B must be a N by P matrix. In other words, the col of the first must be the rows of the next.
A <- matrix(seq(1,6), nrow = 3, ncol = 2)
A
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
B <- matrix(c(1), nrow = 2, ncol = 3)
B
##      [,1] [,2] [,3]
## [1,]    1    1    1
## [2,]    1    1    1
#matrix multiplication: dot product: 
A%*%B
##      [,1] [,2] [,3]
## [1,]    5    5    5
## [2,]    7    7    7
## [3,]    9    9    9

4.3 : Identity Matrix:

  • a n by n square whose diagnol are all 1. #### Diag() function: By inputting a number, the diag() function will generatean identity matrix of that size.
identity_matrix <- diag(3)
identity_matrix
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    1    0
## [3,]    0    0    1
diag(c(1,2,3))
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    2    0
## [3,]    0    0    3
#The  nrow  and  ncol  arguments can also be used to specify the dimensions for a rectangular (non-square)  matrix.
diag(c(1,2), nrow = 2, ncol = 3)
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    2    0

4.4 : The Inverse Matrix:

  • this is the matrix that multiplied by the original matrix gives the identity matrix
A <- matrix(1:4, ncol = 2, nrow = 2)
#computes inverse: 
solve(A)
##      [,1] [,2]
## [1,]   -2  1.5
## [2,]    1 -0.5
#proof it is the inverse: should be identity matrix
solve(A) %*% A
##      [,1] [,2]
## [1,]    1    0
## [2,]    0    1

SIDE NOTES:

  • The inverse DOESNT ALWAYS exist!

  • A matrix with an inverse is called: non-singular or invertible

  • A matrix that cant be solved is called: singular

5: Operations on Matrix Columns and Rows

vapply() function applies some function to each element of a vector. apply() function: applies a function to the rows or columns of a matrix or data frame

h_w_i_data <- matrix(c(62, 71, 66, 115, 201, 119, 4000, NA, 2000), nrow = 3, byrow = FALSE, 
                   dimnames = list(c("Leslie", "Ron", "April"), 
                                   c("Height", "Weight", "Income")))
h_w_i_data
##        Height Weight Income
## Leslie     62    115   4000
## Ron        71    201     NA
## April      66    119   2000
#Find mean of each row 
apply(h_w_i_data, 1, mean, na.rm = TRUE)
##    Leslie       Ron     April 
## 1392.3333  136.0000  728.3333
#Find mean of each col 
apply(h_w_i_data, 2, mean, na.rm = TRUE)
##     Height     Weight     Income 
##   66.33333  145.00000 3000.00000