Note
Go to the end to download the full example code
Cross-nested logit
Example of a cross-nested logit model with two nests:
one with existing alternatives (car and train),
one with public transportation alternatives (train and Swissmetro)
- author:
Michel Bierlaire, EPFL
- date:
Sun Apr 9 18:06:44 2023
import biogeme.biogeme_logging as blog
import biogeme.biogeme as bio
from biogeme import models
from biogeme.expressions import Beta
from biogeme.nests import OneNestForCrossNestedLogit, NestsForCrossNestedLogit
See the data processing script: Data preparation for Swissmetro.
from swissmetro_data import (
database,
CHOICE,
SM_AV,
CAR_AV_SP,
TRAIN_AV_SP,
TRAIN_TT_SCALED,
TRAIN_COST_SCALED,
SM_TT_SCALED,
SM_COST_SCALED,
CAR_TT_SCALED,
CAR_CO_SCALED,
)
logger = blog.get_screen_logger(level=blog.INFO)
logger.info('Example b11cnl.py')
Example b11cnl.py
Parameters to be estimated.
ASC_CAR = Beta('ASC_CAR', 0, None, None, 0)
ASC_TRAIN = Beta('ASC_TRAIN', 0, None, None, 0)
ASC_SM = Beta('ASC_SM', 0, None, None, 1)
B_TIME = Beta('B_TIME', 0, None, None, 0)
B_COST = Beta('B_COST', 0, None, None, 0)
MU_EXISTING = Beta('MU_EXISTING', 1, 1, 10, 0)
MU_PUBLIC = Beta('MU_PUBLIC', 1, 1, 10, 0)
Nest membership parameters.
ALPHA_EXISTING = Beta('ALPHA_EXISTING', 0.5, 0, 1, 0)
ALPHA_PUBLIC = 1 - ALPHA_EXISTING
Definition of the utility functions
V1 = ASC_TRAIN + B_TIME * TRAIN_TT_SCALED + B_COST * TRAIN_COST_SCALED
V2 = ASC_SM + B_TIME * SM_TT_SCALED + B_COST * SM_COST_SCALED
V3 = ASC_CAR + B_TIME * CAR_TT_SCALED + B_COST * CAR_CO_SCALED
Associate utility functions with the numbering of alternatives
V = {1: V1, 2: V2, 3: V3}
Associate the availability conditions with the alternatives
av = {1: TRAIN_AV_SP, 2: SM_AV, 3: CAR_AV_SP}
Definition of nests.
nest_existing = OneNestForCrossNestedLogit(
nest_param=MU_EXISTING,
dict_of_alpha={1: ALPHA_EXISTING, 2: 0.0, 3: 1.0},
name='existing',
)
nest_public = OneNestForCrossNestedLogit(
nest_param=MU_PUBLIC, dict_of_alpha={1: ALPHA_PUBLIC, 2: 1.0, 3: 0.0}, name='public'
)
nests = NestsForCrossNestedLogit(
choice_set=[1, 2, 3], tuple_of_nests=(nest_existing, nest_public)
)
The choice model is a cross-nested logit, with availability conditions.
logprob = models.logcnl_avail(V, av, nests, CHOICE)
/Users/bierlair/OnlineFiles/FilesOnGoogleDrive/github/biogeme/docs/examples/swissmetro/plot_b11cnl.py:91: DeprecationWarning: The function logcnl_avail is deprecated. It has been replaced by the function logcnl
logprob = models.logcnl_avail(V, av, nests, CHOICE)
Create the Biogeme object
the_biogeme = bio.BIOGEME(database, logprob)
the_biogeme.modelName = 'b11cnl'
File biogeme.toml has been parsed.
Estimate the parameters.
results = the_biogeme.estimate()
*** Initial values of the parameters are obtained from the file __b11cnl.iter
Cannot read file __b11cnl.iter. Statement is ignored.
Optimization algorithm: hybrid Newton/BFGS with simple bounds [simple_bounds]
** Optimization: Newton with trust region for simple bounds
Iter. ALPHA_EXISTING ASC_CAR ASC_TRAIN B_COST B_TIME MU_EXISTING MU_PUBLIC Function Relgrad Radius Rho
0 0.57 -0.088 -0.83 -0.27 -1 1.5 1.5 5.6e+03 0.081 1 0.61 +
1 0.86 -0.29 -0.32 -1.3 -0.93 1.8 1.7 5.3e+03 0.049 1 0.63 +
2 0.86 -0.29 -0.32 -1.3 -0.93 1.8 1.7 5.3e+03 0.049 0.5 0.013 -
3 0.79 -0.12 -0.34 -0.77 -0.9 2 1.8 5.2e+03 0.012 0.5 0.79 +
4 0.56 -0.25 -0.1 -0.88 -0.8 2.5 2.2 5.2e+03 0.013 0.5 0.69 +
5 0.55 -0.25 -0.057 -0.86 -0.8 2.5 2.6 5.2e+03 0.0039 5 1.3 ++
6 0.51 -0.25 0.049 -0.84 -0.79 2.5 3.3 5.2e+03 0.0054 50 1.2 ++
7 0.5 -0.24 0.077 -0.83 -0.78 2.5 3.7 5.2e+03 0.0017 5e+02 1.2 ++
8 0.5 -0.24 0.095 -0.82 -0.78 2.5 4 5.2e+03 0.00053 5e+03 1.1 ++
9 0.5 -0.24 0.098 -0.82 -0.78 2.5 4.1 5.2e+03 3.3e-05 5e+04 1 ++
10 0.5 -0.24 0.098 -0.82 -0.78 2.5 4.1 5.2e+03 1.5e-07 5e+04 1 ++
Results saved in file b11cnl.html
Results saved in file b11cnl.pickle
print(results.short_summary())
Results for model b11cnl
Nbr of parameters: 7
Sample size: 6768
Excluded data: 3960
Final log likelihood: -5214.049
Akaike Information Criterion: 10442.1
Bayesian Information Criterion: 10489.84
pandas_results = results.getEstimatedParameters()
pandas_results
Total running time of the script: (0 minutes 2.963 seconds)