class_docstr: Detect features that are nearly unused by the model.
  
  The check uses feature importance (either internally computed in appropriate models or calculated by permutation
  feature importance) to detect features that are not used by the model. From this list, the check sorts the features
  by their variance (as calculated by a PCA transformation). High variance unused features may be containing
  information that is ignored by the model.
  
  Parameters
  ----------
  feature_importance_threshold : float , default: 0.2
      A cutoff value for the feature importance, measured by the ratio of
      each features' feature importance to the mean feature importance. Features with lower importance
      are not shown in the check display.
  feature_variance_threshold : float , default: 0.4
      A cutoff value for the feature variance, measured by the ratio of
      each features' feature variance to the mean feature variance. Unused features with lower variance
      are not shown in the check display.
  n_top_fi_to_show : int , default: 5
      The max number of important features to show in the check display.
  n_top_unused_to_show : int , default: 15
      The max number of unused features to show in the check display, from among
      unused features that have higher variance then is defined by feature_variance_threshold.
  n_samples : int , default: 1_000_000
      number of samples to use for this check.
  random_state : int , default: 42
      The random state to use for permutation feature importance and PCA.
class_docstr_tok: ["Detect","features","that","are","nearly","unused","by","the","model",".","The","check","uses","feature","importance","(","either","internally","computed","in","appropriate","models","or","calculated","by","permutation","feature","importance",")","to","detect","features","that","are","not","used","by","the","model",".","From","this","list",",","the","check","sorts","the","features","by","their","variance","(","as","calculated","by","a","PCA","transformation",")",".","High","variance","unused","features","may","be","containing","information","that","is","ignored","by","the","model",".","Parameters","--","--","--","--","--","feature_importance_threshold",":","float",",","default",":","0.2","A","cutoff","value","for","the","feature","importance",",","measured","by","the","ratio","of","each","features","'","feature","importance","to","the","mean","feature","importance",".","Features","with","lower","importance","are","not","shown","in","the","check","display",".","feature_variance_threshold",":","float",",","default",":","0.4","A","cutoff","value","for","the","feature","variance",",","measured","by","the","ratio","of","each","features","'","feature","variance","to","the","mean","feature","variance",".","Unused","features","with","lower","variance","are","not","shown","in","the","check","display",".","n_top_fi_to_show",":","int",",","default",":","5","The","max","number","of","important","features","to","show","in","the","check","display",".","n_top_unused_to_show",":","int",",","default",":","15","The","max","number","of","unused","features","to","show","in","the","check","display",",","from","among","unused","features","that","have","higher","variance","then","is","defined","by","feature_variance_threshold",".","n_samples",":","int",",","default",":","1_000_000","number","of","samples","to","use","for","this","check",".","random_state",":","int",",","default",":","42","The","random","state","to","use","for","permutation","feature","importance","and","PCA","."]
docstr: Run check.
  
  Returns
  -------
  CheckResult
      value is dictionary of 2 values:
          used features : list
              A list of features that are considered important.
          unused features : dict
              A dictionary of features that are considered unimportant. The dictionary contains two keys:
              'high variance' and 'low variance'. Each key contains a list of features.
