code: def unit_change(
      background_df: pd.DataFrame,
      foreground_df: pd.DataFrame,
      input_column_names: List[str],
      background_mechanism: PredictionModel,
      foreground_mechanism: Optional[PredictionModel] = None,
      shapley_config: Optional[ShapleyConfig] = None,
  ) -> pd.DataFrame:
      """
      This function attributes the change in the output value of a deterministic mechanism for a statistical unit to each input and optionally for the mechanism if `foreground_mechanism` is provided.
      The technical method is described in the following research paper:
      Kailash Budhathoki, George Michailidis, Dominik Janzing. *Explaining the root causes of unit-level changes*. arXiv, 2022.
  
      :param background_df: The background dataset.
      :param foreground_df: The foreground dataset.
      :param input_column_names: The names of the input columns.
      :param background_mechanism: The background mechanism. If the mechanism does not change, then this mechanism is used for attribution.
      :param foreground_mechanism: The foreground mechanism. If provided, the method also attributes the output change to the change in the mechanism.
      :param shapley_config: The configuration for calculating Shapley values.
      :return: A dataframe containing the contributions of each input and optionally the mechanism to the change in the output values of the deterministic mechanism(s) for given inputs.
      """
      if foreground_mechanism:
          if isinstance(background_mechanism, LinearPredictionModel):
              return unit_change_linear(
                  background_mechanism,
                  background_df,
                  foreground_mechanism,
                  foreground_df,
                  input_column_names,
              )
          else:
              return unit_change_nonlinear(
                  background_mechanism,
                  background_df,
                  foreground_mechanism,
                  foreground_df,
                  input_column_names,
                  shapley_config,
              )
  
      if isinstance(background_mechanism, LinearPredictionModel):
          return unit_change_linear_input_only(
              background_mechanism,
              background_df,
              foreground_df,
              input_column_names,
          )
      else:
          return unit_change_nonlinear_input_only(
              background_mechanism,
              background_df,
              foreground_df,
              input_column_names,
              shapley_config,
          )
  
imports: from abc import abstractmethod
  from typing import List, Optional
  import numpy
  import pandas
  from sklearn.linear_model._base import LinearModel
  from sklearn.utils.validation import check_is_fitted
  from dowhy.gcm.ml.prediction_model import PredictionModel
  from dowhy.gcm.ml.regression import SklearnRegressionModel
  from dowhy.gcm.shapley import ShapleyConfig, estimate_shapley_values
label_desc: Use image node_id 1 for calling a global function with example usage: unit_change(background_df, foreground_df, input_column_names, background_mechanism, foreground_mechanism, shapley_config) and returns: unit_change_linear_input_only, unit_change_nonlinear_input_only, unit_change_linear, unit_change_nonlinear