biogeme.models: examples of use

This webpage is for programmers who need examples of use of the functions of the class. The examples are designed to illustrate the syntax. They do not correspond to any meaningful model. For examples of models, visit biogeme.epfl.ch.

In [1]:
import datetime
print(datetime.datetime.now())
2019-12-29 21:18:23.490683
In [2]:
import biogeme.version as ver
print(ver.getText())
biogeme 3.2.5 [2019-12-29]
Version entirely written in Python
Home page: http://biogeme.epfl.ch
Submit questions to https://groups.google.com/d/forum/biogeme
Michel Bierlaire, Transport and Mobility Laboratory, Ecole Polytechnique Fédérale de Lausanne (EPFL)

In [3]:
import numpy as np
import pandas as pd
import biogeme.database as db
import biogeme.models as models
import matplotlib.pyplot as plt

Definition of a database

In [4]:
df = pd.DataFrame({'Person':[1,1,1,2,2],
                   'Exclude':[0,0,1,0,1],
                   'Variable1':[1,2,3,4,5],
                   'Variable2':[10,20,30,40,50],
                   'Choice':[1,2,3,1,2],
                   'Av1':[0,1,1,1,1],
                   'Av2':[1,1,1,1,1],
                   'Av3':[0,1,1,1,1]})
myData = db.Database('test',df)

Piecewise linear specification

In [5]:
from biogeme.expressions import *

