Nested Logit Model for Mode and Departure time Choice

132 views
Skip to first unread message

Amin As

unread,
Mar 6, 2024, 3:11:07 AMMar 6
to Biogeme
Dear Michel, 
I want to do a nested logit model on the SP data that I have. 
I have 4 different modes including: Driving, Passenger, Ridesharing and Transit
and 3 departure times including: 30 mins Earlier, On time and 30 mins Later. 
So, a total of 12 alternatives. 
Now, my upper level nests are modes and lower levels are departure times. 
by writing the following code, I got all MUs less than 1, which makes my model invalid. 
I also tried to define departure times as upper level and modes as lower level, but I got the same issue, all MUs were less than one. 

Screenshot 2024-03-05 140335.png
Is there any way to fix it?

Michel Bierlaire

unread,
Mar 8, 2024, 4:04:47 AMMar 8
to ashn...@gmail.com, Michel Bierlaire, Biogeme
First, instead of grouping by mode, try grouping by deparure time.
But the correct thing to do is to specify a cross-nested logit model,

> On 5 Mar 2024, at 22:06, Amin As <ashn...@gmail.com> wrote:
>
> Dear Michel,
> I want to do a nested logit model on the SP data that I have.
> I have 4 different modes including: Driving, Passenger, Ridesharing and Transit
> and 3 departure times including: 30 mins Earlier, On time and 30 mins Later.
> So, a total of 12 alternatives.
> Now, my upper level nests are modes and lower levels are departure times.
> by writing the following code, I got all MUs less than 1, which makes my model invalid.
> I also tried to define departure times as upper level and modes as lower level, but I got the same issue, all MUs were less than one.
>
> <Screenshot 2024-03-05 140335.png>
> Is there any way to fix it?
>
> --
> You received this message because you are subscribed to the Google Groups "Biogeme" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to biogeme+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/biogeme/78899480-8cb0-406e-99f6-0a363bd7eea3n%40googlegroups.com.
> <Screenshot 2024-03-05 140335.png>

Michel Bierlaire
Transport and Mobility Laboratory
School of Architecture, Civil and Environmental Engineering
EPFL - Ecole Polytechnique Fédérale de Lausanne
http://transp-or.epfl.ch
http://people.epfl.ch/michel.bierlaire

Amin As

unread,
Mar 18, 2024, 3:41:53 AMMar 18
to Biogeme
Hi again Michel, 

I tried to do cross-nested as you advised. following is the way I modelled my problem. 
1. Did I do it correctly? I have divided my modes into: private and public; while I have set the departure times to: rigid and flexible. so, each alternative is exactly member of two nests. 
2. When I ran this code, the algorithm failed to converge as the number of iterations was set to 100 by default. How can I increase the number of iterations in the new biogeme version? I tried "cnl_results = biogeme.estimate(algoParameters={‘maxiter’:5000})", but I got error!

Thanks in advance for your help and support!
Amin


# Defining scale parameters for each nest
MU_Private = Beta('MU_Private', 1, 1, None, 0)
MU_Public = Beta('MU_Public', 1, 1, None, 0)

MU_Rigid = Beta('MU_Rigid', 1, 1, None, 0)
MU_Flex = Beta('MU_Flex', 1, 1, None, 0)

