class_docstr: Uses Tree SHAP algorithms to explain the output of ensemble tree models.
  
  Tree SHAP is a fast and exact method to estimate SHAP values for tree models and ensembles of trees,
  under several different possible assumptions about feature dependence. It depends on fast C++
  implementations either inside an external model package or in the local compiled C extension.
class_docstr_tok: ["Uses","Tree","SHAP","algorithms","to","explain","the","output","of","ensemble","tree","models",".","Tree","SHAP","is","a","fast","and","exact","method","to","estimate","SHAP","values","for","tree","models","and","ensembles","of","trees",",","under","several","different","possible","assumptions","about","feature","dependence",".","It","depends","on","fast","C++","implementations","either","inside","an","external","model","package","or","in","the","local","compiled","C","extension","."]
docstr: Build a new Tree explainer for the passed model.
  
  Parameters
  ----------
  model : model object
      The tree based machine learning model that we want to explain. XGBoost, LightGBM, CatBoost, Pyspark
      and most tree-based scikit-learn models are supported.
  
  data : numpy.array or pandas.DataFrame
      The background dataset to use for integrating out features. This argument is optional when
      ``feature_perturbation="tree_path_dependent"``, since in that case we can use the number of training
      samples that went down each tree path as our background dataset (this is recorded in the ``model``
      object).
  
  feature_perturbation : "interventional" (default) or "tree_path_dependent" (default when data=None)
      Since SHAP values rely on conditional expectations, we need to decide how to handle correlated
      (or otherwise dependent) input features.
      The "interventional" approach breaks the dependencies between features according to the rules
      dictated by causal inference (Janzing et al. 2019). Note that the "interventional" option
      requires a background dataset ``data``, and its runtime scales linearly with the size of the
      background dataset you use. Anywhere from 100 to 1000 random background samples are good
      sizes to use.
      The "tree_path_dependent" approach is to just follow the trees and use the number of training
      examples that went down each leaf to represent the background distribution. This approach
      does not require a background dataset, and so is used by default when no background dataset
      is provided.
  
  model_output : "raw", "probability", "log_loss", or model method name
      What output of the model should be explained.
      If "raw", then we explain the raw output of the trees, which varies by model. For regression models,
      "raw" is the standard output. For binary classification in XGBoost, this is the log odds ratio.
      If ``model_output`` is the name of a supported prediction method on the ``model`` object, then we
      explain the output of that model method name. For example, ``model_output="predict_proba"``
      explains the result of calling ``model.predict_proba``.
      If "probability", then we explain the output of the model transformed into probability space
      (note that this means the SHAP values now sum to the probability output of the model).
      If "log_loss", then we explain the log base e of the model loss function, so that the SHAP values
      sum up to the log loss of the model for each sample. This is helpful for breaking down model
      performance by feature.
      Currently the "probability" and "log_loss" options are only supported when
      ``feature_perturbation="interventional"``.
  
  Examples
  --------
  See `Tree explainer examples <https://shap.readthedocs.io/en/latest/api_examples/explainers/Tree.html>`_
