Make a prediction based on the nearest neighbors.

@param \Rubix\ML\Datasets\Dataset $dataset
@throws \InvalidArgumentException
@throws \RuntimeException
@return array
338376
public function predict(Dataset $dataset) : array
    {
        if (empty($this->samples) or empty($this->labels)) {
            throw new RuntimeException('Estimator has not been trained.');
        }

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

        $predictions = [];

        foreach ($dataset as $sample) {
            [$labels, $distances] = $this->nearest($sample);

            if ($this->weighted) {
                $weights = [];

                foreach ($distances as $i => $distance) {
                    $weights[] = 1. / (1. + $distance);
                }

                $outcome = Stats::weightedMean($labels, $weights);
            } else {
                $outcome = Stats::mean($labels);
            }

            $predictions[] = $outcome;
        }

        return $predictions;
    }
802855
public function rank(Dataset $dataset) : array
    {
        if ($this->tree->bare()) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }
        
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

        return array_map([self::class, 'localOutlierFactor'], $dataset->samples());
    }
1355878
protected function score(Dataset $dataset) : array
    {
        $scores = array_fill(
            0,
            $dataset->numRows(),
            array_fill_keys($this->classes, 0.)
        );

        foreach ($this->ensemble as $i => $estimator) {
            $influence = $this->influences[$i];

            foreach ($estimator->predict($dataset) as $j => $prediction) {
                $scores[$j][$prediction] += $influence;
            }
        }

        return $scores;
    }
573190
public function predict(Dataset $dataset) : array
    {
        if (!$this->centroids) {
            throw new RuntimeException('Estimator has not been trained.');
        }

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

        return array_map([self::class, 'assign'], $dataset->samples());
    }
1080487
public function fit(Dataset $dataset) : void
    {
        $this->minimums = $this->maximums = $this->scales = $this->mins = [];

        foreach ($dataset->types() as $column => $type) {
            if ($type === DataType::CONTINUOUS) {
                $this->minimums[$column] = INF;
                $this->maximums[$column] = -INF;
            }
        }

        $this->update($dataset);
    }
1023816
public function update(Dataset $dataset) : void
    {
        if ($this->minimums === null or $this->maximums === null) {
            $this->fit($dataset);
            
            return;
        }

        $columns = $dataset->columnsByType(DataType::CONTINUOUS);

        foreach ($columns as $column => $values) {
            $min = min($values);
            $max = max($values);

            $min = min($min, $this->minimums[$column]);
            $max = max($max, $this->maximums[$column]);

            $scale = ($this->max - $this->min)
                / (($max - $min) ?: EPSILON);

            $minHat = $this->min - $min * $scale;

            $this->minimums[$column] = $min;
            $this->maximums[$column] = $max;
            $this->scales[$column] = $scale;
            $this->mins[$column] = $minHat;
        }
    }
374013
public function proba(Dataset $dataset) : array
    {
        if ($this->bare()) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }

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

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

        $probabilities = [];

        foreach ($dataset as $sample) {
            $node = $this->search($sample);

            $probabilities[] = $node instanceof Outcome
                ? array_replace($template, $node->probabilities())
                : null;
        }

        return $probabilities;
    }
58474
@Override
    public List<String> predict(DataSet dataSet) {
        int[] intRet = predict(dataSet.getFeatures());
        List<String> ret = new ArrayList<>();
        for (int i : intRet) {
            ret.add(i, dataSet.getLabelName(i));
        }
        return ret;
    }
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);
    }
1239152
public function train(Dataset $dataset) : void
    {
        if (!$dataset instanceof Labeled) {
            throw new InvalidArgumentException('This estimator requires a'
                . ' labeled training set.');
        }

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

        $samples = $dataset->samples();
        $labels = $dataset->labels();

        $biases = Matrix::ones($dataset->numRows(), 1);

        $x = Matrix::build($samples)->augmentLeft($biases);
        $y = Vector::build($labels);

        $alphas = array_fill(0, $x->n() - 1, $this->alpha);

        $penalty = Matrix::diagonal(array_merge([0.], $alphas));

        $xT = $x->transpose();

        $coefficients = $xT->matmul($x)
            ->add($penalty)
            ->inverse()
            ->dot($xT->dot($y))
            ->asArray();

        $this->bias = (float) array_shift($coefficients);
        $this->weights = Vector::quick($coefficients);
    }