A piecewise linear specification (sometimes called 'spline') is a continuous but not differentiable function of the variable. It is defined based on thresholds. Between two thresholds, the function is linear. And the slope is changing after each threshold. Consider a variable $t$ and an interval $[a,a+b]$. We define a new variable $$ x_{[a,b]}(t) = \max(0,\min(t-a,b)) = \left\{ \begin{array}{ll} 0 & \text{if } t < a, \\ t-a & \text{if } a \leq t < a+b, \\ b & \text{otherwise}. \end{array} \right. $$ For each interval $]-\infty,a]$, we have $$ x_{]-\infty,a]}(t) = \min(t,a) = \left\{ \begin{array}{ll} t & \text{if } t < a, \\ a & \text{otherwise}. \end{array} \right.. $$ For each interval $[a,+\infty[$, we have $$ x_{]-\infty,a]}(t) = \max(0,t-a) = \left\{ \begin{array}{ll} 0& \text{if } t < a, \\ t-a & \text{otherwise}. \end{array} \right.. $$ If we consider a series of threshold $$\alpha_1 < \alpha_2 < \ldots <\alpha_K,$$ the piecewise linear transform of variable $t$ is $$ \sum_{k=1}^{K-1} \beta_k x_{[\alpha_k,\alpha_{k+1}]},$$ where $\beta_k$ is the slope of the linear function in interval $[\alpha_k,\alpha_{k+1}]$.

The next statement generates the variables, given the thresholds. A 'None' is equivalent to $\infty$, and can only appear first (and it means $-\infty$) or last (and it means $+\infty$).

In [6]:
x = Variable('x')
thresholds = [None,90,180,270,None]
variables = models.piecewiseVariables(x,thresholds)
print(variables)
[bioMin(x,`90`), bioMax(`0`,bioMin((x - `90`),`90`)), bioMax(`0`,bioMin((x - `180`),`90`)), bioMax(`0`,(x - `270`))]

The next statement automatically generates the formula, including the Beta parameters, that are initialized to zero.

In [7]:
formula = models.piecewiseFormula(x,thresholds)
print(formula)
bioMultSum((beta_x_lessthan_90(0) * bioMin(x,`90`)) + (beta_x_90_180(0) * bioMax(`0`,bioMin((x - `90`),`90`))) + (beta_x_180_270(0) * bioMax(`0`,bioMin((x - `180`),`90`))) + (beta_x_270_more(0) * bioMax(`0`,(x - `270`))))

It is also possible to initialize the Beta parameters with other values.

In [8]:
betas = [-0.016806308,-0.010491137,-0.002012234,-0.020051303]
formula = models.piecewiseFormula(x,thresholds,betas)
print(formula)
bioMultSum((beta_x_lessthan_90(-0.016806308) * bioMin(x,`90`)) + (beta_x_90_180(-0.010491137) * bioMax(`0`,bioMin((x - `90`),`90`))) + (beta_x_180_270(-0.002012234) * bioMax(`0`,bioMin((x - `180`),`90`))) + (beta_x_270_more(-0.002012234) * bioMax(`0`,(x - `270`))))

We provide a plot of a piecewise linear specification.

In [9]:
X = np.arange(0,300,0.1)
Y = [models.piecewiseFunction(x,thresholds,[-0.016806308,-0.010491137,-0.002012234,-0.020051303]) for x in X]
plt.plot(X,Y)
Out[9]:
[<matplotlib.lines.Line2D at 0x11d53b550>]

Logit

In [10]:
V = {1:Variable('Variable1'), 2:0.1, 3:-0.1} 
av = {1:1, 2:0, 3:1}

Calculation of the (log of the) logit for the three alternatives, based on their availability.

In [11]:
p1 = models.logit(V,av,1)
p1.getValue_c(myData)
Out[11]:
[0.7502601058743209,
 0.8909031789492188,
 0.9568927451203795,
 0.9836975006524559,
 0.9939401985173909]
In [12]:
p1 = models.loglogit(V,av,1)
p1.getValue_c(myData)
Out[12]:
[-0.2873353247432888,
 -0.11551952301718771,
 -0.044063967874339305,
 -0.016436847228616713,
 -0.00607823659274942]
In [13]:
p2 = models.logit(V,av,2)
p2.getValue_c(myData)
Out[13]:
[0.0, 0.0, 0.0, 0.0, 0.0]
In [14]:
p2 = models.loglogit(V,av,2)
p2.getValue_c(myData)
Out[14]:
[-inf, -inf, -inf, -inf, -inf]
In [15]:
p3 = models.logit(V,av,3)
p3.getValue_c(myData)
Out[15]:
[0.24973989412567965,
 0.10909682105078158,
 0.043107254879620284,
 0.016302499347544356,
 0.006059801482609025]
In [16]:
p3 = models.loglogit(V,av,3)
p3.getValue_c(myData)
Out[16]:
[-1.387335326233405,
 -2.215519524507304,
 -3.1440639693644554,
 -4.116436848718733,
 -5.1060782380828655]

Calculation of the log of the logit for the three alternatives, assuming that they are all available.

In [17]:
pa1 = models.logit(V,av=None,i=1)
pa1.getValue_c(myData)
Out[17]:
[0.5748974224669351,
 0.786148041622905,
 0.9090310597545885,
 0.964492603287176,
 0.9866376411916378]
In [18]:
pa1 = models.loglogit(V,av=None,i=1)
pa1.getValue_c(myData)
Out[18]:
[-0.5535636498088721,
 -0.24061015616746673,
 -0.09537601624144809,
 -0.03615311562669721,
 -0.01345243847602795]
In [19]:
pa2 = models.logit(V,av=None,i=2)
pa2.getValue_c(myData)
Out[19]:
[0.2337358497864228,
 0.11758307726532896,
 0.05001781611351815,
 0.019523173894964156,
 0.007347079166982375]
In [20]:
pa2 = models.loglogit(V,av=None,i=2)
pa2.getValue_c(myData)
Out[20]:
[-1.453563648318756,
 -2.1406101546773506,
 -2.995376014751332,
 -3.936153114136581,
 -4.913452436985912]
In [21]:
pa3 = models.logit(V,av=None,i=3)
pa3.getValue_c(myData)
Out[21]:
[0.1913667277466427,
 0.09626888111176568,
 0.04095112413189287,
 0.015984222817859703,
 0.006015279641380101]
In [22]:
pa3 = models.loglogit(V,av=None,i=3)
pa3.getValue_c(myData)
Out[22]:
[-1.6535636512989882,
 -2.340610157657583,
 -3.195376017731564,
 -4.136153117116813,
 -5.113452439966144]

Boxcox transform

The Box-Cox transform of a variable $x$ is defined as $$B(x,\ell) = \frac{x^{\ell}-1}{\ell},$$ where $\ell > 0$ is a parameter that can be estimated from data. It has the property that $$\lim_{\ell \to 0} B(x,\ell)=\log(x).$$

In [23]:
x = Variable('Variable1')
models.boxcox(x,4)
Out[23]:
(((Variable1 ** `4`) - `1.0`) / `4`)
In [24]:
x = Variable('Variable1')
models.boxcox(x,0)
Out[24]:
log(Variable1)
In [25]:
l = Variable('Variable2')
e = models.boxcox(x,l)
print(e)
{{0:(((Variable1 ** Variable2) - `1.0`) / Variable2),1:log(Variable1)}[(Variable2 < `1.4901161193847656e-08`)]
In [26]:
e.getValue_c(myData)
Out[26]:
[0.0,
 52428.75,
 6863037736488.267,
 3.022314549036573e+22,
 1.7763568394002505e+33]
In [27]:
for l in range(1,16):
    print(f'l=l0^(-{l}): {models.boxcox(3,10**-l)} - {np.log(3)} = {models.boxcox(3,10**-l) - np.log(3)}')
l=l0^(-1): 1.1612317403390437 - 1.0986122886681098 = 0.06261945167093397
l=l0^(-2): 1.104669193785357 - 1.0986122886681098 = 0.006056905117247213
l=l0^(-3): 1.0992159842040383 - 1.0986122886681098 = 0.000603695535928539
l=l0^(-4): 1.0986726383266365 - 1.0986122886681098 = 6.034965852674823e-05
l=l0^(-5): 1.0986183234251712 - 1.0986122886681098 = 6.034757061401663e-06
l=l0^(-6): 1.0986128922141347 - 1.0986122886681098 = 6.035460249353974e-07
l=l0^(-7): 1.0986123499812095 - 1.0986122886681098 = 6.131309970847099e-08
l=l0^(-8): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-9): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-10): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-11): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-12): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-13): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-14): 1.0986122886681098 - 1.0986122886681098 = 0.0
l=l0^(-15): 1.0986122886681098 - 1.0986122886681098 = 0.0

