docstr: This function optimizes probability threshold for a trained classifier. It
  uses the SHGO optimizer from ``scipy`` to optimize for the given metric.
  This function will display a plot of the performance metrics at each probability
  threshold checked by the optimizer and returns the best model based on the metric
  defined under ``optimize`` parameter.
  
  
  Example
  -------
  >>> from pycaret.datasets import get_data
  >>> juice = get_data('juice')
  >>> experiment_name = setup(data = juice,  target = 'Purchase')
  >>> lr = create_model('lr')
  >>> best_lr_threshold = optimize_threshold(lr)
  
  
  Parameters
  ----------
  estimator : object
      A trained model object should be passed as an estimator.
  
  
  optimize : str, default = 'Accuracy'
      Metric to be used for selecting best model.
  
  
  return_data :  bool, default = False
      When set to True, data used for visualization is also returned.
  
  
  plot_kwargs :  dict, default = {} (empty dict)
      Dictionary of arguments passed to the visualizer class.
  
  
  **shgo_kwargs:
      Kwargs to pass to ``scipy.optimize.shgo``.
  
  
  Returns
  -------
  Trained Model
  
  
  Warnings
  --------
  - This function does not support multiclass classification problems.
docstr_tok: ["This","function","optimizes","probability","threshold","for","a","trained","classifier",".","It","uses","the","SHGO","optimizer","from","``","scipy","``","to","optimize","for","the","given","metric",".","This","function","will","display","a","plot","of","the","performance","metrics","at","each","probability","threshold","checked","by","the","optimizer","and","returns","the","best","model","based","on","the","metric","defined","under","``","optimize","``","parameter",".","Example","--","--","--","-",">",">",">","from","pycaret.datasets","import","get_data",">",">",">","juice","=","get_data","(","'juice","'",")",">",">",">","experiment_name","=","setup","(","data","=","juice",",","target","=","'Purchase","'",")",">",">",">","lr","=","create_model","(","'lr","'",")",">",">",">","best_lr_threshold","=","optimize_threshold","(","lr",")","Parameters","--","--","--","--","--","estimator",":","object","A","trained","model","object","should","be","passed","as","an","estimator",".","optimize",":","str",",","default","=","'Accuracy'","Metric","to","be","used","for","selecting","best","model",".","return_data",":","bool",",","default","=","False","When","set","to","True",",","data","used","for","visualization","is","also","returned",".","plot_kwargs",":","dict",",","default","=","{","}","(","empty","dict",")","Dictionary","of","arguments","passed","to","the","visualizer","class",".","*","*","shgo_kwargs",":","Kwargs","to","pass","to","``","scipy.optimize.shgo","``",".","Returns","--","--","--","-","Trained","Model","Warnings","--","--","--","--","-","This","function","does","not","support","multiclass","classification","problems","."]
code: def optimize_threshold(
      self,
      estimator,
      optimize: str = "Accuracy",
      return_data: bool = False,
      plot_kwargs: Optional[dict] = None,
      **shgo_kwargs,
  ):
      """
      This function optimizes probability threshold for a trained classifier. It
      uses the SHGO optimizer from ``scipy`` to optimize for the given metric.
      This function will display a plot of the performance metrics at each probability
      threshold checked by the optimizer and returns the best model based on the metric
      defined under ``optimize`` parameter.
  
  
      Example
      -------
      >>> from pycaret.datasets import get_data
      >>> juice = get_data('juice')
      >>> experiment_name = setup(data = juice,  target = 'Purchase')
      >>> lr = create_model('lr')
      >>> best_lr_threshold = optimize_threshold(lr)
  
  
      Parameters
      ----------
      estimator : object
          A trained model object should be passed as an estimator.
  
  
      optimize : str, default = 'Accuracy'
          Metric to be used for selecting best model.
  
  
      return_data :  bool, default = False
          When set to True, data used for visualization is also returned.
  
  
      plot_kwargs :  dict, default = {} (empty dict)
          Dictionary of arguments passed to the visualizer class.
  
  
      **shgo_kwargs:
          Kwargs to pass to ``scipy.optimize.shgo``.
  
  
      Returns
      -------
      Trained Model
  
  
      Warnings
      --------
      - This function does not support multiclass classification problems.
      """
  
      function_params_str = ", ".join(
          [f"{k}={v}" for k, v in locals().items()]
      )
  
      self.logger.info("Initializing optimize_threshold()")
      self.logger.info(f"optimize_threshold({function_params_str})")
  
      self.logger.info("Importing libraries")
  
      # import libraries
  
      np.random.seed(self.seed)
  
      """
          ERROR HANDLING STARTS HERE
          """
  
      self.logger.info("Checking exceptions")
  
      # exception 1 for multi-class
      if self.is_multiclass:
          raise TypeError(
              "optimize_threshold() cannot be used when target is multi-class."
          )
  
      # check predict_proba value
      if type(estimator) is not list:
          if not hasattr(estimator, "predict_proba"):
              raise TypeError(
                  "Estimator doesn't support predict_proba function and cannot be used in optimize_threshold()."
              )
  
      if (
          "func" in shgo_kwargs
          or "bounds" in shgo_kwargs
          or "args" in shgo_kwargs
      ):
          raise ValueError(
              "shgo_kwargs cannot contain 'func', 'bounds' or 'args'."
          )
  
      shgo_kwargs.setdefault("sampling_method", "sobol")
      shgo_kwargs.setdefault("options", {})
      shgo_kwargs.setdefault("minimizer_kwargs", {})
      shgo_kwargs["minimizer_kwargs"].setdefault("options", {})
      shgo_kwargs["minimizer_kwargs"]["options"].setdefault(
          "ftol", 1e-4
      )
      shgo_kwargs.setdefault("n", 8)
      shgo_kwargs["options"].setdefault("maxiter", 4)
      shgo_kwargs["options"].setdefault("f_tol", 1e-4)
  
      # checking optimize parameter
      optimize = self._get_metric_by_name_or_id(optimize)
      if optimize is None:
          raise ValueError(
              "Optimize method not supported. See docstring for list of available parameters."
          )
      direction = -1 if optimize.greater_is_better else 1
      optimize = optimize.display_name
  
      """
          ERROR HANDLING ENDS HERE
          """
  
      self.logger.info("defining variables")
      # get estimator name
      model_name = self._get_model_name(estimator)
  
      # defines empty list
      results_df = []
  
      self.logger.info("starting optimization")
  
      def objective(x, *args):
          probability_threshold = x[0]
          model = self._create_model(
              estimator,
              verbose=False,
              system=False,
              probability_threshold=probability_threshold,
          )
          model_results = (
              self.pull(pop=True)
              .reset_index()
              .drop(columns=["Split"], errors="ignore")
              .set_index(["Fold"])
              .loc[
                  [
                      self._get_return_train_score_indices_for_logging(
                          return_train_score=False
                      )
                  ]
              ]
          )
          model_results["probability_threshold"] = probability_threshold
          model_results["model"] = model[0]
          results_df.append(model_results)
          return model_results[optimize] * direction
  
      # This is necessary to make sure the sampler has a
      # deterministic seed.
      class FixedRandom(np.random.RandomState):
          def __init__(self_, seed=None) -> None:  # noqa
              super().__init__(self.seed)
  
      with patch("numpy.random.RandomState", FixedRandom):
          result = shgo(objective, ((0, 1),), **shgo_kwargs)
  
      message = (
          "optimization loop finished successfully. "
          f"Best threshold: {result.x[0]} with {optimize}={result.fun*direction}"
      )
      print(message)
      self.logger.info(message)
  
      results_concat = pd.concat(results_df, axis=0)
      results_concat = results_concat.sort_values(
          "probability_threshold"
      )
      results_concat_melted = results_concat.drop("model", axis=1).melt(
          id_vars=["probability_threshold"],
          value_vars=list(results_concat.columns[:-1]),
      )
      best_model_by_metric = results_concat[
          results_concat["probability_threshold"] == result.x[0]
      ]["model"].iloc[0]
      assert isinstance(
          best_model_by_metric, CustomProbabilityThresholdClassifier
      )
      assert best_model_by_metric.probability_threshold == result.x[0]
  
      self.logger.info("plotting optimization threshold using plotly")
  
      title = f"{model_name} Probability Threshold Optimization (default = 0.5)"
      plot_kwargs = plot_kwargs or {}
      fig = px.line(
          results_concat_melted,
          x="probability_threshold",
          y="value",
          title=title,
          color="variable",
          **plot_kwargs,
      )
      fig.show()
  
      self.logger.info("returning model with best metric")
      if return_data:
          self.logger.info("also returning data as return_data = True")
          self.logger.info(
              "optimize_threshold() successfully completed......................................"
          )
          return (results_concat_melted, best_model_by_metric)
      else:
          self.logger.info(
              "optimize_threshold() successfully completed......................................"
          )
          return best_model_by_metric
  
