Nested logit choice#

simple_choice runs a multinomial logit model by default. Give it an ActivitySim-style nest_spec to run a nested logit model instead. The same methods remain available in both cases: utility, probability, logsum, simulate_choice, analytic_share, and the analytic-share calibration methods.

from traveler.steps import simple_choice

tour_mode = simple_choice(
    "tour_mode",
    tour_mode_utilities,
    altnames=("SOV", "HOV", "Walk", "Bike"),
    param={"auto_nest": 0.7},
    on=Tours,
    result_name="tour_mode",
    nest_spec={
        "name": "root",
        "coefficient": 1.0,
        "alternatives": [
            {
                "name": "auto",
                "coefficient": "auto_nest",
                "alternatives": ["SOV", "HOV"],
            },
            {
                "name": "nonmotorized",
                "coefficient": 0.8,
                "alternatives": ["Walk", "Bike"],
            },
        ],
    },
)

Each nest has a unique name, a coefficient, and a non-empty list of alternatives. An alternative may be another nest or one of the values in altnames. Every elemental alternative must appear exactly once. The root coefficient is 1; lower-level coefficients must be greater than zero and no larger than one.

Nested logit currently requires explicit string or integer altnames; the categorical-group shorthand (such as "@TAZ") is available only for MNL.

A coefficient may be a number or the name of an entry in param. Named nest coefficients participate in JAX automatic differentiation, so they can be used with analytic-share calibration. Coefficients use ActivitySim’s relative convention: an elemental utility is divided by the product of coefficients on its path from the root.