Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

The logit model is the workhorse of the whole course: every dynamic discrete choice model we solve and estimate later has a logit formula at its core, evaluated millions of times inside a fixed point iteration nested inside a likelihood maximization.

Today we build the static logit model in code and, along the way, set up the boilerplate that every model in the course will reuse.

Background on static discrete choiceΒΆ

Deterministic model: the levels and scale do not matterΒΆ

A decision maker (DM) in state xx picks dd from a finite set D(x)D(x) to maximize u(x,d)u(x,d):

dβˆ—(x)=arg⁑max⁑d∈D(x)u(x,d)d^*(x) = \arg\max_{d \in D(x)} u(x,d)

Two implications, used below for identification and, immediately, for numerics.

  1. Only differences in utilities matter β€” adding a constant changes nothing:

    dβˆ—(x)=arg⁑max⁑d∈D(x)u(x,d)=arg⁑max⁑d∈D(x)[u(x,d)+const(x)]d^*(x) =\arg\max_{d \in D(x)} u(x,d) = \arg\max_{d \in D(x)} \big[u(x,d) + \mathrm{const}(x) \big]
    • one alternative’s utility has to be normalized, say to zero

    • an attribute of the DM are identical across alternatives β€…β€ŠβŸΉβ€…β€Š\implies cannot enter additively separably, only non-linearly, i.e. through cross-effects with attributes of choice

  2. The scale of utility is irrelevant β€” multiplying by a positive constant changes nothing:

    dβˆ—(x)=arg⁑max⁑d∈D(x)u(x,d)=arg⁑max⁑d∈D(x)[const(x)β‹…u(x,d)],β€…β€Šconst(x)>0d^*(x) =\arg\max_{d \in D(x)} u(x,d) = \arg\max_{d \in D(x)} \big[ \mathrm{const}(x)\cdot u(x,d) \big], \; \mathrm{const}(x)>0
    • when we add an additively separable random component Ο΅(d)\epsilon(d) to the utility, its scale has to be normalized

    • the variance of the random component is a normalization, not a parameter

    • it returns below as the scale parameter Οƒ\sigma

Probabilistic choiceΒΆ

Now assume that the DM has private information Ο΅\epsilon that the econometrician does not observe, and assume that it enters additively separably in the utility:

dβˆ—(x,Ο΅)=arg⁑max⁑d∈D(x)[u(x,d)+Ο΅(d)]d^*(x,\epsilon)= \arg\max_{d \in D(x)} [u(x,d)+\epsilon(d)]

The object of interest is then conditional choice probability (CCP)

P(d∣x)=Prob{dβˆ—(x,Ο΅)=d∣x}=∫ϡI{dβˆ—(x,Ο΅)=d}q(ϡ∣x)dΟ΅,P(d|x)= \hbox{Prob}\left\{d^*(x,\epsilon)=d|x\right\} = \int_\epsilon I\left\{ d^*(x,\epsilon)=d\right\}q(\epsilon|x) d\epsilon,

where I(β‹…)I(\cdot) is the indicator function and q(ϡ∣x)q(\epsilon|x) the density of Ο΅\epsilon given xx.

This is the random utility model (RUM) as we know it.

Luce’s own statement is equivalent β€” with P(d1,d2)P(d_1,d_2) the probability of choosing d1d_1 over d2d_2 and B={d1,d2}βŠ‚D(x)B=\{d_1,d_2\} \subset D(x), he required

P(d1,d2)P(d2,d1)=P(d1∣x,B)P(d2∣x,B),β€…β€Šβˆ€B∈D(x)\frac{P(d_1,d_2)}{P(d_2,d_1)} = \frac{P(d_1|x,B)}{P(d_2|x,B)}, \; \forall B \in D(x)

so the relative odds of two alternatives do not depend on what else is available.

The logit structure thus comes out with no distributional assumption anywhere, and without specifying v(d,x)v(d,x) at all.

Extreme value distribution and max-stabilityΒΆ

Luce’s structure comes out of a RUM when the unobserved components have the type I extreme value (Gumbel) distribution:

NotationEV1(ΞΌ\mu,Οƒ\sigma)
ParametersLocation ΞΌ\mu, scale Οƒ\sigma
CDFF(x)=exp⁑(βˆ’exp⁑(βˆ’xβˆ’ΞΌΟƒ))F(x) = \exp\left(-\exp(-\tfrac{x-\mu}{\sigma})\right)
PDFf(x)=1Οƒexp⁑(βˆ’xβˆ’ΞΌΟƒβˆ’exp⁑(βˆ’xβˆ’ΞΌΟƒ))f(x) = \tfrac{1}{\sigma}\exp\left(-\tfrac{x-\mu}{\sigma}-\exp(-\tfrac{x-\mu}{\sigma})\right)
Supportx∈Rx\in \mathbb{R}
ExpectationE(x)=ΞΌ+σγ\mathbb{E}(x) = \mu + \sigma \gamma
ModeM=ΞΌM = \mu
VarianceVar(x)=Οƒ2Ο€26Var(x) = \frac{\sigma^2 \pi^2}{6}
Standard normalizationΞΌ=0,Οƒ=1\mu =0, \sigma = 1

where Ξ³=lim⁑nβ†’βˆž(βˆ‘k=1n1kβˆ’ln⁑n)=0.57721…\gamma = \lim_{n \to \infty}\left( \sum_{k=1}^n \frac{1}{k} - \ln n \right) = 0.57721\dots is the Euler–Mascheroni constant (np.euler_gamma).

Source
<Figure size 900x400 with 1 Axes>

For independent {Xi}\{X_i\} with CDFs FiF_i, Fnmax(x)≑Pr{max⁑iXiβ©½x}=∏i=1nFi(x)F^{\mathrm{max}}_n(x) \equiv Pr\{\max_i X_i \leqslant x\} = \prod_{i=1}^n F_i(x), and for Xi∼EV1(ΞΌi,Οƒ)X_i \sim \mathrm{EV1}(\mu_i,\sigma) the product telescopes:

Fnmax(x)=Ξ i=1nexp⁑(βˆ’exp⁑(βˆ’xβˆ’ΞΌiΟƒ))==exp⁑(βˆ’βˆ‘i=1nexp⁑(βˆ’xβˆ’ΞΌiΟƒ))==exp⁑(βˆ’exp⁑ln⁑[exp⁑(βˆ’xΟƒ)βˆ‘i=1nexp⁑μiΟƒ])==exp⁑(βˆ’exp⁑[βˆ’xβˆ’Οƒlnβ‘βˆ‘i=1nexp⁑μiσσ])\begin{array}{l} F^{\mathrm{max}}_n(x) = \Pi_{i=1}^n \exp\left(-\exp(-\tfrac{x-\mu_i}{\sigma})\right) =\\ = \exp\left(- \sum_{i=1}^n \exp(-\tfrac{x-\mu_i}{\sigma})\right) =\\ = \exp\left(-\exp \ln \big[ \exp(-\tfrac{x}{\sigma}) \sum_{i=1}^n \exp \tfrac{\mu_i}{\sigma}\big]\right) =\\ = \exp\left(-\exp \left[ -\frac{x-{\color{red} \sigma \ln \sum_{i=1}^n \exp \tfrac{\mu_i}{\sigma}}}{\sigma} \right]\right) \end{array}

so the maximum is EV1 with the same scale Οƒ\sigma and location

ΞΌnmax=Οƒlnβ‘βˆ‘i=1nexp⁑μiΟƒ\mu^{\mathrm{max}}_n = \sigma \ln \sum_{i=1}^n \exp \tfrac{\mu_i}{\sigma}

This is the logsum formula which describes the expected maximum of independent EV1 variables:

Xi∼EV1(ΞΌi,Οƒ),i=1,…,nβ€…β€ŠβŸΊβ€…β€ŠEmax⁑i=1,…,n{Xi}=Οƒlnβ‘βˆ‘i=1nexp⁑μiΟƒ+σγX_i \sim \mathrm{EV1}(\mu_i, \sigma), i=1,\dots,n \iff \mathbb{E} \max_{i=1,\dots,n} \{X_i\} = \sigma \ln \sum_{i=1}^n \exp \tfrac{\mu_i}{\sigma} + \sigma \gamma

