Linear Functions
Linear FunctionsΒΆ
In many discrete choice models, the probability of selecting any particular alternative is represented as some function based on the utility of the various alternatives.
In Larch, the utility is created based on one or more linear-in-parameters
functions, which combine raw or pre-computed data values with
named model parameters. To facilitate writing these functions,
Larch provides two special classes: parameter references (P
) and
data references (X
).
from larch import P, X
Parameter and data references can be defined using either a function-like notation, or a attribute-like notation.
P('NamedParameter')
P.NamedParameter
X.NamedDataValue
X.NamedDataValue
In either case, if the named value contains any spaces or non-alphanumeric characters, it must be given in function-like notation only, as Python will not accept those characters in the attribute-like form.
P('Named Parameter')
P('Named Parameter')
Data references can name an exact data element that appears in the data used for model estimation or application, or can include simple transformations of that data, so long as these transformations can be done without regard to any estimated parameter. For example, we can use the log of income:
X("log(INCOME)")
X('log(INCOME)')
To write a linear-in-parameters utility function, we simply multiply together a parameter reference and a data reference, and then optionally add that to one or more similar terms.
P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_COST
P.InVehTime * X.AUTO_TIME
+ P.Cost * X.AUTO_COST
It is permissible to omit the data reference on a term (in which case it is implicitly set to 1.0).
P.ASC + P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_COST
P.ASC
+ P.InVehTime * X.AUTO_TIME
+ P.Cost * X.AUTO_COST
On the other hand, Larch does not currently permit you to omit the parameter reference from a term.
P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_COST + X.GEN_COST
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
Input In [12], in <cell line: 1>()
----> 1 P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_COST + X.GEN_COST
File ~/work/larch/larch/larch/larch/model/linear.pyx:951, in larch.model.linear.LinearFunction_C.__add__()
NotImplementedError: <LinearFunction_C> + X.GEN_COST
Although you cannot include a term with an implicit parameter set to 1, you can achieve the same model structure by including that parameter explicitly. Later in the model setup process you can explicitly lock any parameter to have a specific fixed value.
P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_COST + X.GEN_COST * P.One
P.InVehTime * X.AUTO_TIME
+ P.Cost * X.AUTO_COST
+ P.One * X.GEN_COST
In addition to writing out a linear function as a single command, you can also compose such functions over several Python commands, using both in-place and regular addition.
f = P.ASC + P.InVehTime * X.AUTO_TIME
f += P.Cost * X.AUTO_COST
f
P.ASC
+ P.InVehTime * X.AUTO_TIME
+ P.Cost * X.AUTO_COST
f + P.Cost * X.AUTO_TOLL
P.ASC
+ P.InVehTime * X.AUTO_TIME
+ P.Cost * X.AUTO_COST
+ P.Cost * X.AUTO_TOLL
Functional simplification is not automatic. Thus, while you can subtract term from a linear function, it does not cancel out existing terms from the function.
f = P.ASC + P.InVehTime * X.AUTO_TIME
f - P.InVehTime * X.AUTO_TIME
P.ASC
+ P.InVehTime * X.AUTO_TIME
+ P.InVehTime * -1.0 * X.AUTO_TIME
Instead, to actually remove terms from a linear function, use the remove_param
or remove_data
methods.
f = P.ASC + P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_TOLL
f.remove_param(P.InVehTime)
P.ASC
+ P.Cost * X.AUTO_TOLL
f = P.ASC + P.InVehTime * X.AUTO_TIME + P.Cost * X.AUTO_TOLL
f.remove_data('AUTO_TOLL')
P.ASC
+ P.InVehTime * X.AUTO_TIME