'Python: generate a random 2d array of integers from given sums of its rows and columns
Is there any way to generate a 2d array with a fixed sum of each row and each column?
for example
TargetArray = 3 rows and 4 columns
Sum of Each row = [30, 20, 30]
Sum of Each column = [23, 10, 27, 20]
I was trying to solve this a lot of days with no result 😢
Solution 1:[1]
(Temporary note until they hopefully unvandalize their question: They added the "random" and "positive" requirements later, after this answer.)
Simple solution:
23 10 27 20
30 -27 10 27 20
20 20 0 0 0
30 30 0 0 0
Code to build it:
R = [30, 20, 30]
C = [23, 10, 27, 20]
assert sum(R) == sum(C)
matrix = [[(0 if j else r) if i else (c if j else r+c-sum(R))
for j, c in enumerate(C)]
for i, r in enumerate(R)]
Or:
matrix = [[0 if i and j else
r if i else
c if j else
r + c - sum(R)
for j, c in enumerate(C)]
for i, r in enumerate(R)]
Or a somewhat cute way, always building a mini-matrix of the four possibilities and picking the right one (assumes a non-empty matrix):
x = R[0] + C[0] - sum(R)
matrix = [[[[x, c],
[r, 0]][i > 0][j > 0]
for j, c in enumerate(C)]
for i, r in enumerate(R)]
Solution 2:[2]
You can achieve this with an algorithm called Iterative Proportional Fitting: https://en.wikipedia.org/wiki/Iterative_proportional_fitting. IPF allows it to reconstruct a non-negative matrix from row an column sum vectors.
There is a Python implementation for this, called ipfn.
from ipfn import ipfn
import numpy as np
seed = np.ones((3,4))
row_sum = [30, 20, 30]
column_sum = [23, 10, 27, 20]
aggregates = [row_sum, column_sum]
dimensions = [[0], [1]]
IPF = ipfn.ipfn(seed, aggregates, dimensions, convergence_rate=1e-6)
X = IPF.iteration()
X = array([[ 8.625, 3.75 , 10.125, 7.5 ],
[ 5.75 , 2.5 , 6.75 , 5. ],
[ 8.625, 3.75 , 10.125, 7.5 ]])
By changing, the seed, you will get different results. If you require X to contain integers only, then you need to resort to an integerized version of IPF. However, as far as I know, there is no Python implementation for this.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | c-wizz |