Skip to content

Commit e4e76cf

Browse files
authored
Merge pull request #808 from bashtage/lm71-unknown-cov-type-error
ENH: Add UnknownOptionError for a name that is not supported
2 parents 181683d + 34c70ee commit e4e76cf

18 files changed

Lines changed: 934 additions & 39 deletions

File tree

‎doc/source/utility.rst‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ Hypothesis Testing
3131
InapplicableTestStatistic
3232

3333

34+
Errors
35+
------
36+
37+
.. currentmodule:: linearmodels.shared.exceptions
38+
39+
The name of a covariance estimator (``cov_type``), of a weight matrix estimator
40+
(``weight_type``) or of a kernel (``kernel``) that is not supported raises an
41+
:class:`UnknownOptionError`, which lists the supported names. It is a ``ValueError``
42+
and a ``KeyError``.
43+
44+
.. autoclass:: linearmodels.shared.exceptions.UnknownOptionError
45+
:show-inheritance:
46+
47+
3448
Covariance Estimation
3549
---------------------
3650

‎linearmodels/asset_pricing/covariance.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
cov_kernel,
1313
kernel_optimal_bandwidth,
1414
)
15+
from linearmodels.shared.exceptions import unknown_option_error
1516
import linearmodels.typing.data
1617

1718

@@ -47,7 +48,7 @@ def _check_kernel(self, kernel: str) -> None:
4748
raise TypeError("kernel must be the name of a kernel")
4849
self._kernel = kernel.lower()
4950
if self._kernel not in KERNEL_LOOKUP:
50-
raise ValueError("Unknown kernel")
51+
raise unknown_option_error("kernel", kernel, KERNEL_LOOKUP)
5152

5253
def _check_bandwidth(self, bandwidth: float | None) -> None:
5354
self._bandwidth = bandwidth

‎linearmodels/asset_pricing/model.py‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@
2828
from linearmodels.iv.data import IVData, IVDataLike
2929
from linearmodels.shared import hypotheses
3030
from linearmodels.shared.alignment import check_alignment, row_labels
31-
from linearmodels.shared.exceptions import missing_warning
31+
from linearmodels.shared.exceptions import missing_warning, unknown_option_error
3232
from linearmodels.shared.hypotheses import WaldTestStatistic
3333
from linearmodels.shared.linalg import has_constant
3434
from linearmodels.shared.typed_getters import get_float, get_string
3535
from linearmodels.shared.utility import AttrDict
3636
import linearmodels.typing.data
3737

38+
# The names of the covariance estimators of the models
39+
COV_TYPES = ("heteroskedastic", "kernel", "robust")
40+
3841