Worth confirming once rather than believing:

simulated mean of the max = 4.0276
logsum + sigma*gamma      = 4.0297
simulated variance        = 3.6895   theory = 3.7011

The logit choice probabilitiesΒΆ

Marschak (1960): Luce’s structure obtains in a RUM whose Ο΅(d)\epsilon(d) are i.i.d. EV1 across alternatives,

dβˆ—(x,Ο΅)=arg⁑max⁑d∈D(x)[u(x,d)+Ο΅(d)],β€…β€ŠΟ΅(d)∼EV1,i.i.d.d^*(x,\epsilon)= \arg\max_{d \in D(x)} [u(x,d)+\epsilon(d)], \; \epsilon(d) \sim \mathrm{EV1, i.i.d.}

The direct derivation β€” condition on Ο΅(d)\epsilon(d), use max-stability for the rest, then substitute t=βˆ’exp⁑(βˆ’ΞΎ)t = -\exp(-\xi) β€” is in the reading. The general route for any RUM:

βˆ‚βˆ‚u(d,x)∫ϡmax⁑dβ€²βˆˆD(x)[u(dβ€²,x)+Ο΅(dβ€²)]q(ϡ∣x)dΟ΅==∫ϡI{dβˆ—(x,Ο΅)=d}q(ϡ∣x)dΟ΅=P(d∣x)\begin{array}{l} \frac{\partial}{\partial u(d,x)} {\displaystyle \int_\epsilon} \max_{d' \in D(x)} \big[ u(d',x) +\epsilon(d') \big] q(\epsilon|x) d\epsilon =\\ = {\displaystyle \int_\epsilon} I\left\{ d^*(x,\epsilon)=d\right\}q(\epsilon|x) d\epsilon =P(d|x) \end{array}

For EV1(0,1) the expected maximum is the logsum, and one line of calculus gives the multinomial logit choice probability:

βˆ‚βˆ‚u(d,x)[lnβ‘βˆ‘dβ€²βˆˆD(x)exp⁑u(dβ€²,x)+Ξ³]=exp⁑u(d,x)βˆ‘dβ€²βˆˆD(x)exp⁑u(dβ€²,x)=P(d∣x)\frac{\partial}{\partial u(d,x)} \left[ \ln \sum_{d'\in D(x)} \exp u(d',x) + \gamma \right] = \frac{\exp u(d,x)}{\sum_{d'\in D(x)} \exp u(d',x)} = P(d|x)

Keeping Οƒ\sigma instead of normalizing it away β€” which we want in models with non-linear utility β€” the same derivation yields

P(d∣x)=exp⁑(u(d,x)/Οƒ)βˆ‘dβ€²βˆˆD(x)exp⁑(u(dβ€²,x)/Οƒ)P(d|x) = \frac{\exp \big(u(d,x)/\sigma\big)}{\sum_{d'\in D(x)} \exp \big(u(d',x)/\sigma\big)}

The price of IIAΒΆ

IIA is an axiom about behavior, and behavior does not always oblige.

The culprit is independence of Ο΅\epsilon across alternatives, plainly wrong when two alternatives differ only in paint. Remedies, in increasing computational cost:

  • The scale parameter Οƒ\sigma is a normalization in a linear-utility model. Why is it not a normalization once utility is non-linear in parameters?

Numerical issues: three formulas and how they breakΒΆ

Everything above reduces to three expressions that our code has to evaluate, over and over, inside solvers and likelihoods:

Pi=exp⁑(vi)βˆ‘jexp⁑(vj),LS=logβ‘βˆ‘jexp⁑(vj),log⁑Pi=viβˆ’LSP_i = \frac{\exp(v_i)}{\sum_j \exp(v_j)}, \qquad \mathrm{LS} = \log \sum_j \exp(v_j), \qquad \log P_i = v_i - \mathrm{LS}

Mathematically they are innocuous. On a computer they are not, because exp is the fastest way to leave the range of a floating point number.

