Balancing a matrix (original) (raw)
This section is concerned with the problem of slightly adjusting a matrix so that its row and column totals add up to given vector usingbalance_matrix()
.
Balancing a simple matrix
Consider the example matrix
example_matrix
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] -0.897 -1.130 0.708 -0.139 -0.393
#> [2,] 0.185 -0.080 -0.240 0.418 -1.040
#> [3,] 1.588 0.132 1.984 0.982 1.782
and the desired row totals
row_totals
#> [1] -1.851 0.243 6.468
and column totals,
col_totals
#> [1] 0.87 -1.07 3.45 0.26 1.35
which are mildly different from those of the matrix.
colSums(example_matrix) - col_totals
#> [1] 0.006 -0.008 -0.998 1.001 -1.001
rowSums(example_matrix) - row_totals
#> [1] 0 -1 0
Let’s use our function to solve this problem.
tallied_matrix <- balance_matrix(example_matrix, col_totals, row_totals)
tallied_matrix - example_matrix
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] -0.06866667 -0.064 0.266 -0.4003333 0.267
#> [2,] 0.13133333 0.136 0.466 -0.2003333 0.467
#> [3,] -0.06866667 -0.064 0.266 -0.4003333 0.267
(rowSums(tallied_matrix) - row_totals) |> round(7)
#> [1] 0 0 0
(colSums(tallied_matrix) - col_totals) |> round(7)
#> [1] 0 0 0 0 0
We don’t need to provide both the row and column totals. If only the column totals (or rows) are provided, the tallying is done to match only those.
tallied_matrix <- balance_matrix(example_matrix, col_totals)
tallied_matrix - example_matrix
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] -0.002 0.00266667 0.3326667 -0.3336667 0.3336667
#> [2,] -0.002 0.00266667 0.3326667 -0.3336667 0.3336667
#> [3,] -0.002 0.00266667 0.3326667 -0.3336667 0.3336667
(rowSums(tallied_matrix) - row_totals) |> round(7)
#> [1] 0.3333333 -0.6666667 0.3333333
(colSums(tallied_matrix) - col_totals) |> round(7)
#> [1] 0 0 0 0 0
Balancing a matrix by blocks
Sometimes one may need to balance a matrix that is made up of blocks. For example, suppose that the following \(16\times4\) matrix is composed of 4 vertical \(4\times 2\) blocks.
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
And we have the following matrix whose rows are the desired column totals for each of the blocks.
block_col_totals
#> [,1] [,2]
#> [1,] -21 3
#> [2,] -9 -56
#> [3,] 0 -32
#> [4,] 16 -23
The balance_by_blocks()
function appliesbalance_matrix()
to each block using the totals given by the argument col_totals
. When the blocks are distributed vertically (layout = 2
), this argument must be a matrix as wide as the matrix to be balanced (Y
), and with a row for each block. We have to indicate also that the bloks 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).
X <- balance_by_blocks(block_matrix, col_totals = block_col_totals,
layout = 2, L = 4)
X[9:12,] - balance_matrix(block_matrix[9:12,], block_col_totals[3,])
#> [,1] [,2]
#> [1,] 0 0
#> [2,] 0 0
#> [3,] 0 0
#> [4,] 0 0
Just as with balance_matrix()
, bothcol_totals
and row_totals
can be provided. In the case of vertically distributed blocks, row_totals
is a vector with an entry for each row of the Y
matrix. The function solves the problem independently for each block.
The blocks can be distributed horizontally and analogous considerations apply.