code: def _make_synthetic_features(
      n_samples,
      missing,
      objects,
      seed,
      categories,
      categorical_floor,
      categorical_digits,
      clip_low,
      clip_high,
  ):
      # EBMs are insensitive to the scale of the feature values since features are binned
      # using quantiles, so we have the flexibility to use any scale that suits our
      # needs. We have selected a scale for the feature values that makes generating
      # synthetic y values easier by keeping the same scale for all features in the
      # range between -2.0 and 2.0. This also helps keep transformations such as exp(x)
      # and x * x from becoming excessively large.
      # We've also adjusted each feature so the average negative value is about -1.0
      # and the average positive value is about +1.0. This establishes a uniform scale
      # with integers, accommodating five integers ranging from -2 to +2.
  
      if isinstance(seed, np.random.Generator):
          rng = seed
      else:
          rng = np.random.default_rng(seed)
  
      clip_low_int = int(np.ceil(clip_low))
      clip_high_int = int(np.floor(clip_high))
  
      names = []
      types = []
      features = []
  
      # Feature 0 - Continuous drawn from a uniform distribution
      names.append("feature_0")
      types.append("continuous")
      features.append(rng.uniform(clip_low, clip_high, n_samples))
  
      # Feature 1 - Continuous drawn from a normal distribution
      names.append("feature_1")
      types.append("continuous")
      features.append(
          np.clip(rng.normal(0.0, 1.5, n_samples), clip_low, clip_high)
      )
  
      # Feature 2 - Continuous time between events with avg time between events of 2.0
      names.append("feature_2")
      types.append("continuous")
      features.append(
          np.clip(
              rng.exponential(scale=2.0, size=n_samples) - 2.0,
              clip_low,
              clip_high,
          )
      )
  
      # Feature 3 - Integer number of events in an interval, with average rate 2.0
      names.append("feature_3_integers")
      types.append("continuous")
      features.append(
          np.clip(
              rng.poisson(lam=2.0, size=n_samples) - 2,
              clip_low_int,
              clip_high_int,
          )
      )
  
      # Feature 4 - Positive correlation with feature 0 and negative with 1
      names.append("feature_4")
      types.append("continuous")
      features.append(
          np.clip(
              0.7 * features[0]
              - 0.6 * features[1]
              + rng.normal(0.0, 0.7, n_samples),
              clip_low,
              clip_high,
          )
      )
  
      # Feature 5 - Correlation with feature 2 when feature 2 is in the center region
      names.append("feature_5")
      types.append("continuous")
      clip_quarter = (clip_high - clip_low) / 4.0
      features.append(
          np.clip(
              np.where(
                  (clip_low + clip_quarter < features[2])
                  & (features[2] < clip_high - clip_quarter),
                  1.5,
                  0.0,
              )
              * features[2]
              + rng.normal(0.0, 1.25, n_samples),
              clip_low,
              clip_high,
          )
      )
  
      # Feature 6 - Interaction between feature 2 and feature 3
      names.append("feature_6")
      types.append("continuous")
      features.append(
          np.clip(
              features[2] * features[3]
              + rng.normal(0.0, 0.5, n_samples),
              clip_low,
              clip_high,
          )
      )
  
      # Feature 7 - Unused feature
      names.append("feature_7_unused")
      types.append("continuous")
      features.append(rng.uniform(10.0, 100.0, n_samples))
  
      # Feature 8 - Categorical with low cardinality
      names.append("feature_8_low_cardinality")
      types.append("nominal")
      col = _make_categorical_float(
          rng,
          n_samples,
          categories[0],
          categorical_floor[0],
          categorical_digits,
      )
      if objects:
          col = _make_categorical_str(col, "l", categorical_digits)
      features.append(col)
  
      # Feature 9 - Categorical with high cardinality
      names.append("feature_9_high_cardinality")
      types.append("nominal")
      col = _make_categorical_float(
          rng,
          n_samples,
          categories[-1],
          categorical_floor[-1],
          categorical_digits,
      )
      if objects:
          col = _make_categorical_str(col, "h", categorical_digits)
      features.append(col)
  
      # Convert list of features to a 2D numpy array and transpose
      X = np.array(features, dtype=object if objects else float).T
  
      if missing is True:
          missing = 0.1  # by default make 10% of feature data missing
      elif missing is False or missing is None:
          missing = 0.0
      elif isinstance(missing, int):
          missing = float(missing)
      elif not isinstance(missing, float):
          raise ValueError(
              f"missing must be bool or float, but is {type(missing)}"
          )
  
      if missing < 0.0:
          raise ValueError(f"missing cannot be negative")
      elif 1.0 < missing:
          raise ValueError(f"missing cannot be more than 1.0")
      elif missing != 0.0:
          mask = rng.choice(
              [False, True],
              tuple(reversed(X.shape)),
              p=[1.0 - missing, missing],
          ).T
          X[mask] = None if objects else np.nan
  
      return (X, 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 2 for calling a global function with example usage: _make_synthetic_features(n_samples, missing, objects, seed, categories, categorical_floor, categorical_digits, clip_low, clip_high) and returns: X,  names,  types