3942
def callback_factory(
4043
obj: (
@@ -506,7 +509,7 @@ def fit(
506509
kernel=kernel,
507510
)
508511
else:
509-
raise ValueError(f"Unknown cov_type: {cov_type}")
512+
raise unknown_option_error("cov_type", cov_type, COV_TYPES)
510513
full_vcv = cov_est.cov
511514
rp_cov = rp_cov_est.cov
512515
if debiased:
@@ -930,8 +933,8 @@ def fit(
930933
# Jacobian
931934
jacobian = self._jacobian(betas, lam, alphas)
932935

933-
if cov_type not in ("robust", "heteroskedastic", "kernel"):
934-
raise ValueError(f"Unknown weight: {cov_type}")
936+
if cov_type not in COV_TYPES:
937+
raise unknown_option_error("cov_type", cov_type, COV_TYPES)
935938
if cov_type in ("robust", "heteroskedastic"):
936939
cov_est_inst = HeteroskedasticCovariance(
937940
moments,
@@ -1347,8 +1350,8 @@ def fit(
13471350
g -= g.mean(0)[None, :] if center else 0
13481351
kernel: str | None = None
13491352
bandwidth: float | None = None
1350-
if cov_type not in ("robust", "heteroskedastic", "kernel"):
1351-
raise ValueError(f"Unknown weight: {cov_type}")
1353+
if cov_type not in COV_TYPES:
1354+
raise unknown_option_error("cov_type", cov_type, COV_TYPES)
13521355
if cov_type in ("robust", "heteroskedastic"):
13531356
weight_est_instance = HeteroskedasticWeight(g, center=center)
13541357
cov_est = HeteroskedasticCovariance

‎linearmodels/iv/absorbing.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
reference_labels,
6666
row_labels,
6767
)
68-
from linearmodels.shared.exceptions import missing_warning
68+
from linearmodels.shared.exceptions import lookup_option, missing_warning
6969
from linearmodels.shared.hypotheses import InvalidTestStatistic, WaldTestStatistic
7070
from linearmodels.shared.inputs import as_array_like
7171
from linearmodels.shared.utility import DataFrameWrapper, SeriesWrapper
@@ -1471,7 +1471,7 @@ def fit(
14711471
else:
14721472
params = lstsq(exog_resid, dep_resid, rcond=None)[0]
14731473

1474-
cov_estimator = COVARIANCE_ESTIMATORS[cov_type]
1474+
cov_estimator = lookup_option(COVARIANCE_ESTIMATORS, cov_type, "cov_type")
14751475
cov_config["debiased"] = debiased
14761476
cov_config["kappa"] = 0.0
14771477
cov_config_copy = dict(cov_config.items())

‎linearmodels/iv/common.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
KernelWeightMatrix,
2727
OneWayClusteredWeightMatrix,
2828
)
29+
from linearmodels.shared.exceptions import unknown_option_error
2930
from linearmodels.shared.hypotheses import InvalidTestStatistic, WaldTestStatistic
3031
import linearmodels.typing.data
3132

@@ -54,7 +55,8 @@ def _cov_family(cov_type: str) -> str:
5455
for family, aliases in _COV_FAMILIES.items():
5556
if name in aliases:
5657
return family
57-
raise ValueError(f"Unsupported cov_type: {cov_type}")
58+
supported = [alias for aliases in _COV_FAMILIES.values() for alias in aliases]
59+
raise unknown_option_error("cov_type", cov_type, supported)
5860

5961

6062
def find_constant(x: linearmodels.typing.data.Float64Array) -> int | None:

‎linearmodels/iv/covariance.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from numpy.linalg import inv, pinv
2727

2828
from linearmodels.shared.covariance import cov_cluster, cov_kernel
29+
from linearmodels.shared.exceptions import unknown_option_error
2930
from linearmodels.shared.inputs import as_ndarray
3031
from linearmodels.shared.linalg import has_constant
3132
import linearmodels.typing
@@ -258,7 +259,7 @@ def kernel_optimal_bandwidth(
258259
q, c = 2, 2.6614
259260
m_star = int(ceil(4 * (t / 100) ** (4 / 25)))
260261
else:
261-
raise ValueError(f"Unknown kernel: {kernel}")
262+
raise unknown_option_error("kernel", kernel, KERNEL_LOOKUP)
262263
sigma = empty(m_star + 1)
263264
sigma[0] = x.T @ x / t
264265
for i in range(1, m_star + 1):
@@ -597,7 +598,7 @@ def __init__(
597598
self._name = "Kernel Covariance (HAC)"
598599

599600
if kernel not in KERNEL_LOOKUP:
600-
raise ValueError(f"Unknown kernel: {kernel}")
601+
raise unknown_option_error("kernel", kernel, KERNEL_LOOKUP)
601602

602603
def __str__(self) -> str:
603604
out = super().__str__()

‎linearmodels/iv/gmm.py‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
kernel_optimal_bandwidth,
1919
)
2020
from linearmodels.shared.covariance import cov_cluster, cov_kernel
21-
from linearmodels.shared.exceptions import DefaultBandwidthWarning
21+
from linearmodels.shared.exceptions import (
22+
DefaultBandwidthWarning,
23+
lookup_option,
24+
unknown_option_error,
25+
)
2226
import linearmodels.typing.data
2327

2428

@@ -375,7 +379,7 @@ def weight_matrix(
375379
self._bandwidth = nobs - 2
376380
bw = self._bandwidth
377381
assert bw is not None
378-
w = self._kernels[self._kernel](bw, nobs - 1)
382+
w = lookup_option(self._kernels, self._kernel, "kernel")(bw, nobs - 1)
379383

380384
s = cov_kernel(ze, w)
381385
s *= 1 if not self._debiased else nobs / (nobs - nvar)
@@ -590,7 +594,15 @@ def __init__(
590594
elif cov_type == "kernel":
591595
score_cov_estimator = KernelWeightMatrix
592596
else:
593-
raise ValueError("Unknown cov_type")
597+
supported = (
598+
"clustered",
599+
"heteroskedastic",
600+
"homoskedastic",
601+
"kernel",
602+
"robust",
603+
"unadjusted",
604+
)
605+
raise unknown_option_error("cov_type", cov_type, supported)
594606
self._score_cov_estimator = score_cov_estimator
595607

596608
def __str__(self) -> str:

‎linearmodels/iv/model.py‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,12 @@
6262
reference_labels,
6363
row_labels,
6464
)
65-
from linearmodels.shared.exceptions import IndexWarning, missing_warning
65+
from linearmodels.shared.exceptions import (
66+
IndexWarning,
67+
lookup_option,
68+
missing_warning,
69+
unknown_option_error,
70+
)
6671
from linearmodels.shared.hypotheses import InvalidTestStatistic, WaldTestStatistic
6772
from linearmodels.shared.linalg import has_constant, inv_sqrth
6873
from linearmodels.shared.utility import DataFrameWrapper, SeriesWrapper
@@ -741,7 +746,7 @@ def fit(
741746

742747
params = self.estimate_parameters(wx, wy, wz, est_kappa)
743748

744-
cov_estimator = COVARIANCE_ESTIMATORS[cov_type]
749+
cov_estimator = lookup_option(COVARIANCE_ESTIMATORS, cov_type, "cov_type")
745750
cov_config["debiased"] = debiased
746751
cov_config["kappa"] = est_kappa
747752
cov_config_copy = dict(cov_config.items())
@@ -1122,7 +1127,9 @@ def __init__(
11221127
self._method = "IV-GMM"
11231128

11241129
self._check_clusters(weight_config)
1125-
weight_matrix_estimator = WEIGHT_MATRICES[weight_type]
1130+
weight_matrix_estimator = lookup_option(
1131+
WEIGHT_MATRICES, weight_type, "weight_type"
1132+
)
11261133
# Kernel weights without a bandwidth select it from the data. fit warns
11271134
# about the change of this default, and makes the choice explicit so that
11281135
# the weight estimators and models that are created from the arguments
@@ -2388,7 +2395,7 @@ def __init__(
23882395
if cov_type == "kernel":
23892396
kernel = cov_config.get("kernel", "bartlett")
23902397
if kernel not in KERNEL_LOOKUP:
2391-
raise ValueError(f"Unknown kernel: {kernel}")
2398+
raise unknown_option_error("kernel", kernel, KERNEL_LOOKUP)
23922399
# Select the bandwidth using the data unless it is given, as in
23932400
# IV2SLS and IVLIML. This is the default of the weight matrix
23942401
# estimator since 7.1, and it is explicit here so that it does not

‎linearmodels/panel/covariance.py‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
kernel_optimal_bandwidth,
1616
)
1717
from linearmodels.shared.covariance import cluster_union, group_debias_coefficient
18+
from linearmodels.shared.exceptions import lookup_option, unknown_option_error
1819
from linearmodels.shared.typed_getters import (
1920
get_array_like,
2021
get_bool,
@@ -451,7 +452,7 @@ def cov(self) -> linearmodels.typing.data.Float64Array:
451452
if self._bandwidth is None:
452453
bw = float(np.floor(4 * (xe_nobs / 100) ** (2 / 9)))
453454
assert bw is not None
454-
w = KERNEL_LOOKUP[self._kernel](bw, xe_nobs - 1)
455+
w = lookup_option(KERNEL_LOOKUP, self._kernel, "kernel")(bw, xe_nobs - 1)
455456
xeex = cov_kernel(np.asarray(xe_df), w) * (xe_nobs / nobs)
456457
xeex *= self._scale
457458

@@ -566,7 +567,7 @@ def _single_cov(
566567
self, xe: linearmodels.typing.data.Float64Array, bw: float
567568
) -> linearmodels.typing.data.Float64Array:
568569
nobs = xe.shape[0]
569-
w = KERNEL_LOOKUP[self._kernel](bw, nobs - 1)
570+
w = lookup_option(KERNEL_LOOKUP, self._kernel, "kernel")(bw, nobs - 1)
570571
return cov_kernel(xe, w)
571572

572573
@cached_property
@@ -644,14 +645,21 @@ def __init__(
644645
self._supported = cov_estimators
645646

646647
def __getitem__(self, item: str) -> CovarianceEstimatorType:
648+
# The names that the model supports, not all of the names that are known
649+
supported = [
650+
name
651+
for name, estimator in self.COVARIANCE_ESTIMATORS.items()
652+
if estimator in self._supported
653+
]
647654
if item not in self.COVARIANCE_ESTIMATORS:
648-
raise KeyError("Unknown covariance estimator type.")
655+
raise unknown_option_error("cov_type", item, supported)
649656
cov_est = self.COVARIANCE_ESTIMATORS[item]
650657
if cov_est not in self._supported:
651-
raise ValueError(
658+
problem = (
652659
"Requested covariance estimator is not supported "
653660
"for the {}.".format(self._estimator)
654661
)
662+
raise unknown_option_error("cov_type", item, supported, problem=problem)
655663
return cov_est
656664

657665

@@ -724,7 +732,7 @@ def cov(self) -> linearmodels.typing.data.Float64Array:
724732

725733
bw = self.bandwidth
726734
assert self._kernel is not None
727-
w = KERNEL_LOOKUP[self._kernel](bw, nobs - 1)
735+
w = lookup_option(KERNEL_LOOKUP, self._kernel, "kernel")(bw, nobs - 1)
728736
cov = cov_kernel(e, w)
729737
return cov / (nobs - int(bool(self._debiased)))
730738

‎linearmodels/panel/model.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
MissingValueWarning,
6363
SingletonWarning,
6464
missing_warning,
65+
unknown_option_error,
6566
)
6667
from linearmodels.shared.hypotheses import (
6768
InapplicableTestStatistic,
@@ -3920,7 +3921,14 @@ def single(z: DataFrame) -> Series:
39203921
"heteroskedastic",
39213922
"kernel",
39223923
):
3923-
raise ValueError("Unknown cov_type")
3924+
supported = (
3925+
"heteroskedastic",
3926+
"homoskedastic",
3927+
"kernel",
3928+
"robust",
3929+
"unadjusted",
3930+
)
3931+
raise unknown_option_error("cov_type", cov_type, supported)
39243932

39253933
bandwidth = 0.0 if cov_type != "kernel" else bandwidth
39263934
cov = FamaMacBethCovariance(

0 commit comments

Comments
 (0)