예제 #1
0
def test_normalize_parameter_df():
    """Check parameters.normalize_parameter_df."""
    parameter_df = pd.DataFrame({
        PARAMETER_ID: ['par0', 'par1', 'par2'],
        PARAMETER_SCALE: [LOG10, LOG10, LIN],
        NOMINAL_VALUE: [1e-2, 1e-3, 1e-4],
        ESTIMATE: [1, 1, 0],
        LOWER_BOUND: [1e-5, 1e-6, 1e-7],
        UPPER_BOUND: [1e5, 1e6, 1e7]
    }).set_index(PARAMETER_ID)

    actual = petab.normalize_parameter_df(parameter_df)

    expected = parameter_df.copy(deep=True)
    expected[PARAMETER_NAME] = parameter_df.reset_index()[PARAMETER_ID]
    expected[INITIALIZATION_PRIOR_TYPE] = [PARAMETER_SCALE_UNIFORM] * 3
    expected[INITIALIZATION_PRIOR_PARAMETERS] = ["-5;5", "-6;6", "1e-7;1e7"]
    expected[OBJECTIVE_PRIOR_TYPE] = [PARAMETER_SCALE_UNIFORM] * 3
    expected[OBJECTIVE_PRIOR_PARAMETERS] = ["-5;5", "-6;6", "1e-7;1e7"]

    # check ids
    assert list(actual.index.values) == list(expected.index.values)

    # check if basic columns match
    for col in PARAMETER_DF_COLS[1:]:
        if col in [INITIALIZATION_PRIOR_PARAMETERS,
                   OBJECTIVE_PRIOR_PARAMETERS]:
            continue
        assert ((actual[col] == expected[col]) |
                (actual[col].isnull() == expected[col].isnull())).all()

    # check if prior parameters match
    for col in [INITIALIZATION_PRIOR_PARAMETERS, OBJECTIVE_PRIOR_PARAMETERS]:
        for (_, actual_row), (_, expected_row) in \
                zip(actual.iterrows(), expected.iterrows()):
            actual_pars = tuple([float(val) for val in
                                 actual_row[col].split(';')])
            expected_pars = tuple([float(val) for val in
                                   expected_row[col].split(';')])

            assert actual_pars == expected_pars

    # check is a projection
    actual2 = petab.normalize_parameter_df(actual)
    assert ((actual == actual2) | (actual.isnull() == actual2.isnull())) \
        .all().all()

    # check is valid petab
    petab.check_parameter_df(actual)
예제 #2
0
def get_scales(parameter_df: pd.DataFrame) -> Tuple[dict, dict]:
    """Unravel whether the priors and evaluations are on or off scale.

    Only the `parameterScale...` priors are on-scale, the other priors are on
    linear scale.

    Parameters
    ----------
    parameter_df: The PEtab parameter data frame.

    Returns
    -------
    prior_scales, scaled_scales:
        Scales for each parameter on prior and evaluation level.
    """
    # fill in objective prior columns
    parameter_df = petab.normalize_parameter_df(parameter_df)
    prior_scales = {}
    scaled_scales = {}
    for _, row in parameter_df.reset_index().iterrows():
        if row[C.ESTIMATE] == 0:
            continue
        prior_scales[row[C.PARAMETER_ID]] = (
            row[C.PARAMETER_SCALE]
            if row[C.OBJECTIVE_PRIOR_TYPE] in SCALED_PRIORS
            else C.LIN
        )
        scaled_scales[row[C.PARAMETER_ID]] = row[C.PARAMETER_SCALE]
    return prior_scales, scaled_scales