# Defining alpha parameters for mode nests (example values, adjust based on your model's needs)
ALPHA_Private0 = Beta('ALPHA_Private0', 0.5, 0, 1, 0)
ALPHA_Private1 = Beta('ALPHA_Private1', 0.5, 0, 1, 0)
ALPHA_Private2 = Beta('ALPHA_Private2', 0.5, 0, 1, 0)
ALPHA_Private3 = Beta('ALPHA_Private3', 0.5, 0, 1, 0)
ALPHA_Private4 = Beta('ALPHA_Private4', 0.5, 0, 1, 0)
ALPHA_Private5 = Beta('ALPHA_Private5', 0.5, 0, 1, 0)
ALPHA_Public6 = Beta('ALPHA_Public6', 0.5, 0, 1, 0)
ALPHA_Public7 = Beta('ALPHA_Public7', 0.5, 0, 1, 0)
ALPHA_Public8 = Beta('ALPHA_Public8', 0.5, 0, 1, 0)
ALPHA_Public9 = Beta('ALPHA_Public9', 0.5, 0, 1, 0)
ALPHA_Public10 = Beta('ALPHA_Public10', 0.5, 0, 1, 0)
ALPHA_Public11 = Beta('ALPHA_Public11', 0.5, 0, 1, 0)

ALPHA_Flex0 = 1- ALPHA_Private0
ALPHA_Rigid1 = 1-ALPHA_Private1
ALPHA_Flex2 = 1- ALPHA_Private2
ALPHA_Flex3 = 1- ALPHA_Private3
ALPHA_Rigid4 = 1-ALPHA_Private4
ALPHA_Flex5 = 1- ALPHA_Private5
ALPHA_Flex6 = 1- ALPHA_Public6
ALPHA_Rigid7 = 1-ALPHA_Public7
ALPHA_Flex8 = 1- ALPHA_Public8
ALPHA_Flex9 = 1- ALPHA_Public9
ALPHA_Rigid10 = 1-ALPHA_Public10
ALPHA_Flex11 = 1- ALPHA_Public11

alpha_private = {0: ALPHA_Private0, 1: ALPHA_Private1, 2: ALPHA_Private2, 3: ALPHA_Private3, 4: ALPHA_Private4, 5: ALPHA_Private5, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0}  
alpha_public = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: ALPHA_Public6, 7: ALPHA_Public7, 8: ALPHA_Public8, 9: ALPHA_Public9, 10: ALPHA_Public10, 11: ALPHA_Public11}
alpha_rigid = {0: 0, 1: ALPHA_Rigid1, 2: 0, 3: 0, 4: ALPHA_Rigid4, 5: 0, 6: 0, 7: ALPHA_Rigid7, 8: 0, 9: 0, 10: ALPHA_Rigid10, 11: 0}
alpha_flex = {0: ALPHA_Flex0, 1: 0, 2: ALPHA_Flex2, 3: ALPHA_Flex3, 4: 0, 5: ALPHA_Flex5, 6: ALPHA_Flex6, 7: 0, 8: ALPHA_Flex8, 9: ALPHA_Flex9, 10: 0, 11: ALPHA_Flex11}

# Define nests
nest_private = MU_Private, alpha_private
nest_public = MU_Public, alpha_public
nest_rigid = MU_Rigid, alpha_rigid
nest_flex = MU_Flex, alpha_flex

nests = nest_private, nest_public, nest_rigid, nest_flex  

# Specify the CNL model with availability conditions
logprob = models.logcnl_avail(V, av, nests, Choice)

# Estimate the parameters
biogeme = bio.BIOGEME(database, logprob)
biogeme.modelName = 'cnl'
cnl_results = biogeme.estimate()



Michel Bierlaire

unread,
Mar 18, 2024, 3:45:17 AMMar 18
to ashn...@gmail.com, Michel Bierlaire, Biogeme
The parameters are defined in the file biogeme.toml, in the section

[SimpleBounds]
second_derivatives = 1.0 # float: proportion (between 0 and 1) of iterations when
# the analytical Hessian is calculated
tolerance = 6.06273418136464e-06 # float: the algorithm stops when this precision
# is reached
max_iterations = 100 # int: maximum number of iterations <<<<<<<<<<<<<<<<<<<<<<<<<
infeasible_cg = "False" # If True, the conjugate gradient algorithm may generate
# infeasible solutions until termination. The result
# will then be projected on the feasible domain. If
# False, the algorithm stops as soon as an infeasible
# iterate is generated
initial_radius = 1 # Initial radius of the trust region
steptol = 1e-05 # The algorithm stops when the relative change in x is below this
# threshold. Basically, if p significant digits of x are needed,
# steptol should be set to 1.0e-p.
enlarging_factor = 10 # If an iteration is very successful, the radius of the
# trust region is multiplied by this factor

