Skip to content

Commit d04b369

Browse files
authored
Multiple fixes (#349)
1 parent 8076105 commit d04b369

File tree

17 files changed

+221
-46
lines changed

17 files changed

+221
-46
lines changed

CHANGES.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ releases are available on `Anaconda.org
77
<https://anaconda.org/OpenSourceEconomics/estimagic>`_.
88

99

10+
0.3.1
11+
-----
12+
13+
- :gh:`349` fixes multiple small bugs and adds test cases for all of them
14+
(:ghuser:`mpetrosian`, :ghuser:`janosg` and :ghuser:`timmens`)
15+
1016
0.3.0
1117
-----
1218

docs/source/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ provides functionality to perform statistical inference on estimated parameters.
101101
</p>
102102
</div>
103103
</div>
104-
</a>
104+
</a>
105105
</div>
106106
</div>
107107
</div>

src/estimagic/estimation/estimate_ml.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from estimagic.parameters.conversion import get_converter
2828
from estimagic.shared.check_option_dicts import check_numdiff_options
2929
from estimagic.shared.check_option_dicts import check_optimization_options
30+
from estimagic.utilities import to_pickle
3031

3132

3233
def estimate_ml(
@@ -81,7 +82,7 @@ def estimate_ml(
8182
upper_bounds (pytree): As lower_bounds. Can be ``np.inf`` for parameters with
8283
no upper bound.
8384
constraints (list, dict): List with constraint dictionaries or single dict.
84-
See .. _link: ../../docs/source/how_to_guides/how_to_use_constraints.ipynb
85+
See :ref:`constraints`.
8586
logging (pathlib.Path, str or False): Path to sqlite3 file (which typically has
8687
the file extension ``.db``. If the file does not exist, it will be created.
8788
The dashboard can only be used when logging is used.
@@ -211,7 +212,7 @@ def estimate_ml(
211212
# Get the converter for params and function outputs
212213
# ==================================================================================
213214

214-
converter, flat_estimates = get_converter(
215+
converter, internal_estimates = get_converter(
215216
func=loglike,
216217
params=estimates,
217218
constraints=constraints,
@@ -241,9 +242,9 @@ def func(x):
241242

242243
jac_res = first_derivative(
243244
func=func,
244-
params=flat_estimates.values,
245-
lower_bounds=flat_estimates.lower_bounds,
246-
upper_bounds=flat_estimates.upper_bounds,
245+
params=internal_estimates.values,
246+
lower_bounds=internal_estimates.lower_bounds,
247+
upper_bounds=internal_estimates.upper_bounds,
247248
**numdiff_options,
248249
)
249250

@@ -284,9 +285,9 @@ def func(x):
284285

285286
hess_res = second_derivative(
286287
func=func,
287-
params=flat_estimates.values,
288-
lower_bounds=flat_estimates.lower_bounds,
289-
upper_bounds=flat_estimates.upper_bounds,
288+
params=internal_estimates.values,
289+
lower_bounds=internal_estimates.lower_bounds,
290+
upper_bounds=internal_estimates.upper_bounds,
290291
**numdiff_options,
291292
)
292293
int_hess = hess_res["derivative"]
@@ -335,7 +336,7 @@ def func(x):
335336
_internal_jacobian=int_jac,
336337
_internal_hessian=int_hess,
337338
_design_info=design_info,
338-
_flat_params=flat_estimates,
339+
_flat_params=internal_estimates,
339340
_has_constraints=constraints not in [None, []],
340341
)
341342

@@ -615,7 +616,7 @@ def summary(
615616

616617
summary = calculate_inference_quantities(
617618
estimates=self.params,
618-
flat_estimates=self._flat_params,
619+
internal_estimates=self._flat_params,
619620
free_cov=free_cov,
620621
ci_level=ci_level,
621622
)
@@ -737,3 +738,12 @@ def p_values(
737738
out = self._converter.params_from_internal(helper)
738739

739740
return out
741+
742+
def to_pickle(self, path):
743+
"""Save the LikelihoodResult object to pickle.
744+
745+
Args:
746+
path (str, pathlib.Path): A str or pathlib.path ending in .pkl or .pickle.
747+
748+
"""
749+
to_pickle(self, path=path)

src/estimagic/estimation/estimate_msm.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from estimagic.sensitivity.msm_sensitivity import calculate_sensitivity_to_weighting
4040
from estimagic.shared.check_option_dicts import check_numdiff_options
4141
from estimagic.shared.check_option_dicts import check_optimization_options
42+
from estimagic.utilities import to_pickle
4243
from pybaum import leaf_names
4344
from pybaum import tree_just_flatten
4445

@@ -107,7 +108,7 @@ def estimate_msm(
107108
Note that "optimal" refers to the asymptotically optimal weighting matrix
108109
and is often not a good choice due to large finite sample bias.
109110
constraints (list, dict): List with constraint dictionaries or single dict.
110-
See .. _link: ../../docs/source/how_to_guides/how_to_use_constraints.ipynb
111+
See :ref:`constraints`.
111112
logging (pathlib.Path, str or False): Path to sqlite3 file (which typically has
112113
the file extension ``.db``. If the file does not exist, it will be created.
113114
The dashboard can only be used when logging is used.
@@ -259,7 +260,7 @@ def helper(params):
259260
else:
260261
func_eval = {"contributions": sim_mom_eval}
261262

262-
converter, flat_estimates = get_converter(
263+
converter, internal_estimates = get_converter(
263264
func=helper,
264265
params=estimates,
265266
constraints=constraints,
@@ -289,9 +290,9 @@ def func(x):
289290

290291
int_jac = first_derivative(
291292
func=func,
292-
params=flat_estimates.values,
293-
lower_bounds=flat_estimates.lower_bounds,
294-
upper_bounds=flat_estimates.upper_bounds,
293+
params=internal_estimates.values,
294+
lower_bounds=internal_estimates.lower_bounds,
295+
upper_bounds=internal_estimates.upper_bounds,
295296
**numdiff_options,
296297
)["derivative"]
297298

@@ -320,7 +321,7 @@ def func(x):
320321
res = MomentsResult(
321322
params=estimates,
322323
weights=weights,
323-
_flat_params=flat_estimates,
324+
_flat_params=internal_estimates,
324325
_converter=converter,
325326
_internal_weights=internal_weights,
326327
_internal_moments_cov=internal_moments_cov,
@@ -659,7 +660,7 @@ def summary(
659660

660661
summary = calculate_inference_quantities(
661662
estimates=self.params,
662-
flat_estimates=self._flat_params,
663+
internal_estimates=self._flat_params,
663664
free_cov=free_cov,
664665
ci_level=ci_level,
665666
)
@@ -930,3 +931,12 @@ def sensitivity(
930931
)
931932
raise ValueError(msg)
932933
return out
934+
935+
def to_pickle(self, path):
936+
"""Save the MomentsResult object to pickle.
937+
938+
Args:
939+
path (str, pathlib.Path): A str or pathlib.path ending in .pkl or .pickle.
940+
941+
"""
942+
to_pickle(self, path=path)

src/estimagic/inference/shared.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def transform_covariance(
2222
internal parameter vector. For background information about internal and
2323
external params see :ref:`implementation_of_constraints`.
2424
constraints (list): List with constraint dictionaries.
25-
See .. _link: ../../docs/source/how_to_guides/how_to_use_constraints.ipynb
25+
See :ref:`constraints`.
2626
n_samples (int): Number of samples used to transform the covariance matrix of
2727
the internal parameter vector into the covariance matrix of the external
2828
parameters.
@@ -78,13 +78,13 @@ def transform_covariance(
7878
return free_cov
7979

8080

81-
def calculate_inference_quantities(estimates, flat_estimates, free_cov, ci_level):
81+
def calculate_inference_quantities(estimates, internal_estimates, free_cov, ci_level):
8282
"""Add standard errors, pvalues and confidence intervals to params.
8383
8484
Args
8585
params (pytree): The input parameter pytree.
86-
flat_estimates (FlatParams): NamedTuple with internal estimated parameter values
87-
and names, lower_bounds and upper_bounds, and free_mask.
86+
internal_estimates (FlatParams): NamedTuple with internal estimated parameter
87+
values and names, lower_bounds and upper_bounds, and free_mask.
8888
free_cov (pd.DataFrame): Quadratic DataFrame containing the covariance matrix
8989
of the free parameters. If parameters were fixed (explicitly or by other
9090
constraints) the index is a subset of params.index. The columns are the same
@@ -101,14 +101,15 @@ def calculate_inference_quantities(estimates, flat_estimates, free_cov, ci_level
101101
102102
"""
103103
if not isinstance(free_cov, pd.DataFrame):
104-
free_index = np.array(flat_estimates.names)[flat_estimates.free_mask]
104+
free_index = np.array(internal_estimates.names)[internal_estimates.free_mask]
105105
free_cov = pd.DataFrame(data=free_cov, columns=free_index, index=free_index)
106106
####################################################################################
107107
# Construct summary data frame for flat estimates
108108
####################################################################################
109+
registry = get_registry(extended=True)
109110

110-
df = pd.DataFrame(index=flat_estimates.names)
111-
df["value"] = flat_estimates.values
111+
df = pd.DataFrame(index=internal_estimates.names)
112+
df["value"] = tree_just_flatten(estimates, registry=registry)
112113
df.loc[free_cov.index, "standard_error"] = np.sqrt(np.diag(free_cov))
113114

114115
df["p_value"] = calculate_p_values(
@@ -134,13 +135,11 @@ def calculate_inference_quantities(estimates, flat_estimates, free_cov, ci_level
134135
# Map summary data into params tree structure
135136
####################################################################################
136137

137-
registry = get_registry(extended=True)
138-
139138
# create tree with values corresponding to indices of df
140-
indices = tree_unflatten(estimates, flat_estimates.names, registry=registry)
139+
indices = tree_unflatten(estimates, internal_estimates.names, registry=registry)
141140

142-
indices_flat = tree_just_flatten(indices)
143141
estimates_flat = tree_just_flatten(estimates)
142+
indices_flat = tree_just_flatten(indices)
144143

145144
# use index chunks in indices_flat to access the corresponding sub data frame of df,
146145
# and use the index information stored in estimates_flat to form the correct (multi)

src/estimagic/optimization/optimize.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def maximize(
8383
soft_upper_bounds (pytree): As soft_lower_bounds.
8484
criterion_kwargs (dict): Additional keyword arguments for criterion
8585
constraints (list, dict): List with constraint dictionaries or single dict.
86-
See .. _link: ../../docs/source/how_to_guides/how_to_use_constraints.ipynb
86+
See :ref:`constraints`.
8787
algo_options (dict): Algorithm specific configuration of the optimization. See
8888
:ref:`list_of_algorithms` for supported options of each algorithm.
8989
derivative (callable): Function that calculates the first derivative
@@ -281,7 +281,7 @@ def minimize(
281281
soft_upper_bounds (pytree): As soft_lower_bounds.
282282
criterion_kwargs (dict): Additional keyword arguments for criterion
283283
constraints (list, dict): List with constraint dictionaries or single dict.
284-
See .. _link: ../../docs/source/how_to_guides/how_to_use_constraints.ipynb
284+
See :ref:`constraints`.
285285
algo_options (dict): Algorithm specific configuration of the optimization. See
286286
:ref:`list_of_algorithms` for supported options of each algorithm.
287287
derivative (callable): Function that calculates the first derivative

src/estimagic/optimization/optimize_result.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import numpy as np
88
import pandas as pd
9+
from estimagic.utilities import to_pickle
910

1011

1112
@dataclass
@@ -88,6 +89,15 @@ def __repr__(self):
8889

8990
return msg
9091

92+
def to_pickle(self, path):
93+
"""Save the OptimizeResult object to pickle.
94+
95+
Args:
96+
path (str, pathlib.Path): A str or pathlib.path ending in .pkl or .pickle.
97+
98+
"""
99+
to_pickle(self, path=path)
100+
91101

92102
def _format_convergence_report(report, algorithm):
93103
report = pd.DataFrame.from_dict(report)

src/estimagic/parameters/consolidate_constraints.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def _consolidate_fixes_with_equality_constraints(
208208
assert (
209209
len(valcounts) == 1
210210
), "Equality constrained parameters cannot be fixed to different values."
211-
fixed_value[eq["index"]] = valcounts.index[0]
211+
fixed_value[eq["index"]] = valcounts[0]
212212

213213
return fixed_value
214214

src/estimagic/parameters/process_selectors.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from collections import Counter
23

34
import numpy as np
@@ -53,7 +54,9 @@ def process_selectors(constraints, params, tree_converter, param_names):
5354
registry=registry,
5455
)
5556
try:
56-
selected = evaluator(helper)
57+
with warnings.catch_warnings():
58+
warnings.simplefilter("ignore", category=pd.errors.PerformanceWarning)
59+
selected = evaluator(helper)
5760
except (KeyboardInterrupt, SystemExit):
5861
raise
5962
except Exception as e:
@@ -94,11 +97,13 @@ def _get_selection_field(constraint, selector_case, params_case):
9497
"dataframe": {"locs", "queries", "selectors"},
9598
"numpy array": {"locs", "selectors"},
9699
"pytree": {"selectors"},
100+
"series": {"locs", "selectors"},
97101
},
98102
"one selector": {
99103
"dataframe": {"loc", "query", "selector"},
100104
"numpy array": {"loc", "selector"},
101105
"pytree": {"selector"},
106+
"series": {"loc", "selector"},
102107
},
103108
}
104109

@@ -180,6 +185,8 @@ def evaluator(params):
180185
def _get_params_case(params):
181186
if isinstance(params, pd.DataFrame) and "value" in params:
182187
params_case = "dataframe"
188+
elif isinstance(params, pd.Series):
189+
params_case = "series"
183190
elif isinstance(params, np.ndarray):
184191
params_case = "numpy array"
185192
else:

src/estimagic/utilities.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import warnings
22
from hashlib import sha1
33

4+
import cloudpickle
45
import numpy as np
5-
from fuzzywuzzy import process as fw_process
6+
import pandas as pd
67
from scipy.linalg import ldl
78
from scipy.linalg import qr
89

10+
with warnings.catch_warnings():
11+
warnings.simplefilter("ignore", category=UserWarning)
12+
from fuzzywuzzy import process as fw_process
13+
914

1015
def chol_params_to_lower_triangular_matrix(params):
1116
dim = number_of_triangular_elements_to_dimension(len(params))
@@ -125,7 +130,9 @@ def propose_alternatives(requested, possibilities, number=3):
125130
126131
"""
127132
number = min(number, len(possibilities))
128-
proposals_w_probs = fw_process.extract(requested, possibilities, limit=number)
133+
with warnings.catch_warnings():
134+
warnings.simplefilter("ignore", category=UserWarning)
135+
proposals_w_probs = fw_process.extract(requested, possibilities, limit=number)
129136
proposals = [proposal[0] for proposal in proposals_w_probs]
130137

131138
return proposals
@@ -277,3 +284,12 @@ def calculate_trustregion_initial_radius(x):
277284
"""
278285
x_norm = np.linalg.norm(x, ord=np.inf)
279286
return 0.1 * max(x_norm, 1)
287+
288+
289+
def to_pickle(obj, path):
290+
with open(path, "wb") as buffer:
291+
cloudpickle.dump(obj, buffer)
292+
293+
294+
def read_pickle(path):
295+
return pd.read_pickle(path)

0 commit comments

Comments
 (0)