def _asym_utility_transform(systematic_utilities,
                            alt_IDs,
                            rows_to_alts,
                            eta,
                            intercept_params,
                            shape_ref_position=None,
                            intercept_ref_pos=None,
                            *args, **kwargs):
    """
    Parameters
    ----------
    systematic_utilities : 1D ndarray.
        Contains the systematic utilities for each each available alternative
        for each observation. All elements should be ints, floats, or longs.
    alt_IDs : 1D ndarray.
       All elements should be ints. There should be one row per obervation per
       available alternative for the given observation. Elements denote the
       alternative corresponding to the given row of the design matrix.
    rows_to_alts : 2D ndarray.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset.
    eta : 1D ndarray.
        Each element should be an int, float, or long. There should be one
        value per transformed shape parameter. Note that if there are J
        possible alternatives in the dataset, then there should be J - 1
        elements in `eta`.
    intercept_params : 1D ndarray or None.
        If an array, each element should be an int, float, or long. For
        identifiability, there should be J- 1 elements where J is the total
        number of observed alternatives for this dataset.
    shape_ref_position : int.
        Specifies the position in the array of natural shape parameters that
        should be equal to 1 - the sum of the other elements. Specifies the
        alternative in the ordered array of unique alternatives that is not
        having its shape parameter estimated (to ensure identifiability).
    intercept_ref_pos : int, or None, optional.
        Specifies the index of the alternative, in the ordered array of unique
        alternatives, that is not having its intercept parameter estimated (in
        order to ensure identifiability). Should only be None if
        intercept_params is None. Default == None.

    Returns
    -------
    transformed_utilities : 2D ndarray.
        Should have shape `(systematic_utilities.shape[0], 1)`. The returned
        array contains the values of the transformed index for this model.
    """
    ##########
    # Convert the reduced shape parameters to the natural shape parameters
    ##########
    natural_shape_params = _convert_eta_to_c(eta, shape_ref_position)

    ##########
    # Calculate the transformed utilities from the natural shape parameters
    ##########
    # Create a vector which contains the appropriate shape for each row in
    # the design matrix
    long_shapes = rows_to_alts.dot(natural_shape_params)

    # Determine the total number of alternatives
    num_alts = rows_to_alts.shape[1]

    # Get the natural log of the long_shapes
    log_long_shapes = np.log(long_shapes)
    # Guard against underflow, aka long_shapes too close to zero
    log_long_shapes[np.isneginf(log_long_shapes)] = -1 * max_comp_value

    # Get the natural log of (1 - long_shapes) / (J - 1)
    log_1_sub_long_shapes = np.log((1 - long_shapes) / float(num_alts - 1))
    # Guard against underflow, aka 1 - long_shapes too close to zero
    small_idx = np.isneginf(log_1_sub_long_shapes)
    log_1_sub_long_shapes[small_idx] = -1 * max_comp_value

    # Compute the transformed utilities
    multiplier = ((systematic_utilities >= 0) * log_long_shapes +
                  (systematic_utilities < 0) * log_1_sub_long_shapes)
    transformed_utilities = log_long_shapes - systematic_utilities * multiplier

    # Perform a guard for shape --> 1 and V --> infinity.
    # It is DEFINITELY not clear if this is the correct thing to do. The limit
    # might not even exist, and there is no clear multivariate L'Hopital's
    # rule. So this is an arbitrary decision
    weird_case = np.isposinf(systematic_utilities) * (long_shapes == 1)
    transformed_utilities[weird_case] = 0

    # Account for the outside intercept parameters if there are any
    if intercept_params is not None and intercept_ref_pos is not None:
        # Get a list of all the indices (or row indices) corresponding to the
        # alternatives whose intercept parameters are being estimated.
        needed_idxs = range(rows_to_alts.shape[1])
        needed_idxs.remove(intercept_ref_pos)

        if len(intercept_params.shape) > 1 and intercept_params.shape[1] > 1:
            # Get an array of zeros with shape
            # (num_possible_alternatives, num_parameter_samples)
            all_intercepts = np.zeros((rows_to_alts.shape[1],
                                       intercept_params.shape[1]))
            # For alternatives having their intercept estimated, replace the
            # zeros with the current value of the estimated intercepts
            all_intercepts[needed_idxs, :] = intercept_params
        else:
            # Get an array of zeros with shape (num_possible_alternatives,)
            all_intercepts = np.zeros(rows_to_alts.shape[1])
            # For alternatives having their intercept estimated, replace the
            # zeros with the current value of the estimated intercepts
            all_intercepts[needed_idxs] = intercept_params

        # Add the intercept values to f(x, beta, c)
        transformed_utilities += rows_to_alts.dot(all_intercepts)

    # Perform final guards against over/underflow in the transformations
    transformed_utilities[np.isposinf(transformed_utilities)] = max_comp_value
    transformed_utilities[np.isneginf(transformed_utilities)] = -max_comp_value

    # Be sure to return a 2D array since other functions will be expecting that
    if len(transformed_utilities.shape) == 1:
        transformed_utilities = transformed_utilities[:, np.newaxis]

    return transformed_utilities
