Direct point elasticities

We use a previously estimated nested logit model and calculate

disaggregate and aggregate direct 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, 19:21:30

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, distance_km, 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 direct elasticities. We use the ‘Derive’ operator to calculate the derivatives.

direct_elas_pt_time = Derive(prob_pt, 'TimePT') * TimePT / prob_pt

direct_elas_pt_cost = Derive(prob_pt, 'MarginalCostPT') * MarginalCostPT / prob_pt

direct_elas_car_time = Derive(prob_car, 'TimeCar') * TimeCar / prob_car

direct_elas_car_cost = Derive(prob_car, 'CostCarCHF') * CostCarCHF / prob_car

direct_elas_sm_dist = Derive(prob_sm, 'distance_km') * distance_km / prob_sm

Formulas to simulate.

simulate = {
    'weight': normalized_weight,
    'Prob. car': prob_car,
    'Prob. public transportation': prob_pt,
    'Prob. slow modes': prob_sm,
    'direct_elas_pt_time': direct_elas_pt_time,
    'direct_elas_pt_cost': direct_elas_pt_cost,
    'direct_elas_car_time': direct_elas_car_time,
    'direct_elas_car_cost': direct_elas_car_cost,
    'direct_elas_sm_dist': direct_elas_sm_dist,
}

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 Pandas 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  ...  direct_elas_car_cost  direct_elas_sm_dist
0     0.893779   0.519163  ...             -0.156973            -6.274840
1     0.868674   0.560879  ...             -0.020209            -0.690991
2     0.868674   0.875042  ...             -0.030371            -6.230364
3     0.965766   0.813492  ...             -0.022263            -1.734015
4     0.868674   0.729611  ...             -0.052690            -4.718199
...        ...        ...  ...                   ...                  ...
1894  2.053830   0.711088  ...             -0.116755           -10.650036
1895  0.868674   0.849006  ...             -0.049510            -8.084167
1896  0.868674   0.688196  ...             -0.030268            -1.857411
1897  0.965766   0.742196  ...             -0.047086            -3.406341
1898  0.965766   0.763148  ...             -0.054500            -3.968144

[1899 rows x 9 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']
)
simulated_values['Weighted prob. SM'] = (
    simulated_values['weight'] * simulated_values['Prob. slow modes']
)

Then the denominators of the aggregate elasticity expressions.

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

And finally the aggregate elasticities themselves.

Elasticity of car with respect to time.

direct_elas_term_car_time = (
    simulated_values['Weighted prob. car']
    * simulated_values['direct_elas_car_time']
    / denominator_car
).sum()

print(
    f'Aggregate direct point elasticity of car wrt time: '
    f'{direct_elas_term_car_time:.3g}'
)
Aggregate direct point elasticity of car wrt time: -0.0437

Elasticity of car with respect to cost.

direct_elas_term_car_cost = (
    simulated_values['Weighted prob. car']
    * simulated_values['direct_elas_car_cost']
    / denominator_car
).sum()
print(
    f'Aggregate direct point elasticity of car wrt cost: '
    f'{direct_elas_term_car_cost:.3g}'
)
Aggregate direct point elasticity of car wrt cost: -0.0917

Elasticity of public transportation with respect to time.

direct_elas_term_pt_time = (
    simulated_values['Weighted prob. PT']
    * simulated_values['direct_elas_pt_time']
    / denominator_pt
).sum()
print(
    f'Aggregate direct point elasticity of PT wrt time: '
    f'{direct_elas_term_pt_time:.3g}'
)
Aggregate direct point elasticity of PT wrt time: -0.268

Elasticity of public transportation with respect to cost.

direct_elas_term_pt_cost = (
    simulated_values['Weighted prob. PT']
    * simulated_values['direct_elas_pt_cost']
    / denominator_pt
).sum()
print(
    f'Aggregate direct point elasticity of PT wrt cost: '
    f'{direct_elas_term_pt_cost:.3g}'
)
Aggregate direct point elasticity of PT wrt cost: -0.324

Elasticity of slow modes with respect to distance.

direct_elas_term_sm_dist = (
    simulated_values['Weighted prob. SM']
    * simulated_values['direct_elas_sm_dist']
    / denominator_sm
).sum()
print(
    f'Aggregate direct point elasticity of SM wrt distance: '
    f'{direct_elas_term_sm_dist:.3g}'
)
Aggregate direct point elasticity of SM wrt distance: -1.09

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

Gallery generated by Sphinx-Gallery