$max) { throw new InvalidArgumentException('Minimum cannot be greater' . ' than maximum.'); } $this->min = $min; $this->max = $max; } /** * 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 $this->minimums and $this->maximums; } /** * Return the minmums of each feature column. * * @return (int|float)[]|null */ public function minimums() : ?array { return $this->minimums; } /** * Return the maximums of each feature column. * * @return (int|float)[]|null */ public function maximums() : ?array { return $this->maximums; } /** * Fit the transformer to a dataset. * * @param Dataset $dataset */ public function fit(Dataset $dataset) : void { SamplesAreCompatibleWithTransformer::with($dataset, $this)->check(); $this->minimums = $this->maximums = $this->scales = []; foreach ($dataset->featureTypes() as $column => $type) { if ($type->isContinuous()) { $values = $dataset->feature($column); /** @var int|float $min */ $min = min($values); /** @var int|float $max */ $max = max($values); $scale = ($this->max - $this->min) / (($max - $min) ?: EPSILON); $this->minimums[$column] = $min; $this->maximums[$column] = $max; $this->scales[$column] = $scale; } } } /** * Update the fitting of the transformer. * * @param Dataset $dataset */ public function update(Dataset $dataset) : void { if (!isset($this->minimums, $this->maximums, $this->scales)) { $this->fit($dataset); return; } SamplesAreCompatibleWithTransformer::with($dataset, $this)->check(); foreach ($this->scales as $column => &$scale) { $values = $dataset->feature($column); /** @var int|float $min */ $min = min($this->minimums[$column], ...$values); /** @var int|float $max */ $max = max($this->maximums[$column], ...$values); $scale = ($this->max - $this->min) / (($max - $min) ?: EPSILON); $this->minimums[$column] = $min; $this->maximums[$column] = $max; } } /** * Transform the dataset in place. * * @param list> $samples * @throws RuntimeException */ public function transform(array &$samples) : void { if (!isset($this->minimums, $this->scales)) { throw new RuntimeException('Transformer has not been fitted.'); } foreach ($samples as &$sample) { foreach ($this->scales as $column => $scale) { $value = &$sample[$column]; $min = $this->minimums[$column]; $value *= $scale; $value += $this->min - $min * $scale; } } } /** * Perform the reverse transformation to the samples. * * @param list> $samples * @throws RuntimeException */ public function reverseTransform(array &$samples) : void { if (!isset($this->minimums, $this->scales)) { throw new RuntimeException('Transformer has not been fitted.'); } foreach ($samples as &$sample) { foreach ($this->scales as $column => $scale) { $value = &$sample[$column]; $min = $this->minimums[$column]; $value -= $this->min - $min * $scale; $value /= $scale; } } } /** * Return the string representation of the object. * * @internal * * @return string */ public function __toString() : string { return "Min Max Normalizer (min: {$this->min}, max: {$this->max})"; } }