l2Penalty = $l2Penalty; } /** * Return the estimator type. * * @internal * * @return EstimatorType */ public function type() : EstimatorType { return EstimatorType::regressor(); } /** * Return the data types that the estimator is compatible with. * * @internal * * @return list */ public function compatibility() : array { return [ DataType::continuous(), ]; } /** * Return the settings of the hyper-parameters in an associative array. * * @internal * * @return mixed[] */ public function params() : array { return [ 'l2 penalty' => $this->l2Penalty, ]; } /** * Has the learner been trained? * * @return bool */ public function trained() : bool { return $this->coefficients and isset($this->bias); } /** * Return the weights of features in the decision function. * * @return (int|float)[]|null */ public function coefficients() : ?array { return $this->coefficients ? $this->coefficients->asArray() : null; } /** * Return the bias added to the decision function. * * @return float|null */ public function bias() : ?float { return $this->bias; } /** * Train the learner with a dataset. * * @param \Rubix\ML\Datasets\Labeled $dataset */ public function train(Dataset $dataset) : void { SpecificationChain::with([ new DatasetIsLabeled($dataset), new DatasetIsNotEmpty($dataset), new SamplesAreCompatibleWithEstimator($dataset, $this), new LabelsAreCompatibleWithLearner($dataset, $this), ])->check(); $biases = Matrix::ones($dataset->numSamples(), 1); $x = Matrix::build($dataset->samples())->augmentLeft($biases); $y = Vector::build($dataset->labels()); /** @var int<0,max> $nHat */ $nHat = $x->n() - 1; $penalties = array_fill(0, $nHat, $this->l2Penalty); array_unshift($penalties, 0.0); $penalties = Matrix::diagonal($penalties); $xT = $x->transpose(); $coefficients = $xT->matmul($x) ->add($penalties) ->inverse() ->dot($xT->dot($y)) ->asArray(); $this->bias = (float) array_shift($coefficients); $this->coefficients = Vector::quick($coefficients); } /** * Make a prediction based on the line calculated from the training data. * * @param Dataset $dataset * @throws RuntimeException * @return list */ public function predict(Dataset $dataset) : array { if (!$this->coefficients or is_null($this->bias)) { throw new RuntimeException('Estimator has not been trained.'); } DatasetHasDimensionality::with($dataset, count($this->coefficients))->check(); return Matrix::build($dataset->samples()) ->dot($this->coefficients) ->add($this->bias) ->asArray(); } /** * Return the importance scores of each feature column of the training set. * * @throws RuntimeException * @return float[] */ public function featureImportances() : array { if (is_null($this->coefficients)) { throw new RuntimeException('Learner has not been trained.'); } return $this->coefficients->abs()->asArray(); } /** * Return the string representation of the object. * * @internal * * @return string */ public function __toString() : string { return 'Ridge (' . Params::stringify($this->params()) . ')'; } }