code: def test_complex_pandas():
      working_set = iris_amp.copy()
      new_data = working_set.loc[range(10), :].copy()
  
      # Customize everything.
      vs = {
          "sl": ["ws", "pl", "pw", "sp", "bc"],
          "ws": ["sl"],
          "pl": ["sp", "bc"],
          "sp": ["sl", "ws", "pl", "pw", "bc"],
          "pw": ["sl", "ws", "pl", "sp", "bc"],
      }
      mmc = {"sl": 4, "ws": 0.01, "pl": 0}
      ds = {"sl": 100, "ws": 0.5}
      io = ["pw", "pl", "ws", "sl"]
  
      imputed_var_names = io
      non_imputed_var_names = [
          c for c in iris_amp if c not in imputed_var_names
      ]
  
      from miceforest.builtin_mean_match_schemes import mean_match_shap
  
      mean_match_custom = mean_match_shap.copy()
      mean_match_custom.set_mean_match_candidates(mmc)
  
      kernel = mf.ImputationKernel(
          data=working_set,
          datasets=2,
          variable_schema=vs,
          mean_match_scheme=mean_match_shap,
          imputation_order=io,
          train_nonmissing=True,
          data_subset=ds,
          categorical_feature="auto",
          copy_data=False,
      )
      kernel2 = mf.ImputationKernel(
          data=working_set,
          datasets=1,
          variable_schema=vs,
          mean_match_scheme=mean_match_shap,
          imputation_order=io,
          train_nonmissing=True,
          data_subset=ds,
          categorical_feature="auto",
          copy_data=False,
      )
      new_file, filename = mkstemp()
      kernel2.save_kernel(filename)
      kernel2 = mf.utils.load_kernel(filename)
  
      assert kernel.data_subset == {
          0: 100,
          1: 56,
          3: 113,
          2: 113,
          4: 113,
      }, "mean_match_subset initialization failed"
      assert (
          kernel.iteration_count() == 0
      ), "iteration initialization failed"
      assert kernel.categorical_variables == [
          4,
          5,
      ], "categorical recognition failed."
  
      # This section tests many things:
      # After saving / loading a kernel, and appending 2 kernels together:
      # mice can continue
      # Aliases are fixed, even when different aliases are passed
      # variable specific parameters supercede globally specified parameters
      # The parameters come through the actual model
      nround = 2
      kernel.mice(
          nround - 1,
          compile_candidates=True,
          variable_parameters={"sl": {"n_iter": 15}},
          num_trees=10,
          verbose=True,
      )
      kernel.compile_candidate_preds()
      kernel2.mice(
          nround - 1,
          variable_parameters={"sl": {"n_estimators": 15}},
          n_estimators=10,
          verbose=True,
      )
      kernel.append(kernel2)
      kernel.compile_candidate_preds()
      assert kernel.get_model(0, 0, nround - 1).num_trees() == 15
      assert kernel.get_model(0, 1, nround - 1).num_trees() == 10
      kernel.mice(
          1,
          variable_parameters={1: {"n_iter": 15}},
          num_trees=10,
          verbose=True,
      )
      assert (
          kernel.iteration_count() == nround
      ), "iteration counting is incorrect."
      assert kernel.get_model(0, 1, nround).num_trees() == 15
      assert kernel.get_model(0, 2, nround).num_trees() == 10
  
      # Make sure we only impute variables in variable_schema
      compdat = kernel.complete_data(0)
      assert all(compdat[imputed_var_names].isnull().sum() == 0)
      assert all(compdat[non_imputed_var_names].isnull().sum() > 0)
  
      # Test the ability to tune parameters with custom setup
      optimization_steps = 2
      op, ol = kernel.tune_parameters(
          dataset=0,
          optimization_steps=optimization_steps,
          variable_parameters={
              1: {
                  "bagging_fraction": 0.9,
                  "feature_fraction_bynode": (0.85, 0.9),
              }
          },
          bagging_fraction=0.8,
          feature_fraction_bynode=(0.70, 0.75),
          verbose=True,
      )
      assert op[1]["bagging_fraction"] == 0.9
      assert op[2]["bagging_fraction"] == 0.8
      assert (op[1]["feature_fraction_bynode"] >= 0.85) and (
          op[1]["feature_fraction_bynode"] <= 0.9
      )
      assert (op[2]["feature_fraction_bynode"] >= 0.70) and (
          op[2]["feature_fraction_bynode"] <= 0.75
      )
      kernel.mice(1, variable_parameters=op, verbose=True)
      model_2_params = kernel.get_model(0, 2, nround + 1).params
      model_1_params = kernel.get_model(0, 1, nround + 1).params
      assert model_2_params["bagging_fraction"] == 0.8
      assert model_1_params["bagging_fraction"] == 0.9
      assert (model_2_params["feature_fraction_bynode"] >= 0.70) and (
          model_2_params["feature_fraction_bynode"] <= 0.75
      )
      assert (model_1_params["feature_fraction_bynode"] >= 0.85) and (
          model_1_params["feature_fraction_bynode"] <= 0.9
      )
  
      new_imp_dat = kernel.impute_new_data(
          new_data=new_data, verbose=True
      )
      new_imp_complete = new_imp_dat.complete_data(0)
      assert all(
          new_imp_complete[imputed_var_names].isnull().sum() == 0
      )
  
      # Plotting on multiple imputed dataset
      new_imp_dat.plot_mean_convergence()
      close()
      new_imp_dat.plot_imputed_distributions()
      close()
  
      # Plotting on Multiple Imputed Kernel
      kernel.plot_feature_importance(0)
      close()
      kernel.plot_mean_convergence()
      close()
      kernel.plot_imputed_distributions()
      close()
  
file_path: miceforest/tests/test_ImputationKernel.py
imports: from sklearn.datasets import load_iris
  import pandas
  import numpy
  import miceforest
  from datetime import datetime
  from miceforest import mean_match_fast_cat, mean_match_shap
  from matplotlib.pyplot import close
  from tempfile import mkstemp
label_desc: Use image node_id 2 for calling a global function with example usage: test_complex_pandas() without return types