Example #1
0
def lagged_choices_probs_template(n_lagged_choices, choices):
    to_concat = []
    for i in range(1, n_lagged_choices + 1):
        probs = np.random.uniform(size=len(choices))
        probs = normalize_probabilities(probs)
        for j, choice in enumerate(choices):
            ind = (f"lagged_choice_{i}_{choice}", "constant")
            dat = [probs[j], f"Probability of choice {choice} being lagged choice {i}"]
            to_concat.append(_base_row(ind, dat))

    return pd.concat(to_concat, axis=0, sort=False)
Example #2
0
def observable_prob_template(observables):
    to_concat = []
    for i in range(len(observables)):
        probs = np.random.uniform(size=observables[i])
        probs = normalize_probabilities(probs)

        for j in range(observables[i]):
            ind = (f"observable_observable_{i}_{j}", "probability")
            dat = [probs[j], f"Probability of observable {i} being level choice {j}"]
            to_concat.append(_base_row(ind, dat))

    out = pd.concat(to_concat, axis=0, sort=False)

    return out
Example #3
0
def _parse_probabilities_or_logit_coefficients(params, regex_for_levels):
    r"""Parse probabilities or logit coefficients of parameter groups.

    Some parameters form a group to specify a distribution. The parameters can either be
    probabilities from a probability mass function. For example, see the specification
    of initial years of schooling in the extended model of Keane and Wolpin (1997).

    On the other hand, parameters and their corresponding covariates can form the inputs
    of a :func:`scipy.specical.softmax` which generates the probability mass function.
    This distribution can be more complex.

    Internally, probabilities are also converted to logit coefficients to align the
    interfaces. To convert probabilities to the appropriate multinomial logit (softmax)
    coefficients, use a constant for covariates and note that the sum in the denominator
    is equal for all probabilities and, thus, can be treated as a constant. The
    following formula shows that the multinomial coefficients which produce the same
    probability mass function are equal to the logs of probabilities.

    .. math::

        p_i      &= \frac{e^{x_i \beta_i}}{\sum_j e^{x_j \beta_j}} \
                 &= \frac{e^{\beta_i}}{\sum_j e^{\beta_j}} \
        log(p_i) &= \beta_i - \log(\sum_j e^{\beta_j}) \
                 &= \beta_i - C

    Raises
    ------
    ValueError
        If probabilities and multinomial logit coefficients are mixed.

    Warnings
    --------
    The user is warned if the discrete probabilities of a probability mass function do
    not sum to one.

    """
    mask = (
        params.index.get_level_values("category")
        .str.extract(regex_for_levels, expand=False)
        .notna()
    )
    n_parameters = mask.sum()

    # If parameters for initial experiences are specified, the parameters can either
    # be probabilities or multinomial logit coefficients.
    if n_parameters:
        # Work on subset.
        sub = params.loc[mask].copy()

        levels = sub.index.get_level_values("category").str.extract(
            regex_for_levels, expand=False
        )
        levels = pd.to_numeric(levels, errors="ignore")
        unique_levels = sorted(levels.unique())

        n_probabilities = (sub.index.get_level_values("name") == "probability").sum()

        # It is allowed to specify the shares of initial experiences as
        # probabilities. Then, the probabilities are replaced with their logs to
        # recover the probabilities with a multinomial logit model.
        if n_probabilities == len(unique_levels) == n_parameters:
            if sub.sum() != 1:
                warnings.warn(
                    f"The probabilities for parameter group {regex_for_levels} do not "
                    "sum to one.",
                    category=UserWarning,
                )
                sub = normalize_probabilities(sub)

            # Clip at the smallest representable number to prevent -infinity for log(0).
            sub = np.log(np.clip(sub, 1 / MAX_FLOAT, None))
            sub = sub.rename(index={"probability": "constant"}, level="name")

        elif n_probabilities > 0:
            raise ValueError(
                "Cannot mix probabilities and multinomial logit coefficients for the "
                f"parameter group: {regex_for_levels}."
            )

        # Drop level 'category' from :class:`pd.MultiIndex`.
        s = sub.droplevel(axis="index", level="category")
        # Insert parameters for every level of initial experiences.
        container = {level: s.loc[levels == level] for level in unique_levels}

    # If no parameters are provided, return `None` so that the default is handled
    # outside the function.
    else:
        container = None

    return container
Example #4
0
def _get_initial_shares(num_groups):
    """We simply need a valid request for the shares of types summing to one."""
    shares = np.random.uniform(size=num_groups)
    shares = normalize_probabilities(shares)

    return shares