817008
public function train(Dataset $dataset) : void
    {
        if (!$dataset instanceof Labeled) {
            throw new InvalidArgumentException('This estimator requires a'
                . ' labeled training set.');
        }

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

        if ($this->logger) {
            $this->logger->info('Learner init ' . Params::stringify([
                'booster' => $this->booster,
                'rate' => $this->rate,
                'estimators' => $this->estimators,
                'ratio' => $this->ratio,
                'min_change' => $this->minChange,
                'tolerance' => $this->tolerance,
                'base' => $this->base,
            ]));
        }

        $n = $dataset->numRows();
        $p = (int) round($this->ratio * $n);

        if ($this->logger) {
            $this->logger->info('Training '
                . Params::shortName($this->base) . ' base estimator');
        }

        $this->base->train($dataset);

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

        $yHat = [];

        foreach ($predictions as $i => $prediction) {
            $yHat[] = $dataset->label($i) - $prediction;
        }

        $residual = Labeled::quick($dataset->samples(), $yHat);

        if ($this->logger) {
            $this->logger->info("Boosting with $this->estimators "
                . Params::shortName($this->booster)
                . ($this->estimators > 1 ? 's' : ''));
        }

        $this->ensemble = $this->steps = [];

        $previous = INF;

        for ($epoch = 1; $epoch <= $this->estimators; $epoch++) {
            $booster = clone $this->booster;

            $subset = $residual->randomize()->head($p);

            $booster->train($subset);

            $predictions = $booster->predict($residual);

            $labels = $residual->labels();

            $loss = 0.;

            foreach ($predictions as $i => $prediction) {
                $label = $labels[$i];

                $loss += ($label - $prediction) ** 2;
                $yHat[$i] = $label - ($this->rate * $prediction);
            }

            $loss /= $n;

            $this->ensemble[] = $booster;
            $this->steps[] = $loss;

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

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

            if (abs($previous - $loss) < $this->minChange) {
                break 1;
            }

            if ($loss < $this->tolerance) {
                break 1;
            }

            $residual = Labeled::quick($residual->samples(), $yHat);

            $previous = $loss;
        }

        if ($this->logger) {
            $this->logger->info('Training complete');
        }
    }
135859
public function bind($dataset)
    {
        if ($dataset === null) {
            return $this;
        }

        if ($dataset instanceof \Traversable) {
            $dataset = iterator_to_array($dataset);
        } elseif (is_object($dataset)) {
            $dataset = [$dataset];
        } elseif (!is_array($dataset)) {
            throw new \InvalidArgumentException('Need an array or object');
        }

        foreach ($dataset as $k => $data) {
            $this[$k] = $data;
        }

        return $this;
    }
1006364
public static function toNQuads($dataset) {
    $quads = array();
    foreach($dataset as $graph_name => $triples) {
      foreach($triples as $triple) {
        if($graph_name === '@default') {
          $graph_name = null;
        }
        $quads[] = self::toNQuad($triple, $graph_name);
      }
    }
    sort($quads);
    return implode($quads);
  }