Exponentiation is dangerousΒΆ

Do you expect the following code to run without errors? What will it print?

Output
i= 0   a=2.000e+00   exp(a)=7.389e+00
i= 1   a=2.378e+00   exp(a)=1.079e+01
i= 2   a=2.954e+00   exp(a)=1.918e+01
i= 3   a=3.872e+00   exp(a)=4.804e+01
i= 4   a=5.432e+00   exp(a)=2.285e+02
i= 5   a=8.292e+00   exp(a)=3.993e+03
i= 6   a=1.407e+01   exp(a)=1.292e+06
i= 7   a=2.725e+01   exp(a)=6.856e+11
i= 8   a=6.227e+01   exp(a)=1.105e+27
i= 9   a=1.749e+02   exp(a)=9.297e+75
i=10   a=6.362e+02   exp(a)=1.892e+276
i=11   a=3.195e+03   exp(a)=inf
i=12   a=2.402e+04   exp(a)=inf
i=13   a=2.990e+05   exp(a)=inf
/tmp/ipykernel_4047/1817667625.py:3: RuntimeWarning: overflow encountered in exp
  print(f'i={i:2d}   a={a:.3e}   exp(a)={np.exp(a):.3e}')

IEEE 754 double precision runs out at about 1.8Γ—103081.8\times10^{308}, so np.exp overflows to inf as soon as its argument exceeds

largest double      = 1.797693e+308
log of it           = 709.782713
smallest normal     = 2.225074e-308
log of it           = -708.396419

So utilities above roughly 709 overflow and utilities below roughly -745 underflow to zero. That sounds like a lot of utility until you remember that we divide by Οƒ\sigma, that vv in a dynamic model is a discounted lifetime value with Ξ²=0.9999\beta = 0.9999, and that an optimizer exploring the parameter space will happily try Ξ²1=104\beta_1 = 10^4 on its way to somewhere sensible. A single inf turns into inf/inf = nan, and nan propagates silently through the whole fixed point.

naive : [nan nan nan]

De-maxingΒΆ

The fix follows from the fact that only utility differences matter. For any constant MM,

exp⁑(vi)βˆ‘jexp⁑(vj)=exp⁑(viβˆ’M)βˆ‘jexp⁑(vjβˆ’M)\frac{\exp(v_i)}{\sum_{j} \exp(v_j)} = \frac{\exp(v_i-M)}{\sum_{j} \exp(v_j-M)}

because exp⁑(βˆ’M)\exp(-M) cancels from numerator and denominator. Choosing M=max⁑jvjM = \max_j v_j means we only ever exponentiate non-positive numbers, so the largest term is exactly 1 and overflow is impossible. Underflow may still happen, but it replaces a astronomically small number by exactly zero, which is harmless β€” and the denominator is at least 1, so we never divide by zero.

The same trick applies to the logsum, where the constant is added back afterwards:

log⁑(βˆ‘jexp⁑(vj))=M+log⁑(βˆ‘jexp⁑(vjβˆ’M))\log \left( \sum_{j} \exp(v_j) \right) = M + \log \left( \sum_{j} \exp(v_j - M) \right)
de-maxed : [0.24472847 0.66524096 0.09003057]
logsum   : 1001.4076059644444
naive: inf
/tmp/ipykernel_4047/1859438880.py:19: RuntimeWarning: overflow encountered in exp
  print('naive:', np.log(np.sum(np.exp(v))))

The de-maxed version returns the same numbers a hand calculation would: utility differences of 1 and 2 give probabilities 0.245,0.665,0.0900.245, 0.665, 0.090 regardless of the level 1000.

Never take the log of a probabilityΒΆ

The log-likelihood needs log⁑Pi\log P_i, and the obvious np.log(logit(v)) is a bad idea: when a probability underflows to zero β€” which it will, for a badly-fitting parameter guess or a small Οƒ\sigma β€” the log is βˆ’βˆž-\infty and the optimizer is handed a wall instead of a gradient. Compute log-probabilities directly instead, where the subtraction happens before any exponentiation can destroy information:

