Source code for biogeme.segmentation.one_segmentation

"""Handles the segmentation of a single parameter using a discrete variable.

This class manages how a single Beta parameter is segmented according to a
discrete variable. It generates distinct parameters for each category in the
segmentation (except the reference), enabling models to estimate category-specific
effects.

Attributes:
    beta: The base Beta parameter being segmented.
    segmentation_tuple: The DiscreteSegmentationTuple defining the segmentation.
    variable: The discrete variable used for segmentation.
    reference: The reference category for the segmentation.
    mapping: Dictionary of category values to category names, excluding the reference.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from .segmentation_context import DiscreteSegmentationTuple
from biogeme.exceptions import BiogemeError

if TYPE_CHECKING:
    from biogeme.expressions import Beta, Variable, Expression, Numeric


[docs] class OneSegmentation: def __init__( self, beta: Beta, segmentation_tuple: DiscreteSegmentationTuple, ): """ Initialize the segmentation of a Beta parameter. Parameters: beta: The base Beta parameter to be segmented. segmentation_tuple: Describes the discrete segmentation including the mapping of values to category names and the reference category. """ self.beta: Beta = beta self.segmentation_tuple = segmentation_tuple self.variable: Variable = segmentation_tuple.variable self.reference: str = segmentation_tuple.reference self.mapping: dict[int, str] = { k: v for k, v in segmentation_tuple.mapping.items() if v != self.reference }
[docs] def beta_name(self, category: str) -> str: """Construct the name of the parameter associated with a specific category :param category: name of the category :return: name of parameter for the category :raise BiogemeError: if the category is not listed in the mapping of the segmentation. """ if category != self.reference and category not in self.mapping.values(): error_msg = ( f'Unknown category: {category}. List of known categories: ' f'{self.mapping.values()}' ) raise BiogemeError(error_msg) return ( f'{self.beta.name}_ref' if category == self.reference else f'{self.beta.name}_diff_{category}' )
[docs] def beta_expression(self, category: str | None = None) -> Beta: """Constructs the expression for the parameter associated with a specific category :param category: name of the category. If None, it is the reference category. :return: expression of the parameter for the category """ from biogeme.expressions import Beta if category is None: category = self.reference name = self.beta_name(category) if category == self.reference: lower_bound = self.beta.lower_bound upper_bound = self.beta.upper_bound else: lower_bound = None upper_bound = None return Beta( name, self.beta.init_value, lower_bound, upper_bound, self.beta.status, )
[docs] def beta_code(self, category: str, assignment: bool) -> str: """Constructs the Python code for the expression of the parameter associated with a specific category :param category: name of the category :param assignment: if True, the code includes the assignment to a variable. :return: the Python code """ if category == self.reference: lower_bound = self.beta.lower_bound upper_bound = self.beta.upper_bound else: lower_bound = None upper_bound = None name = self.beta_name(category) if assignment: return ( f"{name} = Beta('{name}', {self.beta.init_value}, " f"{lower_bound}, {upper_bound}, {self.beta.status})" ) return ( f"Beta('{name}', {self.beta.init_value}, {lower_bound}, " f"{upper_bound}, {self.beta.status})" )
[docs] def list_of_expressions(self) -> list[Expression]: """Create a list of expressions involved in the segmentation of the parameter :return: list of expressions :rtype: list(biogeme.expressions.Expression) """ from biogeme.expressions import Numeric terms = [ self.beta_expression(category) * (self.variable == Numeric(value)) for value, category in self.mapping.items() ] return terms
[docs] def list_of_code(self) -> list[str]: """Create a list of Python codes for the expressions involved in the segmentation of the parameter :return: list of codes """ return [ ( f"{self.beta_name(category)} " f"* (Variable('{self.variable.name}') == {value})" ) for value, category in self.mapping.items() ]