This vignette shows an easy way to work with submatrices and matrix lists.
The following functions apply to both rectangular and square matrices. In data analysis, a square matrix can emerge, for example, from covariance calculations, or by calculating the distances between all the points belonging to a given set;
(A, B, C)
A B C
A x x x
B x x x
C x x x
a rectangular matrix instead can still emerge between distance calculations, but between two sets with different number of points.
(A, B, C)
(D, E)
A B C
D x x x
E x x x
Basic operations: mean, max, min
Given a matrix, it may be useful to consider its blocks and observe
some essential characteristics of each block. To do this you can use the
blockmean()
, blockmax()
and
blockmin()
functions that take a matrix and the block size
as input and return the average, maximum and minimum values of each
block respectively.
(mat1 <- matrix(1:64, nrow = 8, byrow = TRUE))
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#> [1,] 1 2 3 4 5 6 7 8
#> [2,] 9 10 11 12 13 14 15 16
#> [3,] 17 18 19 20 21 22 23 24
#> [4,] 25 26 27 28 29 30 31 32
#> [5,] 33 34 35 36 37 38 39 40
#> [6,] 41 42 43 44 45 46 47 48
#> [7,] 49 50 51 52 53 54 55 56
#> [8,] 57 58 59 60 61 62 63 64
It is important that the blocks fill the entire matrix, that is, that
the total number of rows and columns is a multiple of the number of rows
and columns in the block. In this case, for example, blocks of size
c(2,4)
, c(4,2)
and so on are good. While it is
possible to work with rectangular blocks, it is very often useful to
work with square blocks. For example we define a 2x2 block and apply the
functions:
blockmean(mat1, 2)
#> [,1] [,2] [,3] [,4]
#> [1,] 5.5 7.5 9.5 11.5
#> [2,] 21.5 23.5 25.5 27.5
#> [3,] 37.5 39.5 41.5 43.5
#> [4,] 53.5 55.5 57.5 59.5
blockmax(mat1, 2)
#> [,1] [,2] [,3] [,4]
#> [1,] 10 12 14 16
#> [2,] 26 28 30 32
#> [3,] 42 44 46 48
#> [4,] 58 60 62 64
blockmin(mat1, 2)
#> [,1] [,2] [,3] [,4]
#> [1,] 1 3 5 7
#> [2,] 17 19 21 23
#> [3,] 33 35 37 39
#> [4,] 49 51 53 55
If the block is square it is sufficient to insert only one dimension,
while for a rectangular block a vector
c(nrow_block, ncol_block)
must be passed.
Lists of submatrices
In some situations it may be necessary to perform more complex operations on the blocks.
Suppose we want to multiply each block by a different integer. To do
this it is convenient to have control over each block. We can collect
all submatrices in one list using blocklist()
function.
(list_matrix <- blocklist(mat1, 4))
#> $`1`
#> [,1] [,2] [,3] [,4]
#> [1,] 1 2 3 4
#> [2,] 9 10 11 12
#> [3,] 17 18 19 20
#> [4,] 25 26 27 28
#>
#> $`2`
#> [,1] [,2] [,3] [,4]
#> [1,] 5 6 7 8
#> [2,] 13 14 15 16
#> [3,] 21 22 23 24
#> [4,] 29 30 31 32
#>
#> $`3`
#> [,1] [,2] [,3] [,4]
#> [1,] 33 34 35 36
#> [2,] 41 42 43 44
#> [3,] 49 50 51 52
#> [4,] 57 58 59 60
#>
#> $`4`
#> [,1] [,2] [,3] [,4]
#> [1,] 37 38 39 40
#> [2,] 45 46 47 48
#> [3,] 53 54 55 56
#> [4,] 61 62 63 64
Like the previous functions, blocklist()
takes the
matrix and the size of the block as input.
An element of the list can be accessed with a double square bracket:
list_matrix[[i]]
; however, often for operations on lists it
is possible to avoid having to access each element individually thanks
to the lapply
function.
We multiply each matrix in the list by a different number: the first
by 4
, the second by 9
, the third by
16
and the fourth by 25
.
lapply(1:4, function(i, l, v) l[[i]] * v[[i]], list_matrix, c(4, 9, 16, 25))
#> [[1]]
#> [,1] [,2] [,3] [,4]
#> [1,] 4 8 12 16
#> [2,] 36 40 44 48
#> [3,] 68 72 76 80
#> [4,] 100 104 108 112
#>
#> [[2]]
#> [,1] [,2] [,3] [,4]
#> [1,] 45 54 63 72
#> [2,] 117 126 135 144
#> [3,] 189 198 207 216
#> [4,] 261 270 279 288
#>
#> [[3]]
#> [,1] [,2] [,3] [,4]
#> [1,] 528 544 560 576
#> [2,] 656 672 688 704
#> [3,] 784 800 816 832
#> [4,] 912 928 944 960
#>
#> [[4]]
#> [,1] [,2] [,3] [,4]
#> [1,] 925 950 975 1000
#> [2,] 1125 1150 1175 1200
#> [3,] 1325 1350 1375 1400
#> [4,] 1525 1550 1575 1600
dblocklist
The block diagonal of a matrix can be more importante than the
off-diagonal blocks. You can collect the diagonal blocks in a list using
the dblocklist()
function analogous to
blocklist()
. The only trick: the blocks must fill the
diagonal. This mathematically translates into the fact that the ratio
between the number of rows in the matrix and the number of rows in the
block must be equal to the ratio between the number of columns in the
matrix and the number of columns in the block. Example: for a 16x8
matrix dblocklist()
accepts 8x4, 4x2 blocks.
dblocklist(mat1, 2)
#> $`1`
#> [,1] [,2]
#> [1,] 1 2
#> [2,] 9 10
#>
#> $`2`
#> [,1] [,2]
#> [1,] 19 20
#> [2,] 27 28
#>
#> $`3`
#> [,1] [,2]
#> [1,] 37 38
#> [2,] 45 46
#>
#> $`4`
#> [,1] [,2]
#> [1,] 55 56
#> [2,] 63 64
From list of matrices to single matrix
Suppose we need to calculate the mean distance over time between all
pairs of two sets of points. For convenience we use
list_matrix
: each matrix
in the list is a set of distances at time
.
The meanMatrix()
function returns the mean of each
element
of matrix
meanMatrix(list_matrix)
#> [,1] [,2] [,3] [,4]
#> [1,] 19 20 21 22
#> [2,] 27 28 29 30
#> [3,] 35 36 37 38
#> [4,] 43 44 45 46
Similarly, sumMatrix()
and dotMatrix()
functions return sum and product of each element
of matrix of the list
sumMatrix(list_matrix)
#> [,1] [,2] [,3] [,4]
#> [1,] 76 80 84 88
#> [2,] 108 112 116 120
#> [3,] 140 144 148 152
#> [4,] 172 176 180 184
dotMatrix(list_matrix)
#> [,1] [,2] [,3] [,4]
#> [1,] 6105 15504 28665 46080
#> [2,] 215865 270480 333465 405504
#> [3,] 927129 1069200 1225785 1397760
#> [4,] 2520825 2804880 3111129 3440640