|null */ protected ?array $categories = null; /** * Return the data types that this transformer is compatible with. * * @internal * * @return list */ public function compatibility() : array { return DataType::all(); } /** * Is the transformer fitted? * * @return bool */ public function fitted() : bool { return isset($this->categories); } /** * Return the categories computed during fitting indexed by feature column. * * @return array|null */ public function categories() : ?array { return isset($this->categories) ? array_map('array_flip', $this->categories) : null; } /** * Fit the transformer to a dataset. * * @param Dataset $dataset */ public function fit(Dataset $dataset) : void { SamplesAreCompatibleWithTransformer::with($dataset, $this)->check(); $this->categories = []; foreach ($dataset->featureTypes() as $column => $type) { if ($type->isCategorical()) { $values = $dataset->feature($column); $categories = array_values(array_unique($values)); /** @var int[] $offsets */ $offsets = array_flip($categories); $this->categories[$column] = $offsets; } } } /** * Transform the dataset in place. * * @param list> $samples * @throws RuntimeException */ public function transform(array &$samples) : void { if ($this->categories === null) { throw new RuntimeException('Transformer has not been fitted.'); } foreach ($samples as &$sample) { $vectors = []; foreach ($this->categories as $column => $categories) { $category = $sample[$column]; $vector = array_fill(0, count($categories), 0); if (isset($categories[$category])) { $vector[$categories[$category]] = 1; } $vectors[] = $vector; unset($sample[$column]); } $sample = array_merge($sample, ...$vectors); } } /** * Return the string representation of the object. * * @internal * * @return string */ public function __toString() : string { return 'One Hot Encoder'; } }