Skip to content

Commit

Permalink
TST: Test fixed sigma
Browse files Browse the repository at this point in the history
Add tests for fixed sigma in GMM estimation
Add tests for repr for GMM weighting matrices

xref #111
  • Loading branch information
bashtage committed Nov 28, 2017
1 parent 469df17 commit bd4fc2b
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 24 deletions.
6 changes: 0 additions & 6 deletions linearmodels/system/covariance.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,9 @@ def __init__(self, x, z, eps, w, *, sigma=None):
self._sigma = sigma
self._w = w
self._name = 'GMM Homoskedastic (Unadjusted) Covariance'
self._str_extra = {}

def __str__(self):
out = self._name
extra = []
for key in self._str_extra:
extra.append(': '.join([key, str(self._str_extra[key])]))
if extra:
out += ' (' + ','.join(extra) + ')'
return out

def __repr__(self):
Expand Down
21 changes: 11 additions & 10 deletions linearmodels/system/gmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,6 @@ def weight_matrix(self, x, z, eps, sigma):
w = blocked_inner_prod(z, sigma) / nobs
return w

def _debias_scale(self, nobs, x):
if not self._debiased:
return 1
nvar = array(list(map(lambda a: a.shape[1], x)))
nvar = repeat(nvar, nvar)
nvar = sqrt(nvar)[:, None]
scale = nobs / (nobs - nvar @ nvar.T)
return scale

@property
def config(self):
"""
Expand Down Expand Up @@ -175,7 +166,17 @@ def weight_matrix(self, x, z, eps, *, sigma=None):
mu = ze.mean(axis=0) if self._center else 0
ze -= mu
w = ze.T @ ze / nobs
scale = self._debias_scale(nobs, x)
scale = self._debias_scale(nobs, x, z)
w *= scale

return w

def _debias_scale(self, nobs, x, z):
if not self._debiased:
return 1
nvar = array(list(map(lambda a: a.shape[1], x)))
ninstr = array(list(map(lambda a: a.shape[1], z)))
nvar = repeat(nvar, ninstr)
nvar = sqrt(nvar)[:, None]
scale = nobs / (nobs - nvar @ nvar.T)
return scale
20 changes: 16 additions & 4 deletions linearmodels/system/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,13 @@ def __init__(self, equations, *, sigma=None):
equations = _to_ordered_dict(equations)

self._equations = equations
self._sigma = asarray(sigma) if sigma is not None else None
self._sigma = None
if sigma is not None:
self._sigma = asarray(sigma)
k = len(self._equations)
if self._sigma.shape != (k, k):
raise ValueError('sigma must be a square matrix with dimensions '
'equal to the number of equations')
self._param_names = []
self._eq_labels = []
self._dependent = []
Expand Down Expand Up @@ -1185,9 +1191,15 @@ def __init__(self, equations, *, sigma=None, weight_type='robust', **weight_conf
self._weight_type = weight_type
self._weight_config = weight_config

if weight_type == 'robust':
if weight_type not in ('unadjusted', 'homoskedastic') and sigma is not None:
import warnings
warnings.warn('sigma has been provided but the estimated weight '
'matrix not unadjusted (homoskedastic). sigma will '
'be ignored.', UserWarning)

if weight_type in ('robust', 'heteroskedastic'):
self._weight_est = HeteroskedasticWeightMatrix(**weight_config)
elif weight_type == 'unadjusted':
elif weight_type in ('unadjusted', 'homoskedastic'):
self._weight_est = HomoskedasticWeightMatrix(**weight_config)
else:
raise ValueError('Unknown estimator for weight_type')
Expand Down Expand Up @@ -1220,7 +1232,7 @@ def fit(self, *, iter_limit=2, tol=1e-6, initial_weight=None,
Returns
-------
results : SystemResults
results : GMMSystemResults
Estimation results
"""
cov_type = str(cov_type).lower()
Expand Down
42 changes: 38 additions & 4 deletions linearmodels/tests/system/test_gmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,19 @@ def test_formula_equivalence_weights(data):


def test_weight_options(data):
mod = IVSystemGMM(data.eqns, weight_type='unadjusted', debiased=True)
mod = IVSystemGMM(data.eqns, weight_type='unadjusted', debiased=True, center=True)
res = mod.fit(cov_type='unadjusted')
assert res.weight_config == {'debiased': True}
assert res.weight_config == {'debiased': True, 'center': True}
assert res.weight_type == 'unadjusted'
assert 'Debiased: True' in str(res.summary)
assert str(hex(id(res._weight_estimtor))) in res._weight_estimtor.__repr__()
assert res._weight_estimtor.config == {'debiased': True, 'center': True}
base_res = IVSystemGMM(data.eqns, weight_type='unadjusted').fit(cov_type='unadjusted')
assert np.all(np.diag(res.w) >= np.diag(base_res.w))

mod = IVSystemGMM(data.eqns, weight_type='robust', debiased=True)
res = mod.fit(cov_type='robust')


def test_no_constant_smoke():
eqns = generate_3sls_data_v2(k=3, const=False)
Expand Down Expand Up @@ -201,6 +207,34 @@ def test_summary(data):


def test_summary_homoskedastic(data):
mod = IVSystemGMM(data.eqns, weight_type='unadjusted')
res = mod.fit(cov_type='homoskedastic')
mod = IVSystemGMM(data.eqns, weight_type='unadjusted', debiased=True)
res = mod.fit(cov_type='homoskedastic', debiased='True')
assert 'Homoskedastic (Unadjusted) Weighting' in res.summary.as_text()


def test_fixed_sigma(data):
mod = IVSystemGMM(data.eqns, weight_type='unadjusted')
res = mod.fit(cov_type='unadjusted')
k = len(data.eqns)
b = np.random.standard_normal((k, 1))
sigma = b @ b.T + np.diag(np.ones(k))
mod_sigma = IVSystemGMM(data.eqns, weight_type='unadjusted', sigma=sigma)
res_sigma = mod_sigma.fit()
assert np.any(res.params != res_sigma.params)
assert np.any(res.sigma != res_sigma.sigma)


def test_incorrect_sigma_shape(data):
k = len(data.eqns)
b = np.random.standard_normal((k + 2, 1))
sigma = b @ b.T + np.diag(np.ones(k + 2))
with pytest.raises(ValueError):
IVSystemGMM(data.eqns, weight_type='unadjusted', sigma=sigma)


def test_invalid_sigma_usage(data):
k = len(data.eqns)
b = np.random.standard_normal((k, 1))
sigma = b @ b.T + np.diag(np.ones(k))
with pytest.warns(UserWarning):
IVSystemGMM(data.eqns, weight_type='robust', sigma=sigma)

0 comments on commit bd4fc2b

Please sign in to comment.