imports: import datetime
  import gc
  import logging
  import re
  import time
  from typing import Any, Callable, Dict, List, Optional, Tuple, Union
  from unittest.mock import patch
  import numpy
  import pandas
  import plotly.express
  import sklearn
  from joblib.memory import Memory
  from scipy.optimize import shgo
  from pycaret.containers.metrics.classification import get_all_metric_containers
  from pycaret.containers.models.classification import ALL_ALLOWED_ENGINES, get_all_model_containers, get_container_default_engines
  from pycaret.internal.display import CommonDisplay
  from pycaret.internal.logging import get_logger
  from pycaret.internal.meta_estimators import CustomProbabilityThresholdClassifier, get_estimator_from_meta_estimator
  from pycaret.internal.parallel.parallel_backend import ParallelBackend
  from pycaret.internal.pipeline import Pipeline
  from pycaret.internal.preprocess.preprocessor import Preprocessor
  from pycaret.internal.pycaret_experiment.non_ts_supervised_experiment import _NonTSSupervisedExperiment
  from pycaret.internal.validation import is_sklearn_cv_generator
  from pycaret.loggers.base_logger import BaseLogger
  from pycaret.utils.constants import DATAFRAME_LIKE, SEQUENCE_LIKE, TARGET_LIKE
  from pycaret.utils.generic import MLUsecase, get_classification_task, get_label_encoder, highlight_setup
label_desc: Use image node_id 17 for calling the ClassificationExperiment obj's underlying member method code with example usage: obj.optimize_threshold(estimator, optimize, return_data, plot_kwargs) and returns: unknown, results_concat_melted,  best_model_by_metric, best_model_by_metric