MEV models

MEV models are defined as $$\frac{e^{V_i + \ln G_i(e^{V_1},\ldots,e^{V_J})}}{\sum_j e^{V_j + \ln G_j(e^{V_1},\ldots,e^{V_J})}},$$ where $G$ is a generating function, and $$G_i=\frac{\partial G}{\partial y_i}(e^{V_1},\ldots,e^{V_J})$$

Nested logit model

The $G$ function for the nested logit model is defined such that $$G_i=\frac{\partial G}{\partial y_i}(e^{V_1},\ldots,e^{V_J}) = \mu e^{(\mu_m-1)V_i} \left(\sum_{i=1}^{J_m} e^{\mu_m V_i}\right)^{\frac{\mu}{\mu_m}-1},$$ where the choice set is partitioned into $J_m$ nests, each associated with a parameter $\mu_m$, and $\mu$ is the scale parameter. The condition is $0 \leq \mu \leq \mu_m$ must be verified. In general, $\mu$ is normalized to 1.0.

In [28]:
V = {1:Variable('Variable1'), 2:0.1, 3:-0.1, 4:-0.2, 5:0.2 }
av = {1:1, 2:0, 3:1, 4:1, 5:1}
nestA = 1.2, [1,2,4]
nestB = 2.3, [3,5]
In [29]:
p1 = models.nested(V,availability=av,nests=(nestA,nestB),choice=1)
p1.getValue_c(myData)
Out[29]:
[0.5578902807433072,
 0.7868463084429763,
 0.9138115025822288,
 0.9678685668603005,
 0.9883631800048074]

If all the alternatives are available, define the availability dictionary as None.

In [30]:
p1 = models.nested(V,availability=None,nests=(nestA,nestB),choice=1)
p1.getValue_c(myData)
Out[30]:
[0.4640404743246681,
 0.7266195584511863,
 0.8885046327706988,
 0.9592159992110431,
 0.9856361499787969]
In [31]:
p2 = models.lognested(V,availability=av,nests=(nestA,nestB),choice=1)
p2.getValue_c(myData)
Out[31]:
[-0.5835929654272203,
 -0.2397223375101296,
 -0.09013096229569495,
 -0.032658978961111806,
 -0.011705057681341557]
In [32]:
p2 = models.lognested(V,availability=None,nests=(nestA,nestB),choice=1)
p2.getValue_c(myData)
Out[32]:
[-0.767783501412131,
 -0.3193522417879944,
 -0.11821541725279872,
 -0.041638995663314304,
 -0.014468008731436832]

If the value of the parameter $\mu$ is not 1, there is another function to call. Note that, for the sake of computational efficiency, it is not verified by the code if the condition $$0 \leq \mu \leq \mu_m$$ is verified.

In [33]:
p1 = models.nestedMevMu(V,availability=av,nests=(nestA,nestB),choice=1,mu=1.1)
p1.getValue_c(myData)
Out[33]:
[0.571515982233625,
 0.8064339470846187,
 0.9281474313936063,
 0.9755474984955133,
 0.991929502399578]
