code: def make_synthetic(
      classes=["class_0", "class_1"],
      n_samples=1000,
      missing=False,
      objects=True,
      seed=None,
      noise_scale=0.25,
      base_shift=0.0,
      higher_class_probs=None,
      categories=[
          9,
          46,
      ],  # 46 is the max categories before the UI hides them
      categorical_floor=[0.2, 0.01],
      categorical_digits=3,
      clip_low=-2.0,
      clip_high=2.0,
  ):
      rng = np.random.default_rng(seed)
  
      X_orig, names, types = _make_synthetic_features(
          n_samples,
          missing,
          objects,
          rng,
          categories,
          categorical_floor,
          categorical_digits,
          clip_low,
          clip_high,
      )
  
      X_imp = _normalize_categoricals(
          X_orig, types, clip_low, clip_high
      )
  
      # Impute missing values with 0
      missings = np.isnan(X_imp, order="F")
      X_imp[missings] = 0.0
  
      # Create some additive term mains for our model to find
      y = rng.normal(base_shift, noise_scale, n_samples)
      y += (
          np.cos(3.14159 * 4.0 / (clip_high - clip_low) * X_imp[:, 0])
          * 0.9
      )
      y += (
          np.sin(3.14159 * 2.0 / (clip_high - clip_low) * X_imp[:, 1])
          * 0.9
      )
      y += X_imp[:, 2] ** 2 * 0.4
      y += (
          X_imp[:, 3] * 0.4
      )  # feature 3 contains poisson distributed integers
      y += np.where(
          ((X_imp[:, 4] - clip_low) * 1.9999).astype(int) % 2,
          +0.7,
          -0.7,
      )
      y += (
          np.modf(X_imp[:, 5] - clip_low)[0] - 0.5
      ) * 1.5  # sawtooth wave
      y += np.exp(X_imp[:, 6]) * 0.15
      # Feature 7 is unused in the generation function
      y += X_imp[:, -2] * 0.4  # low cardinality categorical
      y += X_imp[:, -1] * 0.4  # high cardinality categorical
  
      # pair interactions
      xor_val = (X_imp[:, 3].astype(int) - int(np.floor(clip_low))) % 2
      y += X_imp[:, 0] * np.where(xor_val, +0.2, -0.2)
      y += X_imp[:, 1] * X_imp[:, 2] * 0.1
  
      # 3-way interaction
      y += X_imp[:, 0] * X_imp[:, 1] * X_imp[:, 2] * 0.02
  
      if classes is not None and classes != 0:
          if isinstance(classes, int):
              classes = np.arange(classes)
          else:
              classes = np.array(classes)
  
          n_classes = len(classes)
          if n_classes == 1:
              y = np.full(n_samples, classes[0])
          else:
              prob = np.exp(y)
              prob /= 1.0 + prob
  
              y = (rng.uniform(0.0, 1.0, n_samples) < prob).astype(int)
  
              if 2 < n_classes:
                  # multiclass. To keep things simple, randomly select classes above
                  # the 0th class with equal probability between the classes above 0.
                  y = np.where(
                      y,
                      rng.choice(
                          n_classes - 1, n_samples, p=higher_class_probs
                      )
                      + 1,
                      0,
                  )
  
              y = classes[y]
  
      return (X_orig, y, names, types)
  
file_path: interpret/python/interpret-core/interpret/utils/_synthetic.py
imports: import numpy
  from itertools import takewhile
  import operator
label_desc: Use image node_id 1 for calling a global function with example usage: make_synthetic(classes, n_samples, missing, objects, seed, noise_scale, base_shift, higher_class_probs, categories, categorical_floor, categorical_digits, clip_low, clip_high) and returns: X_orig,  y,  names,  types