.
> To view this discussion on the web visit https://groups.google.com/d/msgid/biogeme/502d00c9-f2bc-40e6-b5b4-68213a913912n%40googlegroups.com.

Amin As

unread,
May 25, 2024, 3:36:34 AMMay 25
to Biogeme
Hi Dr.  Bierlaire
Regarding my previous questions, Can I run Mixed-Nested logit Model for this project in Biogeme?
I have tried the following code, but I got error:

#Mixed logit time heterogeneity

B_TIME_SL = Beta('B_TIME_SL', 1, None, None, 0)
B_TIMEC_RNDL = -exp(B_TIMEC + B_TIME_SL * bioDraws('B_TIMEC_RNDL', 'NORMAL'))
B_TIMEP_RNDL = -exp(B_TIMEP + B_TIME_SL * bioDraws('B_TIMEP_RNDL', 'NORMAL'))
B_TIMER_RNDL = -exp(B_TIMER + B_TIME_SL * bioDraws('B_TIMER_RNDL', 'NORMAL'))
B_TIMET_RNDL = -exp(B_TIMET + B_TIME_SL * bioDraws('B_TIMET_RNDL', 'NORMAL'))

#setting nests for different modes
MUD = Beta('MUD', 1, 1, None, 0)
MUP = Beta('MUP', 1, 1, None, 0)
MUR = Beta('MUR', 1, 1, None, 0)
MUT = Beta('MUT', 1, 1, None, 0)

Drive = OneNestForNestedLogit(nest_param=MUD, list_of_alternatives=[0,1,2], name='Drive')
Passenger = OneNestForNestedLogit(nest_param=MUP, list_of_alternatives=[3,4,5], name='Passenger')
Ridesharing = OneNestForNestedLogit(nest_param=MUR, list_of_alternatives=[6,7,8], name='Ridesharing')
Transit = OneNestForNestedLogit(nest_param=MUT, list_of_alternatives=[9,10,11], name='Transit')

nests = NestsForNestedLogit(choice_set=list(V), tuple_of_nests=(Drive, Passenger, Ridesharing, Transit))

#running the code
prob = models.lognested(V, av, nests, Choice)
logprob = log(MonteCarlo(prob))
biogeme = bio.BIOGEME(database, logprob, numberOfDraws=100)
biogeme.modelName = 'mixedlogitnormalnested'
results_mixedlogitnormalnested = biogeme.estimate()



Thanks, 
Amin

Michael Nassar

unread,
May 29, 2024, 2:20:39 AMMay 29
to ashn...@gmail.com, Biogeme

Michel Bierlaire

unread,
May 29, 2024, 2:23:44 AMMay 29
to ashn...@gmail.com, Michel Bierlaire, Biogeme


> On 24 May 2024, at 19:32, Amin As <ashn...@gmail.com> wrote:
>
> Hi Dr. Bierlaire
> Regarding my previous questions, Can I run Mixed-Nested logit Model for this project in Biogeme?

Yes. Although it is not necessarily simple to estimate.

> I have tried the following code, but I got error:

What kind of error?
> To view this discussion on the web visit https://groups.google.com/d/msgid/biogeme/8b02f4fa-52a9-4ec4-b9ad-fdcc680e7f9fn%40googlegroups.com.

Amin As

unread,
May 30, 2024, 1:54:58 AMMay 30
to Biogeme
The error message indicates that the log function encountered a non-positive number. I tried with different initial values but I got the same error each time.
This is the error message I got:


