<- matrix( c(1,2,3,4), nrow=2, ncol=2)
m m
[,1] [,2]
[1,] 1 3
[2,] 2 4
In R, a matrix is a vector, with two additional attributes: The number of rows, and the number of columns
As with vectors, every element of a matrix must be of the same mode ; either purely numeric, or purely text, etc.
Given a vector, convert it to a matrix by specifying the number of rows and columns.
<- matrix( c(1,2,3,4), nrow=2, ncol=2)
m m
[,1] [,2]
[1,] 1 3
[2,] 2 4
attributes(m)
$dim
[1] 2 2
dim(m)
[1] 2 2
class(m)
[1] "matrix" "array"
Note that by default, the columns of the matrix are filled with the vector’s elements, in the so-called column-major order.
matrix(1:6, nrow=3, ncol=2)
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
To force a row-major order instead, set the byrow
parameter to TRUE
.
matrix( 1:6, nrow=3, ncol=2, byrow=TRUE )
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
If we provide only nrow
or only ncol
, the unspecified parameter will be determined using the length of the vector.
matrix( 1:6, nrow=2 )
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
matrix( 1:6, ncol=3 )
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
If the specified matrix sizes are not compatible with the vector’s length, the vector is recycled until it fills the matrix.
matrix( 1:5, nrow=2, ncol=4)
Warning in matrix(1:5, nrow = 2, ncol = 4): data length [5] is not a
sub-multiple or multiple of the number of rows [2]
[,1] [,2] [,3] [,4]
[1,] 1 3 5 2
[2,] 2 4 1 3
The same recycling is done also when one of the shape parameters is omitted.
matrix( 1:5, nrow=2 )
Warning in matrix(1:5, nrow = 2): data length [5] is not a sub-multiple or
multiple of the number of rows [2]
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 1
The element in the r
-th row and the c
-th column of a matrix m
can be accessed with the m[r,c]
notation.
<- matrix(1:6, nrow=2)
m m
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
1,1] m[
[1] 1
2,3] m[
[1] 6
To get the entire r
-th row as a vector, we use the m[r,]
notation. Similarly, m[,c]
gives the column c
.
<- matrix(1:6, nrow=2)
m m
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
1,] # first row, all columns m[
[1] 1 3 5
1] # first column, all rows m[,
[1] 1 2
As with vectors, we can provide a vector of indices to extract a subset of rows or columns.
<- matrix( 1:12, nrow=3 )
m m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
Select rows 1 and 2, all columns:
1:2,] m[
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
Select rows 1 and 2, second column only.
1:2, 2] m[
[1] 4 5
Select rows 1 and 2, and columns 1,4 and 3, in that order.
1:2, c(1,4,3)] m[
[,1] [,2] [,3]
[1,] 1 10 7
[2,] 2 11 8
As with vectors, negative indices can be used to get a new matrix with some rows/columns removed.
<- matrix( 1:12, nrow=3 )
m m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
Remove 3rd row.
-3,] m[
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
Remove 2nd column
-2] m[,
[,1] [,2] [,3]
[1,] 1 7 10
[2,] 2 8 11
[3,] 3 9 12
Remove 1st row and 3rd column
-1,-3] m[
[,1] [,2] [,3]
[1,] 2 5 11
[2,] 3 6 12
Remove columns from 1 to 2.
-1:-2] m[,
[,1] [,2]
[1,] 7 10
[2,] 8 11
[3,] 9 12
The functions rownames()
and colnames()
are used to set the names for rows and columns, respectively.
<- matrix( 1:6, nrow=2)
m m
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
rownames(m) <- c("row I", "row II")
colnames(m) <- c("col a", "col b", "col c")
m
col a col b col c
row I 1 3 5
row II 2 4 6
When called without an assignment, they return the existing names.
rownames(m)
[1] "row I" "row II"
colnames(m)
[1] "col a" "col b" "col c"
These names provide an alternative method to access matrix elements.
"row I", "col b"] m[
[1] 3
"row I",] m[
col a col b col c
1 3 5
"col a"] m[,
row I row II
1 2
Sometimes we may not have all the data at hand at once. It is possible to start with an empty matrix, and fill it up element-by-element.
<- matrix(nrow=2, ncol=2)
m m
[,1] [,2]
[1,] NA NA
[2,] NA NA
1,1] <- 1
m[2,1] <- 2
m[1,2] <- 3
m[2,2] <- 4
m[ m
[,1] [,2]
[1,] 1 3
[2,] 2 4
When we have several different vectors, we can combine them in columns using cbind()
, or by rows using rbind()
.
cbind( c(1,2), c(3,4) )
[,1] [,2]
[1,] 1 3
[2,] 2 4
rbind( c(1,2), c(3,4), c(-2, 6))
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] -2 6
The functions cbind()
and rbind()
can also be used to extend an existing matrix.
<- matrix( 1:4, nrow = 2)
m m
[,1] [,2]
[1,] 1 3
[2,] 2 4
Add a new column at the end of the matrix.
cbind(m, c(10,11))
[,1] [,2] [,3]
[1,] 1 3 10
[2,] 2 4 11
Add a new column at the beginning of the matrix.
cbind(c(10,11), m)
[,1] [,2] [,3]
[1,] 10 1 3
[2,] 11 2 4
Add a new row at the end of the matrix
rbind(m, c(10,11))
[,1] [,2]
[1,] 1 3
[2,] 2 4
[3,] 10 11
Add a new row at the beginning of the matrix.
rbind(c(10,11), m)
[,1] [,2]
[1,] 10 11
[2,] 1 3
[3,] 2 4
Another application of cbind()
and rbind()
is inserting columns and rows to existing matrices. As with vectors, such insertion is not done on the original matrix. We generate a new matrix using existing rows/columns, combine them with rbind()
/cbind()
, and reassign to the variable.
<- matrix( 1:9, nrow=3, ncol=3)
m m
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
Insert a row between second and third rows.
rbind(m[1:2,], c(-1, -2, -3), m[3,])
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] -1 -2 -3
[4,] 3 6 9
Insert a column between first and second columns
cbind( m[,1], c(-4,-5,-6), m[,2:3] )
[,1] [,2] [,3] [,4]
[1,] 1 -4 4 7
[2,] 2 -5 5 8
[3,] 3 -6 6 9
A matrix can be changed in-place by selecting a submatrix using index notation, and assigning a new matrix to it.
<- matrix( 1:9, nrow=3 )
m m
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
1,1] <- m[1,1] + 1
m[ m
[,1] [,2] [,3]
[1,] 2 4 7
[2,] 2 5 8
[3,] 3 6 9
1,1] <- m[1,1]*m[2,1]
m[ m
[,1] [,2] [,3]
[1,] 4 4 7
[2,] 2 5 8
[3,] 3 6 9
c(1,2), c(2,3) ] <- matrix(c(20,21,22,23),nrow=2,byrow = T)
m[ m
[,1] [,2] [,3]
[1,] 4 20 21
[2,] 2 22 23
[3,] 3 6 9
To remove some selected rows or colums, we just use the index notation to specify the rows and columns we want to keep, and assign the result to the variable’s name.
<- matrix( 1:9, nrow=3 )
m m
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
<- m[c(1,3),c(2,3)] # remove row 2, col 1
m m
[,1] [,2]
[1,] 4 7
[2,] 6 9
<- matrix( 1:9, nrow=3 )
m <- m[-2,-1] # remove row 2, col 1
m m
[,1] [,2]
[1,] 4 7
[2,] 6 9
Remove 2nd row.
<- matrix( 1:9, nrow=3 )
m <- m[-2,]
m m
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 3 6 9
Remove 1st column.
<- matrix( 1:9, nrow=3 )
m <- m[, -1]
m m
[,1] [,2]
[1,] 4 7
[2,] 5 8
[3,] 6 9
<- matrix( c(2,9,4,7,5,3,6,1,8) , nrow=3 )
m m
[,1] [,2] [,3]
[1,] 2 7 6
[2,] 9 5 1
[3,] 4 3 8
>= 5 m
[,1] [,2] [,3]
[1,] FALSE TRUE TRUE
[2,] TRUE TRUE FALSE
[3,] FALSE FALSE TRUE
>=5] m[m
[1] 9 7 5 6 8
<5 ] <- 0
m[ m m
[,1] [,2] [,3]
[1,] 0 7 6
[2,] 9 5 0
[3,] 0 0 8
<- matrix(1:4, nrow=2)
m m
[,1] [,2]
[1,] 1 3
[2,] 2 4
t(m)
[,1] [,2]
[1,] 1 2
[2,] 3 4
m
[,1] [,2]
[1,] 1 3
[2,] 2 4
* m m
[,1] [,2]
[1,] 1 9
[2,] 4 16
m
[,1] [,2]
[1,] 1 3
[2,] 2 4
%*% m m
[,1] [,2]
[1,] 7 15
[2,] 10 22
m
[,1] [,2]
[1,] 1 3
[2,] 2 4
3 * m
[,1] [,2]
[1,] 3 9
[2,] 6 12
m
[,1] [,2]
[1,] 1 3
[2,] 2 4
+ m m
[,1] [,2]
[1,] 2 6
[2,] 4 8
<- matrix( 1:12, nrow=3 )
m m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
rowSums(m)
[1] 22 26 30
colSums(m)
[1] 6 15 24 33
m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
rowMeans(m)
[1] 5.5 6.5 7.5
colMeans(m)
[1] 2 5 8 11
<- matrix(1:4, nrow=2)
m sqrt(m)
[,1] [,2]
[1,] 1.000000 1.732051
[2,] 1.414214 2.000000
sin(m)
[,1] [,2]
[1,] 0.8414710 0.1411200
[2,] 0.9092974 -0.7568025
exp(m)
[,1] [,2]
[1,] 2.718282 20.08554
[2,] 7.389056 54.59815
log(m)
[,1] [,2]
[1,] 0.0000000 1.098612
[2,] 0.6931472 1.386294
apply()
function<- matrix( 1:9, nrow=3)
m m
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
apply(m, 1, mean) # same as rowMeans()
[1] 4 5 6
apply(m, 2, mean) # same as colMeans()
[1] 2 5 8
apply(m,1,prod)
[1] 28 80 162
We can also use apply()
with user-defined functions.
<- function(x) sum(1/x)
inverse_sum inverse_sum(c(2,4,8,16))
[1] 0.9375
<- matrix(1:12, nrow=3)
m m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
apply(m,1,inverse_sum)
[1] 1.4928571 0.9159091 0.6944444
apply(m,2,inverse_sum)
[1] 1.8333333 0.6166667 0.3789683 0.2742424
matrix(runif(12, min=1, max=5), nrow = 3)
[,1] [,2] [,3] [,4]
[1,] 4.564854 4.551840 4.164703 1.089320
[2,] 4.346013 1.489592 4.191915 1.444391
[3,] 4.136161 2.482901 1.296362 1.788233
<- function(size, min, max, ...){
randmat matrix(runif(size, min=min, max=max), ...)
}
randmat(size=12,min=1,max=5,nrow=3)
[,1] [,2] [,3] [,4]
[1,] 2.005379 3.358715 4.966565 3.749742
[2,] 1.121260 3.504683 3.631245 1.787730
[3,] 4.470369 1.387189 4.099974 2.554748
<- 4
n <- matrix(0, nrow=n, ncol=n)
m for (i in 1:n) m[i,i] <- 1
m
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 0 1 0 0
[3,] 0 0 1 0
[4,] 0 0 0 1
R already has a built-in function for this:
diag(n)
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 0 1 0 0
[3,] 0 0 1 0
[4,] 0 0 0 1
<- 5
nrow <- 7
ncol <- matrix(1, nrow=nrow, ncol=ncol)
m 2:(nrow-1), 2:(ncol-1)] <- 0
m[ m
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1 1 1 1 1 1 1
[2,] 1 0 0 0 0 0 1
[3,] 1 0 0 0 0 0 1
[4,] 1 0 0 0 0 0 1
[5,] 1 1 1 1 1 1 1
Alternatively
<- matrix(0, nrow=nrow, ncol=ncol)
m c(1,nrow),] <- 1
m[c(1,ncol)] <- 1
m[, m
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1 1 1 1 1 1 1
[2,] 1 0 0 0 0 0 1
[3,] 1 0 0 0 0 0 1
[4,] 1 0 0 0 0 0 1
[5,] 1 1 1 1 1 1 1
<- matrix(1:16, nrow=4)
m m
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
<- nrow(m)
n <- vector(mode = "numeric", length = n)
v for (i in 1:n) v[i] <- m[i, n-i+1]
v
[1] 13 10 7 4
Convert to a function
<- function(m){
antidiag if(nrow(m) != ncol(m)){
print("Matrix must be square")
return()
}<- nrow(m)
n <- vector(mode = "numeric", length = n)
v for (i in 1:n) v[i] <- m[i, n-i+1]
v
}
antidiag(matrix(1:25, nrow=5))
[1] 21 17 13 9 5
A magic square is a square table of positive integers, arranged such that every row sum, every column sum, and every diagonal sum are equal. For a 3-by-3 square this total is 15.
Write a function that takes a 3-by-3 integer matrix, returns TRUE
if the matrix is a magic square, and FALSE
otherwise.
<- function(m){
is.magic if( !(nrow(m) == 3 & ncol(m) == 3)) {
print("The matrix must be 3-by-3.")
return()
}all(
rowSums(m) == rep(15,3),
colSums(m) == rep(15,3),
sum(diag(m)) == 15,
1,3]+m[2,2]+m[3,1] == 15
m[
)
}
is.magic( matrix(c(2,9,4,7,5,3,6,1,8), nrow = 3) ) # TRUE
[1] TRUE
is.magic( matrix(1:9, ncol = 3)) # FALSE
[1] FALSE
is.magic( matrix(1:12, ncol = 3)) # error message
[1] "The matrix must be 3-by-3."
NULL
Generate many random 3-by-3 matrices with entries from 1 to 9, and try to find magic squares.
for (i in 1:1e5) {
<- matrix(sample(1:9),nrow=3)
m if (is.magic(m))
print(m)
}
[,1] [,2] [,3]
[1,] 6 7 2
[2,] 1 5 9
[3,] 8 3 4
[,1] [,2] [,3]
[1,] 4 9 2
[2,] 3 5 7
[3,] 8 1 6
[,1] [,2] [,3]
[1,] 4 9 2
[2,] 3 5 7
[3,] 8 1 6