Source code for vtra.mrio.ras_method
# -*- coding: utf-8 -*-
"""RAS Method
Purpose
-------
Estimate a new matrix X with exogenously given row and column
totals that is a close as possible to a given original matrix X0 using
the Generalized RAS (GRAS) approach
Usage
-----
X = gras(X0, u, v) OR [X, r, s] = gras(X0, u, v) with or without eps
included as the fourth argument, where
Input
-----
- X0 = benchmark (base) matrix, not necessarily square
- u = column vector of (new) row totals
- v = column vector of (new) column totals
- eps = convergence tolerance level; if empty, the default threshold is 0.1e-5 (=0.000001)
Output
------
- X = estimated/adjusted/updated matrix
- r = substitution effects (row multipliers)
- s = fabrication effects (column multipliers)
References
----------
1) Junius T. and J. Oosterhaven (2003), The solution of
updating or regionalizing a matrix with both positive and negative
entries, Economic Systems Research, 15, pp. 87-96.
2) Lenzen M., R. Wood and B. Gallego (2007), Some comments on the GRAS
method, Economic Systems Research, 19, pp. 461-465.
3) Temurshoev, U., R.E. Miller and M.C. Bouwmeester (2013), A note on the
GRAS method, Economic Systems Research, 25, pp. 361-367.
"""
import numpy as np
[docs]def invd(x):
"""Extract projection, data bands numbers and valuees from raster
Parameters
- file_path - String name of input GeoTff file path
Outputs
- counts - Number of bans in raster
- crs - Projection system of raster
- data_vals - Numpy array of raster values
"""
invd = 1./x
invd[x == 0] = 1
return np.diag(invd)
[docs]def ras_method(X0, u, v, eps=1e-5):
"""Extract projection, data bands numbers and valuees from raster
Parameters
- file_path - String name of input GeoTff file path
Outputs
- counts - Number of bans in raster
- crs - Projection system of raster
- data_vals - Numpy array of raster values
"""
m, n = np.shape(X0)
N = np.zeros((m, n))
N[X0 < 0] = -X0[X0 < 0]
P = X0+N
# initial guess for r (suggested by J&O, 2003)
r = np.ones((m))
pr = np.dot(P.T, r)
nr = N.T.dot(invd(r)).dot(np.ones((m)))
s1 = np.dot(invd(2*pr), (v+np.sqrt((np.square(v)+4*(pr.dot(nr))))))
ss = -invd(v).dot(nr)
s1[pr == 0] = ss[pr == 0]
ps = np.dot(P, s1)
ns = N.dot(invd(s1)).dot(np.ones((n)))
r = np.dot(invd(2*ps), (u+np.sqrt((np.square(u)+4*(ps.dot(ns))))))
rr = - invd(u).dot(ns)
r[ps == 0] = rr[ps == 0]
pr = np.dot(P.T, r)
nr = N.T.dot(invd(r)).dot(np.ones((m)))
# %second step s
s2 = np.dot(invd(2*pr), v+np.sqrt((np.square(v)+4*(pr.dot(nr)))))
ss = -invd(v).dot(nr)
s2[pr == 0] = ss[pr == 0]
dif = s2-s1
M = np.max(abs(dif))
i = 1 # first iteration
while (M > eps):
print(M)
s1 = s2
ps = P.dot(s1)
ns = N.dot(invd(s1)).dot(np.ones((n)))
r = np.dot(invd(2*ps), (u+np.sqrt((np.square(u)+4*(ps.dot(ns))))))
rr = -invd(u).dot(ns)
r[ps == 0] = rr[ps == 0]
pr = P.T.dot(r)
nr = N.T.dot(invd(r)).dot(np.ones((m)))
s2 = np.dot(invd(2*pr), v+np.sqrt((np.square(v)+4*(pr.dot(nr)))))
ss = -invd(v).dot(nr)
s2[pr == 0] = ss[pr == 0]
dif = s2-s1
i = i+1
M = np.max(abs(dif))
if i == 10000:
break
# %final step s
s = s2
ps = P.dot(s)
ns = N.dot(invd(s)).dot(np.ones((n)))
r = np.dot(invd(2*ps), (u+np.sqrt((np.square(u)+4*(ps.dot(ns))))))
rr = -invd(u).dot(ns)
r[ps == 0] = rr[ps == 0]
return np.diag(r).dot(P).dot(np.diag(s))-invd(r).dot(N).dot(invd(s)) # %updated matrix