.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/bayesian_swissmetro/plot_b15_panel_discrete.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_bayesian_swissmetro_plot_b15_panel_discrete.py: .. _plot_b15_panel_discrete: 15. Discrete mixture with panel data ==================================== Bayesian estimation of a discrete mixture of logit models, also called latent class model. The datafile is organized as panel data. Michel Bierlaire, EPFL Sat Nov 15 2025, 17:39:13 .. GENERATED FROM PYTHON SOURCE LINES 15-20 .. code-block:: Python from pathlib import Path from IPython.core.display_functions import display .. GENERATED FROM PYTHON SOURCE LINES 21-22 See the data processing script ``swissmetro_panel.py``. .. GENERATED FROM PYTHON SOURCE LINES 22-55 .. code-block:: Python from swissmetro_panel import ( CAR_AV_SP, CAR_CO_SCALED, CAR_TT_SCALED, CHOICE, SM_AV, SM_COST_SCALED, SM_TT_SCALED, TRAIN_AV_SP, TRAIN_COST_SCALED, TRAIN_TT_SCALED, database, ) import biogeme.biogeme_logging as blog from biogeme.bayesian_estimation import ( BayesianResults, BayesianResultsSummary, get_pandas_estimated_parameters, ) from biogeme.biogeme import BIOGEME from biogeme.expressions import ( Beta, DistributedParameter, Draws, exp, log, ) from biogeme.models import logit logger = blog.get_screen_logger(level=blog.INFO) logger.info('Example b15_panel_discrete.py') .. rst-class:: sphx-glr-script-out .. code-block:: none Example b15_panel_discrete.py .. GENERATED FROM PYTHON SOURCE LINES 56-57 Parameters to be estimated. One version for each latent_old class. .. GENERATED FROM PYTHON SOURCE LINES 57-60 .. code-block:: Python NUMBER_OF_CLASSES = 2 b_cost = [Beta(f'b_cost_class{i}', 0, None, None, 0) for i in range(NUMBER_OF_CLASSES)] .. GENERATED FROM PYTHON SOURCE LINES 61-63 Define a random parameter, normally distributed across individuals, designed to be used for Monte-Carlo simulation .. GENERATED FROM PYTHON SOURCE LINES 63-65 .. code-block:: Python b_time = [Beta(f'b_time_class{i}', 0, None, None, 0) for i in range(NUMBER_OF_CLASSES)] .. GENERATED FROM PYTHON SOURCE LINES 66-67 It is advised not to use 0 as starting value for the following parameter. .. GENERATED FROM PYTHON SOURCE LINES 67-78 .. code-block:: Python b_time_s = [ Beta(f'b_time_s_class{i}', 1, None, None, 0) for i in range(NUMBER_OF_CLASSES) ] b_time_rnd = [ DistributedParameter( f'b_time_rnd_class{i}', b_time[i] + b_time_s[i] * Draws(f'b_time_eps_class{i}', 'NORMAL'), ) for i in range(NUMBER_OF_CLASSES) ] .. GENERATED FROM PYTHON SOURCE LINES 79-80 We do the same for the constants, to address serial correlation. .. GENERATED FROM PYTHON SOURCE LINES 80-120 .. code-block:: Python asc_car = [ Beta(f'asc_car_class{i}', 0, None, None, 0) for i in range(NUMBER_OF_CLASSES) ] asc_car_s = [ Beta(f'asc_car_s_class{i}', 1, None, None, 0) for i in range(NUMBER_OF_CLASSES) ] asc_car_rnd = [ DistributedParameter( f'asc_car_rnd_class{i}', asc_car[i] + asc_car_s[i] * Draws(f'asc_car_eps_class{i}', 'NORMAL'), ) for i in range(NUMBER_OF_CLASSES) ] asc_train = [ Beta(f'asc_train_class{i}', 0, None, None, 0) for i in range(NUMBER_OF_CLASSES) ] asc_train_s = [ Beta(f'asc_train_s_class{i}', 1, None, None, 0) for i in range(NUMBER_OF_CLASSES) ] asc_train_rnd = [ DistributedParameter( f'asc_train_rnd_class{i}', asc_train[i] + asc_train_s[i] * Draws(f'asc_train_eps_class{i}', 'NORMAL'), ) for i in range(NUMBER_OF_CLASSES) ] asc_sm = [Beta(f'asc_sm_class{i}', 0, None, None, 1) for i in range(NUMBER_OF_CLASSES)] asc_sm_s = [ Beta(f'asc_sm_s_class{i}', 1, None, None, 0) for i in range(NUMBER_OF_CLASSES) ] asc_sm_rnd = [ DistributedParameter( f'asc_sm_rnd_class{i}', asc_sm[i] + asc_sm_s[i] * Draws(f'asc_sm_eps_class{i}', 'NORMAL'), ) for i in range(NUMBER_OF_CLASSES) ] .. GENERATED FROM PYTHON SOURCE LINES 121-122 Class membership probability. Note: for Bayesian estimation, this should not call the logit model. .. GENERATED FROM PYTHON SOURCE LINES 122-126 .. code-block:: Python score_class_0 = Beta('score_class_0', -1.7, None, None, 0) probability_class_1 = 1 / (1 + exp(score_class_0)) probability_class_0 = 1 - probability_class_1 .. GENERATED FROM PYTHON SOURCE LINES 127-128 In class 0, it is assumed that the time coefficient is zero. .. GENERATED FROM PYTHON SOURCE LINES 128-130 .. code-block:: Python b_time_rnd[0] = 0 .. GENERATED FROM PYTHON SOURCE LINES 131-132 Utility functions. .. GENERATED FROM PYTHON SOURCE LINES 132-149 .. code-block:: Python v_train_per_class = [ asc_train_rnd[i] + b_time_rnd[i] * TRAIN_TT_SCALED + b_cost[i] * TRAIN_COST_SCALED for i in range(NUMBER_OF_CLASSES) ] v_swissmetro_per_class = [ asc_sm_rnd[i] + b_time_rnd[i] * SM_TT_SCALED + b_cost[i] * SM_COST_SCALED for i in range(NUMBER_OF_CLASSES) ] v_car_per_class = [ asc_car_rnd[i] + b_time_rnd[i] * CAR_TT_SCALED + b_cost[i] * CAR_CO_SCALED for i in range(NUMBER_OF_CLASSES) ] v_per_class = [ {1: v_train_per_class[i], 2: v_swissmetro_per_class[i], 3: v_car_per_class[i]} for i in range(NUMBER_OF_CLASSES) ] .. GENERATED FROM PYTHON SOURCE LINES 150-151 Associate the availability conditions with the alternatives. .. GENERATED FROM PYTHON SOURCE LINES 151-153 .. code-block:: Python av = {1: TRAIN_AV_SP, 2: SM_AV, 3: CAR_AV_SP} .. GENERATED FROM PYTHON SOURCE LINES 154-156 The choice model is a discrete mixture of logit, with availability conditions We calculate the conditional probability for each class. .. GENERATED FROM PYTHON SOURCE LINES 156-160 .. code-block:: Python conditional_probability_per_class = [ logit(v_per_class[i], av, CHOICE) for i in range(NUMBER_OF_CLASSES) ] .. GENERATED FROM PYTHON SOURCE LINES 161-162 Conditional to the random variables, likelihood for the individual. .. GENERATED FROM PYTHON SOURCE LINES 162-167 .. code-block:: Python conditional_choice_probability = ( probability_class_0 * conditional_probability_per_class[0] + probability_class_1 * conditional_probability_per_class[1] ) .. GENERATED FROM PYTHON SOURCE LINES 168-169 We need the log probability per observation .. GENERATED FROM PYTHON SOURCE LINES 169-171 .. code-block:: Python conditional_log_probability = log(conditional_choice_probability) .. GENERATED FROM PYTHON SOURCE LINES 172-181 .. code-block:: Python the_biogeme = BIOGEME( database, conditional_log_probability, warmup=4000, bayesian_draws=4000, chains=4, ) the_biogeme.model_name = 'b15_panel_discrete' .. rst-class:: sphx-glr-script-out .. code-block:: none Biogeme parameters read from biogeme.toml. .. GENERATED FROM PYTHON SOURCE LINES 182-184 Estimate the posterior distribution of the parameters, or read the results if already available. .. GENERATED FROM PYTHON SOURCE LINES 184-191 .. code-block:: Python yaml_file = Path('saved_results') / f'{the_biogeme.model_name}.yaml' try: summary_results = BayesianResultsSummary.from_yaml_file(filename=yaml_file) except FileNotFoundError: results: BayesianResults = the_biogeme.bayesian_estimation() summary_results = results.to_summary() .. GENERATED FROM PYTHON SOURCE LINES 192-194 .. code-block:: Python print(summary_results.short_summary()) .. rst-class:: sphx-glr-script-out .. code-block:: none Sample size 6768 Sampler NUTS Number of chains 4 Number of draws per chain 4000 Total number of draws 16000 Acceptance rate target 0.9 Run time 0:27:27.347566 Posterior predictive log-likelihood (sum of log mean p) -2156.93 Expected log-likelihood E[log L(Y|θ)] -2342.30 Best-draw log-likelihood (posterior upper bound) -2232.19 LOO (Leave-One-Out Cross-Validation) -3043.55 LOO Standard Error 78.39 Effective number of parameters (p_LOO) 886.62 .. GENERATED FROM PYTHON SOURCE LINES 195-196 Present the parameter estimates in a pandas table. .. GENERATED FROM PYTHON SOURCE LINES 196-201 .. code-block:: Python pandas_results = get_pandas_estimated_parameters( estimation_results=summary_results, ) display(pandas_results) .. rst-class:: sphx-glr-script-out .. code-block:: none Name Value (mean) ... ESS (bulk) ESS (tail) 0 score_class_0 -5.269729 ... 1107.881335 1279.186401 1 asc_train_class0 -2.572247 ... 4185.700594 8295.082582 2 asc_train_s_class0 0.745081 ... 6338.755023 7886.597741 3 b_cost_class0 2.733313 ... 2353.080701 2203.302640 4 asc_sm_s_class0 1.367400 ... 2252.533260 2750.966721 5 asc_car_class0 -0.729003 ... 3928.727344 5681.970166 6 asc_car_s_class0 0.995962 ... 5495.069755 8217.012967 7 asc_train_class1 -0.315026 ... 1456.703040 2634.804557 8 asc_train_s_class1 2.271266 ... 559.042723 869.542749 9 b_time_class1 -6.518591 ... 1623.510543 2064.187908 10 b_time_s_class1 -4.018999 ... 2015.845568 3133.353383 11 b_cost_class1 -4.218585 ... 2141.955596 3048.286362 12 asc_sm_s_class1 -0.166371 ... 36.034480 217.660331 13 asc_car_class1 0.500710 ... 3180.093599 5338.435005 14 asc_car_s_class1 -2.014075 ... 7.172490 10.306197 [15 rows x 12 columns] .. GENERATED FROM PYTHON SOURCE LINES 202-203 Report the variables stored in the Bayesian estimation results. .. GENERATED FROM PYTHON SOURCE LINES 203-204 .. code-block:: Python display(summary_results.report_stored_variables()) .. rst-class:: sphx-glr-script-out .. code-block:: none group variable dims shape 0 constant_data CAR_AV_SP [obs] [6768] 1 constant_data CAR_CO_SCALED [obs] [6768] 2 constant_data CAR_TT_SCALED [obs] [6768] 3 constant_data CHOICE [obs] [6768] 4 constant_data SM_AV [obs] [6768] .. ... ... ... ... 87 sample_stats energy [chain, draw] [4, 4000] 88 sample_stats lp [chain, draw] [4, 4000] 89 sample_stats n_steps [chain, draw] [4, 4000] 90 sample_stats step_size [chain, draw] [4, 4000] 91 sample_stats tree_depth [chain, draw] [4, 4000] [92 rows x 4 columns] .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.049 seconds) .. _sphx_glr_download_auto_examples_bayesian_swissmetro_plot_b15_panel_discrete.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_b15_panel_discrete.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_b15_panel_discrete.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_b15_panel_discrete.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_