Skip to content

Commit eeb6aaa

Browse files
authored
Merge pull request #334 from bashtage/bug-sur-homogeneity-gls
BUG: t-stats in SUR with GLS are not homogeneous deg 0
2 parents ea85e15 + 57d410a commit eeb6aaa

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

linearmodels/system/covariance.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,8 @@ def __init__(
233233
bigxe = bigx * e
234234
m = bigx.shape[1]
235235
xe = zeros((nobs, m))
236-
for i in range(nobs):
237-
xe[i, :] = bigxe[i::nobs].sum(0)[None, :]
236+
for i in range(len(x)):
237+
xe += bigxe[i * nobs : (i + 1) * nobs]
238238
else:
239239
# Do not require blocking when not using GLS
240240
k_tot = sum(map(lambda a: a.shape[1], x))

linearmodels/system/model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ def _gls_finalize(
10451045
eps = np.reshape(eps, (k, eps.shape[0] // k)).T
10461046
cov_est = cov_estimator(
10471047
self._wxhat,
1048-
gls_eps,
1048+
eps,
10491049
sigma,
10501050
full_sigma,
10511051
gls=True,

linearmodels/tests/system/test_sur.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,3 +786,68 @@ def test_system_r2_direct():
786786
assert_allclose(ref, res.system_rsquared.mcelroy)
787787
ref = reference_berndt(res.resids, y)
788788
assert_allclose(ref, res.system_rsquared.berndt, atol=1e-3, rtol=1e-3)
789+
790+
791+
def direct_gls(eqns, scale):
792+
y = []
793+
x = []
794+
for key in eqns:
795+
y.append(eqns[key]["dependent"])
796+
x.append(eqns[key]["exog"])
797+
y = scale * np.vstack(y)
798+
from scipy.sparse import csc_matrix
799+
800+
n, k = x[0].shape
801+
_x = csc_matrix((len(x) * n, len(x) * k))
802+
for i, val in enumerate(x):
803+
_x[i * n : (i + 1) * n, i * k : (i + 1) * k] = val
804+
from scipy.sparse.linalg import inv as spinv
805+
806+
b = spinv(_x.T @ _x) @ (_x.T @ y)
807+
e = y - _x @ b
808+
e = e.reshape((-1, n)).T
809+
sigma = e.T @ e / n
810+
omega_inv = np.kron(np.linalg.inv(sigma), np.eye(n))
811+
b_gls = np.linalg.inv(_x.T @ omega_inv @ _x) @ (_x.T @ omega_inv @ y)
812+
xpx = _x.T @ omega_inv @ _x / n
813+
xpxi = np.linalg.inv(xpx)
814+
e = y - _x @ b_gls
815+
xe = (_x.T @ omega_inv).T * e
816+
_xe = np.zeros((n, len(x) * k))
817+
for i in range(len(x)):
818+
_xe += xe[i * n : (i + 1) * n]
819+
xeex = _xe.T @ _xe / n
820+
cov = xpxi @ xeex @ xpxi / n
821+
return b_gls, cov, xpx, xeex, _xe
822+
823+
824+
@pytest.mark.parametrize("method", ["ols", "gls"])
825+
@pytest.mark.parametrize("cov_type", ["unadjusted", "robust", "hac", "clustered"])
826+
def test_tvalues_homogeneity(method, cov_type):
827+
eqns = generate_data(k=3)
828+
mod = SUR(eqns)
829+
kwargs = {}
830+
831+
base = direct_gls(eqns, 1)
832+
base_tstat = np.squeeze(base[0]) / np.sqrt(np.diag(base[1]))
833+
base_100 = direct_gls(eqns, 1 / 100)
834+
base_100_tstat = np.squeeze(base_100[0]) / np.sqrt(np.diag(base_100[1]))
835+
assert_allclose(base_tstat, base_100_tstat)
836+
837+
if cov_type == "hac":
838+
kwargs["bandwidth"] = 1
839+
elif cov_type == "clustered":
840+
key0 = list(eqns.keys())[0]
841+
nobs = eqns[key0]["dependent"].shape[0]
842+
rs = np.random.RandomState(231823)
843+
kwargs["clusters"] = rs.randint(0, nobs // 5, size=(nobs, 1))
844+
res0 = mod.fit(method=method, cov_type=cov_type, **kwargs)
845+
for key in eqns:
846+
eqns[key]["dependent"] = eqns[key]["dependent"] / 100.0
847+
848+
mod = SUR(eqns)
849+
res1 = mod.fit(method=method, cov_type=cov_type, **kwargs)
850+
assert_allclose(res0.tstats, res1.tstats)
851+
if cov_type == "robust" and method == "gls":
852+
assert_allclose(res0.tstats, base_tstat)
853+
assert_allclose(res1.tstats, base_100_tstat)

0 commit comments

Comments
 (0)