1217154
public function train(Dataset $dataset) : void
    {
        if ($this->type === self::CLASSIFIER or $this->type === self::REGRESSOR) {
            if (!$dataset instanceof Labeled) {
                throw new InvalidArgumentException('This estimator requires a'
                    . ' labeled training set.');
            }
        }

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

        if ($this->logger) {
            $this->logger->info('Learner init ' . Params::stringify([
                'experts' => $this->experts,
                'influences' => $this->influences,
                'workers' => $this->workers,
            ]));
        }

        Loop::run(function () use ($dataset) {
            $pool = new DefaultPool($this->workers);

            $coroutines = [];

            foreach ($this->experts as $index => $estimator) {
                $task = new CallableTask(
                    [$this, '_train'],
                    [$estimator, $dataset]
                );

                $coroutines[] = call(function () use ($pool, $task, $index) {
                    $estimator = yield $pool->enqueue($task);

                    if ($this->logger) {
                        $this->logger->info(Params::stringify([
                            $index => $estimator,
                        ]) . ' finished training');
                    }

                    return $estimator;
                });
            }

            $this->experts = yield all($coroutines);
            
            return yield $pool->shutdown();
        });

        if ($this->type === self::CLASSIFIER and $dataset instanceof Labeled) {
            $this->classes = $dataset->possibleOutcomes();
        }

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

        $n = $dataset->numRows();
        
        $maxDepth = (int) ceil(log(max($n, 2), 2));

        $p = (int) round($this->ratio * $n);

        $this->forest = [];

        for ($epoch = 1; $epoch <= $this->estimators; $epoch++) {
            $tree = new ITree($maxDepth);

            $subset = $dataset->randomize()->head($p);

            $tree->grow($subset);

            $this->forest[] = $tree;
        }

        $this->pHat = $this->c($p);

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

        $p = 100. - (100. * $this->contamination);

        $shift = Stats::percentile($scores, $p);

        $this->offset = $shift;
    }
719504
public static function terminate(Labeled $dataset) : self
    {
        $samples = $dataset->samples();
        $labels = $dataset->labels();

        $min = $max = [];

        foreach ($dataset->columns() as $values) {
            $min[] = min($values);
            $max[] = max($values);
        }

        return new self($samples, $labels, $min, $max);
    }
677582
public function partial(Dataset $dataset) : void
    {
        if (!$this->network) {
            $this->train($dataset);

            return;
        }

        if (!$dataset instanceof Labeled) {
            throw new InvalidArgumentException('This estimator requires a'
                . ' labeled training set.');
        }

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

        if ($this->logger) {
            $this->logger->info('Learner init ' . Params::stringify([
                'batch_size' => $this->batchSize,
                'optimizer' => $this->optimizer,
                'alpha' => $this->alpha,
                'epochs' => $this->epochs,
                'min_change' => $this->minChange,
                'cost_fn' => $this->costFn,
            ]));
        }

        $n = $dataset->numRows();

        [$testing, $training] = $dataset->stratifiedSplit($this->holdout);

        [$min, $max] = $this->metric->range();

        $randomize = $n > $this->batchSize ? true : false;

        $bestScore = $min;
        $bestSnapshot = null;
        $previous = INF;

        for ($epoch = 1; $epoch <= $this->epochs; $epoch++) {
            if ($randomize) {
                $training->randomize();
            }

            $batches = $training->batch($this->batchSize);

            $loss = 0.;

            foreach ($batches as $batch) {
                $loss += $this->network->roundtrip($batch);
            }

            $loss /= $n;

            $predictions = $this->predict($testing);

            $score = $this->metric->score($predictions, $testing->labels());

            $this->steps[] = $loss;
            $this->scores[] = $score;

            if ($score > $bestScore) {
                $bestScore = $score;
                $bestSnapshot = new Snapshot($this->network);
            }

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

            if (is_nan($loss) or is_nan($score)) {
                break 1;
            }

            if (abs($previous - $loss) < $this->minChange) {
                break 1;
            }

            if ($loss < EPSILON or $score >= $max) {
                break 1;
            }

            if ($epoch > $this->window) {
                $window = array_slice($this->scores, -$this->window);

                $worst = $window;
                rsort($worst);

                if ($window === $worst) {
                    break 1;
                }
            }
        }

        if (end($this->scores) < $bestScore) {
            if ($bestSnapshot) {
                $this->network->restore($bestSnapshot);

                if ($this->logger) {
                    $this->logger->info('Network restored'
                        . ' from previous snapshot');
                }
            }
        }

        if ($this->logger) {
            $this->logger->info('Training complete');
            $this->logger->info("Best validation score=$bestScore");
        }
    }