larray.ipfp(target_sums, a=None, axes=None, maxiter=1000, threshold=0.5, stepstoabort=10, nzvzs='raise', no_convergence='raise', display_progress=False)[source]

Apply Iterative Proportional Fitting Procedure (also known as bi-proportional fitting in statistics, RAS algorithm in economics) to array a, with target_sums as targets.

target_sumstuple/list of array-like

Target sums to achieve. First element must be the sum to achieve along axis 0, the second the sum along axis 1, …

aarray-like, optional

Starting values to fit, if not given starts with an array filled with 1.

axeslist/tuple of axes, optional

Axes on which the fitting procedure should be applied. Defaults to all axes.

maxiterint, optional

Maximum number of iteration, defaults to 1000.

thresholdfloat, optional

Threshold below which the result is deemed acceptable, defaults to 0.5.

stepstoabortint, optional

Number of consecutive steps with no improvement after which to abort. Defaults to 10.

nzvzs‘fix’, ‘warn’ or ‘raise’, optional

Behavior when detecting non zero values where the sum is zero ‘fix’: set to zero (silently) ‘warn’: set to zero and print a warning ‘raise’: raise an exception (default)

no_convergence‘ignore’, ‘warn’ or ‘raise, optional

Behavior when the algorithm does not seem to converge. This condition is triggered both when the maximum number of iteration is reached or when the maximum absolute difference between the target and the current sums does not improve for stepstoabort iterations. ‘ignore’: return values computed up to that point (silently) ‘warn’: return values computed up to that point and print a warning ‘raise’: raise an exception (default)

display_progressFalse, True or ‘condensed’, optional

Whether or not to display progress. Defaults to False. If ‘condensed’ will display progress using a denser template (using one line per iteration).



>>> from larray import *
>>> a = Axis('a=a0,a1')
>>> b = Axis('b=b0,b1')
>>> initial = LArray([[2, 1], [1, 2]], [a, b])
>>> initial
a\b  b0  b1
 a0   2   1
 a1   1   2
>>> target_sum_along_a = LArray([2, 1], b)
>>> target_sum_along_a
b  b0  b1
    2   1
>>> target_sum_along_b = LArray([1, 2], a)
>>> target_sum_along_b
a  a0  a1
    1   2
>>> result = ipfp([target_sum_along_a, target_sum_along_b], initial, threshold=0.01)
>>> # round result so that its display is nicer
... round(result, 2)
a\b    b0    b1
 a0  0.85  0.15
 a1  1.15  0.85

Now let us assume you have a 3D array like this:

>>> year = Axis('year=2014..2016')
>>> initial = ndtest([a, b, year])
>>> initial
 a  b\year  2014  2015  2016
a0      b0     0     1     2
a0      b1     3     4     5
a1      b0     6     7     8
a1      b1     9    10    11

and some targets for each year:

>>> btargets = initial.sum(X.a) + 1
>>> btargets
b\year  2014  2015  2016
    b0     7     9    11
    b1    13    15    17
>>> atargets = initial.sum(X.b) + 1
>>> atargets
a\year  2014  2015  2016
    a0     4     6     8
    a1    16    18    20

You want to apply a 2D fitting procedure for each value of that year axis. You could call ipfp within a loop on the year axis, but you can also apply the procedure for all years at once by using the axes argument. This is much faster than an explicit loop.

>>> result = ipfp([btargets, atargets], initial, axes=(X.a, X.b))