Skip to content

Commit

Permalink
ENH: raise more informative errors when there are non-finite values i…
Browse files Browse the repository at this point in the history
…n data
  • Loading branch information
jeffgortmaker committed Feb 14, 2023
1 parent fd0e65c commit 16b5ddc
Showing 1 changed file with 23 additions and 3 deletions.
26 changes: 23 additions & 3 deletions pyblp/primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ def __new__(
X1, X1_formulations, X1_data = product_formulations[0]._build_matrix(product_data)
if 'shares' in X1_data:
raise NameError("shares cannot be included in the formulation for X1.")
if X1 is not None and not np.isfinite(X1).all():
raise ValueError("Variables in product_data that contribute to X1 should not have NaNs or infinities.")

# build X2
X2 = None
Expand All @@ -102,6 +104,8 @@ def __new__(
X2, X2_formulations, X2_data = product_formulations[1]._build_matrix(product_data)
if 'shares' in X2_data:
raise NameError("shares cannot be included in the formulation for X2.")
if X2 is not None and not np.isfinite(X2).all():
raise ValueError("Variables in product_data that contribute to X2 should not have NaNs or infinities.")

# check that prices are in X1 or X2
if 'prices' not in X1_data and 'prices' not in X2_data:
Expand All @@ -115,11 +119,15 @@ def __new__(
X3, X3_formulations, X3_data = product_formulations[2]._build_matrix(product_data)
if 'prices' in X3_data:
raise NameError("prices cannot be included in the formulation for X3.")
if X3 is not None and not np.isfinite(X3).all():
raise ValueError("Variables in product_data that contribute to X3 should not have NaNs or infinities.")

# load excluded demand-side instruments and supplement them with exogenous characteristics in X1
ZD = None
if instruments:
ZD = extract_matrix(product_data, 'demand_instruments')
if ZD is not None and not np.isfinite(ZD).all():
raise ValueError("The demand_instruments field of product_data should not have NaNs or infinities.")
if add_exogenous:
for index, formulation in enumerate(X1_formulations):
if 'prices' not in formulation.names:
Expand All @@ -129,6 +137,8 @@ def __new__(
ZS = None
if instruments and X3 is not None:
ZS = extract_matrix(product_data, 'supply_instruments')
if ZS is not None and not np.isfinite(ZS).all():
raise ValueError("The supply_instruments field of product_data should not have NaNs or infinities.")
if add_exogenous:
for index, formulation in enumerate(X3_formulations):
if 'shares' not in formulation.names:
Expand Down Expand Up @@ -172,10 +182,10 @@ def __new__(
raise KeyError("product_data must have a shares field.")
if shares.shape[1] > 1:
raise ValueError("The shares field of product_data must be one-dimensional.")
if not np.isfinite(shares).all():
raise ValueError("The shares field of product_data should not have NaNs or infinities.")
if (shares <= 0).any() or (shares >= 1).any():
raise ValueError(
"The shares field of product_data must consist of values between zero and one, exclusive."
)
raise ValueError("The shares field of product_data must consist of values between zero and one, exclusive.")

# verify that shares sum to less than one in each market
market_groups = Groups(market_ids)
Expand All @@ -189,6 +199,8 @@ def __new__(
if firm_ids is not None:
ownership = extract_matrix(product_data, 'ownership')
if ownership is not None:
if not np.isfinite(ownership).all():
raise ValueError("The ownership field of product_data should not have NaNs or infinities.")
max_J = market_groups.counts.max()
if ownership.shape[1] != max_J:
raise ValueError(
Expand Down Expand Up @@ -285,6 +297,10 @@ def __new__(
raise ValueError("agent_formulation does not support fixed effect absorption.")
demographics, demographics_formulations = build_demographics(products, agent_data, agent_formulation)
assert demographics is not None
if not np.isfinite(demographics).all():
raise ValueError(
"Variables in agent_data that contribute to demographics should not have NaNs or infinities."
)

# load IDs
if agent_data is not None:
Expand Down Expand Up @@ -333,8 +349,12 @@ def __new__(
if check_weights:
raise KeyError("Since integration is None, agent_data must have weights.")
weights = np.full((nodes.shape[0], 1), np.nan, options.dtype)
elif not np.isfinite(weights).all():
raise ValueError("The weights field in agent_data should not have NaNs or infinities.")
if weights.shape[1] != 1:
raise ValueError("The weights field of agent_data must be one-dimensional.")
if not np.isfinite(nodes).all():
raise ValueError("The nodes field in agent_data should not have NaNs or infinities.")

# delete columns of nodes if there are too many
if nodes.shape[1] > K2:
Expand Down

0 comments on commit 16b5ddc

Please sign in to comment.