Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
83.33% |
5 / 6 |
CRAP | |
98.41% |
62 / 63 |
| SupportVectorMachine | |
0.00% |
0 / 1 |
|
83.33% |
5 / 6 |
10 | |
98.41% |
62 / 63 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
16 / 16 |
|||
| train | |
100.00% |
1 / 1 |
1 | |
100.00% |
11 / 11 |
|||
| getModel | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| predict | |
100.00% |
1 / 1 |
3 | |
100.00% |
17 / 17 |
|||
| getOSExtension | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
| buildTrainCommand | |
100.00% |
1 / 1 |
2 | |
100.00% |
15 / 15 |
|||
| <?php | |
| declare (strict_types = 1); | |
| namespace Phpml\SupportVectorMachine; | |
| class SupportVectorMachine | |
| { | |
| /** | |
| * @var int | |
| */ | |
| private $type; | |
| /** | |
| * @var int | |
| */ | |
| private $kernel; | |
| /** | |
| * @var float | |
| */ | |
| private $cost; | |
| /** | |
| * @var float | |
| */ | |
| private $nu; | |
| /** | |
| * @var int | |
| */ | |
| private $degree; | |
| /** | |
| * @var float | |
| */ | |
| private $gamma; | |
| /** | |
| * @var float | |
| */ | |
| private $coef0; | |
| /** | |
| * @var float | |
| */ | |
| private $epsilon; | |
| /** | |
| * @var float | |
| */ | |
| private $tolerance; | |
| /** | |
| * @var int | |
| */ | |
| private $cacheSize; | |
| /** | |
| * @var bool | |
| */ | |
| private $shrinking; | |
| /** | |
| * @var bool | |
| */ | |
| private $probabilityEstimates; | |
| /** | |
| * @var string | |
| */ | |
| private $binPath; | |
| /** | |
| * @var string | |
| */ | |
| private $varPath; | |
| /** | |
| * @var string | |
| */ | |
| private $model; | |
| /** | |
| * @var array | |
| */ | |
| private $labels; | |
| /** | |
| * @param int $type | |
| * @param int $kernel | |
| * @param float $cost | |
| * @param float $nu | |
| * @param int $degree | |
| * @param float|null $gamma | |
| * @param float $coef0 | |
| * @param float $epsilon | |
| * @param float $tolerance | |
| * @param int $cacheSize | |
| * @param bool $shrinking | |
| * @param bool $probabilityEstimates | |
| */ | |
| public function __construct( | |
| int $type, int $kernel, float $cost = 1.0, float $nu = 0.5, int $degree = 3, | |
| float $gamma = null, float $coef0 = 0.0, float $epsilon = 0.1, float $tolerance = 0.001, | |
| int $cacheSize = 100, bool $shrinking = true, bool $probabilityEstimates = false | |
| ) { | |
| $this->type = $type; | |
| $this->kernel = $kernel; | |
| $this->cost = $cost; | |
| $this->nu = $nu; | |
| $this->degree = $degree; | |
| $this->gamma = $gamma; | |
| $this->coef0 = $coef0; | |
| $this->epsilon = $epsilon; | |
| $this->tolerance = $tolerance; | |
| $this->cacheSize = $cacheSize; | |
| $this->shrinking = $shrinking; | |
| $this->probabilityEstimates = $probabilityEstimates; | |
| $rootPath = realpath(implode(DIRECTORY_SEPARATOR, [dirname(__FILE__), '..', '..', '..'])).DIRECTORY_SEPARATOR; | |
| $this->binPath = $rootPath.'bin'.DIRECTORY_SEPARATOR.'libsvm'.DIRECTORY_SEPARATOR; | |
| $this->varPath = $rootPath.'var'.DIRECTORY_SEPARATOR; | |
| } | |
| /** | |
| * @param array $samples | |
| * @param array $labels | |
| */ | |
| public function train(array $samples, array $labels) | |
| { | |
| $this->labels = $labels; | |
| $trainingSet = DataTransformer::trainingSet($samples, $labels, in_array($this->type, [Type::EPSILON_SVR, Type::NU_SVR])); | |
| file_put_contents($trainingSetFileName = $this->varPath.uniqid(), $trainingSet); | |
| $modelFileName = $trainingSetFileName.'-model'; | |
| $command = $this->buildTrainCommand($trainingSetFileName, $modelFileName); | |
| $output = ''; | |
| exec(escapeshellcmd($command), $output); | |
| $this->model = file_get_contents($modelFileName); | |
| unlink($trainingSetFileName); | |
| unlink($modelFileName); | |
| } | |
| /** | |
| * @return string | |
| */ | |
| public function getModel() | |
| { | |
| return $this->model; | |
| } | |
| /** | |
| * @param array $samples | |
| * | |
| * @return array | |
| */ | |
| public function predict(array $samples) | |
| { | |
| $testSet = DataTransformer::testSet($samples); | |
| file_put_contents($testSetFileName = $this->varPath.uniqid(), $testSet); | |
| file_put_contents($modelFileName = $testSetFileName.'-model', $this->model); | |
| $outputFileName = $testSetFileName.'-output'; | |
| $command = sprintf('%ssvm-predict%s %s %s %s', $this->binPath, $this->getOSExtension(), $testSetFileName, $modelFileName, $outputFileName); | |
| $output = ''; | |
| exec(escapeshellcmd($command), $output); | |
| $predictions = file_get_contents($outputFileName); | |
| unlink($testSetFileName); | |
| unlink($modelFileName); | |
| unlink($outputFileName); | |
| if (in_array($this->type, [Type::C_SVC, Type::NU_SVC])) { | |
| $predictions = DataTransformer::predictions($predictions, $this->labels); | |
| } else { | |
| $predictions = explode(PHP_EOL, trim($predictions)); | |
| } | |
| if (!is_array($samples[0])) { | |
| return $predictions[0]; | |
| } | |
| return $predictions; | |
| } | |
| /** | |
| * @return string | |
| */ | |
| private function getOSExtension() | |
| { | |
| if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
| return '.exe'; | |
| } | |
| return ''; | |
| } | |
| /** | |
| * @param $trainingSetFileName | |
| * @param $modelFileName | |
| * | |
| * @return string | |
| */ | |
| private function buildTrainCommand(string $trainingSetFileName, string $modelFileName): string | |
| { | |
| return sprintf('%ssvm-train%s -s %s -t %s -c %s -n %s -d %s%s -r %s -p %s -m %s -e %s -h %d -b %d \'%s\' \'%s\'', | |
| $this->binPath, | |
| $this->getOSExtension(), | |
| $this->type, | |
| $this->kernel, | |
| $this->cost, | |
| $this->nu, | |
| $this->degree, | |
| $this->gamma !== null ? ' -g '.$this->gamma : '', | |
| $this->coef0, | |
| $this->epsilon, | |
| $this->cacheSize, | |
| $this->tolerance, | |
| $this->shrinking, | |
| $this->probabilityEstimates, | |
| $trainingSetFileName, | |
| $modelFileName | |
| ); | |
| } | |
| } |