def _asym_utility_transform ( systematic_utilities , alt_IDs , rows_to_alts , eta , intercept_params , shape_ref_position = None , intercept_ref_pos = None , * args , ** kwargs ) : natural_shape_params = _convert_eta_to_c ( eta , shape_ref_position ) long_shapes = rows_to_alts . dot ( natural_shape_params ) num_alts = rows_to_alts . shape [ 1 ] log_long_shapes = np . log ( long_shapes ) log_long_shapes [ np . isneginf ( log_long_shapes ) ] = - 1 * max_comp_value log_1_sub_long_shapes = np . log ( ( 1 - long_shapes ) / float ( num_alts - 1 ) ) small_idx = np . isneginf ( log_1_sub_long_shapes ) log_1_sub_long_shapes [ small_idx ] = - 1 * max_comp_value multiplier = ( ( systematic_utilities >= 0 ) * log_long_shapes + ( systematic_utilities < 0 ) * log_1_sub_long_shapes ) transformed_utilities = log_long_shapes - systematic_utilities * multiplier weird_case = np . isposinf ( systematic_utilities ) * ( long_shapes == 1 ) transformed_utilities [ weird_case ] = 0 if intercept_params is not None and intercept_ref_pos is not None : needed_idxs = range ( rows_to_alts . shape [ 1 ] ) needed_idxs . remove ( intercept_ref_pos ) if len ( intercept_params . shape ) > 1 and intercept_params . shape [ 1 ] > 1 : all_intercepts = np . zeros ( ( rows_to_alts . shape [ 1 ] , intercept_params . shape [ 1 ] ) ) all_intercepts [ needed_idxs , : ] = intercept_params else : all_intercepts = np . zeros ( rows_to_alts . shape [ 1 ] ) all_intercepts [ needed_idxs ] = intercept_params transformed_utilities += rows_to_alts . dot ( all_intercepts ) transformed_utilities [ np . isposinf ( transformed_utilities ) ] = max_comp_value transformed_utilities [ np . isneginf ( transformed_utilities ) ] = - max_comp_value if len ( transformed_utilities . shape ) == 1 : transformed_utilities = transformed_utilities [ : , np . newaxis ] return transformed_utilities
Parameters
    ----------
    systematic_utilities : 1D ndarray.
        Contains the systematic utilities for each each available alternative
        for each observation. All elements should be ints, floats, or longs.
    alt_IDs : 1D ndarray.
       All elements should be ints. There should be one row per obervation per
       available alternative for the given observation. Elements denote the
       alternative corresponding to the given row of the design matrix.
    rows_to_alts : 2D ndarray.
        There should be one row per observation per available alternative and
        one column per possible alternative. This matrix maps the rows of the
        design matrix to the possible alternatives for this dataset.
    eta : 1D ndarray.
        Each element should be an int, float, or long. There should be one
        value per transformed shape parameter. Note that if there are J
        possible alternatives in the dataset, then there should be J - 1
        elements in `eta`.
    intercept_params : 1D ndarray or None.
        If an array, each element should be an int, float, or long. For
        identifiability, there should be J- 1 elements where J is the total
        number of observed alternatives for this dataset.
    shape_ref_position : int.
        Specifies the position in the array of natural shape parameters that
        should be equal to 1 - the sum of the other elements. Specifies the
        alternative in the ordered array of unique alternatives that is not
        having its shape parameter estimated (to ensure identifiability).
    intercept_ref_pos : int, or None, optional.
        Specifies the index of the alternative, in the ordered array of unique
        alternatives, that is not having its intercept parameter estimated (in
        order to ensure identifiability). Should only be None if
        intercept_params is None. Default == None.

    Returns
    -------
    transformed_utilities : 2D ndarray.
        Should have shape `(systematic_utilities.shape[0], 1)`. The returned
        array contains the values of the transformed index for this model.