Fit the training set to the given guessing strategy.

@param \Rubix\ML\Datasets\Dataset $dataset
@throws \InvalidArgumentException
487786
public function train(Dataset $dataset) : void
    {
        if (!$dataset instanceof Labeled) {
            throw new InvalidArgumentException('This estimator requires a'
                . ' labeled training set.');
        }

        $this->strategy->fit($dataset->labels());

        $this->trained = true;
    }
655108
public function rank(Dataset $dataset) : array
    {
        if (empty($this->samples)) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }
        
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        return array_map([self::class, 'localOutlierFactor'], $dataset->samples());
    }
170842
public function predict(Dataset $dataset) : array
    {
        if (!$this->medians or !$this->mads) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }

        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $p = $dataset->numColumns();

        $predictions = [];

        foreach ($dataset as $sample) {
            $score = 0.;

            foreach ($sample as $column => $feature) {
                $median = $this->medians[$column];
                $mad = $this->mads[$column];

                $z = abs((self::LAMBDA * ($feature - $median)) / $mad);

                if ($z > $this->threshold) {
                    $predictions[] = 1;

                    continue 2;
                }

                $score += $z;
            }

            $predictions[] = ($score / $p) > $this->tolerance ? 1 : 0;
        }

        return $predictions;
    }
736016
public function predict(Dataset $dataset) : array
    {
        if (empty($this->ensemble)) {
            throw new RuntimeException('Estimator has not been trained.');
        }

        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $predictions = $this->base->predict($dataset);

        foreach ($this->ensemble as $estimator) {
            foreach ($estimator->predict($dataset) as $j => $prediction) {
                $predictions[$j] += $this->rate * $prediction;
            }
        }

        return $predictions;
    }
583652
public function partial(Dataset $dataset) : void
    {
        if (!$dataset instanceof Labeled) {
            throw new InvalidArgumentException('This estimator requires a'
                . ' labeled training set.');
        }

        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $this->classes = array_unique(array_merge($this->classes, $dataset->possibleOutcomes()));
        $this->samples = array_merge($this->samples, $dataset->samples());
        $this->labels = array_merge($this->labels, $dataset->labels());
    }
194102
public function append(Dataset $dataset) : Dataset
    {
        return self::quick(array_merge($this->samples, $dataset->samples()));
    }
733329
public function update(Dataset $dataset) : void
    {
        if (!$dataset->homogeneous() or $dataset->columnType(0) !== DataType::CONTINUOUS) {
            throw new InvalidArgumentException('This transformer only works'
                . ' with continuous features.');
        }

        if ($this->dfs === null or $this->n === null) {
            $this->fit($dataset);
            
            return;
        }

        foreach ($dataset as $sample) {
            foreach ($sample as $column => $feature) {
                if ($feature > 0) {
                    $this->dfs[$column]++;
                }
            }
        }

        $this->n += $dataset->numRows();

        $idfs = [];

        foreach ($this->dfs as $df) {
            $idfs[] = log($this->n / $df) + 1.;
        }

        $this->idfs = $idfs;
    }
1281025
public function train(Dataset $dataset) : void
    {
        if (!$dataset instanceof Labeled) {
            throw new InvalidArgumentException('This Estimator requires a'
                . ' Labeled training set.');
        }

        $classes = $dataset->possibleOutcomes();

        $this->classes = $classes;
        $this->weights = array_fill_keys($classes, 0);

        $this->counts = $this->probs = array_fill_keys(
            $classes,
            array_fill(0, $dataset->numColumns(), [])
        );

        $this->partial($dataset);
    }
219237
protected function bindDataset($dataset)
    {
        $datasetClass = $this->datasetClass;
        $object = new $datasetClass();

        if ($object instanceof DataSetInterface) {
            return $object->bind($dataset);
        }

        if ($dataset instanceof \Traversable) {
            $dataset = iterator_to_array($dataset);
        } elseif (is_object($dataset)) {
            $dataset = [$dataset];
        } elseif (!is_array($dataset)) {
            throw new \InvalidArgumentException(sprintf('Need an array or object in %s::%s()', __CLASS__, __METHOD__));
        }

        foreach ($dataset as $data) {
            $object[] = $data;
        }

        return $object;
    }
200113
public static function check(Dataset $dataset, Estimator $estimator) : void
    {
        $types = $dataset->uniqueTypes();

        $same = array_intersect($types, $estimator->compatibility());

        if (count($same) < count($types)) {
            throw new InvalidArgumentException('Estimator is not'
                . ' compatible with the data types given.');
        }
    }
755694
public function train(Dataset $dataset) : void
    {
        $this->samples = $this->kdistances = $this->lrds = [];

        $this->partial($dataset);
    }