log⁑Pi=viβˆ’LSΟƒ(v)Οƒ,LSΟƒ(v)=Οƒlogβ‘βˆ‘jexp⁑(vj/Οƒ)\log P_i = \frac{v_i - \mathrm{LS}_\sigma(v)}{\sigma}, \qquad \mathrm{LS}_\sigma(v) = \sigma \log \sum_j \exp(v_j/\sigma)
log(logit(w)) : [  0. -40. -inf]
loglogit(w)   : [   0.  -40. -900.]

The third alternative has log-probability -900, not βˆ’βˆž-\infty: a small number that a likelihood can work with, rather than a missing value that stops the optimizer.

The scale parameter is a numerical hazardΒΆ

Dividing by Οƒ\sigma before de-maxing is what keeps small Οƒ\sigma usable. As Οƒβ†’0\sigma \to 0 the scaled utilities diverge, but their differences after de-maxing stay finite or underflow gracefully to zero.

sigma=10       naive=[0.33  0.347 0.323]   de-maxed=[0.33  0.347 0.323]
sigma=1        naive=[0.288 0.475 0.236]   de-maxed=[0.288 0.475 0.236]
sigma=0.1      naive=[6.687e-03 9.924e-01 9.050e-04]   de-maxed=[6.687e-03 9.924e-01 9.050e-04]
sigma=0.001    naive=[nan nan nan]   de-maxed=[7.125e-218 1.000e+000 9.860e-305]
sigma=1e-08    naive=[nan nan nan]   de-maxed=[0. 1. 0.]

At Οƒ=10βˆ’3\sigma=10^{-3} the naive formula is already nan, while the de-maxed one reports the deterministic choice, which is the correct limit. Note also what the de-maxed answer does not do: it never returns a probability outside [0,1][0,1], and the row still sums to one, which is the check to write into the code.

[[6.69282615e-03 5.52776578e-04]
 [9.93303472e-01 3.72457929e-06]
 [3.70169754e-06 9.99443499e-01]]

sums over alternatives: [1. 1.]

Logit as a smoothing deviceΒΆ

There is a second reason to have this machinery at hand, unrelated to discrete choice: the logsum is a smooth maximum, and the logit probability is a smooth indicator. Many objects in structural models are kinked or discontinuous β€” progressive tax schedules, eligibility thresholds, the upper envelope of value functions in discrete-continuous choice Iskhakov et al., 2017, the likelihood correspondence in games with multiple equilibria β€” and a solver that needs derivatives cannot cope with them.

For two functions f(x)f(x) and g(x)g(x), the kinked h(x)=max⁑(f(x),g(x))h(x) = \max\big(f(x), g(x)\big) is approximated by

h~(x)=Οƒlog⁑(exp⁑(f(x)/Οƒ)+exp⁑(g(x)/Οƒ))β†’h(x)β€…β€ŠΒ asΒ β€…β€ŠΟƒβ†’0\tilde{h}(x) = \sigma\log\big(\exp(f(x)/\sigma) + \exp(g(x)/\sigma)\big) \to h(x) \;\text{ as }\;\sigma \to 0

and the approximation error is uniformly bounded and known. Since exp⁑(β‹…/Οƒ)\exp(\cdot/\sigma) is monotone,

exp⁑h~(x)βˆ’h(x)Οƒ=exp⁑(f(x)/Οƒ)+exp⁑(g(x)/Οƒ)exp⁑(max⁑[f(x),g(x)]/Οƒ)\exp\frac{\tilde h(x) - h(x)}{\sigma} = \frac{\exp(f(x)/\sigma) + \exp(g(x)/\sigma)} {\exp(\max\big[f(x),g(x)\big]/\sigma)}

If f(x)β©Ύg(x)f(x)\geqslant g(x) this collapses to 1+exp⁑g(x)βˆ’f(x)Οƒβ©½21 + \exp\frac{g(x) - f(x)}{\sigma} \leqslant 2, and symmetrically otherwise, with the bound 2 attained exactly where f(x)=g(x)f(x) = g(x). Hence

max⁑x{h~(x)βˆ’h(x)}=Οƒln⁑2\max_x \{ \tilde h(x) - h(x) \} = \sigma \ln2

