Example on a nested logit model - Cupid Matching

Skip to content

# `example_nestedlogit` module

example using a simple two-layer nested logit model One nest on each side must consist of the 0 option. The other nests are specified as nested lists. E.g. [[1, 3], [2,4]] describes two nests, one with types 1 and 3, and the other with types 2 and 4. On each side, the nests are the same for each type, with the same parameters.

## `create_nestedlogit_population(X, Y, K, std_alphas=0.5, std_betas=1.0)`

we simulate a nested logit population with equal numbers of men and women of each type and random bases dunctions and coefficients

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    Args:
     X: number of types of men
     Y: number of types of women
     K: random basis functions
     std_alphas: the nest parameters are drawn from a U[0, std_alphas] distribution
     std_betas: the coefficients of the bases are drawn from a centered normal
                 with this standard deviation

    Returns:
        a NestedLogitPrimitives instance, the basis functions, the true coefficients,
        and the entropy functions

Source code in `cupid_matching/example_nestedlogit.py`

    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    def create_nestedlogit_population(
        X: int,
        Y: int,
        K: int,
        std_alphas: Optional[float] = 0.5,
        std_betas: Optional[float] = 1.0,
    ) -> Tuple[
        NestedLogitPrimitives,
        np.ndarray,
        np.ndarray,
        EntropyFunctions,
        EntropyFunctions,
    ]:
        """
        we simulate a nested logit population
        with equal numbers of men and women of each type
        and random bases dunctions and coefficients

            Args:
             X: number of types of men
             Y: number of types of women
             K: random basis functions
             std_alphas: the nest parameters are drawn from a U[0, std_alphas] distribution
             std_betas: the coefficients of the bases are drawn from a centered normal
                         with this standard deviation

            Returns:
                a NestedLogitPrimitives instance, the basis functions, the true coefficients,
                and the entropy functions
        """
        X, Y, K = 10, 12, 5
        nests_for_each_x = [
            list(range(1, Y // 2 + 1)),
            list(range(Y // 2 + 1, Y + 1)),
        ]
        nests_for_each_y = [
            list(range(1, X // 2 + 1)),
            list(range(X // 2 + 1, X + 1)),
        ]

        n = np.ones(X)
        m = np.ones(Y)
        phi_bases = np.random.randn(X, Y, K)

        (
            entropy_nested_logit,
            entropy_nested_logit_numeric,
        ) = setup_standard_nested_logit(nests_for_each_x, nests_for_each_y)
        n_rhos, n_deltas = len(nests_for_each_x), len(nests_for_each_y)
        n_alphas = n_rhos + n_deltas

        betas_true = std_betas * np.random.randn(K)
        alphas_true = std_alphas * np.random.uniform(size=n_alphas)

        Phi = phi_bases @ betas_true
        nested_logit_instance = NestedLogitPrimitives(
            Phi, n, m, nests_for_each_x, nests_for_each_y, alphas_true
        )
        true_coeffs = np.concatenate((alphas_true, betas_true))
        return (
            nested_logit_instance,
            phi_bases,
            true_coeffs,
            entropy_nested_logit,
            entropy_nested_logit_numeric,
        )

## `mde_estimate(mus_sim, phi_bases, true_coeffs, entropy, title)`

we estimate the parameters using the minimum distance estimator

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`mus_sim` | `Matching` | a Choo and Siow Matching | required
`phi_bases` | `np.ndarray` | the basis functions | required
`true_coeffs` | `np.ndarray` | their true coefficients and the nesting parameters | required
`entropy` | `EntropyFunctions` | the entropy functions we use | required
`title` | `str` | the name of the estimator | required

Returns:

Type | Description
--- | ---
`float` | the largest absolute difference between the true and estimated coefficients

Source code in `cupid_matching/example_nestedlogit.py`

     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    def mde_estimate(
        mus_sim: Matching,
        phi_bases: np.ndarray,
        true_coeffs: np.ndarray,
        entropy: EntropyFunctions,
        title: str,
    ) -> float:
        """we estimate the parameters using the minimum distance estimator

        Args:
            mus_sim: a Choo and Siow Matching
            phi_bases: the basis functions
            true_coeffs: their true coefficients and  the nesting parameters
            entropy: the entropy functions we use
            title: the name of the estimator

        Returns:
            the largest absolute difference between the true and estimated coefficients
        """
        print_stars(f"    {title}")
        mde_results = estimate_semilinear_mde(
            mus_sim,
            phi_bases,
            entropy,
            additional_parameters=entropy.additional_parameters,
        )
        mde_discrepancy = mde_results.print_results(true_coeffs=true_coeffs)
        return mde_discrepancy