docstr_tok: ["Run","check",".","Returns","--","--","--","-","CheckResult","value","is","dictionary","of","2","values",":","used","features",":","list","A","list","of","features","that","are","considered","important",".","unused","features",":","dict","A","dictionary","of","features","that","are","considered","unimportant",".","The","dictionary","contains","two","keys",":","'high","variance","'","and","'low","variance","'",".","Each","key","contains","a","list","of","features","."]
code: def run_logic(self, context: Context, dataset_kind) -> CheckResult:
      """Run check.
  
      Returns
      -------
      CheckResult
          value is dictionary of 2 values:
              used features : list
                  A list of features that are considered important.
              unused features : dict
                  A dictionary of features that are considered unimportant. The dictionary contains two keys:
                  'high variance' and 'low variance'. Each key contains a list of features.
      """
      dataset = context.get_data_by_kind(dataset_kind).sample(
          self.n_samples, random_state=self.random_state
      )
      _ = context.model  # validate model
  
      feature_importance = context.feature_importance
      if feature_importance is None:
          raise DeepchecksValueError(
              "Feature Importance is not available."
          )
      dataset.assert_features()
  
      # Calculate normalized variance per feature based on PCA decomposition
      features_to_use = (
          dataset.numerical_features + dataset.cat_features
      )
      pre_pca_transformer = naive_encoder(
          dataset.numerical_features, dataset.cat_features
      )
      pca_trans = PCA(
          n_components=len(features_to_use) // 2,
          random_state=self.random_state,
      )
      fit_data = dataset.features_columns[features_to_use]
      # The naive encoder drops columns which are all nans, so fill only them with zeros
      columns_all_none = fit_data.columns[fit_data.isnull().all()]
      fit_data = fit_data.drop(columns_all_none, axis=1)
      fit_data[columns_all_none] = 0
      pca_trans.fit(pre_pca_transformer.fit_transform(fit_data))
  
      feature_normed_variance = pd.Series(
          np.abs(pca_trans.components_).sum(axis=0),
          index=features_to_use,
      )
      feature_normed_variance = (
          feature_normed_variance / feature_normed_variance.sum()
      )
  
      feature_df = pd.concat(
          [feature_importance, feature_normed_variance], axis=1
      )
      feature_df.columns = ["Feature Importance", "Feature Variance"]
      feature_df.sort_values(
          by="Feature Importance", ascending=False, inplace=True
      )
  
      # For feature importance and variance, calculate their "ratio to average" per feature. The ratio to average
      # is, for example, the amount of feature importance a feature has, divided by the amount he would have
      # if all features where equally important (which is basically 1 / n_of_features).
      feature_ratio_to_avg_df = feature_df / (
          1 / len(feature_importance)
      )
  
      # Find last viable feature (not unused). All features from there on are sorted by variance
      last_important_feature_index = (
          sum(
              feature_ratio_to_avg_df["Feature Importance"]
              > self.feature_importance_threshold
          )
          - 1
      )
  
      unviable_feature_df = feature_df.iloc[
          (last_important_feature_index + 1) :
      ]
      # Only display if there are features considered unimportant
      if not unviable_feature_df.empty:
          unviable_feature_df.sort_values(
              by="Feature Variance", ascending=False, inplace=True
          )
          unviable_feature_ratio_to_avg_df = unviable_feature_df / (
              1 / len(feature_df)
          )
          last_variable_feature_index = sum(
              unviable_feature_ratio_to_avg_df["Feature Variance"]
              > self.feature_variance_threshold
          )
  
          # display only if high variance features exist (as set by self.feature_variance_threshold)
          if context.with_display and last_variable_feature_index:
              # limit display to n_top_to_show params
              display_feature_df = pd.concat(
                  [
                      feature_df.iloc[
                          : (last_important_feature_index + 1)
                      ].head(self.n_top_fi_to_show),
                      unviable_feature_df.iloc[
                          :last_variable_feature_index
                      ].head(self.n_top_unused_to_show),
                  ],
                  axis=0,
              )
  
              fig = go.Figure()
              fig.add_trace(
                  go.Bar(
                      y=display_feature_df.index,
                      x=display_feature_df["Feature Importance"]
                      .multiply(100)
                      .values.flatten(),
                      name="Feature Importance %",
                      marker=dict(color="indianred"),
                      orientation="h",
                  )
              )
              fig.add_trace(
                  go.Bar(
                      y=display_feature_df.index,
                      x=display_feature_df["Feature Variance"]
                      .multiply(100)
                      .values.flatten(),
                      name="Feature Variance %",
                      marker=dict(color="lightsalmon"),
                      orientation="h",
                  )
              )
  
              fig.update_yaxes(autorange="reversed")
              fig.update_layout(
                  title_text="Unused features compared to top important features",
                  height=500,
              )
  
              last_important_feature_index_to_plot = min(
                  last_important_feature_index,
                  self.n_top_fi_to_show - 1,
              )
  
              if (
                  last_important_feature_index_to_plot
                  < len(display_feature_df) - 1
              ):
                  last_important_feature_line_loc = (
                      last_important_feature_index_to_plot + 0.5
                  )
                  fig.add_hline(
                      y=last_important_feature_line_loc,
                      line_width=2,
                      line_dash="dash",
                      line_color="green",
                      annotation_text="Last shown significant feature",
                  )
              display_list = [
                  "Features above the line are a sample of the most important features, while the features "
                  "below the line are the unused features with highest variance, as defined by check"
                  " parameters",
                  fig,
              ]
          else:
              display_list = []
  
      else:
          display_list = []
  
      return_value = {
          "used features": feature_df.index[
              : (last_important_feature_index + 1)
          ].values.tolist(),
          "unused features": {
              "high variance": (
                  []
                  if unviable_feature_df.empty
                  else unviable_feature_df.index[
                      :last_variable_feature_index
                  ].values.tolist()
              ),
              "low variance": (
                  []
                  if unviable_feature_df.empty
                  else unviable_feature_df.index[
                      last_variable_feature_index:
                  ].values.tolist()
              ),
          },
      }
  
      return CheckResult(
          return_value, header="Unused Features", display=display_list
      )
  
file_path: deepchecks/deepchecks/tabular/checks/model_evaluation/unused_features.py
imports: import numpy
  import pandas
  import plotly.graph_objects
  from sklearn.base import TransformerMixin
  from sklearn.compose import ColumnTransformer
  from sklearn.decomposition import PCA
  from sklearn.impute import SimpleImputer
  from sklearn.pipeline import Pipeline
  from sklearn.preprocessing import OrdinalEncoder, RobustScaler
  from deepchecks.core import CheckResult, ConditionCategory, ConditionResult
  from deepchecks.core.errors import DeepchecksValueError
  from deepchecks.tabular import Context, SingleDatasetCheck
  from deepchecks.utils.function import run_available_kwargs
label_desc: Use image node_id 2 for calling the UnusedFeatures obj's underlying member method code with example usage: obj.run_logic(context, dataset_kind) and returns: CheckResult