In [34]:
p1 = models.nestedMevMu(V,availability=None,nests=(nestA,nestB),choice=1,mu=1.1)
p1.getValue_c(myData)
Out[34]:
[0.4762357879291408,
 0.7442702929692306,
 0.9022330455719387,
 0.9667826523447208,
 0.9891858426536316]
In [35]:
p1 = models.lognestedMevMu(V,availability=av,nests=(nestA,nestB),choice=1,mu=1.1)
p1.getValue_c(myData)
Out[35]:
[-0.5594628307251295,
 -0.21513328547194988,
 -0.07456468877823053,
 -0.024756428668673003,
 -0.00810324035203891]
In [36]:
p1 = models.lognestedMevMu(V,availability=None,nests=(nestA,nestB),choice=1,mu=1.1)
p1.getValue_c(myData)
Out[36]:
[-0.7418421946050984,
 -0.295351013123768,
 -0.10288242691101068,
 -0.033781573689133815,
 -0.010873055352343286]

The validity of the nested structure can be verified.

In [37]:
models.checkValidityNestedLogit(V,(nestA,nestB))
Out[37]:
(True, 'The nested logit model is based on a partition. ')

If one alternative does not belong to any nest...

In [38]:
nestA = 1.2, [1,4]
nestB = 2.3, [3,5]
models.checkValidityNestedLogit(V,(nestA,nestB))
Out[38]:
(False,
 'The nested logit model is based on a partition. Alternatives in the choice set, but not in any nest: {2}\n')

If an alternative belongs to two nests

In [39]:
nestA = 1.2, [1,2,3,4]
nestB = 2.3, [3,5]
models.checkValidityNestedLogit(V,(nestA,nestB))
Out[39]:
(False,
 'The nested logit model is based on a partition. Two nests contain the following alternative(s): {3}\nTwo nests contain the following alternative(s): {3}\n')

Cross-nested logit model

The $G$ function for the cross nested logit model is defined such that $$G_i=\frac{\partial G}{\partial y_i}(e^{V_1},\ldots,e^{V_J}) = \mu \sum_{m=1}^{M} \alpha_{im}^{\frac{\mu_m}{\mu}} e^{(\mu_m-1) V_i}\left( \sum_{j=1}^{J} \alpha_{jm}^{\frac{\mu_m}{\mu}} e^{\mu_m V_j} \right)^{\frac{\mu}{\mu_m}-1},$$ where each nest $m$ is associated with a parameter $\mu_m$ and, for each alternative $i$, a parameter $\alpha_{im} \geq 0$ that captures the degree of membership of alternative $i$ to nest $m$. $\mu$ is the scale parameter. For each alternative $i$, there must be at least one nest $m$ such that $\alpha_{im}>0$. The condition is $0 \leq \mu \leq \mu_m$ must be also verified. In general, $\mu$ is normalized to 1.0.

In [40]:
V = {1:Variable('Variable1'), 2:0.1, 3:-0.1, 4:-0.2, 5:0.2 }
av = {1:1, 2:0, 3:1, 4:1, 5:1}
alphaA = {1:1, 2:1, 3:0.5, 4:0, 5:0}
alphaB = {1:0, 2:0, 3:0.5, 4:1, 5:1}
nestA = 1.2, alphaA
nestB = 2.3, alphaB
In [41]:
p1 = models.cnl(V,availability=av,nests=(nestA,nestB),choice=1)
p1.getValue_c(myData)
Out[41]:
[0.6016107584485123,
 0.8108041306905538,
 0.9231765502321484,
 0.9709891867942788,
 0.9893390254981359]

If all the alternatives are available, define the availability dictionary as None.

In [42]:
p1 = models.cnl(V,availability=None,nests=(nestA,nestB),choice=1)
p1.getValue_c(myData)
Out[42]:
[0.4934592795712728,
 0.7469558260955984,
 0.897353160521319,
 0.9622808946939261,
 0.9866066131596022]

If the value of the parameter $\mu$ is not 1, there is another function to call. Note that, for the sake of computational efficiency, it is not verified by the code if the condition $$0 \leq \mu \leq \mu_m$$ is verified.

In [43]:
p1 = models.cnlmu(V,availability=av,nests=(nestA,nestB),choice=1,mu=1.1)
p1.getValue_c(myData)
Out[43]:
[0.6110353981400448,
 0.8286540022678524,
 0.9367570385747355,
 0.9783775241112526,
 0.9928053581656079]
