
    UgR                        d dl mZ d dlmZmZ d dlZddlmZm	Z	m
Z
mZmZ ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZmZmZmZ ddlmZ ddlmZmZm Z m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z'm(Z( ddl)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/m0Z0 d Z1d Z2 G d de	e
e          Z3 G d de3          Z4 G d de          Z5d Z6d Z7 G d de3          Z8dS )    )MutableMapping)IntegralRealN   )BaseEstimatorClassifierMixinMetaEstimatorMixin_fit_contextclone)NotFittedError)check_scoringget_scorer_names)_BaseScorer)_safe_indexing)
HasMethodsInterval
RealNotInt
StrOptions)_get_response_values_binary)MetadataRouterMethodMapping_raise_for_paramsprocess_routing)available_if)type_of_target)Paralleldelayed)_check_method_params_num_samplescheck_is_fitted	indexable   )StratifiedShuffleSplitcheck_cvc                       fd}|S )zCheck if we can delegate a method to the underlying estimator.

    First, we check the fitted estimator if available, otherwise we
    check the unfitted estimator.
    c                 ~    t          | d          rt          | j                   nt          | j                   dS )N
estimator_T)hasattrgetattrr'   	estimator)selfattrs    p/var/www/surfInsights/venv3-11/lib/python3.11/site-packages/sklearn/model_selection/_classification_threshold.pycheckz_estimator_has.<locals>.check/   sA    4&& 	*DOT****DND)))t     )r,   r.   s   ` r-   _estimator_hasr1   (   s#         Lr/   c                 ,   |t          j        ddg          }nRt          j        ||k              d         }t          j        ||k              d         }t          j        ||g          }||| |k                        t                                      S )z;Threshold `y_score` and return the associated class labels.Nr   r"   )nparrayflatnonzeroastypeint)y_score	thresholdclasses	pos_labelmap_thresholded_score_to_labelpos_label_idxneg_label_idxs          r-   !_threshold_scores_to_class_labelsr?   9   s    )+1a&)9)9&&w)';<<Q?w)';<<Q?)+=-2P)Q)Q&17i3G2O2OPS2T2TUVVr/   c                   |   e Zd ZU dZdgZ eddg           eddg          g eh d          gdZee	d<   d	d
dZ
d Z ed          d             Zed             Z e ed                    d             Z e ed                    d             Z e ed                    d             Zd ZdS )BaseThresholdClassifiera  Base class for binary classifiers that set a non-default decision threshold.

    In this base class, we define the following interface:

    - the validation of common parameters in `fit`;
    - the different prediction methods that can be used with the classifier.

    .. versionadded:: 1.5

    Parameters
    ----------
    estimator : estimator instance
        The binary classifier, fitted or not, for which we want to optimize
        the decision threshold used during `predict`.

    response_method : {"auto", "decision_function", "predict_proba"}, default="auto"
        Methods by the classifier `estimator` corresponding to the
        decision function for which we want to find a threshold. It can be:

        * if `"auto"`, it will try to invoke, for each classifier,
          `"predict_proba"` or `"decision_function"` in that order.
        * otherwise, one of `"predict_proba"` or `"decision_function"`.
          If the method is not implemented by the classifier, it will raise an
          error.
    r*   fitpredict_probadecision_function>   autorC   rD   r*   response_method_parameter_constraintsrE   rG   c                "    || _         || _        d S NrF   )r+   r*   rG   s      r-   __init__z BaseThresholdClassifier.__init__i   s    ".r/   c                 4    | j         dk    rddg}n| j         }|S )zDefine the response method.rE   rC   rD   rI   )r+   rG   s     r-   _get_response_methodz,BaseThresholdClassifier._get_response_methodm   s+    6)).0CDOO"2Or/   F)prefer_skip_nested_validationc                 V   t          || d           t          ||          \  }}t          |d          }|dk    rt          d|            | j        ||fi | t          | j        d          r| j        j        | _        t          | j        d          r| j        j        | _        | S )  Fit the classifier.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training data.

        y : array-like of shape (n_samples,)
            Target values.

        **params : dict
            Parameters to pass to the `fit` method of the underlying
            classifier.

        Returns
        -------
        self : object
            Returns an instance of self.
        Ny)
