55import numpy as np
66
77from preliz .internal .optimization import optimize_pymc_model
8- from preliz .ppls .agnostic import back_fitting_idata , get_engine
8+ from preliz .ppls .agnostic import get_engine
99from preliz .ppls .bambi_io import get_pymc_model , write_bambi_string
1010from preliz .ppls .pymc_io import (
1111 back_fitting_pymc ,
1818)
1919
2020
21- def ppe (model , target , method = "projective " , engine = "auto" , random_state = 0 ):
21+ def ppe (model , target , engine = "auto " , new_families = None , random_state = 0 ):
2222 """
2323 Prior Predictive Elicitation.
2424
2525 This method is experimental and under development. It does not offers guarantees of
2626 correctness. Use with caution and triple-check the results.
2727
28+ With the projective method we attempt to find a prior that induces
29+ a prior predictive distribution as close as possible to the target distribution
30+
2831 Parameters
2932 ----------
3033 model : a probabilistic model
3134 Currently it only works with PyMC model. More PPls coming soon.
32- method : str
33- Method used to generate samples that match the target distribution.
34- Defaults to `"projective"`, another option is `"pathfinder"`.
35- If `"projective"`, the parameters of the priors are only used to provide an initial
36- guess for the optimization routine. Thus their effect on the result is smaller than in
37- traditional Bayesian inference, unless the priors are very vague or very strong.
38- If `"projective"`, the observed values are ignored, but not their size.
39- Pathfinder is a variational inference method so the role of the priors and observed values
40- is what is expected in Bayesian inference.
41- engine : str
42- Library used to define the model. Either `"auto"` (default), `"pymc"` or `"bambi"`.
43- Ig `"auto"`, the library is automatically detected.
4435 target : a PreliZ distribution or list
4536 Instance of a PreliZ distribution or a list of tuples where each tuple contains a PreliZ
4637 distribution and a weight.
4738 This represents the prior predictive distribution **previously** elicited by the user,
4839 possibly using other PreliZ's methods to obtain this distribution, such as maxent,
4940 roulette, quartile, etc.
5041 This should represent the domain-knowledge of the user and not any observed dataset.
42+ engine : str
43+ Library used to define the model. Either `"auto"` (default), `"pymc"` or `"bambi"`.
44+ Ig `"auto"`, the library is automatically detected.
45+ new_families : "auto", list or dict
46+ Defaults to None, the samples are fit to the original prior distribution.
47+ If "auto", the method evaluates the fit to the original prior plus a set of
48+ predefined distributions.
49+ Use a list of PreliZ distribution to specify the alternative distributions
50+ you want to consider.
51+ Use a dict with variables names in ``model`` as keys and a list of PreliZ
52+ distributions as values. This allows to specify alternative distributions
53+ per variable.
5154 random_state : {None, int, numpy.random.Generator, numpy.random.RandomState}
5255 Defaults to 0. Ignored if `method` is `"pathfinder"`.
5356
@@ -73,44 +76,31 @@ def ppe(model, target, method="projective", engine="auto", random_state=0):
7376 preliz_model = extract_preliz_distributions (model )
7477 var_info , num_draws = retrieve_variable_info (model )
7578
76- # With the projective method we attempt to find a prior that induces
77- # a prior predictive distribution as close as possible to the target distribution
78- if method == "projective" :
79- # Initial point for optimization
80- initial_guess = get_initial_guess (model )
81- # compile PyMC model
82- fmodel , old_y_value , obs_rvs = compile_mllk (model )
83- projection_raveled = optimize_pymc_model (
84- fmodel ,
85- target ,
86- num_draws ,
87- opt_iterations ,
88- initial_guess ,
89- rng ,
90- )
91- # restore obs_rvs value in the model
92- model .rvs_to_values [obs_rvs ] = old_y_value
93-
94- projection_unraveled = unravel_projection (projection_raveled , var_info , opt_iterations )
95-
96- # Backfit `projected_posterior` into the model's prior-families
97- projection_backfitted = back_fitting_pymc (projection_unraveled , preliz_model , var_info )
98-
99- if engine == "bambi" :
100- new_priors = write_bambi_string (projection_backfitted , var_info )
101- elif engine == "pymc" :
102- new_priors = write_pymc_string (projection_backfitted , var_info )
103-
104- elif method == "pathfinder" :
105- from pymc_experimental import fit
106-
107- with model :
108- idata = fit (method = "pathfinder" , num_samples = opt_iterations )
109-
110- projection_backfitted = back_fitting_idata (idata , preliz_model , new_families = False )
111- if engine == "bambi" :
112- new_priors = write_bambi_string (projection_backfitted , var_info )
113- elif engine == "pymc" :
114- new_priors = write_pymc_string (projection_backfitted , var_info )
79+ # Initial point for optimization
80+ initial_guess = get_initial_guess (model )
81+ # compile PyMC model
82+ fmodel , old_y_value , obs_rvs = compile_mllk (model )
83+ projection_raveled = optimize_pymc_model (
84+ fmodel ,
85+ target ,
86+ num_draws ,
87+ opt_iterations ,
88+ initial_guess ,
89+ rng ,
90+ )
91+ # restore obs_rvs value in the model
92+ model .rvs_to_values [obs_rvs ] = old_y_value
93+
94+ projection_unraveled = unravel_projection (projection_raveled , var_info , opt_iterations )
95+
96+ # Backfit `projected_posterior` into the model's prior-families
97+ projection_backfitted = back_fitting_pymc (
98+ projection_unraveled , preliz_model , var_info , new_families
99+ )
100+
101+ if engine == "bambi" :
102+ new_priors = write_bambi_string (projection_backfitted , var_info )
103+ elif engine == "pymc" :
104+ new_priors = write_pymc_string (projection_backfitted , var_info )
115105
116106 return new_priors
0 commit comments