so the error is controlled by choosing Οƒ\sigma β€” and note that this is the same Οƒ\sigma that has an economic interpretation as the scale of the taste shocks. Smoothing a kink and adding an EV1 shock are the same operation.

Source
<Figure size 1000x600 with 1 Axes>

Note that the plot above is computed with the naive np.exp(f1/s), which is fine at Οƒ=0.02\sigma = 0.02 for functions of order one and starts overflowing well before Οƒ=10βˆ’3\sigma = 10^{-3}. The de-maxed logsum written above handles the whole range β€” a good first exercise in the practical.

A jump is smoothed by the logit probability rather than the logsum. If f(x)f(x) is smooth except for a jump of size fˉ\bar f at x0x_0,

f~(x)=f(x)+fΛ‰[exp⁑xβˆ’x0Οƒ1+exp⁑xβˆ’x0Οƒβˆ’I{x>x0}]β†’f(x)β€…β€ŠΒ asΒ β€…β€ŠΟƒβ†’0,\tilde f(x) = f(x) + \bar{f} \left[ \frac{\exp\tfrac{x-x_0}{\sigma}}{1 + \exp\tfrac{x-x_0}{\sigma}} - I\{x>x_0\} \right] \to f(x) \;\text{ as }\;\sigma \to 0,

where fΛ‰=lim⁑xβ†’x0+f(x)βˆ’lim⁑xβ†’x0βˆ’f(x)\bar{f} = \lim_{x\to x_0^+} f(x) - \lim_{x\to x_0^-} f(x). Convergence here is only pointwise, not uniform: at x0x_0 itself the smoothed function is off by fΛ‰/2\bar f/2 no matter how small Οƒ\sigma is.

Source
<Figure size 1000x600 with 1 Axes>

The model we build todayΒΆ

The point of the practical is not the logit formula itself β€” it is one line β€” but the shape of the code around it. Every structural project in this course, and your own project later in the semester, has the same six parts:

  1. a model object holding the parameters, with the β€œmodel parts” (utility, transitions) attached to it

  2. a solver that maps parameters into the model solution

  3. a simulator that generates data from a solved model

  4. a graphical module that shows what the model and the data look like

  5. an estimator that recovers parameters from data (from the NFXP class onwards)

  6. a counterfactual simulator that changes something and re-solves (later still)

Keep these separate from the run scripts that call them. A run script is throwaway; the model, solver and simulator are what you reuse for the whole semester.

SpecificationΒΆ

A decision maker in state x∈{1,2}x \in \{1,2\} chooses one of ∣D∣|D| alternatives, each described by a vector YdY^d of KK attributes. We consider two utility specifications:

  1. Linear: u(d,x)=YdΞ²xu(d,x) = Y^d \beta^x

  2. Log: u(d,x)=ln⁑(Yd) βxu(d,x) = \ln(Y^d)\, \beta^x

with state-dependent coefficients tied together as Ξ²1=Ξ²\beta^1 = \beta and Ξ²2=Ξ²/2\beta^2 = \beta/2, so the vector of structural parameters is β∈RK\beta \in \mathbb{R}^K plus the scale Οƒ\sigma. Choice probabilities are logit with scale Οƒ\sigma, as derived above.

The state enters only through the coefficients here, which is deliberately minimal β€” enough to have something to compare across states, and few enough parameters that the dashboard is readable.

The model objectΒΆ

Start with what holds the parameters. Two details are worth the extra lines: __str__, so that printing a model tells you what it is, and __setattr__, so that an inconsistent model cannot be created in the first place. Shape bugs found at assignment time cost minutes; the same bug found inside a likelihood costs an afternoon.

  • __setattr__ is called for every assignment, including the ones inside __init__. Why must self.nalt be set before self.attr?

  • What would break if beta_coef were computed once in __init__ and stored?

  • Where would the transition matrix live in this design, once the model becomes dynamic?

The solverΒΆ

With logit already written and tested, the solver is three lines. Notice that it both returns the solution and stores it on the model β€” convenient for plotting, and the reason the simulator can assert that the model has been solved.

