← Back
Editing: MonteCarlo.php
<?php namespace Rubix\ML\CrossValidation; use Rubix\ML\Learner; use Rubix\ML\Parallel; use Rubix\ML\Estimator; use Rubix\ML\Helpers\Stats; use Rubix\ML\Backends\Serial; use Rubix\ML\Datasets\Labeled; use Rubix\ML\Datasets\Dataset; use Rubix\ML\Traits\Multiprocessing; use Rubix\ML\CrossValidation\Metrics\Metric; use Rubix\ML\Backends\Tasks\TrainAndValidate; use Rubix\ML\Specifications\EstimatorIsCompatibleWithMetric; use Rubix\ML\Exceptions\InvalidArgumentException; use Rubix\ML\Exceptions\RuntimeException; /** * Monte Carlo * * Monte Carlo cross validation (or *repeated random subsampling*) is a technique that * averages the validation score of a learner over a user-defined number of simulations * where the learner is trained and tested on random splits of the dataset. The estimated * validation score approaches the actual validation score as the number of simulations * goes to infinity, however, only a tiny fraction of all possible simulations are needed * to produce a pretty good approximation. * * @category Machine Learning * @package Rubix/ML * @author Andrew DalPino */ class MonteCarlo implements Validator, Parallel { use Multiprocessing; /** * The number of simulations i.e. random subsamplings of the dataset. * * @var int */ protected int $simulations; /** * The hold out ratio. i.e. the ratio of samples to use for testing. * * @var float */ protected float $ratio; /** * @param int $simulations * @param float $ratio * @throws InvalidArgumentException */ public function __construct(int $simulations = 10, float $ratio = 0.2) { if ($simulations < 1) { throw new InvalidArgumentException('Number of simulations' . " must be greater than 0, $simulations given."); } if ($ratio <= 0.0 or $ratio >= 1.0) { throw new InvalidArgumentException('Ratio must be' . " between 0 and 1, $ratio given."); } $this->simulations = $simulations; $this->ratio = $ratio; $this->backend = new Serial(); } /** * Test the estimator with the supplied dataset and return a validation score. * * @param Learner $estimator * @param Labeled $dataset * @param Metric $metric * @throws RuntimeException * @return float */ public function test(Learner $estimator, Labeled $dataset, Metric $metric) : float { EstimatorIsCompatibleWithMetric::with($estimator, $metric)->check(); if ($dataset->numSamples() * $this->ratio < 1) { throw new RuntimeException('Dataset does not contain' . ' enough records to create a validation set with a' . " hold out ratio of {$this->ratio}."); } $stratify = $dataset->labelType()->isCategorical(); $this->backend->flush(); for ($i = 0; $i < $this->simulations; ++$i) { $dataset->randomize(); [$testing, $training] = $stratify ? $dataset->stratifiedSplit($this->ratio) : $dataset->split($this->ratio); $this->backend->enqueue( new TrainAndValidate($estimator, $training, $testing, $metric) ); } $scores = $this->backend->process(); return Stats::mean($scores); } /** * Return the string representation of the object. * * @internal * * @return string */ public function __toString() : string { return "Monte Carlo (simulations: {$this->simulations}, ratio: {$this->ratio})"; } }
Save File
Cancel