--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) Cell In[36], line 5 3 biogeme = bio.BIOGEME(database, logprob, numberOfDraws=numberOfDraws) 4 biogeme.modelName = 'mixedlogitnormalnested' ----> 5 results_mixedlogitnormalnested = biogeme.estimate() File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\biogeme\biogeme.py:1461, in BIOGEME.estimate(self, recycle, run_bootstrap, **kwargs) 1455 logger.info( 1456 f"*** Initial values of the parameters are " 1457 f"obtained from the file {self._saveIterationsFileName()}" 1458 ) 1459 self._loadSavedIteration() -> 1461 self.calculateInitLikelihood() 1462 self.bestIteration = None 1464 start_time = datetime.now() File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\biogeme\biogeme.py:947, in BIOGEME.calculateInitLikelihood(self) 939 """Calculate the value of the log likelihood function 940 941 The default values of the parameters are used. (...) 944 :rtype: float. 945 """ 946 # Value of the loglikelihood for the default values of the parameters. --> 947 self.initLogLike = self.calculateLikelihood( 948 self.id_manager.free_betas_values, scaled=False 949 ) 950 return self.initLogLike File ~\AppData\Local\Programs\Python\Python312\Lib\site-packages\biogeme\biogeme.py:991, in BIOGEME.calculateLikelihood(self, x, scaled, batch) 988 raise ValueError(error_msg) 990 self._prepareDatabaseForFormula() --> 991 f = self.theC.calculateLikelihood(x, self.id_manager.fixed_betas_values) 993 logger.debug(f"Log likelihood (N = {self.database.getSampleSize()}): {f:10.7g}") 995 if scaled: File src\\cythonbiogeme\\cpp\\cythonbiogeme.pyx:134, in cythonbiogeme.cythonbiogeme.pyBiogeme.calculateLikelihood() RuntimeError: src/cythonbiogeme/cpp/biogeme.cc:442: Biogeme exception: Error for data entry 0 : src/cythonbiogeme/cpp/bioExprLog.cc:56: Biogeme exception: Current values of the literals: ASC_DRIVE = 1.23 ASC_PASSENGER = 0 ASC_RIDESHARING = -0.75 ASC_TRANSIT = -0.37 Age18-24 = 0 Age25-34 = 1 Age65 = 0 B_Age65DO = 0 B_Age65TO = 0 B_AgeYoungE = 0 B_COST = -0.027 B_Early = -1.3172 B_EducationUniversityDO = 0 B_FreeParkDO = 0 B_GenderP = -0.356273 B_HouseholdsizeDO = 0 B_HouseholdsizePO = 0 B_IncomeHRO = 0 B_Late = -2.58004 B_NoVehicleR = 0.795643 B_NoVehicleT = 0.705743 B_RaceWhiteDO = 0 B_TIMEC = -0.0335238 B_TIMEP = 0 B_TIMER = -0.0416655 B_TIMET = -0.0213128 B_TIME_SL = 1 B_TOLL = -0.0251594 B_TransitUsualTO = 0 B_UberUsualRO = 0 B_VehicleOwnershipDO = 0 B_WAIT = -0.004 Choice = 10 Drive Cost = 3.4 Drive Park = 2.5 Drive Time Early = 9 Drive Time Late = 9 Drive Time On-Time = 10 Drive Toll Early = 0 Drive Toll Late = 0 Drive Toll On-Time = 0 DriveAv = 1 EducationUniversity = 1 Free Parking = 0 Household3+ = 0 Income110-150 = 0 Income150 = 0 MUD = 1 MUP = 1 MUR = 1 MUT = 1 Male = 1 Pass Cost = 1.7 Pass Park = 1.3 Pass Time Early = 9 Pass Time Late = 9 Pass Time On-Time = 10 Pass Toll Early = 0 Pass Toll Late = 0 Pass Toll OnTime = 0 Pass Wait = 8 PassAv = 1 Race White = 0 Ride Cost = 3.4 Ride Time Early = 11 Ride Time Late = 10 Ride Time On-Time = 12 Ride Toll Early = 0 Ride Toll Late = 0 Ride Toll On-Time = 0 Ride Wait = 5 RideAv = 1 Transit Cost = 1 Transit Time Early = 20 Transit Time Late = 18 Transit Time On-Time = 21 Transit Wait Early = 14 Transit Wait Late = 15 Transit Wait On-Time = 15 TransitAv = 1 TransitUsual = 0 UberUsual = 0 Vehicle0 = 0 Vehicle2 = 0 Vehicle3+ = 0 row number: 0, Cannot take the log of a non positive number [-39.227]
[ ]:


Michel Bierlaire

unread,
May 30, 2024, 2:06:59 AMMay 30
to ashn...@gmail.com, Michel Bierlaire, Biogeme
First, try to set a lower bound on the scale parameter, and start with a large value:
B_TIME_SL = Beta('B_TIME_SL', 100, 0.1, None, 0)

If it does not work, use the simulation mode to detect which observation causes the problem, and why,so that you can address the isse.
> To view this discussion on the web visit https://groups.google.com/d/msgid/biogeme/04cc7cfe-094f-4b6f-ad6f-e3fd365cb41dn%40googlegroups.com.

tran...@gmail.com

unread,
Jun 10, 2024, 3:09:19 AMJun 10
to Biogeme
Hi Prof Bierlaire,

I got the same error with my model after installing the current version of Biogeme (3.2.13). 
My model was run without any error with the previous version. Is there any solution so far to fix this error?

Thank you.
Best regard,
Tran

Vào lúc 13:06:59 UTC+7 ngày Thứ Năm, 30 tháng 5, 2024, michel.b...@epfl.ch đã viết:

Michel Bierlaire

unread,
Jun 10, 2024, 3:12:34 AMJun 10
to tran...@gmail.com, Michel Bierlaire, Biogeme
The error is clear:
Cannot take the log of a non positive number [-39.227]
The simulation mode should help you detect the source of the problem.
> To view this discussion on the web visit https://groups.google.com/d/msgid/biogeme/c1086b96-af27-4d43-903b-896a3845ab4bn%40googlegroups.com.

Michael Nassar

unread,
Jun 11, 2024, 7:51:56 AMJun 11
to michel.b...@epfl.ch, ashn...@gmail.com, Biogeme

Michel Bierlaire

unread,
Jun 11, 2024, 8:08:48 AMJun 11
to tran...@gmail.com, Michel Bierlaire, Biogeme
Your error is to integrate the log of the logit instead of the logit. The log of a probability is always negative.

condprob = models.logit(V, None, Choice)
instead of
condprob = models.loglogit(V, None, Choice)


> On 10 Jun 2024, at 09:57, tran...@gmail.com wrote:
>
> Dear Prof Bierlaire,
>
> Thank you so much for your response.
>
> So far, I haven't found the issue. Please help to have a look at my script and data as attached.
> I ran this model four years ago with the data without any errors.
>
> Appreciate your support.
>
> Thank you.
> Tran
>
>
> Vào Th 2, 10 thg 6, 2024 vào lúc 14:13 Michel Bierlaire <michel.b...@epfl.ch> đã viết:
> If you don't find the problem, send me the script and the data in a zipped file, in a private email. I'll have a look.
>
>
> > On 10 Jun 2024, at 08:41, tran...@gmail.com <tran...@gmail.com> wrote:
> >
> > Cannot take the log of a non positive number [-39.227]
>
>
> Michel Bierlaire
> Transport and Mobility Laboratory
> School of Architecture, Civil and Environmental Engineering
> EPFL - Ecole Polytechnique Fédérale de Lausanne
> http://transp-or.epfl.ch
> http://people.epfl.ch/michel.bierlaire
>
>
>
> --
> Vanduy, Tran
Mixed MNL.zip
Reply all
Reply to author
Forward
0 new messages