input_namebinaryz=Only binary classification is supported. Unknown label type: n_features_in_feature_names_in_)	r   r!   r   
ValueError_fitr(   r'   rU   rV   )r+   XrR   paramsy_types        r-   rB   zBaseThresholdClassifier.fitu   s    0 	&$---A1c222XXPVXX   		!Q!!&!!!4?$455 	A"&/"@D4?$788 	G%)_%FD"r/   c                     | j         j        S )zClasses labels.)r'   classes_r+   s    r-   r]   z BaseThresholdClassifier.classes_   s     ''r/   c                 V    t          | d           | j                            |          S )a  Predict class probabilities for `X` using the fitted estimator.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training vectors, where `n_samples` is the number of samples and
            `n_features` is the number of features.

        Returns
        -------
        probabilities : ndarray of shape (n_samples, n_classes)
            The class probabilities of the input samples.
        r'   )r    r'   rC   r+   rY   s     r-   rC   z%BaseThresholdClassifier.predict_proba   s*     	l+++,,Q///r/   predict_log_probac                 V    t          | d           | j                            |          S )a  Predict logarithm class probabilities for `X` using the fitted estimator.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training vectors, where `n_samples` is the number of samples and
            `n_features` is the number of features.

        Returns
        -------
        log_probabilities : ndarray of shape (n_samples, n_classes)
            The logarithm class probabilities of the input samples.
        r'   )r    r'   ra   r`   s     r-   ra   z)BaseThresholdClassifier.predict_log_proba   *     	l+++00333r/   c                 V    t          | d           | j                            |          S )a  Decision function for samples in `X` using the fitted estimator.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training vectors, where `n_samples` is the number of samples and
            `n_features` is the number of features.

        Returns
        -------
        decisions : ndarray of shape (n_samples,)
            The decision function computed the fitted estimator.
        r'   )r    r'   rD   r`   s     r-   rD   z)BaseThresholdClassifier.decision_function   rc   r/   c                     dddddS )NTz*Threshold at probability 0.5 does not holdzDue to the cross-validation and sample ordering, removing a sample is not strictly equal to putting is weight to zero. Specific unit tests are added for TunedThresholdClassifierCV specifically.)check_classifiers_traincheck_sample_weights_invariance)binary_only_xfail_checksr0   r^   s    r-   
_more_tagsz"BaseThresholdClassifier._more_tags   s'    +WT 

 

 
	