In [44]:
p1 = models.cnlmu(V,availability=None,nests=(nestA,nestB),choice=1,mu=1.1)
p1.getValue_c(myData)
Out[44]:
[0.5031397449964665,
 0.7631318370685222,
 0.9103649098609138,
 0.9695618814330564,
 0.9900568500377006]

If the sample is endogenous, a correstion must be included in the model, as proposed by Bierlaire, Bolduc and McFadden (2008). In this case, the generating function must first be defined, and the MEV model with correction is then called.

In [45]:
logGi = models.getMevForCrossNested(V,availability=av,nests=(nestA,nestB))
logGi
Out[45]:
{1: log(bioMultSum(((`1.0` * exp((`0.19999999999999996` * Variable1))) * (bioMultSum((`1.0` * exp((`1.2` * Variable1))) + (`0.0` * exp(`0.12`)) + (`0.43527528164806206` * exp(`-0.12`)) + (`0.0` * exp(`-0.24`)) + (`0.0` * exp(`0.24`))) ** `-0.16666666666666663`)) + ((`0.0` * exp((`1.2999999999999998` * Variable1))) * (bioMultSum((`0.0` * exp((`2.3` * Variable1))) + (`0.0` * exp(`0.22999999999999998`)) + (`0.2030630990890589` * exp(`-0.22999999999999998`)) + (`1.0` * exp(`-0.45999999999999996`)) + (`1.0` * exp(`0.45999999999999996`))) ** `-0.5652173913043478`)))),
 2: log(bioMultSum(((`1.0` * exp(`0.019999999999999997`)) * (bioMultSum((`1.0` * exp((`1.2` * Variable1))) + (`0.0` * exp(`0.12`)) + (`0.43527528164806206` * exp(`-0.12`)) + (`0.0` * exp(`-0.24`)) + (`0.0` * exp(`0.24`))) ** `-0.16666666666666663`)) + ((`0.0` * exp(`0.12999999999999998`)) * (bioMultSum((`0.0` * exp((`2.3` * Variable1))) + (`0.0` * exp(`0.22999999999999998`)) + (`0.2030630990890589` * exp(`-0.22999999999999998`)) + (`1.0` * exp(`-0.45999999999999996`)) + (`1.0` * exp(`0.45999999999999996`))) ** `-0.5652173913043478`)))),
 3: log(bioMultSum(((`0.43527528164806206` * exp(`-0.019999999999999997`)) * (bioMultSum((`1.0` * exp((`1.2` * Variable1))) + (`0.0` * exp(`0.12`)) + (`0.43527528164806206` * exp(`-0.12`)) + (`0.0` * exp(`-0.24`)) + (`0.0` * exp(`0.24`))) ** `-0.16666666666666663`)) + ((`0.2030630990890589` * exp(`-0.12999999999999998`)) * (bioMultSum((`0.0` * exp((`2.3` * Variable1))) + (`0.0` * exp(`0.22999999999999998`)) + (`0.2030630990890589` * exp(`-0.22999999999999998`)) + (`1.0` * exp(`-0.45999999999999996`)) + (`1.0` * exp(`0.45999999999999996`))) ** `-0.5652173913043478`)))),
 4: log(bioMultSum(((`0.0` * exp(`-0.039999999999999994`)) * (bioMultSum((`1.0` * exp((`1.2` * Variable1))) + (`0.0` * exp(`0.12`)) + (`0.43527528164806206` * exp(`-0.12`)) + (`0.0` * exp(`-0.24`)) + (`0.0` * exp(`0.24`))) ** `-0.16666666666666663`)) + ((`1.0` * exp(`-0.25999999999999995`)) * (bioMultSum((`0.0` * exp((`2.3` * Variable1))) + (`0.0` * exp(`0.22999999999999998`)) + (`0.2030630990890589` * exp(`-0.22999999999999998`)) + (`1.0` * exp(`-0.45999999999999996`)) + (`1.0` * exp(`0.45999999999999996`))) ** `-0.5652173913043478`)))),
 5: log(bioMultSum(((`0.0` * exp(`0.039999999999999994`)) * (bioMultSum((`1.0` * exp((`1.2` * Variable1))) + (`0.0` * exp(`0.12`)) + (`0.43527528164806206` * exp(`-0.12`)) + (`0.0` * exp(`-0.24`)) + (`0.0` * exp(`0.24`))) ** `-0.16666666666666663`)) + ((`1.0` * exp(`0.25999999999999995`)) * (bioMultSum((`0.0` * exp((`2.3` * Variable1))) + (`0.0` * exp(`0.22999999999999998`)) + (`0.2030630990890589` * exp(`-0.22999999999999998`)) + (`1.0` * exp(`-0.45999999999999996`)) + (`1.0` * exp(`0.45999999999999996`))) ** `-0.5652173913043478`))))}
