Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
<?php

declare(strict_types=1);

namespace Phpml\Preprocessing;

use Phpml\Exception\NormalizerException;
use Phpml\Math\Statistic\Mean;
use Phpml\Math\Statistic\StandardDeviation;

class Normalizer implements Preprocessor
{
    public const NORM_L1 = 1;

    public const NORM_L2 = 2;

    public const NORM_STD = 3;

    /**
     * @var int
     */
    private $norm;

    /**
     * @var bool
     */
    private $fitted = false;

    /**
     * @var array
     */
    private $std = [];

    /**
     * @var array
     */
    private $mean = [];

    /**
     * @throws NormalizerException
     */
    public function __construct(int $norm = self::NORM_L2)
    {
        if (!in_array($norm, [self::NORM_L1, self::NORM_L2, self::NORM_STD], true)) {
            throw new NormalizerException('Unknown norm supplied.');
        }

        $this->norm = $norm;
    }

    public function fit(array $samples, ?array $targets = null): void
    {
        if ($this->fitted) {
            return;
        }

        if ($this->norm === self::NORM_STD) {
            $features = range(0, count($samples[0]) - 1);
            foreach ($features as $i) {
                $values = array_column($samples, $i);
                $this->std[$i] = StandardDeviation::population($values);
                $this->mean[$i] = Mean::arithmetic($values);
            }
        }

        $this->fitted = true;
    }

< public function transform(array &$samples): void
> public function transform(array &$samples, ?array &$targets = null): void
{ $methods = [ self::NORM_L1 => 'normalizeL1', self::NORM_L2 => 'normalizeL2', self::NORM_STD => 'normalizeSTD', ]; $method = $methods[$this->norm]; $this->fit($samples); foreach ($samples as &$sample) { $this->{$method}($sample); } } private function normalizeL1(array &$sample): void { $norm1 = 0; foreach ($sample as $feature) { $norm1 += abs($feature); } if ($norm1 == 0) { $count = count($sample); $sample = array_fill(0, $count, 1.0 / $count); } else { array_walk($sample, function (&$feature) use ($norm1): void { $feature /= $norm1; }); } } private function normalizeL2(array &$sample): void { $norm2 = 0; foreach ($sample as $feature) { $norm2 += $feature * $feature; } $norm2 **= .5; if ($norm2 == 0) { $sample = array_fill(0, count($sample), 1); } else { array_walk($sample, function (&$feature) use ($norm2): void { $feature /= $norm2; }); } } private function normalizeSTD(array &$sample): void { foreach (array_keys($sample) as $i) { if ($this->std[$i] != 0) { $sample[$i] = ($sample[$i] - $this->mean[$i]) / $this->std[$i]; } else { // Same value for all samples. $sample[$i] = 0; } } } }