r/   N)__name__
__module____qualname____doc___required_parametersr   r   rH   dict__annotations__rL   rN   r
   rB   propertyr]   r   r1   rC   ra   rD   rj   r0   r/   r-   rA   rA   E   s         4 (= J/00J2344
 'J'U'U'UVVW$ $D    6< / / / / /   \&+  % %	 %N ( ( X( \..11220 0 320" \..!455664 4 764" \..!455664 4 764"
 
 
 
 
r/   rA   c                        e Zd ZU dZi ej         edh          egeeddgdZe	e
d<   dddd fd
Zd	 Zd
 Zd Z xZS )FixedThresholdClassifiera  Binary classifier that manually sets the decision threshold.

    This classifier allows to change the default decision threshold used for
    converting posterior probability estimates (i.e. output of `predict_proba`) or
    decision scores (i.e. output of `decision_function`) into a class label.

    Here, the threshold is not optimized and is set to a constant value.

    Read more in the :ref:`User Guide <FixedThresholdClassifier>`.

    .. versionadded:: 1.5

    Parameters
    ----------
    estimator : estimator instance
        The binary classifier, fitted or not, for which we want to optimize
        the decision threshold used during `predict`.

    threshold : {"auto"} or float, default="auto"
        The decision threshold to use when converting posterior probability estimates
        (i.e. output of `predict_proba`) or decision scores (i.e. output of
        `decision_function`) into a class label. When `"auto"`, the threshold is set
        to 0.5 if `predict_proba` is used as `response_method`, otherwise it is set to
        0 (i.e. the default threshold for `decision_function`).

    pos_label : int, float, bool or str, default=None
        The label of the positive class. Used to process the output of the
        `response_method` method. When `pos_label=None`, if `y_true` is in `{-1, 1}` or
        `{0, 1}`, `pos_label` is set to 1, otherwise an error will be raised.

    response_method : {"auto", "decision_function", "predict_proba"}, default="auto"
        Methods by the classifier `estimator` corresponding to the
        decision function for which we want to find a threshold. It can be:

        * if `"auto"`, it will try to invoke `"predict_proba"` or `"decision_function"`
          in that order.
        * otherwise, one of `"predict_proba"` or `"decision_function"`.
          If the method is not implemented by the classifier, it will raise an
          error.

    Attributes
    ----------
    estimator_ : estimator instance
        The fitted classifier used when predicting.

    classes_ : ndarray of shape (n_classes,)
        The class labels.

    n_features_in_ : int
        Number of features seen during :term:`fit`. Only defined if the
        underlying estimator exposes such an attribute when fit.

    feature_names_in_ : ndarray of shape (`n_features_in_`,)
        Names of features seen during :term:`fit`. Only defined if the
        underlying estimator exposes such an attribute when fit.

    See Also
    --------
    sklearn.model_selection.TunedThresholdClassifierCV : Classifier that post-tunes
        the decision threshold based on some metrics and using cross-validation.
    sklearn.calibration.CalibratedClassifierCV : Estimator that calibrates
        probabilities.

    Examples
    --------
    >>> from sklearn.datasets import make_classification
    >>> from sklearn.linear_model import LogisticRegression
    >>> from sklearn.metrics import confusion_matrix
    >>> from sklearn.model_selection import FixedThresholdClassifier, train_test_split
    >>> X, y = make_classification(
    ...     n_samples=1_000, weights=[0.9, 0.1], class_sep=0.8, random_state=42
    ... )
    >>> X_train, X_test, y_train, y_test = train_test_split(
    ...     X, y, stratify=y, random_state=42
    ... )
    >>> classifier = LogisticRegression(random_state=0).fit(X_train, y_train)
    >>> print(confusion_matrix(y_test, classifier.predict(X_test)))
    [[217   7]
     [ 19   7]]
    >>> classifier_other_threshold = FixedThresholdClassifier(
    ...     classifier, threshold=0.1, response_method="predict_proba"
    ... ).fit(X_train, y_train)
    >>> print(confusion_matrix(y_test, classifier_other_threshold.predict(X_test)))
    [[184  40]
     [  6  20]]
    rE   booleanN)r9   r;   rH   )r9   r;   rG   c                j    t                                          ||           || _        || _        d S NrF   )superrL   r;   r9   )r+   r*   r9   r;   rG   	__class__s        r-   rL   z!FixedThresholdClassifier.__init__G  s4     	9oNNN""r/   c                     t          | dfi |} t          | j                  j        ||fi |j        j        | _        | S )rQ   rB   )r   r   r*   rB   r'   )r+   rY   rR   rZ   routed_paramss        r-   rX   zFixedThresholdClassifier._fitS  sN    ( (e>>v>>3%//3AqXXM<S<WXXr/   c                     t          | d           t          | j        ||                                 | j        d          \  }}}| j        dk    r|dk    rdnd}n| j        }t          ||| j        | j                  S )O  Predict the target of new samples.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            The samples, as accepted by `estimator.predict`.

        Returns
        -------
        class_labels : ndarray of shape (n_samples,)
            The predicted class.
        r'   T)r;   return_response_method_usedrE   rC   g      ?        )r    r   r'   rN   r;   r9   r?   r]   )r+   rY   r8   _response_method_useddecision_thresholds         r-   predictz FixedThresholdClassifier.predictk  s     	l++++FO%%''n(,,
 ,
 ,
(( >V##(<(O(OUX!%0'
 
 	
r/   c                     t          | j        j                                      | j        t                                          dd                    }|S )K  Get metadata routing of this object.

        Please check :ref:`User Guide <metadata_routing>` on how the routing
        mechanism works.

        Returns
        -------
        routing : MetadataRouter
            A :class:`~sklearn.utils.metadata_routing.MetadataRouter` encapsulating
            routing information.
        ownerrB   calleecallerr*   method_mapping)r   ry   rk   addr*   r   r+   routers     r-   get_metadata_routingz-FixedThresholdClassifier.get_metadata_routing  sU      dn&=>>>BBn(??..eE.JJ C 
 
 r/   )rk   rl   rm   rn   rA   rH   r   r   strrp   rq   rL   rX   r   r   __classcell__ry   s   @r-   rt   rt      s         U Un$
