def dimension_subset(hyperparameters, dimensions):
    """Return only the values of `hyperparameters` specified by `dimensions`, in the same order as
    `dimensions`

    Parameters
    ----------
    hyperparameters: Dict
        Dict of hyperparameters containing at least the following keys: ['model_init_params',
        'model_extra_params', 'feature_engineer', 'feature_selector']
    dimensions: List of: (strings, or tuples)
        Locations and order of the values to return from `hyperparameters`. If a value is a string,
        it is assumed to belong to `model_init_params`, and its path will be adjusted accordingly

    Returns
    -------
    List of hyperparameter values"""
    dimensions = [("model_init_params", _) if isinstance(_, str) else _
                  for _ in dimensions]
    values = [
        get_path(hyperparameters, _, default=RejectedOptional())
        for _ in dimensions
    ]
    return values
예제 #2
0
def validate_fe_steps(candidate: Union[list, FeatureEngineer],
                      template: Union[list, FeatureEngineer]) -> list:
    """Check `candidate` "feature_engineer" `steps` compatibility with `template` and sanitize
    `candidate`

    Parameters
    ----------
    candidate: List, or FeatureEngineer
        Candidate "feature_engineer" `steps` to compare to `template`. If compatible with
        `template`, a sanitized version of `candidate` will be returned (described below)
    template: List, or FeatureEngineer
        Template "feature_engineer" `steps` to which `candidate` will be compared. `template` is
        also used to sanitize `candidate` (described below)

    Returns
    -------
    List
        If `candidate` is compatible with `template`, returns a list resembling `candidate`, with
        the following changes: 1) all step dicts in `candidate` are reinitialized to proper
        `EngineerStep` instances; and 2) wherever `candidate` was missing a step that was tagged as
        `optional` in `template`, `RejectedOptional` is added. In the end, if a list is returned, it
        is built from `candidate`, guaranteed to be the same length as `template` and guaranteed
        to contain only `EngineerStep` and `RejectedOptional` instances

    Raises
    ------
    IncompatibleCandidateError
        If `candidate` is incompatible with `template`. `candidate` may be incompatible with
        `template` for any of the following reasons:

        1. `candidate` has more steps than `template`
        2. `candidate` has a step that differs from a concrete (non-`Categorical`) `template` step
        2. `candidate` has a step that differs from a concrete (non-`Categorical`) `template` step
        3. `candidate` has a step that does not fit in a `Categorical` `template` step
        4. `candidate` is missing a concrete step in `template`
        5. `candidate` is missing a non-`optional` `Categorical` step in `template`"""
    # Extract `steps` if given `FeatureEngineer`
    if isinstance(candidate, FeatureEngineer):
        candidate = candidate.steps
    if isinstance(template, FeatureEngineer):
        template = template.steps

    if len(template) == 0:
        if len(candidate) == 0:
            # All steps have been exhausted and passed, so `candidate` was a match
            return []
        # `candidate` steps remain while `template` is empty, so `candidate` is incompatible
        raise IncompatibleCandidateError(candidate, template)

    #################### Categorical Template Step ####################
    if isinstance(template[-1], Categorical):
        #################### Optional Categorical Template Step ####################
        if template[-1].optional is True:
            if len(candidate) == 0 or (candidate[-1] not in template[-1]):
                # `candidate` is either empty or doesn't match an `optional` template step
                candidate.append(RejectedOptional())

        #################### Non-Optional Categorical Template Step ####################
        elif len(candidate) == 0:
            # `candidate` is empty while non-`optional` `template` steps remain - Incompatible
            raise IncompatibleCandidateError(candidate, template)
        elif candidate[-1] not in template[-1]:
            raise IncompatibleCandidateError(candidate, template)

    elif len(candidate) == 0:
        raise IncompatibleCandidateError(candidate, template)

    #################### Concrete Template Step ####################
    elif candidate[-1] != template[-1]:
        raise IncompatibleCandidateError(candidate, template)

    #################### Reinitialize EngineerStep Dict ####################
    if isinstance(candidate[-1], dict):
        if isinstance(template[-1], Categorical):
            candidate[-1] = EngineerStep.honorary_step_from_dict(
                candidate[-1], template[-1])
        elif isinstance(template[-1],
                        EngineerStep) and template[-1] == candidate[-1]:
            candidate[-1] = template[
                -1]  # Adopt template value if `EngineerStep` equivalent

    return validate_fe_steps(candidate[:-1], template[:-1]) + [candidate[-1]]
예제 #3
0
 ),
 pytest.param(
     [es_a, es_c, es_e],
     [CAT(es_a, es_b), CAT(es_c, es_d), es_e],
     [es_a, es_c, es_e],
     id="cat+cat+concrete",
 ),
 pytest.param(
     [es_a, es_c, es_e],
     [es_a, CAT(es_b, es_c), CAT(es_d, es_e)],
     [es_a, es_c, es_e],
     id="concrete+cat+cat",
 ),
 #################### Exclusively Optional Scenarios ####################
 pytest.param([es_a], [CAT(es_a, ...)], [es_a], id="opt_single_0"),
 pytest.param([], [CAT(es_a, ...)], [RejectedOptional()],
              id="opt_single_1"),
 pytest.param(
     [],
     [CAT(es_a, ...), CAT(es_b, ...),
      CAT(es_c, ...)],
     [RejectedOptional(),
      RejectedOptional(),
      RejectedOptional()],
     id="opt+opt+opt_0",
 ),
 pytest.param(
     [es_a],
     [CAT(es_a, ...), CAT(es_b, ...),
      CAT(es_c, ...)],
     [es_a, RejectedOptional(),
예제 #4
0
def test_rejected_optional_repr():
    assert "{!r}".format(RejectedOptional()) == "RejectedOptional()"