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

author:

Michel Bierlaire, EPFL

date:

Wed Apr 12 21:00:58 2023

import sys

from IPython.core.display_functions import display

import biogeme.biogeme as bio
from biogeme import models
from biogeme.exceptions import BiogemeError
import biogeme.results as res
from biogeme.expressions import Derive
from biogeme.data.optima import read_data, normalized_weight

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

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 = models.nested(V, None, nests, 0)
prob_CAR = models.nested(V, None, nests, 1)
prob_SM = models.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 = bio.BIOGEME(database, simulate)

Read the estimation results from the file

try:
    results = res.bioResults(pickle_file='saved_results/b02estimation.pickle')
except excep.BiogemeError:
    sys.exit(
        'Run first the script b02estimation.py in order to generate '
        'the file b02estimation.pickle.'
    )

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.886023   0.508061  ...             0.088764             0.000000
2     0.861136   0.574899  ...             0.039943             0.055117
3     0.861136   0.888093  ...             0.023328             0.197357
4     0.957386   0.790872  ...             0.051348             0.033850
5     0.861136   0.733898  ...             0.062363             0.194662
...        ...        ...  ...                  ...                  ...
2259  2.036009   0.710676  ...             0.091112             0.241483
2261  0.861136   0.849664  ...             0.142624             0.171358
2262  0.861136   0.688689  ...             0.092332             0.090492
2263  0.957386   0.747552  ...             0.051636             0.188157
2264  0.957386   0.767021  ...             0.059141             0.200758

[1906 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.0842

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.132

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.0767

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.221

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

Gallery generated by Sphinx-Gallery