!
8$ j&**D1CD1$ $ $D    
# 
# 
# 
# 
# 
# 
#  0
 
 
>      r/   rt   c                   >     e Zd ZdZ fdZed             Zd Z xZS )_CurveScorera  Scorer taking a continuous response and output a score for each threshold.

    Parameters
    ----------
    score_func : callable
        The score function to use. It will be called as
        `score_func(y_true, y_pred, **kwargs)`.

    sign : int
        Either 1 or -1 to returns the score with `sign * score_func(estimator, X, y)`.
        Thus, `sign` defined if higher scores are better or worse.

    kwargs : dict
        Additional parameters to pass to the score function.

    thresholds : int or array-like
        Related to the number of decision thresholds for which we want to compute the
        score. If an integer, it will be used to generate `thresholds` thresholds
        uniformly distributed between the minimum and maximum predicted scores. If an
        array-like, it will be used as the thresholds.

    response_method : str
        The method to call on the estimator to get the response values.
    c                 `    t                                          ||||           || _        d S )N)
score_funcsignkwargsrG   )rx   rL   _thresholds)r+   r   r   r   
thresholdsrG   ry   s         r-   rL   z_CurveScorer.__init__  s@    !+	 	 	
 	
 	
 &r/   c                 v     | |j         |j        |||j                  }|                                |_        |S )z0Create a continuous scorer from a normal scorer.)r   r   rG   r   r   )_score_func_sign_kwargs_get_metadata_request_metadata_request)clsscorerrG   r   instances        r-   from_scorerz_CurveScorer.from_scorer  sK     3)+!>
 
 
 &,%A%A%C%C"r/   c                    	
                                    | j        |          
i  j        |	t           j        t
                    r@t          j        t          j        
          t          j	        
           j                  }nt          j
         j                  }	 
fd|D             }t          j        |          |fS )a  Evaluate predicted target values for X relative to y_true.

        Parameters
        ----------
        method_caller : callable
            Returns predictions given an estimator, method name, and other
            arguments, potentially caching results.

        estimator : object
            Trained estimator to use for scoring.

        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Test data that will be fed to estimator.predict.

        y_true : array-like of shape (n_samples,)
            Gold standard target values for X.

        **kwargs : dict
            Other parameters passed to the scorer. Refer to
            :func:`set_score_request` for more details.

        Returns
        -------
        scores : ndarray of shape (thresholds,)
            The scores associated to each threshold.

        potential_thresholds : ndarray of shape (thresholds,)
            The potential thresholds used to compute the scores.
        r;   c                 h    g | ].}j          j        t          |j                  fi z  /S r0   )r   r   r?   r]   ).0thr*   r;   scoring_kwargsr+   r8   y_trues     r-   
<listcomp>z'_CurveScorer._score.<locals>.<listcomp>  so     

 

 

  Jd1R!3Y  
 ! 

 

 

r/   )_get_pos_label_response_methodr   
isinstancer   r   r3   linspaceminmaxasarrayr4   )r+   method_callerr*   rY   r   r   potential_thresholdsscore_thresholdsr;   r   r8   s   ` ` `   @@@r-   _scorez_CurveScorer._score  s   < ''))	-t,a9
 
 
 4DL3F3d&11 	@#%;w$2B$ $   $&:d.>#?#? 

 

 

 

 

 

 

 

 

 +

 

 

 x())+???r/   )	rk   rl   rm   rn   rL   classmethodr   r   r   r   s   @r-   r   r     ss         2& & & & &   [5@ 5@ 5@ 5@ 5@ 5@ 5@r/   r   c                   |tt          ||          t          ||          }	}t          ||          t          ||          }}
