# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# --------------------------------------------------------------------------------------------
# - Generated by tools/entrypoint_compiler.py: do not edit by hand
"""
OneVsRestClassifier
"""

__all__ = ["OneVsRestClassifier"]


from ...entrypoints.models_oneversusall import models_oneversusall
from ...utils.utils import trace
from ..base_pipeline_item import BasePipelineItem, DefaultSignatureWithRoles


class OneVsRestClassifier(
        BasePipelineItem,
        DefaultSignatureWithRoles):
    """

    One-vs-All macro (OVA)


    .. remarks::
        `OneVsRestClassifier
        <https://en.wikipedia.org/wiki/Multiclass_classification>` converts
        any binary classifiers into mult-class.
        A multi-class classification problem (with K classes) can be
        decomposed into K binary classification
        problems per class, with label as 0 or 1 (if a sample belongs to the
        class). OneVsRestClassifier
        predicts the label with the highest score from the basic learners.

    :param classifier: The subgraph for the binary trainer used to construct
        the OVA learner. This should be a TrainBinary node.

    :param output_for_sub_graph: The training subgraph output.

    :param use_probabilities: Use probabilities in OVA combiner.

    :param normalize: If ``Auto``, the choice to normalize depends on the
        preference declared by the algorithm. This is the default choice. If
        ``No``, no normalization is performed. If ``Yes``, normalization always
        performed. If ``Warn``, if normalization is needed by the algorithm, a
        warning message is displayed but normalization is not performed. If
        normalization is performed, a ``MaxMin`` normalizer is used. This
        normalizer preserves sparsity by mapping zero to zero.

    :param caching: Whether learner should cache input training data.

    :param params: Additional arguments sent to compute engine.

    .. note::

        This algorithm can be treated as a wrapper for all the binary
        classifiers in nimbusml. A few binary
        classifiers already have implementation for multi-class problems,
        thus users can choose either one
        depending on the context. The OVA version of a binary classifier,
        such as wrapping a :py:class:`LightGbmBinaryClassifier
        <nimbusml.ensemble.LightGbmBinaryClassifier>` ,
        can be different from :py:class:`LightGbmClassifier
        <nimbusml.ensemble.LightGbmClassifier>` ,
        which develops a multi-class classifier directly.

    .. seealso::
        :py:class:`FastForestBinaryClassifier
        <nimbusml.ensemble.FastForestBinaryClassifier>`,
        :py:class:`FastTreesBinaryClassifier
        <nimbusml.ensemble.FastTreesBinaryClassifier>`,
        :py:class:`GamBinaryClassifier
        <nimbusml.ensemble.GamBinaryClassifier>`,
        :py:class:`LightGbmBinaryClassifier
        <nimbusml.ensemble.LightGbmBinaryClassifier>`,
        :py:class:`AveragedPerceptronBinaryClassifier
        <nimbusml.linear_model.AveragedPerceptronBinaryClassifier>`,
        :py:class:`FastLinearBinaryClassifier
        <nimbusml.linear_model.FastLinearBinaryClassifier>`,
        :py:class:`LogisticRegressionBinaryClassifier
        <nimbusml.linear_model.LogisticRegressionBinaryClassifier>`,
        :py:class:`SgdBinaryClassifier
        <nimbusml.linear_model.SgdBinaryClassifier>`.

    .. index:: models, classification, multi-class

    Example:
       .. literalinclude:: /../nimbusml/examples/OneVsRestClassifier.py
              :language: python
    """

    @trace
    def __init__(
            self,
            classifier,
            output_for_sub_graph=0,
            use_probabilities=True,
            normalize='Auto',
            caching='Auto',
            **params):
        BasePipelineItem.__init__(
            self, type='classifier', **params)

        self.classifier = classifier
        self.output_for_sub_graph = output_for_sub_graph
        self.use_probabilities = use_probabilities
        self.normalize = normalize
        self.caching = caching

    @property
    def _entrypoint(self):
        return models_oneversusall

    @trace
    def _get_node(self, **all_args):
        algo_args = dict(
            feature_column=self._getattr_role(
                'feature_column',
                all_args),
            label_column=self._getattr_role(
                'label_column',
                all_args),
            weight_column=self._getattr_role(
                'weight_column',
                all_args),
            nodes=self.classifier,
            output_for_sub_graph=self.output_for_sub_graph,
            use_probabilities=self.use_probabilities,
            normalize_features=self.normalize,
            caching=self.caching)

        all_args.update(algo_args)
        node = self.classifier._get_node(**all_args)
        all_args['nodes'] = [node]
        all_args['output_for_sub_graph'] = {
            'Model': all_args['predictor_model']}
        return self._entrypoint(**all_args)
