code: def normalization_helper(
      max_unique_enum_values: int,
      quantile_size: int,
      quantile_k2_threshold: float,
      skip_box_cox: bool = False,
      skip_quantiles: bool = False,
      feature_overrides: Optional[Dict[int, str]] = None,
      allowedlist_features: Optional[List[int]] = None,
      assert_allowedlist_feature_coverage: bool = True,
  ):
      """Construct a preprocessing closure to obtain normalization parameters
      from rows of feature_name and a sample of feature_values.
      """
  
      norm_params = {
          "max_unique_enum_values": max_unique_enum_values,
          "quantile_size": quantile_size,
          "quantile_k2_threshold": quantile_k2_threshold,
          "skip_box_cox": skip_box_cox,
          "skip_quantiles": skip_quantiles,
          "feature_overrides": feature_overrides,
      }
      # pyre-fixme[9]: allowedlist_features has type `Optional[List[int]]`; used as
      #  `Set[int]`.
      # pyre-fixme[9]: allowedlist_features has type `Optional[List[int]]`; used as
      #  `Set[int]`.
      allowedlist_features = set(allowedlist_features or [])
  
      def validate_allowedlist_features(
          params: Dict[int, NormalizationParameters]
      ) -> None:
          if not allowedlist_features:
              return
          allowedlist_feature_set = {
              int(fid) for fid in allowedlist_features
          }
          available_features = set(params.keys())
          assert allowedlist_feature_set == available_features, (
              "Could not identify preprocessing type for these features: {}; "
              "extra features: {}".format(
                  allowedlist_feature_set - available_features,
                  available_features - allowedlist_feature_set,
              )
          )
  
      def process(rows: List) -> Dict[int, NormalizationParameters]:
          params = {}
          for row in rows:
              assert "feature_name" in row
              assert "feature_values" in row
              norm_metdata = get_feature_norm_metadata(
                  row["feature_name"],
                  row["feature_values"],
                  norm_params,
              )
              if norm_metdata is not None and (
                  not allowedlist_features
                  or row["feature_name"] in allowedlist_features
              ):
                  params[row["feature_name"]] = norm_metdata
  
          if assert_allowedlist_feature_coverage:
              validate_allowedlist_features(params)
          return params
  
      return process
  
file_path: ReAgent/reagent/workflow/identify_types_flow.py
imports: from typing import Dict, List, Optional
  import reagent.core.types
  from pyspark.sql.functions import col, collect_list, explode
  from reagent.data.spark_utils import get_spark_session
  from reagent.preprocessing.normalization import get_feature_norm_metadata, NormalizationParameters
  from .types import PreprocessingOptions, TableSpec
label_desc: Use image node_id 1 for calling a global function with example usage: normalization_helper(max_unique_enum_values, quantile_size, quantile_k2_threshold, skip_box_cox, skip_quantiles, feature_overrides, allowedlist_features, assert_allowedlist_feature_coverage) and returns: process, params