Rounding a matrix
round-matrix.Rmd
Rounding matrices while preserving totals
A typical problem in official statistics is that of rounding a matrix whose columns are quarterly components of a total. In rounding, the rounded sum of the components for each quarter must be preserved and also the annual sum of each component.
Remark: To be able to round the matrix in this fashion, the following things must be equal:
- the sum of the differences between the row totals and the rounded row totals
- the sum of the differences between the column totals and the rounded row totals
Rounding a simple matrix
Consider the example matrix
example_matrix
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 2.696060 17.2719552 -13.0920430 -10.48397 6.532067
#> [2,] -6.299854 0.2418764 7.3862193 17.27851 -3.685665
#> [3,] 8.686598 3.6802518 0.4487299 -11.78600 -5.995546
The round_matrix()
function returns the following
matrix.
rounded_matrix <- round_matrix(example_matrix)
rounded_matrix
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 3 17 -13 -11 7
#> [2,] -6 0 7 18 -4
#> [3,] 8 4 1 -12 -6
And we may check that the rounded totals are preserved.
colSums(rounded_matrix) - round(colSums(example_matrix))
#> [1] 0 0 0 0 0
rowSums(rounded_matrix) - round(rowSums(example_matrix))
#> [1] 0 0 0
Sometimes we don’t need to preserve the rounded sum in both
directions. The argument MARGIN
works like that of the
apply()
function. If we just need to round the matrix and
preserve the rounded sums of each column independently, we may do it by
setting MARGIN = 2
.
rounded_matrix <- round_matrix(example_matrix, MARGIN = 2)
rounded_matrix
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 3 17 -13 -10 7
#> [2,] -6 0 7 17 -4
#> [3,] 8 4 1 -12 -6
colSums(rounded_matrix) - round(colSums(example_matrix))
#> [1] 0 0 0 0 0
rowSums(rounded_matrix) - round(rowSums(example_matrix))
#> [1] 1 -1 0
Rounding a matrix by blocks
Going back to the example of time series in official statistics, let
us consider now a longer series, encompassing several years. We wish to
apply round_matrix()
to each year separately. This may be
seen as applying the function to blocks
The round_by_blocks()
function applies
round_matrix()
to each block. We have to indicate that the
blocks are distributed vertically (layout = 2
) and also
that they are 4 rows long (L = 4
). Blocks are assumed to be
as wide as the matrix (or as tall as the matrix if distributed
horizontally).
The choice of the direction in which the rounded sums are preserved
in each block is done with the argument MARGING_BLOCK
,
which is then passed to MARGIN
in when
round_matrix()
is applied to the block.
example_block_matrix
#> [,1] [,2]
#> [1,] 0.187 -9.549
#> [2,] -1.843 -1.952
#> [3,] -13.713 9.255
#> [4,] -5.992 4.830
#> [5,] 2.945 -5.963
#> [6,] 3.898 -21.853
#> [7,] -12.081 -6.749
#> [8,] -3.637 -21.191
#> [9,] -16.267 -12.652
#> [10,] -2.565 -3.737
#> [11,] 11.018 -6.876
#> [12,] 7.558 -8.722
#> [13,] -2.382 -1.018
#> [14,] 9.874 -2.538
#> [15,] 7.414 -18.537
#> [16,] 0.893 -0.779
X <- round_by_blocks(example_block_matrix, 2, 4)
U <- example_block_matrix[5:8,] |> round_matrix()
X[5:8,] - U
#> [,1] [,2]
#> [1,] 0 0
#> [2,] 0 0
#> [3,] 0 0
#> [4,] 0 0
The function solves the problem independently for each block. The blocks can be distributed horizontally and analogous considerations apply.