t          |||          }t          |||          } | j        ||
fi | n|||}}}	 || |	|fi |S )a  Fit a classifier and compute the scores for different decision thresholds.

    Parameters
    ----------
    classifier : estimator instance
        The classifier to fit and use for scoring. If `classifier` is already fitted,
        it will be used as is.

    X : {array-like, sparse matrix} of shape (n_samples, n_features)
        The entire dataset.

    y : array-like of shape (n_samples,)
        The entire target vector.

    fit_params : dict
        Parameters to pass to the `fit` method of the underlying classifier.

    train_idx : ndarray of shape (n_train_samples,) or None
        The indices of the training set. If `None`, `classifier` is expected to be
        already fitted.

    val_idx : ndarray of shape (n_val_samples,)
        The indices of the validation set used to score `classifier`. If `train_idx`,
        the entire set will be used.

    curve_scorer : scorer instance
        The scorer taking `classifier` and the validation set as input and outputting
        decision thresholds and scores as a curve. Note that this is different from
        the usual scorer that output a single score value:

        * when `score_method` is one of the four constraint metrics, the curve scorer
          will output a curve of two scores parametrized by the decision threshold, e.g.
          TPR/TNR or precision/recall curves for each threshold;
        * otherwise, the curve scorer will output a single score value for each
          threshold.

    score_params : dict
        Parameters to pass to the `score` method of the underlying scorer.

    Returns
    -------
    scores : ndarray of shape (thresholds,) or tuple of such arrays
        The scores computed for each decision threshold. When TPR/TNR or precision/
        recall are computed, `scores` is a tuple of two arrays.

    potential_thresholds : ndarray of shape (thresholds,)
        The decision thresholds used to compute the scores. They are returned in
        ascending order.
    Nindices)r   r   rB   )
classifierrY   rR   
fit_params	train_idxval_idxcurve_scorerscore_paramsX_trainX_valy_trainy_valfit_params_trainscore_params_vals                 r-   _fit_and_score_over_thresholdsr     s    z '955~a7Q7Q'955~a7Q7Q/:yQQQ/<QQQ
w<<+;<<<<)*A|&u<
E5EE4DEEEr/   c                 d     t          j         fdt          ||          D             d          S )al  Compute the mean interpolated score across folds by defining common thresholds.

    Parameters
    ----------
    target_thresholds : ndarray of shape (thresholds,)
        The thresholds to use to compute the mean score.

    cv_thresholds : ndarray of shape (n_folds, thresholds_fold)
        The thresholds used to compute the scores for each fold.

    cv_scores : ndarray of shape (n_folds, thresholds_fold)
        The scores computed for each threshold for each fold.

    Returns
    -------
    mean_score : ndarray of shape (thresholds,)
        The mean score across all folds for each target threshold.
    c                 B    g | ]\  }}t          j        ||          S r0   )r3   interp)r   split_thresholdssplit_scoretarget_thresholdss      r-   r   z,_mean_interpolated_score.<locals>.<listcomp>c  s>     	
 	
 	