In [46]:
correction = {1:-0.1, 2:0.1, 3:0.2, 4:-0.2, 5:0}
p1 = models.mev_endogenousSampling(V,logGi,av,correction,choice=1) 
p1.getValue_c(myData)
Out[46]:
[0.5746072240749459,
 0.7941580542348711,
 0.9158433919531815,
 0.9682229374475843,
 0.9883533124960259]
In [47]:
correction = {1:-0.1, 2:0.1, 3:0.2, 4:-0.2, 5:0}
p1 = models.logmev_endogenousSampling(V,logGi,av,correction,choice=1) 
p1.getValue_c(myData)
Out[47]:
[-0.5540685601613919,
 -0.2304727767957555,
 -0.08790989840838126,
 -0.03229291094164832,
 -0.011715041418330685]
In [48]:
correction = {1:-0.1, 2:0.1, 3:0.2, 4:-0.2, 5:0}
p1 = models.mev_endogenousSampling(V,logGi,av=None,correction=correction,choice=1) 
p1.getValue_c(myData)
Out[48]:
[0.46401513036213726,
 0.7224778913810144,
 0.8853333953129141,
 0.957713686118543,
 0.9850300164944686]
In [49]:
correction = {1:-0.1, 2:0.1, 3:0.2, 4:-0.2, 5:0}
p1 = models.logmev_endogenousSampling(V,logGi,av=None,correction=correction,choice=1) 
p1.getValue_c(myData)
Out[49]:
[-0.7678381187484398,
 -0.32506845962843034,
 -0.12179098704686808,
 -0.04320641194526775,
 -0.01508316467591353]

The MEV generating function for the following models are available.

Nested logit model

In [50]:
V = {1:Variable('Variable1'), 2:0.1, 3:-0.1, 4:-0.2, 5:0.2 }
av = {1:1, 2:0, 3:1, 4:1, 5:1}
nestA = Beta('muA',1.2,1.0,None,0), [1,2,4]
nestB = Beta('muB',2.3,1.0,None,0), [3,5]
In [51]:
logGi = models.getMevForNested(V,availability=None,nests=(nestA,nestB))
logGi
Out[51]:
{1: (((muA(1.2) - `1.0`) * Variable1) + (((`1.0` / muA(1.2)) - `1.0`) * log(bioMultSum(exp((muA(1.2) * Variable1)) + exp((muA(1.2) * `0.1`)) + exp((muA(1.2) * `-0.2`)))))),
 2: (((muA(1.2) - `1.0`) * `0.1`) + (((`1.0` / muA(1.2)) - `1.0`) * log(bioMultSum(exp((muA(1.2) * Variable1)) + exp((muA(1.2) * `0.1`)) + exp((muA(1.2) * `-0.2`)))))),
 4: (((muA(1.2) - `1.0`) * `-0.2`) + (((`1.0` / muA(1.2)) - `1.0`) * log(bioMultSum(exp((muA(1.2) * Variable1)) + exp((muA(1.2) * `0.1`)) + exp((muA(1.2) * `-0.2`)))))),
 3: (((muB(2.3) - `1.0`) * `-0.1`) + (((`1.0` / muB(2.3)) - `1.0`) * log(bioMultSum(exp((muB(2.3) * `-0.1`)) + exp((muB(2.3) * `0.2`)))))),
 5: (((muB(2.3) - `1.0`) * `0.2`) + (((`1.0` / muB(2.3)) - `1.0`) * log(bioMultSum(exp((muB(2.3) * `-0.1`)) + exp((muB(2.3) * `0.2`))))))}

And with the $\mu$ parameter

