code: def unify_feature_names(
      X, feature_names_given=None, feature_types_given=None
  ):
      # called under: fit
  
      # if feature_names_given and feature_types_given were the outputs of a fit function, then this function
      # is re-callable because it will return the same feature names as previously generated
  
      if isinstance(X, np.ndarray):  # this includes ma.masked_array
          X_names = None
          n_cols = X.shape[1]
      elif _pandas_installed and isinstance(X, pd.DataFrame):
          X_names = list(map(str, X.columns))
          n_cols = len(X_names)
      elif _pandas_installed and isinstance(X, pd.Series):
          X_names = None
          n_cols = 1
      elif _scipy_installed and isinstance(X, sp.sparse.spmatrix):
          X_names = None
          n_cols = X.shape[1]
      elif isinstance(X, dict):
          X_names = list(map(str, X.keys()))
          # there is no natural order for dictionaries, but we want a consistent order, so sort them by string
          # python uses unicode code points for sorting, which is what we want for cross-language equivalent results
          X_names.sort()
          n_cols = len(X_names)
      else:
          msg = "internal error"
          _log.error(msg)
          raise ValueError(msg)
  
      n_ignored = 0
      if feature_types_given is not None:
          n_ignored = sum(
              1
              for feature_type_given in feature_types_given
              if feature_type_given == "ignore"
          )
  
      if feature_names_given is None:
          if feature_types_given is not None:
              if (
                  len(feature_types_given) != n_cols
                  and len(feature_types_given) != n_cols + n_ignored
              ):
                  msg = f"There are {len(feature_types_given)} feature_types, but X has {n_cols} columns"
                  _log.error(msg)
                  raise ValueError(msg)
              n_cols = len(feature_types_given)
  
          feature_names_in = X_names
          if X_names is None:
              feature_names_in = []
              # this isn't used other than to indicate new names need to be created
              feature_types_given = ["ignore"] * n_cols
      else:
          n_final = len(feature_names_given)
          if feature_types_given is not None:
              n_final = len(feature_types_given)
              if (
                  n_final != len(feature_names_given)
                  and n_final != len(feature_names_given) + n_ignored
              ):
                  msg = f"There are {n_final} feature_types and {len(feature_names_given)} feature_names which is a mismatch"
                  _log.error(msg)
                  raise ValueError(msg)
  
          feature_names_in = list(map(str, feature_names_given))
  
          if X_names is None:
              # ok, need to use position indexing
              if n_final != n_cols and n_final != n_cols + n_ignored:
                  msg = f"There are {n_final} features, but X has {n_cols} columns"
                  _log.error(msg)
                  raise ValueError(msg)
          else:
              # we might be indexing by name
              names_used = feature_names_in
              if feature_types_given is not None and len(
                  feature_names_in
              ) == len(feature_types_given):
                  names_used = [
                      feature_name_in
                      for feature_name_in, feature_type_given in zip(
                          feature_names_in, feature_types_given
                      )
                      if feature_type_given != "ignore"
                  ]
  
              X_names_unique = set(
                  name
                  for name, n_count in Counter(X_names).items()
                  if n_count == 1
              )
              if any(name not in X_names_unique for name in names_used):
                  # ok, need to use position indexing
                  if (
                      n_final != n_cols
                      and n_final != n_cols + n_ignored
                  ):
                      msg = f"There are {n_final} features, but X has {n_cols} columns"
                      _log.error(msg)
                      raise ValueError(msg)
  
      if feature_types_given is not None:
          if len(feature_types_given) == len(feature_names_in):
              if len(feature_names_in) - n_ignored != len(
                  set(
                      feature_name_in
                      for feature_name_in, feature_type_given in zip(
                          feature_names_in, feature_types_given
                      )
                      if feature_type_given != "ignore"
                  )
              ):
                  msg = "cannot have duplicate feature names"
                  _log.error(msg)
                  raise ValueError(msg)
  
              return feature_names_in
  
          names_set = set(feature_names_in)
  
          names = []
          names_idx = 0
          feature_idx = 0
          for feature_type_given in feature_types_given:
              if feature_type_given == "ignore":
                  while True:
                      # give 4 digits to the number so that anything below 9999 gets sorted in the right order in string format
                      name = f"feature_{feature_idx:04}"
                      feature_idx += 1
                      if name not in names_set:
                          break
              else:
                  name = feature_names_in[names_idx]
                  names_idx += 1
              names.append(name)
  
          feature_names_in = names
  
      if len(feature_names_in) != len(set(feature_names_in)):
          msg = "cannot have duplicate feature names"
          _log.error(msg)
          raise ValueError(msg)
  
      return feature_names_in
  
imports: from collections import Counter
  from itertools import count
  import numpy
  import numpy.ma
  import logging
label_desc: Use image node_id 15 for calling a global function with example usage: unify_feature_names(X, feature_names_given, feature_types_given) and returns: feature_names_in, feature_names_in