- + I')9;GG	
 	
 	
r/   r   )axis)r3   meanzip)r   cv_thresholds	cv_scoress   `  r-   _mean_interpolated_scorer   O  sS    & 7	
 	
 	
 	
14]I1N1N	
 	
 	
    r/   c                       e Zd ZU dZi ej         e e e                                e	e
g eeddd          dgd edh           eed	d
d          gdgedgdgdgdZeed<   ddddddddd fd
Zd Zd Zd Zd Z xZS )TunedThresholdClassifierCVa>  Classifier that post-tunes the decision threshold using cross-validation.

    This estimator post-tunes the decision threshold (cut-off point) that is
    used for converting posterior probability estimates (i.e. output of
    `predict_proba`) or decision scores (i.e. output of `decision_function`)
    into a class label. The tuning is done by optimizing a binary metric,
    potentially constrained by a another metric.

    Read more in the :ref:`User Guide <TunedThresholdClassifierCV>`.

    .. versionadded:: 1.5

    Parameters
    ----------
    estimator : estimator instance
        The classifier, fitted or not, for which we want to optimize
        the decision threshold used during `predict`.

    scoring : str or callable, default="balanced_accuracy"
        The objective metric to be optimized. Can be one of:

        * a string associated to a scoring function for binary classification
          (see model evaluation documentation);
        * a scorer callable object created with :func:`~sklearn.metrics.make_scorer`;

    response_method : {"auto", "decision_function", "predict_proba"}, default="auto"
        Methods by the classifier `estimator` corresponding to the
        decision function for which we want to find a threshold. It can be:

        * if `"auto"`, it will try to invoke, for each classifier,
          `"predict_proba"` or `"decision_function"` in that order.
        * otherwise, one of `"predict_proba"` or `"decision_function"`.
          If the method is not implemented by the classifier, it will raise an
          error.

    thresholds : int or array-like, default=100
        The number of decision threshold to use when discretizing the output of the
        classifier `method`. Pass an array-like to manually specify the thresholds
        to use.

    cv : int, float, cross-validation generator, iterable or "prefit", default=None
        Determines the cross-validation splitting strategy to train classifier.
        Possible inputs for cv are:

        * `None`, to use the default 5-fold stratified K-fold cross validation;
        * An integer number, to specify the number of folds in a stratified k-fold;
        * A float number, to specify a single shuffle split. The floating number should
          be in (0, 1) and represent the size of the validation set;
        * An object to be used as a cross-validation generator;
        * An iterable yielding train, test splits;
        * `"prefit"`, to bypass the cross-validation.

        Refer :ref:`User Guide <cross_validation>` for the various
        cross-validation strategies that can be used here.

        .. warning::
            Using `cv="prefit"` and passing the same dataset for fitting `estimator`
            and tuning the cut-off point is subject to undesired overfitting. You can
            refer to :ref:`TunedThresholdClassifierCV_no_cv` for an example.

            This option should only be used when the set used to fit `estimator` is
            different from the one used to tune the cut-off point (by calling
            :meth:`TunedThresholdClassifierCV.fit`).

    refit : bool, default=True
        Whether or not to refit the classifier on the entire training set once
        the decision threshold has been found.
        Note that forcing `refit=False` on cross-validation having more
        than a single split will raise an error. Similarly, `refit=True` in
        conjunction with `cv="prefit"` will raise an error.

    n_jobs : int, default=None
        The number of jobs to run in parallel. When `cv` represents a
        cross-validation strategy, the fitting and scoring on each data split
        is done in parallel. ``None`` means 1 unless in a
        :obj:`joblib.parallel_backend` context. ``-1`` means using all
        processors. See :term:`Glossary <n_jobs>` for more details.

    random_state : int, RandomState instance or None, default=None
        Controls the randomness of cross-validation when `cv` is a float.
        See :term:`Glossary <random_state>`.

    store_cv_results : bool, default=False
        Whether to store all scores and thresholds computed during the cross-validation
        process.

    Attributes
    ----------
    estimator_ : estimator instance
        The fitted classifier used when predicting.

    best_threshold_ : float
        The new decision threshold.

    best_score_ : float or None
        The optimal score of the objective metric, evaluated at `best_threshold_`.

    cv_results_ : dict or None
        A dictionary containing the scores and thresholds computed during the
        cross-validation process. Only exist if `store_cv_results=True`. The
        keys are `"thresholds"` and `"scores"`.

    classes_ : ndarray of shape (n_classes,)
        The class labels.

    n_features_in_ : int
        Number of features seen during :term:`fit`. Only defined if the
        underlying estimator exposes such an attribute when fit.

    feature_names_in_ : ndarray of shape (`n_features_in_`,)
        Names of features seen during :term:`fit`. Only defined if the
        underlying estimator exposes such an attribute when fit.

    See Also
    --------
    sklearn.model_selection.FixedThresholdClassifier : Classifier that uses a
        constant threshold.
    sklearn.calibration.CalibratedClassifierCV : Estimator that calibrates
        probabilities.

    Examples
    --------
    >>> from sklearn.datasets import make_classification
    >>> from sklearn.ensemble import RandomForestClassifier
    >>> from sklearn.metrics import classification_report
    >>> from sklearn.model_selection import TunedThresholdClassifierCV, train_test_split
    >>> X, y = make_classification(
    ...     n_samples=1_000, weights=[0.9, 0.1], class_sep=0.8, random_state=42
    ... )
    >>> X_train, X_test, y_train, y_test = train_test_split(
    ...     X, y, stratify=y, random_state=42
    ... )
    >>> classifier = RandomForestClassifier(random_state=0).fit(X_train, y_train)
    >>> print(classification_report(y_test, classifier.predict(X_test)))
                  precision    recall  f1-score   support
    <BLANKLINE>
               0       0.94      0.99      0.96       224
               1       0.80      0.46      0.59        26
    <BLANKLINE>
        accuracy                           0.93       250
       macro avg       0.87      0.72      0.77       250
    weighted avg       0.93      0.93      0.92       250
    <BLANKLINE>
    >>> classifier_tuned = TunedThresholdClassifierCV(
    ...     classifier, scoring="balanced_accuracy"
    ... ).fit(X_train, y_train)
    >>> print(
    ...     f"Cut-off point found at {classifier_tuned.best_threshold_:.3f}"
    ... )
    Cut-off point found at 0.342
    >>> print(classification_report(y_test, classifier_tuned.predict(X_test)))
                  precision    recall  f1-score   support
    <BLANKLINE>
               0       0.96      0.95      0.96       224
               1       0.61      0.65      0.63        26
    <BLANKLINE>
        accuracy                           0.92       250
       macro avg       0.78      0.80      0.79       250
    weighted avg       0.92      0.92      0.92       250
    <BLANKLINE>
    r"   Nleft)closedz
array-like	cv_objectprefitr   g      ?neitherru   random_state)scoringr   cvrefitn_jobsr   store_cv_resultsrH   balanced_accuracyrE   d   TF)r   rG   r   r   r   r   r   r   c                    t                                          ||           || _        || _        || _        || _        || _        || _        |	| _        d S rw   )	rx   rL   r   r   r   r   r   r   r   )r+   r*   r   rG   r   r   r   r   r   r   ry   s             r-   rL   z#TunedThresholdClassifierCV.__init__!  s[     	9oNNN$
( 0r/   c           
          t           j        t                    r2d j        cxk     rdk     r n nt          d j         j                  n j        dk    rY j        du rt          d          	 t           j        d           n"# t          $ r}t          d          |d	}~ww xY w j        nGt           j        d
           j        du r'                                dk    rt          d          t           dfi |                                  _        dk    r3 j         _         j        d	t!          t#                              fg}nt%           j                   _        t%           j                   j        fi j        j        } j        rj        j        }}}net-           j        fi j        j                  \  }	}
t/          |	          }t/          |	          }t1          j        j        |	          }  j        j        ||fi | t3           t5           j                   fd|D                        \  }}t9          d |D                       rt          d          t;          d |D                       }t=          d |D                       }t           j        t@                    rtC          j"        || j                  }ntC          j#         j                  }tI          |||          }|%                                }||          _&        ||          _'         j(        r
||d _)         S )a  Fit the classifier and post-tune the decision threshold.

        Parameters
        ----------
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
            Training data.

        y : array-like of shape (n_samples,)
            Target values.

        **params : dict
            Parameters to pass to the `fit` method of the underlying
            classifier and to the `scoring` scorer.

        Returns
        -------
        self : object
            Returns an instance of self.
        r   r"   )n_splits	test_sizer   r   Tz'When cv='prefit', refit cannot be True.r]   z-When cv='prefit', `estimator` must be fitted.N)rR   r   Fz1When cv has several folds, refit cannot be False.rB   r   )r   c              3      K   | ]Z\  }} t          t                    d k    rt                    nj        j        ||j        j        j                  V  [dS )r   )r   r   r   r   r   N)r   r   r   r*   rB   _curve_scorerr   score)	r   r   r   rY   r   r   r{   r+   rR   s	      r-   	<genexpr>z2TunedThresholdClassifierCV._fit.<locals>.<genexpr>}  s       * * 'Iw 8677)+xE*%%%Z,6:'#!%!3!.!5!;	 	 	* * * * * *r/   c              3   X   K   | ]%}t          j        |d          |d                   V  &dS )r   N)r3   isclose)r   r   s     r-   r   z2TunedThresholdClassifierCV._fit.<locals>.<genexpr>  s6      AARrz"Q%B((AAAAAAr/   zrThe provided estimator makes constant predictions. Therefore, it is impossible to optimize the decision threshold.c              3   >   K   | ]}|                                 V  d S rK   )r   r   r   s     r-   r   z2TunedThresholdClassifierCV._fit.<locals>.<genexpr>  @       
 
'7  ""
 
 
 
 
 
r/   c              3   >   K   | ]}|                                 V  d S rK   )r   r   s     r-   r   z2TunedThresholdClassifierCV._fit.<locals>.<genexpr>  r   r/   )num)r   scores)*r   r   r   r#   r   r   rW   r    r*   r   r$   get_n_splitsr   _get_curve_scorerr   r'   ranger   r   splitsplitterrB   nextr   r   r   r   r   anyr   r   r   r   r3   r   r   r   argmaxbest_score_best_threshold_r   cv_results_)r+   rY   rR   rZ   excsplitsr   r   r   r   r   r   r   min_thresholdmax_thresholddecision_thresholdsobjective_scoresbest_idxr   r   r{   s   ```               @@@r-   rX   zTunedThresholdClassifierCV._fit7  s4   ( dgt$$ 	VTWq'dgD<M  BB W  zT!! !JKKK
;;;;!   $G  BB$'Q4888BzU""r'8'81'<'< !TUUU'e>>v>>!3355 >>"nDOJU<??3345FF#DN33DOt~..JRXaCCm&<&BCCFz 
56=;R;V"2  $HBHQ$R$R]5K5Q$R$RSS	1(I66(I66#7}.2I$ $ $   DOEE4DEEE#&)XT[))) * * * * * * * * * +1* * *  $
 	=  AA=AAAAA 	A    
 
;H
 
 
 
 
  
 
;H
 
 
 
 
 dox00 	>"$+}$/# # # #%*T_"="=3	
 
 $**,,+H528<  	1*   D
 s   7B 
B,B''B,c                     t          | d           | j                                        }t          | j        ||                                 |          \  }}t          || j        | j        |          S )r}   r'   r   )	r    r   r   r   r'   rN   r?   r   r]   )r+   rY   r;   r8   r   s        r-   r   z"TunedThresholdClassifierCV.predict  s|     	l+++&5577	0O%%''	
 
 

 1T)4=)
 
 	