In [52]:
logGi = models.getMevForNestedMu(V,availability=None,nests=(nestA,nestB),mu=1.1)
logGi
Out[52]:
{1: ((log(`1.1`) + ((muA(1.2) - `1.0`) * Variable1)) + (((`1.1` / muA(1.2)) - `1.0`) * log(bioMultSum(exp((muA(1.2) * Variable1)) + exp((muA(1.2) * `0.1`)) + exp((muA(1.2) * `-0.2`)))))),
 2: ((log(`1.1`) + ((muA(1.2) - `1.0`) * `0.1`)) + (((`1.1` / muA(1.2)) - `1.0`) * log(bioMultSum(exp((muA(1.2) * Variable1)) + exp((muA(1.2) * `0.1`)) + exp((muA(1.2) * `-0.2`)))))),
 4: ((log(`1.1`) + ((muA(1.2) - `1.0`) * `-0.2`)) + (((`1.1` / muA(1.2)) - `1.0`) * log(bioMultSum(exp((muA(1.2) * Variable1)) + exp((muA(1.2) * `0.1`)) + exp((muA(1.2) * `-0.2`)))))),
 3: ((log(`1.1`) + ((muB(2.3) - `1.0`) * `-0.1`)) + (((`1.1` / muB(2.3)) - `1.0`) * log(bioMultSum(exp((muB(2.3) * `-0.1`)) + exp((muB(2.3) * `0.2`)))))),
 5: ((log(`1.1`) + ((muB(2.3) - `1.0`) * `0.2`)) + (((`1.1` / muB(2.3)) - `1.0`) * log(bioMultSum(exp((muB(2.3) * `-0.1`)) + exp((muB(2.3) * `0.2`))))))}

Cross nested logit model

In [53]:
V = {1:Variable('Variable1'), 2:0.1, 3:-0.1, 4:-0.2, 5:0.2 }
av = {1:1, 2:0, 3:1, 4:1, 5:1}
alphaA = {1:1, 2:1, 3:0.5, 4:0, 5:0}
alphaB = {1:0, 2:0, 3:0.5, 4:1, 5:1}
nestA = Beta('muA',1.2,1.0,None,0), alphaA
nestB = Beta('muB',2.3,1.0,None,0), alphaB
In [54]:
logGi = models.getMevForCrossNested(V,availability=None,nests=(nestA,nestB))
logGi
Out[54]:
{1: log(bioMultSum((((`1` ** muA(1.2)) * exp(((muA(1.2) - `1`) * Variable1))) * (bioMultSum(((`1` ** muA(1.2)) * exp((muA(1.2) * Variable1))) + ((`1` ** muA(1.2)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** muA(1.2)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `0.2`)))) ** ((`1.0` / muA(1.2)) - `1.0`))) + (((`0` ** muB(2.3)) * exp(((muB(2.3) - `1`) * Variable1))) * (bioMultSum(((`0` ** muB(2.3)) * exp((muB(2.3) * Variable1))) + ((`0` ** muB(2.3)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** muB(2.3)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `0.2`)))) ** ((`1.0` / muB(2.3)) - `1.0`))))),
 2: log(bioMultSum((((`1` ** muA(1.2)) * exp(((muA(1.2) - `1`) * `0.1`))) * (bioMultSum(((`1` ** muA(1.2)) * exp((muA(1.2) * Variable1))) + ((`1` ** muA(1.2)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** muA(1.2)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `0.2`)))) ** ((`1.0` / muA(1.2)) - `1.0`))) + (((`0` ** muB(2.3)) * exp(((muB(2.3) - `1`) * `0.1`))) * (bioMultSum(((`0` ** muB(2.3)) * exp((muB(2.3) * Variable1))) + ((`0` ** muB(2.3)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** muB(2.3)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `0.2`)))) ** ((`1.0` / muB(2.3)) - `1.0`))))),
 3: log(bioMultSum((((`0.5` ** muA(1.2)) * exp(((muA(1.2) - `1`) * `-0.1`))) * (bioMultSum(((`1` ** muA(1.2)) * exp((muA(1.2) * Variable1))) + ((`1` ** muA(1.2)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** muA(1.2)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `0.2`)))) ** ((`1.0` / muA(1.2)) - `1.0`))) + (((`0.5` ** muB(2.3)) * exp(((muB(2.3) - `1`) * `-0.1`))) * (bioMultSum(((`0` ** muB(2.3)) * exp((muB(2.3) * Variable1))) + ((`0` ** muB(2.3)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** muB(2.3)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `0.2`)))) ** ((`1.0` / muB(2.3)) - `1.0`))))),
 4: log(bioMultSum((((`0` ** muA(1.2)) * exp(((muA(1.2) - `1`) * `-0.2`))) * (bioMultSum(((`1` ** muA(1.2)) * exp((muA(1.2) * Variable1))) + ((`1` ** muA(1.2)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** muA(1.2)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `0.2`)))) ** ((`1.0` / muA(1.2)) - `1.0`))) + (((`1` ** muB(2.3)) * exp(((muB(2.3) - `1`) * `-0.2`))) * (bioMultSum(((`0` ** muB(2.3)) * exp((muB(2.3) * Variable1))) + ((`0` ** muB(2.3)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** muB(2.3)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `0.2`)))) ** ((`1.0` / muB(2.3)) - `1.0`))))),
 5: log(bioMultSum((((`0` ** muA(1.2)) * exp(((muA(1.2) - `1`) * `0.2`))) * (bioMultSum(((`1` ** muA(1.2)) * exp((muA(1.2) * Variable1))) + ((`1` ** muA(1.2)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** muA(1.2)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** muA(1.2)) * exp((muA(1.2) * `0.2`)))) ** ((`1.0` / muA(1.2)) - `1.0`))) + (((`1` ** muB(2.3)) * exp(((muB(2.3) - `1`) * `0.2`))) * (bioMultSum(((`0` ** muB(2.3)) * exp((muB(2.3) * Variable1))) + ((`0` ** muB(2.3)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** muB(2.3)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** muB(2.3)) * exp((muB(2.3) * `0.2`)))) ** ((`1.0` / muB(2.3)) - `1.0`)))))}