313392
public function train(Dataset $dataset) : void
    {
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        if ($this->logger) {
            $this->logger->info('Learner init ' . Params::stringify([
                'radius' => $this->radius,
                'kernel' => $this->kernel,
                'max_leaf_size' => $this->maxLeafSize,
                'epochs' => $this->epochs,
                'min_change' => $this->minChange,
                'seeder' => $this->seeder,
                'ratio' => $this->ratio,
            ]));
        }

        $n = $dataset->numRows();

        $tree = new BallTree($this->maxLeafSize, $this->kernel);

        if ($this->seeder and $n > self::MIN_SEEDS) {
            $k = (int) round($this->ratio * $n);

            $centroids = $this->seeder->seed($dataset, $k);
        } else {
            $centroids = $dataset->samples();
        }

        $tree->grow($dataset);

        $previous = $centroids;

        $this->steps = [];
 
        for ($epoch = 1; $epoch <= $this->epochs; $epoch++) {
            foreach ($centroids as $i => &$centroid) {
                [$samples, $labels, $distances] = $tree->range($centroid, $this->radius);

                $step = Matrix::quick($samples)
                    ->transpose()
                    ->mean()
                    ->asArray();

                $mu2 = Stats::mean($distances) ** 2;

                $weight = exp(-$mu2 / $this->delta);

                foreach ($centroid as $column => &$mean) {
                    $mean = ($weight * $step[$column]) / $weight;
                }

                foreach ($centroids as $j => $neighbor) {
                    if ($i === $j) {
                        continue 1;
                    }

                    $distance = $this->kernel->compute($centroid, $neighbor);

                    if ($distance < $this->radius) {
                        unset($centroids[$j]);
                    }
                }
            }

            $shift = $this->shift($centroids, $previous);

            $this->steps[] = $shift;

            if ($this->logger) {
                $this->logger->info("Epoch $epoch complete, shift=$shift");
            }

            if (is_nan($shift)) {
                break 1;
            }

            if ($shift < $this->minChange) {
                break 1;
            }

            $previous = $centroids;
        }

        $this->centroids = array_values($centroids);

        if ($this->logger) {
            $this->logger->info('Training complete');
        }
    }
281042
public function train(Dataset $dataset) : void
    {
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $columns = $dataset->columns();

        $this->medians = $this->mads = [];

        foreach ($columns as $column => $values) {
            [$median, $mad] = Stats::medMad($values);

            $this->medians[$column] = $median;
            $this->mads[$column] = $mad;
        }
    }
914906
public function train(Dataset $dataset) : void
    {
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $samples = $dataset->samples();

        $dataset = Labeled::quick($samples, array_keys($samples));

        $this->tree->grow($dataset);

        $this->kdistances = $this->lrds = [];

        $indices = $distances = [];

        foreach ($dataset as $sample) {
            [$iHat, $dHat] = $this->tree->nearest($sample, $this->k);

            $distances[] = $dHat;
            $indices[] = $iHat;
            
            $this->kdistances[] = end($dHat);
        }

        foreach ($distances as $i => $row) {
            $this->lrds[] = $this->localReachabilityDensity($indices[$i], $row);
        }

        $lofs = [];

        foreach ($dataset as $sample) {
            $lofs[] = $this->localOutlierFactor($sample);
        }

        $shift = Stats::percentile($lofs, 100. * $this->contamination);
        
        $this->offset = self::THRESHOLD + $shift;
    }
600242
protected function initialize(Dataset $dataset) : array
    {
        $centroids = $this->seeder->seed($dataset, $this->k);

        $kernel = new Euclidean();

        $clusters = array_fill(0, $this->k, []);

        foreach ($dataset as $sample) {
            $bestDistance = INF;
            $bestCluster = -1;
    
            foreach ($centroids as $cluster => $centroid) {
                $distance = $kernel->compute($sample, $centroid);
    
                if ($distance < $bestDistance) {
                    $bestDistance = $distance;
                    $bestCluster = $cluster;
                }
            }

            $clusters[$bestCluster][] = $sample;
        }

        $means = $variances = [];

        foreach ($clusters as $cluster => $samples) {
            $mHat = $vHat = [];

            $columns = array_map(null, ...$samples);

            foreach ($columns as $values) {
                [$mean, $variance] = Stats::meanVar($values);

                $mHat[] = $mean;
                $vHat[] = $variance;
            }

            $means[$cluster] = $mHat;
            $variances[$cluster] = $vHat;
        }

        return [$means, $variances];
    }
959146
public function train(Dataset $dataset) : void
    {
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $this->centroids = $this->seeder->seed($dataset, $this->k);

        $sizes = array_fill(1, $this->k, 0);
        $sizes[0] = $dataset->numRows();

        $this->sizes = $sizes;

        $this->steps = [];

        $this->partial($dataset);
    }
100490
public function partial(Dataset $dataset) : void
    {
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        $this->samples = array_merge($this->samples, $dataset->samples());

        $distances = [];

        foreach ($this->samples as $i => $sample) {
            $distances[] = $d = $this->localRegion($sample);

            $this->kdistances[$i] = end($d);
        }

        foreach ($distances as $i => $row) {
            $this->lrds[$i] = $this->localReachabilityDensity($row);
        }

        $lofs = $this->rank($dataset);

        $shift = Stats::percentile($lofs, 100. * $this->contamination);
        
        $this->offset = self::THRESHOLD + $shift;
    }