예제 #3
0
    def get_parameter_names(self, target_scale: str = 'prior'):
        """Get meaningful parameter names, corrected for target scale."""
        parameter_df = petab.normalize_parameter_df(
            self.petab_problem.parameter_df
        )

        # scale
        if target_scale == C.LIN:
            target_scales = {key: C.LIN for key in self.prior_scales}
        elif target_scale == 'prior':
            target_scales = self.prior_scales
        elif target_scale == 'scaled':
            target_scales = self.scaled_scales
        else:
            raise ValueError(f"Did not recognize target scale {target_scale}")

        names = {}
        for _, row in parameter_df.reset_index().iterrows():
            if row[C.ESTIMATE] == 0:
                continue
            key = row[C.PARAMETER_ID]
            name = str(key)
            if C.PARAMETER_NAME in parameter_df:
                if not petab.is_empty(row[C.PARAMETER_NAME]):
                    name = str(row[C.PARAMETER_NAME])

            target_scale = target_scales[key]
            if target_scale != C.LIN:
                # mini check whether the name might indicate the scale already
                if not name.startswith("log"):
                    name = target_scale + "(" + name + ")"
            names[key] = name
        return names
예제 #4
0
파일: base.py 프로젝트: lcdvissc/pyABC
    def create_prior(self) -> pyabc.Distribution:
        """
        Create prior.

        Returns
        -------
        prior:
            A valid pyabc.Distribution for the parameters to estimate.
        """
        # add default values
        parameter_df = petab.normalize_parameter_df(
            self.petab_problem.parameter_df)

        prior_dct = {}

        # iterate over parameters
        for _, row in parameter_df.reset_index().iterrows():
            # check whether we can ignore
            if not self.fixed_parameters and row[petab.C.ESTIMATE] == 0:
                # ignore fixed parameters
                continue
            if not self.free_parameters and row[petab.C.ESTIMATE] == 1:
                # ignore free parameters
                continue

            # pyabc currently only knows objective priors, no
            #  initialization priors
            prior_type = row[petab.C.OBJECTIVE_PRIOR_TYPE]
            pars_str = row[petab.C.OBJECTIVE_PRIOR_PARAMETERS]
            prior_pars = tuple([float(val) for val in pars_str.split(';')])

            # create random variable from table entry
            if prior_type in [
                    petab.C.PARAMETER_SCALE_UNIFORM, petab.C.UNIFORM
            ]:
                lb, ub = prior_pars
                rv = pyabc.RV('uniform', lb, ub - lb)
            elif prior_type in [
                    petab.C.PARAMETER_SCALE_NORMAL, petab.C.NORMAL
            ]:
                mean, std = prior_pars
                rv = pyabc.RV('norm', mean, std)
            elif prior_type in [
                    petab.C.PARAMETER_SCALE_LAPLACE, petab.C.LAPLACE
            ]:
                mean, scale = prior_pars
                rv = pyabc.RV('laplace', mean, scale)
            elif prior_type == petab.C.LOG_NORMAL:
                mean, std = prior_pars
                rv = pyabc.RV('lognorm', mean, std)
            elif prior_type == petab.C.LOG_LAPLACE:
                mean, scale = prior_pars
                rv = pyabc.RV('loglaplace', mean, scale)
            else:
                raise ValueError(f"Cannot handle prior type {prior_type}.")

            prior_dct[row[petab.C.PARAMETER_ID]] = rv

        # create prior distribution
        prior = pyabc.Distribution(**prior_dct)

        return prior