docstr_tok: ["Build","a","new","Tree","explainer","for","the","passed","model",".","Parameters","--","--","--","--","--","model",":","model","object","The","tree","based","machine","learning","model","that","we","want","to","explain",".","XGBoost",",","LightGBM",",","CatBoost",",","Pyspark","and","most","tree-based","scikit-learn","models","are","supported",".","data",":","numpy.array","or","pandas.DataFrame","The","background","dataset","to","use","for","integrating","out","features",".","This","argument","is","optional","when","``","feature_perturbation=","''","tree_path_dependent","''","``",",","since","in","that","case","we","can","use","the","number","of","training","samples","that","went","down","each","tree","path","as","our","background","dataset","(","this","is","recorded","in","the","``","model","``","object",")",".","feature_perturbation",":","``","interventional","''","(","default",")","or","``","tree_path_dependent","''","(","default","when","data=None",")","Since","SHAP","values","rely","on","conditional","expectations",",","we","need","to","decide","how","to","handle","correlated","(","or","otherwise","dependent",")","input","features",".","The","``","interventional","''","approach","breaks","the","dependencies","between","features","according","to","the","rules","dictated","by","causal","inference","(","Janzing","et","al",".","2019",")",".","Note","that","the","``","interventional","''","option","requires","a","background","dataset","``","data","``",",","and","its","runtime","scales","linearly","with","the","size","of","the","background","dataset","you","use",".","Anywhere","from","100","to","1000","random","background","samples","are","good","sizes","to","use",".","The","``","tree_path_dependent","''","approach","is","to","just","follow","the","trees","and","use","the","number","of","training","examples","that","went","down","each","leaf","to","represent","the","background","distribution",".","This","approach","does","not","require","a","background","dataset",",","and","so","is","used","by","default","when","no","background","dataset","is","provided",".","model_output",":","``","raw","''",",","``","probability","''",",","``","log_loss","''",",","or","model","method","name","What","output","of","the","model","should","be","explained",".","If","``","raw","''",",","then","we","explain","the","raw","output","of","the","trees",",","which","varies","by","model",".","For","regression","models",",","``","raw","''","is","the","standard","output",".","For","binary","classification","in","XGBoost",",","this","is","the","log","odds","ratio",".","If","``","model_output","``","is","the","name","of","a","supported","prediction","method","on","the","``","model","``","object",",","then","we","explain","the","output","of","that","model","method","name",".","For","example",",","``","model_output=","''","predict_proba","''","``","explains","the","result","of","calling","``","model.predict_proba","``",".","If","``","probability","''",",","then","we","explain","the","output","of","the","model","transformed","into","probability","space","(","note","that","this","means","the","SHAP","values","now","sum","to","the","probability","output","of","the","model",")",".","If","``","log_loss","''",",","then","we","explain","the","log","base","e","of","the","model","loss","function",",","so","that","the","SHAP","values","sum","up","to","the","log","loss","of","the","model","for","each","sample",".","This","is","helpful","for","breaking","down","model","performance","by","feature",".","Currently","the","``","probability","''","and","``","log_loss","''","options","are","only","supported","when","``","feature_perturbation=","''","interventional","''","``",".","Examples","--","--","--","--","See","`","Tree","explainer","examples","<","https",":","\/\/shap.readthedocs.io\/en\/latest\/api_examples\/explainers\/Tree.html",">","`","_"]
code: def __init__(
      self,
      model,
      data=None,
      model_output="raw",
      feature_perturbation="interventional",
      feature_names=None,
      approximate=False,
      **deprecated_options,
  ):
      """Build a new Tree explainer for the passed model.
  
      Parameters
      ----------
      model : model object
          The tree based machine learning model that we want to explain. XGBoost, LightGBM, CatBoost, Pyspark
          and most tree-based scikit-learn models are supported.
  
      data : numpy.array or pandas.DataFrame
          The background dataset to use for integrating out features. This argument is optional when
          ``feature_perturbation="tree_path_dependent"``, since in that case we can use the number of training
          samples that went down each tree path as our background dataset (this is recorded in the ``model``
          object).
  
      feature_perturbation : "interventional" (default) or "tree_path_dependent" (default when data=None)
          Since SHAP values rely on conditional expectations, we need to decide how to handle correlated
          (or otherwise dependent) input features.
          The "interventional" approach breaks the dependencies between features according to the rules
          dictated by causal inference (Janzing et al. 2019). Note that the "interventional" option
          requires a background dataset ``data``, and its runtime scales linearly with the size of the
          background dataset you use. Anywhere from 100 to 1000 random background samples are good
          sizes to use.
          The "tree_path_dependent" approach is to just follow the trees and use the number of training
          examples that went down each leaf to represent the background distribution. This approach
          does not require a background dataset, and so is used by default when no background dataset
          is provided.
  
      model_output : "raw", "probability", "log_loss", or model method name
          What output of the model should be explained.
          If "raw", then we explain the raw output of the trees, which varies by model. For regression models,
          "raw" is the standard output. For binary classification in XGBoost, this is the log odds ratio.
          If ``model_output`` is the name of a supported prediction method on the ``model`` object, then we
          explain the output of that model method name. For example, ``model_output="predict_proba"``
          explains the result of calling ``model.predict_proba``.
          If "probability", then we explain the output of the model transformed into probability space
          (note that this means the SHAP values now sum to the probability output of the model).
          If "log_loss", then we explain the log base e of the model loss function, so that the SHAP values
          sum up to the log loss of the model for each sample. This is helpful for breaking down model
          performance by feature.
          Currently the "probability" and "log_loss" options are only supported when
          ``feature_perturbation="interventional"``.
  
      Examples
      --------
      See `Tree explainer examples <https://shap.readthedocs.io/en/latest/api_examples/explainers/Tree.html>`_
      """
      if feature_names is not None:
          self.data_feature_names = feature_names
      elif isinstance(data, pd.DataFrame):
          self.data_feature_names = list(data.columns)
  
      masker = data
      super().__init__(model, masker, feature_names=feature_names)
  
      if type(self.masker) is maskers.Independent:
          data = self.masker.data
      elif masker is not None:
          raise InvalidMaskerError(
              "Unsupported masker type: %s!" % str(type(self.masker))
          )
  
      if getattr(self.masker, "clustering", None) is not None:
          raise ExplainerError(
              "TreeExplainer does not support clustered data inputs! Please use shap.Explainer or pass an unclustered masker!"
          )
  
      # check for deprecated options
      if model_output == "margin":
          warnings.warn(
              'model_output = "margin" has been renamed to model_output = "raw"'
          )
          model_output = "raw"
      if model_output == "logloss":
          warnings.warn(
              'model_output = "logloss" has been renamed to model_output = "log_loss"'
          )
          model_output = "log_loss"
      if "feature_dependence" in deprecated_options:
          dep_val = deprecated_options["feature_dependence"]
          if (
              dep_val == "independent"
              and feature_perturbation == "interventional"
          ):
              warnings.warn(
                  'feature_dependence = "independent" has been renamed to feature_perturbation'
                  ' = "interventional"! See GitHub issue #882.'
              )
          elif feature_perturbation != "interventional":
              warnings.warn(
                  'feature_dependence = "independent" has been renamed to feature_perturbation'
                  ' = "interventional", you can\'t supply both options! See GitHub issue #882.'
              )
          if (
              dep_val == "tree_path_dependent"
              and feature_perturbation == "interventional"
          ):
              raise ValueError(
                  "The feature_dependence option has been renamed to feature_perturbation! "
                  "Please update the option name before calling TreeExplainer. See GitHub issue #882."
              )
      if feature_perturbation == "independent":
          raise InvalidFeaturePerturbationError(
              'feature_perturbation = "independent" is not a valid option value, please use '
              'feature_perturbation = "interventional" instead. See GitHub issue #882.'
          )
  
      if isinstance(data, pd.DataFrame):
          self.data = data.values
      elif isinstance(data, DenseData):
          self.data = data.data
      else:
          self.data = data
      if self.data is None:
          feature_perturbation = "tree_path_dependent"
          # warnings.warn("Setting feature_perturbation = \"tree_path_dependent\" because no background data was given.")
      elif (
          feature_perturbation == "interventional"
          and self.data.shape[0] > 1_000
      ):
          wmsg = (
              f"Passing {self.data.shape[0]} background samples may lead to slow runtimes. Consider "
              "using shap.sample(data, 100) to create a smaller background data set."
          )
          warnings.warn(wmsg)
      self.data_missing = (
          None if self.data is None else pd.isna(self.data)
      )
      self.feature_perturbation = feature_perturbation
      self.expected_value = None
      self.model = TreeEnsemble(
          model, self.data, self.data_missing, model_output
      )
      self.model_output = model_output
      # self.model_output = self.model.model_output # this allows the TreeEnsemble to translate model outputs types by how it loads the model
  
      self.approximate = approximate
  
      if feature_perturbation not in feature_perturbation_codes:
          raise InvalidFeaturePerturbationError(
              "Invalid feature_perturbation option!"
          )
  
      # check for unsupported combinations of feature_perturbation and model_outputs
      if feature_perturbation == "tree_path_dependent":
          if self.model.model_output != "raw":
              raise ValueError(
                  'Only model_output="raw" is supported for feature_perturbation="tree_path_dependent"'
              )
      elif data is None:
          raise ValueError(
              'A background dataset must be provided unless you are using feature_perturbation="tree_path_dependent"!'
          )
  
      if self.model.model_output != "raw":
          if (
              self.model.objective is None
              and self.model.tree_output is None
          ):
              emsg = (
                  "Model does not have a known objective or output type! When model_output is "
                  'not "raw" then we need to know the model\'s objective or link function.'
              )
              raise Exception(emsg)
  
      # A change in the signature of `xgboost.Booster.predict()` method has been introduced in XGBoost v1.4:
      # The introduced `iteration_range` parameter is used when obtaining SHAP (incl. interaction) values from XGBoost models.
      if self.model.model_type == "xgboost":
          import xgboost
  
          if version.parse(xgboost.__version__) < version.parse("1.4"):
              raise RuntimeError(
                  f"SHAP requires XGBoost >= v1.4 , but found version {xgboost.__version__}. Please upgrade XGBoost!"
              )
  
      # compute the expected value if we have a parsed tree for the cext
      if self.model.model_output == "log_loss":
          self.expected_value = self.__dynamic_expected_value
      elif data is not None:
          try:
              self.expected_value = self.model.predict(self.data).mean(
                  0
              )
          except ValueError:
              raise ExplainerError(
                  "Currently TreeExplainer can only handle models with categorical splits when "
                  'feature_perturbation="tree_path_dependent" and no background data is passed. Please try again using '
                  'shap.TreeExplainer(model, feature_perturbation="tree_path_dependent").'
              )
          if (
              hasattr(self.expected_value, "__len__")
              and len(self.expected_value) == 1
          ):
              self.expected_value = self.expected_value[0]
      elif hasattr(self.model, "node_sample_weight"):
          self.expected_value = self.model.values[:, 0].sum(0)
          if self.expected_value.size == 1:
              self.expected_value = self.expected_value[0]
          self.expected_value += self.model.base_offset
          if self.model.model_output != "raw":
              self.expected_value = None  # we don't handle transforms in this case right now...
  
      # if our output format requires binary classification to be represented as two outputs then we do that here
      if (
          self.model.model_output == "probability_doubled"
          and self.expected_value is not None
      ):
          self.expected_value = [
              1 - self.expected_value,
              self.expected_value,
          ]
  
imports: import json
  import os
  import struct
  import time
  import warnings
  import numpy
  import pandas
  import scipy.sparse
  import scipy.special
  from packaging import version
  from ..None import maskers
  from .._explanation import Explanation
  from ..utils import assert_import, record_import_error, safe_isinstance
  from ..utils._exceptions import DimensionError, ExplainerError, InvalidFeaturePerturbationError, InvalidMaskerError, InvalidModelError
  from ..utils._legacy import DenseData
  from ._explainer import Explainer
label_desc: Use image node_id 1 to create a new TreeExplainer object from inherited base classes: Explainer with example: obj = TreeExplainer(model, data, model_output, feature_perturbation, feature_names, approximate)