Cross point elasticities

We use a previously estimated nested logit model and calculate disaggregate and aggregate cross point elasticities.

Details about this example are available in Section 3 of Bierlaire (2018) Calculating indicators with PandasBiogeme

Michel Bierlaire, EPFL Sat Jun 28 2025, 20:58:34

import sys

from IPython.core.display_functions import display
from biogeme.biogeme import BIOGEME
from biogeme.data.optima import normalized_weight, read_data
from biogeme.expressions import Derive
from biogeme.models import nested
from biogeme.results_processing import EstimationResults

from scenarios import CostCarCHF, MarginalCostPT, TimeCar, TimePT, scenario

Obtain the specification for the default scenario The definition of the scenarios is available in Specification of a nested logit model.

v, nests, _, _ = scenario()

Obtain the expression for the choice probability of each alternative.

prob_pt = nested(v, None, nests, 0)
prob_car = nested(v, None, nests, 1)
prob_sm = nested(v, None, nests, 2)

Calculation of the cross elasticities. We use the ‘Derive’ operator to calculate the derivatives.

cross_elas_pt_time = Derive(prob_pt, 'TimeCar') * TimeCar / prob_pt
cross_elas_pt_cost = Derive(prob_pt, 'CostCarCHF') * CostCarCHF / prob_pt
cross_elas_car_time = Derive(prob_car, 'TimePT') * TimePT / prob_car
cross_elas_car_cost = Derive(prob_car, 'MarginalCostPT') * MarginalCostPT / prob_car

Formulas to simulate.

simulate = {
    'weight': normalized_weight,
    'Prob. car': prob_car,
    'Prob. public transportation': prob_pt,
    'Prob. slow modes': prob_sm,
    'cross_elas_pt_time': cross_elas_pt_time,
    'cross_elas_pt_cost': cross_elas_pt_cost,
    'cross_elas_car_time': cross_elas_car_time,
    'cross_elas_car_cost': cross_elas_car_cost,
}

Read the data

database = read_data()

Create the Biogeme object.

the_biogeme = BIOGEME(database, simulate)

Read the estimation results from the file

try:
    results = EstimationResults.from_yaml_file(
        filename='saved_results/b02estimation.yaml'
    )
except FileNotFoundError:
    sys.exit(
        'Run first the script b02estimation.py in order to generate '
        'the file b02estimation.yaml.'
    )

simulated_values is a Panda dataframe with the same number of rows as the database, and as many columns as formulas to simulate.

simulated_values = the_biogeme.simulate(results.get_beta_values())
display(simulated_values)
        weight  Prob. car  ...  cross_elas_car_time  cross_elas_car_cost
0     0.893779   0.519165  ...             0.112659             0.000000
1     0.868674   0.560868  ...             0.054643             0.051997
2     0.868674   0.875040  ...             0.035465             0.206901
3     0.965766   0.813507  ...             0.077714             0.039783
4     0.868674   0.729616  ...             0.083253             0.179205
...        ...        ...  ...                  ...                  ...
1894  2.053830   0.711097  ...             0.118187             0.216012
1895  0.868674   0.849018  ...             0.166123             0.154992
1896  0.868674   0.688197  ...             0.116736             0.088844
1897  0.965766   0.742202  ...             0.072428             0.181998
1898  0.965766   0.763156  ...             0.081890             0.191696

[1899 rows x 8 columns]

We calculate the aggregate elasticities.

First, the weighted probabilities.

simulated_values['Weighted prob. car'] = (
    simulated_values['weight'] * simulated_values['Prob. car']
)
simulated_values['Weighted prob. PT'] = (
    simulated_values['weight'] * simulated_values['Prob. public transportation']
)

Then the denominators of the aggregate elasticity expressions.

denominator_car = simulated_values['Weighted prob. car'].sum()
denominator_pt = simulated_values['Weighted prob. PT'].sum()

And finally the aggregate elasticities themselves.

Elasticity of car with respect to public transportation travel time.

cross_elas_term_car_time = (
    simulated_values['Weighted prob. car']
    * simulated_values['cross_elas_car_time']
    / denominator_car
).sum()
print(
    f'Aggregate cross elasticity of car wrt PT time: ' f'{cross_elas_term_car_time:.3g}'
)
Aggregate cross elasticity of car wrt PT time: 0.105

Elasticity of car with respect to public transportation travel cost.

cross_elas_term_car_cost = (
    simulated_values['Weighted prob. car']
    * simulated_values['cross_elas_car_cost']
    / denominator_car
).sum()
print(
    f'Aggregate cross elasticity of car wrt PT cost: ' f'{cross_elas_term_car_cost:.3g}'
)
Aggregate cross elasticity of car wrt PT cost: 0.125

Elasticity of public transportatiom with respect to car travel time.

cross_elas_term_pt_time = (
    simulated_values['Weighted prob. PT']
    * simulated_values['cross_elas_pt_time']
    / denominator_pt
).sum()
print(
    f'Aggregate cross elasticity of PT wrt car time: ' f'{cross_elas_term_pt_time:.3g}'
)
Aggregate cross elasticity of PT wrt car time: 0.0941

Elasticity of public transportatiom with respect to car travel cost.

cross_elas_term_pt_cost = (
    simulated_values['Weighted prob. PT']
    * simulated_values['cross_elas_pt_cost']
    / denominator_pt
).sum()
print(
    f'Aggregate cross direct elasticity of PT wrt car cost: '
    f'{cross_elas_term_pt_cost:.3g}'
)
Aggregate cross direct elasticity of PT wrt car cost: 0.201

Total running time of the script: (0 minutes 3.507 seconds)

Gallery generated by Sphinx-Gallery