예제 #5
0
def get_bounds(
    parameter_df: pd.DataFrame,
    target_scale: str,
    prior_scales: dict,
    scaled_scales: dict,
    use_prior: bool,
) -> dict:
    """Get bounds.

    Parameters
    ----------
    parameter_df: The PEtab parameter data frame.
    target_scale:
        Scale to get the nominal parameters on.
        Can be 'lin', 'scaled', or 'prior'.
    prior_scales: Prior scales.
    scaled_scales: On-scale scales.
    use_prior: Whether to use prior overrides if of type uniform.

    Returns
    -------
    bounds: Dictionary with a (lower, upper) tuple per parameter.
    """
    parameter_df = petab.normalize_parameter_df(parameter_df)

    # scale
    if target_scale == C.LIN:
        target_scales = {key: C.LIN for key in prior_scales}
    elif target_scale == 'prior':
        target_scales = prior_scales
    elif target_scale == 'scaled':
        target_scales = scaled_scales
    else:
        raise ValueError(f"Did not recognize target scale {target_scale}")

    # extract bounds
    bounds = {}
    for _, row in parameter_df.reset_index().iterrows():
        if row[C.ESTIMATE] == 0:
            # ignore fixed parameters
            continue

        key = row[C.PARAMETER_ID]

        # from lower and upper bound
        lower, upper = row[C.LOWER_BOUND], row[C.UPPER_BOUND]
        origin_scale = C.LIN

        # from prior
        prior_type = row[C.OBJECTIVE_PRIOR_TYPE]
        if use_prior and prior_type in [C.UNIFORM, C.PARAMETER_SCALE_UNIFORM]:
            pars_str = row[C.OBJECTIVE_PRIOR_PARAMETERS]
            lower, upper = tuple(float(val) for val in pars_str.split(';'))
            if prior_type == C.PARAMETER_SCALE_UNIFORM:
                origin_scale = row[C.PARAMETER_SCALE]

        # convert to target scale
        lower = rescale(
            lower, origin_scale=origin_scale, target_scale=target_scales[key]
        )
        upper = rescale(
            upper, origin_scale=origin_scale, target_scale=target_scales[key]
        )
        bounds[key] = (lower, upper)
    return bounds
예제 #6
0
def create_prior(parameter_df: pd.DataFrame) -> pyabc.Distribution:
    """Create prior.

    Note: The prior generates samples according to
    `OBJECTIVE_PRIOR_TYPE` and `OBJECTIVE_PRIOR_PARAMETERS`.
    These samples are only scaled if the prior type is `PARAMETER_SCALE_...`,
    otherwise unscaled. The model has to take care of converting samples
    accordingly.

    Parameters
    ----------
    parameter_df: The PEtab parameter data frame.

    Returns
    -------
    prior: A valid pyabc.Distribution for the parameters to estimate.
    """
    # add default values
    parameter_df = petab.normalize_parameter_df(parameter_df)

    prior_dct = {}

    # iterate over parameters
    for _, row in parameter_df.reset_index().iterrows():
        if row[C.ESTIMATE] == 0:
            # ignore fixed parameters
            continue

        # pyabc currently only knows objective priors, no
        #  initialization priors
        prior_type = row[C.OBJECTIVE_PRIOR_TYPE]
        pars_str = row[C.OBJECTIVE_PRIOR_PARAMETERS]
        prior_pars = tuple(float(val) for val in pars_str.split(';'))

        # create random variable from table entry
        if prior_type in [C.PARAMETER_SCALE_UNIFORM, C.UNIFORM]:
            lb, ub = prior_pars
            # scipy pars are location, width
            rv = pyabc.RV('uniform', loc=lb, scale=ub - lb)
        elif prior_type in [C.PARAMETER_SCALE_NORMAL, C.NORMAL]:
            mean, std = prior_pars
            # scipy pars are mean, std
            rv = pyabc.RV('norm', loc=mean, scale=std)
        elif prior_type in [C.PARAMETER_SCALE_LAPLACE, C.LAPLACE]:
            mean, b = prior_pars
            # scipy pars are loc=mean, scale=b
            rv = pyabc.RV('laplace', loc=mean, scale=b)
        elif prior_type == C.LOG_NORMAL:
            mean, std = prior_pars
            # petab pars are mean, std of the underlying normal distribution
            # scipy pars are s, loc, scale where s = std, scale = exp(mean)
            #  as a simple calculation shows
            rv = pyabc.RV('lognorm', s=std, loc=0, scale=np.exp(mean))
        elif prior_type == C.LOG_LAPLACE:
            mean, b = prior_pars
            # petab pars are mean, b of the underlying laplace distribution
            # scipy pars are c, loc, scale where c = 1 / b, scale = exp(mean)
            #  as a simple calculation shows
            rv = pyabc.RV('loglaplace', c=1 / b, scale=np.exp(mean))
        else:
            raise ValueError(f"Cannot handle prior type {prior_type}.")

        prior_dct[row[C.PARAMETER_ID]] = rv

    # create prior distribution
    prior = pyabc.Distribution(**prior_dct)

    return prior