Train an learner using a dataset and return it.

@param \Rubix\ML\Learner $estimator
@param \Rubix\ML\Datasets\Dataset $dataset
@return \Rubix\ML\Learner
1227
public function _train(Learner $estimator, Dataset $dataset) : Learner
    {
        $estimator->train($dataset);

        return $estimator;
    }
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);
    }
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());
    }
133561
public function train(Dataset $dataset) : void
    {
        DatasetIsCompatibleWithEstimator::check($dataset, $this);

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

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

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

        $samples = $dataset->samples();
        $rotated = $dataset->columns();

        $previous = INF;

        for ($epoch = 1; $epoch <= $this->epochs; $epoch++) {
            $memberships = array_map([self::class, 'membership'], $samples);

            foreach ($this->centroids as $cluster => &$centroid) {
                foreach ($rotated as $column => $values) {
                    $sigma = $total = 0.;

                    foreach ($memberships as $i => $probabilities) {
                        $weight = $probabilities[$cluster] ** $this->fuzz;

                        $sigma += $weight * $values[$i];
                        $total += $weight;
                    }

                    $centroid[$column] = $sigma / ($total ?: EPSILON);
                }
            }

            $inertia = $this->inertia($dataset, $memberships);

            $this->steps[] = $inertia;

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

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

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

            $previous = $inertia;
        }

        if ($this->logger) {
            $this->logger->info('Training complete');
        }
    }
60704
public function saveDataset($key, $dataset)
    {
        $data = $this->session->get(self::KEY);
        $data[$key] = $dataset;
        $this->session->set(self::KEY, $data);
        return $this;
    }
952709
public function proba(Dataset $dataset) : array
    {
        if (empty($this->samples) or empty($this->labels)) {
            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) {
            [$labels, $distances] = $this->nearest($sample);

            if ($this->weighted) {
                $weights = array_fill_keys($labels, 0.);

                foreach ($labels as $i => $label) {
                    $weights[$label] += 1. / (1. + $distances[$i]);
                }
            } else {
                $weights = array_count_values($labels);
            }

            $total = array_sum($weights) ?: EPSILON;

            $dist = $template;

            foreach ($weights as $class => $weight) {
                $dist[$class] = $weight / $total;
            }

            $probabilities[] = $dist;
        }

        return $probabilities;
    }
417909
protected function update(Dataset $dataset) : void
    {
        foreach ($this->transformers as $transformer) {
            if ($transformer instanceof Elastic) {
                $transformer->update($dataset);

                if ($this->logger) {
                    $this->logger->info('Updated '
                        . Params::shortName($transformer));
                }
            }

            $dataset->apply($transformer);

            if ($this->logger) {
                $this->logger->info('Applied '
                    . Params::shortName($transformer));
            }
        }
    }
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;
        }
    }
294792
public function predict(Dataset $dataset) : array
    {
        if (!$this->model) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }

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

        $predictions = [];

        foreach ($dataset as $sample) {
            $predictions[] = $this->model->predict($sample) !== 1. ? 0 : 1;
        }

        return $predictions;
    }
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);
    }
518590
public function prepend(Dataset $dataset) : Dataset
    {
        return self::quick(array_merge($dataset->samples(), $this->samples));
    }
1047502
public function proba(Dataset $dataset) : array
    {
        if (empty($this->forest)) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }

        $probabilities = array_fill(
            0,
            $dataset->numRows(),
            array_fill_keys($this->classes, 0.)
        );

        foreach ($this->forest as $tree) {
            foreach ($tree->proba($dataset) as $i => $joint) {
                foreach ($joint as $class => $probability) {
                    $probabilities[$i][$class] += $probability;
                }
            }
        }

        foreach ($probabilities as &$joint) {
            foreach ($joint as &$probability) {
                $probability /= $this->estimators;
            }
        }

        return $probabilities;
    }
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;
    }
1303127
public function predict(Dataset $dataset) : array
    {
        if (empty($this->weights) or empty($this->probs)) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }

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

        $predictions = [];

        foreach ($dataset as $sample) {
            $jll = $this->jointLogLikelihood($sample);

            $predictions[] = argmax($jll);
        }

        return $predictions;
    }
442803
public function predict(Dataset $dataset) : array
    {
        if (empty($this->ensemble) or empty($this->influences)) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }
        
        return array_map('Rubix\ML\argmax', $this->score($dataset));
    }
664596
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);

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

        $this->ensemble = [];

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

            $coroutines = [];

            for ($i = 0; $i < $this->estimators; $i++) {
                $estimator = clone $this->base;

                $subset = $dataset->randomSubsetWithReplacement($p);

                $task = new CallableTask(
                    [$this, '_train'],
                    [$estimator, $subset]
                );

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

            $this->ensemble = yield all($coroutines);
            
            return yield $pool->shutdown();
        });
    }
583706
public function predict(Dataset $dataset) : array
    {
        if ($this->offset === null) {
            throw new RuntimeException('The learner has not'
                . ' been trained.');
        }

        return array_map([self::class, 'decide'], $this->rank($dataset));
    }