Cross nested logit model with $\mu$ parameter

In [55]:
logGi = models.getMevForCrossNestedMu(V,availability=None,nests=(nestA,nestB),mu=1.1)
logGi
Out[55]:
{1: log((`1.1` * bioMultSum((((`1` ** (muA(1.2) / `1.1`)) * exp(((muA(1.2) - `1`) * Variable1))) * (bioMultSum(((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * Variable1))) + ((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.2`)))) ** ((`1.1` / muA(1.2)) - `1.0`))) + (((`0` ** (muB(2.3) / `1.1`)) * exp(((muB(2.3) - `1`) * Variable1))) * (bioMultSum(((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * Variable1))) + ((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.2`)))) ** ((`1.1` / muB(2.3)) - `1.0`)))))),
 2: log((`1.1` * bioMultSum((((`1` ** (muA(1.2) / `1.1`)) * exp(((muA(1.2) - `1`) * `0.1`))) * (bioMultSum(((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * Variable1))) + ((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.2`)))) ** ((`1.1` / muA(1.2)) - `1.0`))) + (((`0` ** (muB(2.3) / `1.1`)) * exp(((muB(2.3) - `1`) * `0.1`))) * (bioMultSum(((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * Variable1))) + ((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.2`)))) ** ((`1.1` / muB(2.3)) - `1.0`)))))),
 3: log((`1.1` * bioMultSum((((`0.5` ** (muA(1.2) / `1.1`)) * exp(((muA(1.2) - `1`) * `-0.1`))) * (bioMultSum(((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * Variable1))) + ((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.2`)))) ** ((`1.1` / muA(1.2)) - `1.0`))) + (((`0.5` ** (muB(2.3) / `1.1`)) * exp(((muB(2.3) - `1`) * `-0.1`))) * (bioMultSum(((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * Variable1))) + ((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.2`)))) ** ((`1.1` / muB(2.3)) - `1.0`)))))),
 4: log((`1.1` * bioMultSum((((`0` ** (muA(1.2) / `1.1`)) * exp(((muA(1.2) - `1`) * `-0.2`))) * (bioMultSum(((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * Variable1))) + ((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.2`)))) ** ((`1.1` / muA(1.2)) - `1.0`))) + (((`1` ** (muB(2.3) / `1.1`)) * exp(((muB(2.3) - `1`) * `-0.2`))) * (bioMultSum(((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * Variable1))) + ((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.2`)))) ** ((`1.1` / muB(2.3)) - `1.0`)))))),
 5: log((`1.1` * bioMultSum((((`0` ** (muA(1.2) / `1.1`)) * exp(((muA(1.2) - `1`) * `0.2`))) * (bioMultSum(((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * Variable1))) + ((`1` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.1`))) + ((`0.5` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.1`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `-0.2`))) + ((`0` ** (muA(1.2) / `1.1`)) * exp((muA(1.2) * `0.2`)))) ** ((`1.1` / muA(1.2)) - `1.0`))) + (((`1` ** (muB(2.3) / `1.1`)) * exp(((muB(2.3) - `1`) * `0.2`))) * (bioMultSum(((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * Variable1))) + ((`0` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.1`))) + ((`0.5` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.1`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `-0.2`))) + ((`1` ** (muB(2.3) / `1.1`)) * exp((muB(2.3) * `0.2`)))) ** ((`1.1` / muB(2.3)) - `1.0`))))))}
In [ ]: