class_docstr: Convert categorical parameters (unordered ChoiceParameters) to
  one-hot-encoded parameters.
  
  Does not convert task parameters.
  
  Parameters will be one-hot-encoded, yielding a set of RangeParameters,
  of type float, on [0, 1]. If there are two values, one single RangeParameter
  will be yielded, otherwise there will be a new RangeParameter for each
  ChoiceParameter value.
  
  In the reverse transform, floats can be converted to a one-hot encoded vector
  using one of two methods:
  
  Strict rounding: Choose the maximum value. With levels ['a', 'b', 'c'] and
      float values [0.2, 0.4, 0.3], the restored parameter would be set to 'b'.
      Ties are broken randomly, so values [0.2, 0.4, 0.4] is randomly set to 'b'
      or 'c'.
  
  Randomized rounding: Sample from the distribution. Float values
      [0.2, 0.4, 0.3] are transformed to 'a' w.p.
      0.2/0.9, 'b' w.p. 0.4/0.9, or 'c' w.p. 0.3/0.9.
  
  Type of rounding can be set using transform_config['rounding'] to either
  'strict' or 'randomized'. Defaults to strict.
  
  Transform is done in-place.
code: def __init__(
      self,
      search_space: Optional[SearchSpace] = None,
      observations: Optional[List[Observation]] = None,
      modelbridge: Optional[
          "modelbridge_module.base.ModelBridge"
      ] = None,
      config: Optional[TConfig] = None,
  ) -> None:
      assert search_space is not None, "OneHot requires search space"
      # Identify parameters that should be transformed
      # pyre-fixme[4]: Attribute must be annotated.
      self.rounding = "strict"
      if config is not None:
          self.rounding = config.get("rounding", "strict")
      self.encoder: Dict[str, OneHotEncoder] = {}
      self.encoded_parameters: Dict[str, List[str]] = {}
      for p in search_space.parameters.values():
          if (
              isinstance(p, ChoiceParameter)
              and not p.is_ordered
              and not p.is_task
          ):
              self.encoder[p.name] = OneHotEncoder(p.values)
              nc = len(self.encoder[p.name].classes)
              if nc == 2:
                  # Two levels handled in one parameter
                  self.encoded_parameters[p.name] = [
                      p.name + OH_PARAM_INFIX
                  ]
              else:
                  self.encoded_parameters[p.name] = [
                      "{}{}_{}".format(p.name, OH_PARAM_INFIX, i)
                      for i in range(nc)
                  ]
  
imports: from typing import Dict, List, Optional, TYPE_CHECKING, TypeVar
  import numpy
  from ax.core.observation import Observation, ObservationFeatures
  from ax.core.parameter import ChoiceParameter, Parameter, ParameterType, RangeParameter
  from ax.core.search_space import SearchSpace
  from ax.core.types import TParameterization
  from ax.modelbridge.transforms.base import Transform
  from ax.modelbridge.transforms.rounding import randomized_onehot_round, strict_onehot_round
  from ax.modelbridge.transforms.utils import construct_new_search_space
  from ax.models.types import TConfig
  from sklearn.preprocessing import LabelBinarizer, LabelEncoder
label_desc: Use image node_id 1 to create a new OneHot object from inherited base classes: Transform with example: obj = OneHot(search_space, observations, modelbridge, config)