r/   c                    t          | j        j                                      | j        t                                          dd                                        | j        t                                          dd                                        |                                 t                                          dd                    }|S )	r   r   rB   r   r   r   )r   r   r   )r   r   )r   ry   rk   r   r*   r   r   r   r   s     r-   r   z/TunedThresholdClassifierCV.get_metadata_routing  s     !8999S.,22%2NN    S,22'%2PP    S--//,22'%2PP    	 r/   c                     t          | j        | j                  }t                              ||                                 | j                  }|S )z8Get the curve scorer based on the objective metric used.)r   )r   r*   r   r   r   rN   r   )r+   r   r   s      r-   r   z,TunedThresholdClassifierCV._get_curve_scorer  sJ    EEE#//T..00$/
 
 r/   )rk   rl   rm   rn   rA   rH   r   setr   callabler   r   r   r   rp   rq   rL   rX   r   r   r   r   r   s   @r-   r   r   k  sp        ` `D$
!
8$ Jss++--..//

  x!T&AAA<PJz""HZc)<<<

 T"'(&K!$ $ $D   . $1 1 1 1 1 1 1,u u un
 
 
4  :      r/   r   )9collections.abcr   numbersr   r   numpyr3   baser   r   r	   r
   r   
exceptionsr   metricsr   r   metrics._scorerr   utilsr   utils._param_validationr   r   r   r   utils._responser   utils.metadata_routingr   r   r   r   utils.metaestimatorsr   utils.multiclassr   utils.parallelr   r   utils.validationr   r   r    r!   _splitr#   r$   r1   r?   rA   rt   r   r   r   r   r0   r/   r-   <module>r     s   * * * * * * " " " " " " " "                  ( ' ' ' ' '        * ) ) ) ) ) " " " " " " R R R R R R R R R R R R 9 9 9 9 9 9            0 / / / / / - - - - - - . . . . . . . .            5 4 4 4 4 4 4 4  "	W 	W 	Wa
 a
 a
 a
 a
o/A= a
 a
 a
Hq q q q q6 q q qhf@ f@ f@ f@ f@; f@ f@ f@RFF FF FFR  8@ @ @ @ @!8 @ @ @ @ @r/   