The simulatorΒΆ

Simulating a discrete choice is the inverse-CDF method: form the cumulative probabilities along the alternatives, draw u∼U[0,1]u \sim U[0,1], and find the interval that contains it. np.searchsorted does the search in O(log⁑∣D∣)O(\log |D|) per draw and is vectorized over draws, which matters when we simulate a hundred thousand agents inside an MSM criterion later.

  • Why side='right' and not side='left'? What happens to a zero-probability alternative under each?

  • The last cumulative probability is 1 only up to floating point. Can searchsorted return an out-of-range index, and what would that do?

  • We draw one uniform per agent. How many draws would the β€œobvious” alternative β€” simulating the Ο΅(d)\epsilon(d) and taking the argmax β€” need, and would it give the same answer?

Model "model 1" [linear]: 5 alternatives, 3 attributes, 2 states, sigma=1
  beta = [0.1 , 0.35, 0.2 ]
Loading...

The graphical moduleΒΆ

Three plotting functions, each of which can either make its own figure or draw into axes handed to it. That second option is what makes the dashboard possible without duplicating a line of plotting code.

Source
<Figure size 1200x700 with 6 Axes>

The dashboard is the whole point of building the graphical module: one function call shows the primitives, the solution and the data side by side, so that changing a parameter and re-running gives an immediate read on what that parameter does. This is how you develop intuition about identification β€” long before writing an estimator, you should be able to say which feature of the data each parameter moves.

Playing with the modelΒΆ

Source

The role of Ξ²\beta. One coefficient moved from 0.1 to 0.9 reshuffles the whole profile of choice probabilities, and does so differently in the two states because Ξ²2=Ξ²/2\beta^2 = \beta/2 shrinks every effect by half.

<Figure size 1000x640 with 4 Axes>

The role of Οƒ\sigma. Same preferences, five times the noise: everything is pulled towards the uniform distribution, exactly as the limit Οƒβ†’βˆž\sigma \to \infty predicts. This is why Οƒ\sigma and the scale of Ξ²\beta cannot both be identified in the linear model β€” multiplying Ξ²\beta and Οƒ\sigma by the same positive constant leaves every choice probability unchanged.

<Figure size 1000x640 with 4 Axes>

Predicted versus simulated behavior. The solution is a probability; the data is a finite sample from it. With 100 agents the histogram is a rough sketch of the CCPs, with 100,000 it is the CCPs. Estimation is this relation run backwards, and the sampling noise you see here is what standard errors measure.

Source
<Figure size 1200x400 with 3 Axes>
<Figure size 1200x400 with 3 Axes>

Linear versus log utility. The same Ξ²\beta means something entirely different once the attributes are logged: differences between alternatives are compressed, so the choice probabilities are flatter, and Οƒ\sigma is no longer a pure normalization.

<Figure size 1000x640 with 4 Axes>
ReferencesΒΆ
  1. Thurstone, L. L. (1959). The measurement of values. Univer. Chicago Press.
  2. Luce, R. D. (1959). Individual choice behavior. John Wiley.
  3. Marschak, J. (1960). Binary Choice Constraints and Random Utility Indicators. In K. Arrow, S. Karlin, & P. Suppes (Eds.), Mathematical methods in the social sciences, 1959β€―: proceedings (Vol. viii). Stanford, CA.β€―: Stanford University Press. http://archive.org/details/mathematicalmeth0000stan
  4. McFadden, D. (1974). Conditional logit analysis of qualitative choice behavior. Frontiers in Econometrics.
  5. McFadden, D. (1981). Econometric models of probabilistic choice. Structural Analysis of Discrete Data with Econometric Applications, 198272.
  6. Iskhakov, F., JΓΈrgensen, T., Rust, J., & Schjerning, B. (2017). The endogenous grid method for discrete-continuous dynamic choice models with (or without) taste shocks. Quantitative Economics, 8(2), 317–365. https://doi.org/10.3982/QE643
  7. Train, K. E. (2009). Discrete Choice Methods with Simulation (2nd ed.). Cambridge University Press. 10.1017/CBO9780511805271