Update easy coding standard to ^5.1 (#317)

This commit is contained in:
Marcin Michalski 2018-10-16 21:42:06 +02:00 committed by Arkadiusz Kondas
parent 9c9705a32c
commit 0beb407b16
33 changed files with 593 additions and 382 deletions

View File

@ -28,8 +28,8 @@
"phpstan/phpstan-shim": "^0.9",
"phpstan/phpstan-strict-rules": "^0.9.0",
"phpunit/phpunit": "^7.0.0",
"symplify/coding-standard": "^4.4",
"symplify/easy-coding-standard": "^4.4"
"symplify/coding-standard": "^5.1",
"symplify/easy-coding-standard": "^5.1"
},
"config": {
"preferred-install": "dist",

669
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,8 @@ use Phpml\Helper\Trainable;
class Apriori implements Associator
{
use Trainable, Predictable;
use Trainable;
use Predictable;
public const ARRAY_KEY_ANTECEDENT = 'antecedent';

View File

@ -12,7 +12,8 @@ use Phpml\Math\Statistic\Mean;
class DecisionTree implements Classifier
{
use Trainable, Predictable;
use Trainable;
use Predictable;
public const CONTINUOUS = 1;
@ -31,7 +32,7 @@ class DecisionTree implements Classifier
/**
* @var DecisionTreeLeaf
*/
protected $tree = null;
protected $tree;
/**
* @var int
@ -219,10 +220,9 @@ class DecisionTree implements Classifier
// Normalize & sort the importances
$total = array_sum($this->featureImportances);
if ($total > 0) {
foreach ($this->featureImportances as &$importance) {
array_walk($this->featureImportances, function (&$importance) use ($total): void {
$importance /= $total;
}
});
arsort($this->featureImportances);
}

View File

@ -16,7 +16,8 @@ use ReflectionClass;
class AdaBoost implements Classifier
{
use Predictable, Trainable;
use Predictable;
use Trainable;
/**
* Actual labels given in the targets array

View File

@ -13,7 +13,8 @@ use ReflectionClass;
class Bagging implements Classifier
{
use Trainable, Predictable;
use Trainable;
use Predictable;
/**
* @var int

View File

@ -16,9 +16,9 @@ class RandomForest extends Bagging
protected $featureSubsetRatio = 'log';
/**
* @var array
* @var array|null
*/
protected $columnNames = null;
protected $columnNames;
/**
* Initializes RandomForest with the given number of trees. More trees
@ -53,7 +53,7 @@ class RandomForest extends Bagging
throw new InvalidArgumentException('When a float is given, feature subset ratio should be between 0.1 and 1.0');
}
if (is_string($ratio) && $ratio != 'sqrt' && $ratio != 'log') {
if (is_string($ratio) && $ratio !== 'sqrt' && $ratio !== 'log') {
throw new InvalidArgumentException("When a string is given, feature subset ratio can only be 'sqrt' or 'log'");
}
@ -69,7 +69,7 @@ class RandomForest extends Bagging
*/
public function setClassifer(string $classifier, array $classifierOptions = [])
{
if ($classifier != DecisionTree::class) {
if ($classifier !== DecisionTree::class) {
throw new InvalidArgumentException('RandomForest can only use DecisionTree as base classifier');
}
@ -100,10 +100,9 @@ class RandomForest extends Bagging
// Normalize & sort the importance values
$total = array_sum($sum);
foreach ($sum as &$importance) {
array_walk($sum, function (&$importance) use ($total): void {
$importance /= $total;
}
});
arsort($sum);
return $sum;
@ -131,7 +130,7 @@ class RandomForest extends Bagging
{
if (is_float($this->featureSubsetRatio)) {
$featureCount = (int) ($this->featureSubsetRatio * $this->featureCount);
} elseif ($this->featureSubsetRatio == 'sqrt') {
} elseif ($this->featureSubsetRatio === 'sqrt') {
$featureCount = (int) sqrt($this->featureCount) + 1;
} else {
$featureCount = (int) log($this->featureCount, 2) + 1;

View File

@ -11,7 +11,8 @@ use Phpml\Math\Distance\Euclidean;
class KNearestNeighbors implements Classifier
{
use Trainable, Predictable;
use Trainable;
use Predictable;
/**
* @var int
@ -47,7 +48,7 @@ class KNearestNeighbors implements Classifier
$predictions = array_combine(array_values($this->targets), array_fill(0, count($this->targets), 0));
foreach ($distances as $index => $distance) {
foreach (array_keys($distances) as $index) {
++$predictions[$this->targets[$index]];
}

View File

@ -13,7 +13,8 @@ use Phpml\Math\Comparison;
class DecisionStump extends WeightedClassifier
{
use Predictable, OneVsRest;
use Predictable;
use OneVsRest;
public const AUTO_SELECT = -1;

View File

@ -87,10 +87,8 @@ class LogisticRegression extends Adaline
);
}
if ($penalty != '' && strtoupper($penalty) !== 'L2') {
throw new InvalidArgumentException(
"Logistic regression supports only 'L2' regularization"
);
if ($penalty !== '' && strtoupper($penalty) !== 'L2') {
throw new InvalidArgumentException('Logistic regression supports only \'L2\' regularization');
}
$this->learningRate = 0.001;
@ -174,7 +172,7 @@ class LogisticRegression extends Adaline
protected function getCostFunction(): Closure
{
$penalty = 0;
if ($this->penalty == 'L2') {
if ($this->penalty === 'L2') {
$penalty = $this->lambda;
}
@ -190,7 +188,7 @@ class LogisticRegression extends Adaline
* The gradient of the cost function to be used with gradient descent:
* ∇J(x) = -(y - h(x)) = (h(x) - y)
*/
$callback = function ($weights, $sample, $y) use ($penalty) {
return function ($weights, $sample, $y) use ($penalty) {
$this->weights = $weights;
$hX = $this->output($sample);
@ -211,9 +209,6 @@ class LogisticRegression extends Adaline
return [$error, $gradient, $penalty];
};
return $callback;
case 'sse':
/*
* Sum of squared errors or least squared errors cost function:
@ -225,7 +220,7 @@ class LogisticRegression extends Adaline
* The gradient of the cost function:
* ∇J(x) = -(h(x) - y) . h(x) . (1 - h(x))
*/
$callback = function ($weights, $sample, $y) use ($penalty) {
return function ($weights, $sample, $y) use ($penalty) {
$this->weights = $weights;
$hX = $this->output($sample);
@ -236,9 +231,6 @@ class LogisticRegression extends Adaline
return [$error, $gradient, $penalty];
};
return $callback;
default:
// Not reached
throw new Exception(sprintf('Logistic regression has invalid cost function: %s.', $this->costFunction));

View File

@ -17,7 +17,8 @@ use Phpml\Preprocessing\Normalizer;
class Perceptron implements Classifier, IncrementalEstimator
{
use Predictable, OneVsRest;
use Predictable;
use OneVsRest;
/**
* @var Optimizer|GD|StochasticGD|null

View File

@ -11,7 +11,8 @@ use Phpml\Math\Statistic\StandardDeviation;
class NaiveBayes implements Classifier
{
use Trainable, Predictable;
use Trainable;
use Predictable;
public const CONTINUOS = 1;

View File

@ -23,7 +23,7 @@ class ArrayDataset implements Dataset
*/
public function __construct(array $samples, array $targets)
{
if (count($samples) != count($targets)) {
if (count($samples) !== count($targets)) {
throw new InvalidArgumentException('Size of given arrays does not match');
}

View File

@ -94,7 +94,7 @@ class SvmDataset extends ArrayDataset
private static function parseFeatureColumn(string $column): array
{
$feature = explode(':', $column, 2);
if (count($feature) != 2) {
if (count($feature) !== 2) {
throw new DatasetException(sprintf('Invalid value "%s".', $column));
}

View File

@ -120,7 +120,7 @@ class PCA extends EigenTransformerBase
}
// Normalize data
foreach ($data as $i => $row) {
foreach (array_keys($data) as $i) {
for ($k = 0; $k < $n; ++$k) {
$data[$i][$k] -= $this->means[$k];
}

View File

@ -48,9 +48,9 @@ class TokenCountVectorizer implements Transformer
public function transform(array &$samples): void
{
foreach ($samples as &$sample) {
array_walk($samples, function (string &$sample): void {
$this->transformSample($sample);
}
});
$this->checkDocumentFrequency($samples);
}
@ -62,7 +62,7 @@ class TokenCountVectorizer implements Transformer
private function buildVocabulary(array &$samples): void
{
foreach ($samples as $index => $sample) {
foreach ($samples as $sample) {
$tokens = $this->tokenizer->tokenize($sample);
foreach ($tokens as $token) {
$this->addTokenToVocabulary($token);

View File

@ -43,7 +43,7 @@ final class UnivariateLinearRegression implements ScoringFunction
}
$correlations = [];
foreach ($samples[0] as $index => $feature) {
foreach (array_keys($samples[0]) as $index) {
$featureColumn = array_column($samples, $index);
$correlations[$index] =
(Matrix::dot($targets, $featureColumn)[0] / (new Matrix($featureColumn, false))->transpose()->frobeniusNorm())
@ -57,15 +57,15 @@ final class UnivariateLinearRegression implements ScoringFunction
}, $correlations);
}
private function centerTargets(&$targets): void
private function centerTargets(array &$targets): void
{
$mean = Mean::arithmetic($targets);
foreach ($targets as &$target) {
array_walk($targets, function (&$target) use ($mean): void {
$target -= $mean;
}
});
}
private function centerSamples(&$samples): void
private function centerSamples(array &$samples): void
{
$means = [];
foreach ($samples[0] as $index => $feature) {

View File

@ -179,7 +179,7 @@ class EigenvalueDecomposition
continue;
}
$o = ($this->e[$i] > 0) ? $i + 1 : $i - 1;
$o = $this->e[$i] > 0 ? $i + 1 : $i - 1;
$D[$i][$o] = $this->e[$i];
}
@ -222,7 +222,7 @@ class EigenvalueDecomposition
}
$this->e[$i] = $scale * $g;
$h = $h - $f * $g;
$h -= $f * $g;
$this->d[$i_] = $f - $g;
for ($j = 0; $j < $i; ++$j) {
@ -395,7 +395,7 @@ class EigenvalueDecomposition
} while (abs($this->e[$l]) > $eps * $tst1);
}
$this->d[$l] = $this->d[$l] + $f;
$this->d[$l] += $f;
$this->e[$l] = 0.0;
}
@ -439,7 +439,7 @@ class EigenvalueDecomposition
// Scale column.
$scale = 0.0;
for ($i = $m; $i <= $high; ++$i) {
$scale = $scale + abs($this->H[$i][$m - 1]);
$scale += abs($this->H[$i][$m - 1]);
}
if ($scale != 0.0) {
@ -477,7 +477,7 @@ class EigenvalueDecomposition
$f += $this->ort[$j] * $this->H[$i][$j];
}
$f = $f / $h;
$f /= $h;
for ($j = $m; $j <= $high; ++$j) {
$this->H[$i][$j] -= $f * $this->ort[$j];
}
@ -568,7 +568,7 @@ class EigenvalueDecomposition
}
for ($j = max($i - 1, 0); $j < $nn; ++$j) {
$norm = $norm + abs($this->H[$i][$j]);
$norm += abs($this->H[$i][$j]);
}
}
@ -593,7 +593,7 @@ class EigenvalueDecomposition
// Check for convergence
// One root found
if ($l == $n) {
$this->H[$n][$n] = $this->H[$n][$n] + $exshift;
$this->H[$n][$n] += $exshift;
$this->d[$n] = $this->H[$n][$n];
$this->e[$n] = 0.0;
--$n;
@ -604,8 +604,8 @@ class EigenvalueDecomposition
$p = ($this->H[$n - 1][$n - 1] - $this->H[$n][$n]) / 2.0;
$q = $p * $p + $w;
$z = sqrt(abs($q));
$this->H[$n][$n] = $this->H[$n][$n] + $exshift;
$this->H[$n - 1][$n - 1] = $this->H[$n - 1][$n - 1] + $exshift;
$this->H[$n][$n] += $exshift;
$this->H[$n - 1][$n - 1] += $exshift;
$x = $this->H[$n][$n];
// Real pair
if ($q >= 0) {
@ -628,8 +628,8 @@ class EigenvalueDecomposition
$p = $x / $s;
$q = $z / $s;
$r = sqrt($p * $p + $q * $q);
$p = $p / $r;
$q = $q / $r;
$p /= $r;
$q /= $r;
// Row modification
for ($j = $n - 1; $j < $nn; ++$j) {
$z = $this->H[$n - 1][$j];
@ -659,7 +659,7 @@ class EigenvalueDecomposition
$this->e[$n] = -$z;
}
$n = $n - 2;
$n -= 2;
$iter = 0;
// No convergence yet
} else {
@ -687,7 +687,7 @@ class EigenvalueDecomposition
// MATLAB's new ad hoc shift
if ($iter == 30) {
$s = ($y - $x) / 2.0;
$s = $s * $s + $w;
$s *= $s + $w;
if ($s > 0) {
$s = sqrt($s);
if ($y < $x) {
@ -705,7 +705,7 @@ class EigenvalueDecomposition
}
// Could check iteration count here.
$iter = $iter + 1;
++$iter;
// Look for two consecutive small sub-diagonal elements
$m = $n - 2;
while ($m >= $l) {
@ -716,9 +716,9 @@ class EigenvalueDecomposition
$q = $this->H[$m + 1][$m + 1] - $z - $r - $s;
$r = $this->H[$m + 2][$m + 1];
$s = abs($p) + abs($q) + abs($r);
$p = $p / $s;
$q = $q / $s;
$r = $r / $s;
$p /= $s;
$q /= $s;
$r /= $s;
if ($m == $l) {
break;
}
@ -747,9 +747,9 @@ class EigenvalueDecomposition
$r = ($notlast ? $this->H[$k + 2][$k - 1] : 0.0);
$x = abs($p) + abs($q) + abs($r);
if ($x != 0.0) {
$p = $p / $x;
$q = $q / $x;
$r = $r / $x;
$p /= $x;
$q /= $x;
$r /= $x;
}
}
@ -769,46 +769,46 @@ class EigenvalueDecomposition
$this->H[$k][$k - 1] = -$this->H[$k][$k - 1];
}
$p = $p + $s;
$p += $s;
$x = $p / $s;
$y = $q / $s;
$z = $r / $s;
$q = $q / $p;
$r = $r / $p;
$q /= $p;
$r /= $p;
// Row modification
for ($j = $k; $j < $nn; ++$j) {
$p = $this->H[$k][$j] + $q * $this->H[$k + 1][$j];
if ($notlast) {
$p = $p + $r * $this->H[$k + 2][$j];
$this->H[$k + 2][$j] = $this->H[$k + 2][$j] - $p * $z;
$p += $r * $this->H[$k + 2][$j];
$this->H[$k + 2][$j] -= $p * $z;
}
$this->H[$k][$j] = $this->H[$k][$j] - $p * $x;
$this->H[$k + 1][$j] = $this->H[$k + 1][$j] - $p * $y;
$this->H[$k][$j] -= $p * $x;
$this->H[$k + 1][$j] -= $p * $y;
}
// Column modification
for ($i = 0; $i <= min($n, $k + 3); ++$i) {
$p = $x * $this->H[$i][$k] + $y * $this->H[$i][$k + 1];
if ($notlast) {
$p = $p + $z * $this->H[$i][$k + 2];
$this->H[$i][$k + 2] = $this->H[$i][$k + 2] - $p * $r;
$p += $z * $this->H[$i][$k + 2];
$this->H[$i][$k + 2] -= $p * $r;
}
$this->H[$i][$k] = $this->H[$i][$k] - $p;
$this->H[$i][$k + 1] = $this->H[$i][$k + 1] - $p * $q;
$this->H[$i][$k] -= $p;
$this->H[$i][$k + 1] -= $p * $q;
}
// Accumulate transformations
for ($i = $low; $i <= $high; ++$i) {
$p = $x * $this->V[$i][$k] + $y * $this->V[$i][$k + 1];
if ($notlast) {
$p = $p + $z * $this->V[$i][$k + 2];
$this->V[$i][$k + 2] = $this->V[$i][$k + 2] - $p * $r;
$p += $z * $this->V[$i][$k + 2];
$this->V[$i][$k + 2] -= $p * $r;
}
$this->V[$i][$k] = $this->V[$i][$k] - $p;
$this->V[$i][$k + 1] = $this->V[$i][$k + 1] - $p * $q;
$this->V[$i][$k] -= $p;
$this->V[$i][$k + 1] -= $p * $q;
}
} // ($s != 0)
} // k loop
@ -831,7 +831,7 @@ class EigenvalueDecomposition
$w = $this->H[$i][$i] - $p;
$r = 0.0;
for ($j = $l; $j <= $n; ++$j) {
$r = $r + $this->H[$i][$j] * $this->H[$j][$n];
$r += $this->H[$i][$j] * $this->H[$j][$n];
}
if ($this->e[$i] < 0.0) {
@ -864,7 +864,7 @@ class EigenvalueDecomposition
$t = abs($this->H[$i][$n]);
if (($eps * $t) * $t > 1) {
for ($j = $i; $j <= $n; ++$j) {
$this->H[$j][$n] = $this->H[$j][$n] / $t;
$this->H[$j][$n] /= $t;
}
}
}
@ -890,8 +890,8 @@ class EigenvalueDecomposition
$ra = 0.0;
$sa = 0.0;
for ($j = $l; $j <= $n; ++$j) {
$ra = $ra + $this->H[$i][$j] * $this->H[$j][$n - 1];
$sa = $sa + $this->H[$i][$j] * $this->H[$j][$n];
$ra += $this->H[$i][$j] * $this->H[$j][$n - 1];
$sa += $this->H[$i][$j] * $this->H[$j][$n];
}
$w = $this->H[$i][$i] - $p;
@ -932,8 +932,8 @@ class EigenvalueDecomposition
$t = max(abs($this->H[$i][$n - 1]), abs($this->H[$i][$n]));
if (($eps * $t) * $t > 1) {
for ($j = $i; $j <= $n; ++$j) {
$this->H[$j][$n - 1] = $this->H[$j][$n - 1] / $t;
$this->H[$j][$n] = $this->H[$j][$n] / $t;
$this->H[$j][$n - 1] /= $t;
$this->H[$j][$n] /= $t;
}
}
} // end else
@ -955,7 +955,7 @@ class EigenvalueDecomposition
for ($i = $low; $i <= $high; ++$i) {
$z = 0.0;
for ($k = $low; $k <= min($j, $high); ++$k) {
$z = $z + $this->V[$i][$k] * $this->H[$k][$j];
$z += $this->V[$i][$k] * $this->H[$k][$j];
}
$this->V[$i][$j] = $z;

View File

@ -133,7 +133,7 @@ class LUDecomposition
$k = $this->piv[$p];
$this->piv[$p] = $this->piv[$j];
$this->piv[$j] = $k;
$this->pivsign = $this->pivsign * -1;
$this->pivsign *= -1;
}
// Compute multipliers.

View File

@ -261,7 +261,7 @@ class Matrix
$squareSum = 0;
for ($i = 0; $i < $this->rows; ++$i) {
for ($j = 0; $j < $this->columns; ++$j) {
$squareSum += ($this->matrix[$i][$j]) ** 2;
$squareSum += $this->matrix[$i][$j] ** 2;
}
}

View File

@ -102,7 +102,7 @@ final class ANOVA
{
foreach ($sums as &$row) {
foreach ($row as &$sum) {
$sum = $sum ** 2;
$sum **= 2;
}
}

View File

@ -54,7 +54,7 @@ class Normalizer implements Preprocessor
return;
}
if ($this->norm == self::NORM_STD) {
if ($this->norm === self::NORM_STD) {
$features = range(0, count($samples[0]) - 1);
foreach ($features as $i) {
$values = array_column($samples, $i);
@ -93,9 +93,9 @@ class Normalizer implements Preprocessor
$count = count($sample);
$sample = array_fill(0, $count, 1.0 / $count);
} else {
foreach ($sample as &$feature) {
array_walk($sample, function (&$feature) use ($norm1): void {
$feature /= $norm1;
}
});
}
}
@ -111,15 +111,15 @@ class Normalizer implements Preprocessor
if ($norm2 == 0) {
$sample = array_fill(0, count($sample), 1);
} else {
foreach ($sample as &$feature) {
array_walk($sample, function (&$feature) use ($norm2): void {
$feature /= $norm2;
}
});
}
}
private function normalizeSTD(array &$sample): void
{
foreach ($sample as $i => $val) {
foreach (array_keys($sample) as $i) {
if ($this->std[$i] != 0) {
$sample[$i] = ($sample[$i] - $this->mean[$i]) / $this->std[$i];
} else {

View File

@ -66,14 +66,13 @@ class KNearestNeighborsTest extends TestCase
$trainLabels = ['a', 'a', 'a', 'b', 'b', 'b'];
$testSamples = [[3, 2], [5, 1], [4, 3], [4, -5], [2, 3], [1, 2], [1, 5], [3, 10]];
$testLabels = ['b', 'b', 'b', 'b', 'a', 'a', 'a', 'a'];
// Using non-default constructor parameters to check that their values are restored.
$classifier = new KNearestNeighbors(3, new Chebyshev());
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$filename = 'knearest-neighbors-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'knearest-neighbors-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);

View File

@ -14,7 +14,9 @@ class AdalineTest extends TestCase
public function testAdalineThrowWhenInvalidTrainingType(): void
{
$this->expectException(InvalidArgumentException::class);
$classifier = new Adaline(
$this->expectExceptionMessage('Adaline can only be trained with batch and online/stochastic gradient descent algorithm');
new Adaline(
0.001,
1000,
true,
@ -86,7 +88,7 @@ class AdalineTest extends TestCase
$testSamples = [[0, 1], [1, 1], [0.2, 0.1]];
$predicted = $classifier->predict($testSamples);
$filename = 'adaline-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'adaline-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);

View File

@ -15,8 +15,11 @@ class LogisticRegressionTest extends TestCase
public function testConstructorThrowWhenInvalidTrainingType(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Logistic regression can only be trained with '.
'batch (gradient descent), online (stochastic gradient descent) '.
'or conjugate batch (conjugate gradients) algorithms');
$classifier = new LogisticRegression(
new LogisticRegression(
500,
true,
-1,
@ -28,8 +31,10 @@ class LogisticRegressionTest extends TestCase
public function testConstructorThrowWhenInvalidCost(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Logistic regression cost function can be one of the following: \n".
"'log' for log-likelihood and 'sse' for sum of squared errors");
$classifier = new LogisticRegression(
new LogisticRegression(
500,
true,
LogisticRegression::CONJUGATE_GRAD_TRAINING,
@ -41,8 +46,9 @@ class LogisticRegressionTest extends TestCase
public function testConstructorThrowWhenInvalidPenalty(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Logistic regression supports only \'L2\' regularization');
$classifier = new LogisticRegression(
new LogisticRegression(
500,
true,
LogisticRegression::CONJUGATE_GRAD_TRAINING,

View File

@ -14,13 +14,15 @@ class PerceptronTest extends TestCase
public function testPerceptronThrowWhenLearningRateOutOfRange(): void
{
$this->expectException(InvalidArgumentException::class);
$classifier = new Perceptron(0, 5000);
$this->expectExceptionMessage('Learning rate should be a float value between 0.0(exclusive) and 1.0(inclusive)');
new Perceptron(0, 5000);
}
public function testPerceptronThrowWhenMaxIterationsOutOfRange(): void
{
$this->expectException(InvalidArgumentException::class);
$classifier = new Perceptron(0.001, 0);
$this->expectExceptionMessage('Maximum number of iterations must be an integer greater than 0');
new Perceptron(0.001, 0);
}
public function testPredictSingleSample(): void
@ -90,7 +92,7 @@ class PerceptronTest extends TestCase
$testSamples = [[0, 1], [1, 1], [0.2, 0.1]];
$predicted = $classifier->predict($testSamples);
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);

View File

@ -53,13 +53,12 @@ class NaiveBayesTest extends TestCase
$trainLabels = ['a', 'b', 'c'];
$testSamples = [[3, 1, 1], [5, 1, 1], [4, 3, 8]];
$testLabels = ['a', 'a', 'c'];
$classifier = new NaiveBayes();
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$filename = 'naive-bayes-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'naive-bayes-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
@ -112,13 +111,12 @@ class NaiveBayesTest extends TestCase
$trainLabels = ['1996', '1997', '1998'];
$testSamples = [[3, 1, 1], [5, 1, 1], [4, 3, 8]];
$testLabels = ['1996', '1996', '1998'];
$classifier = new NaiveBayes();
$classifier->train($trainSamples, $trainLabels);
$predicted = $classifier->predict($testSamples);
$filename = 'naive-bayes-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'naive-bayes-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);

View File

@ -136,77 +136,77 @@ class SvmDatasetTest extends TestCase
public function testSvmDatasetMissingFile(): void
{
$this->expectException(FileException::class);
$this->expectExceptionMessage('File "err_file_not_exists.svm" missing.');
$filePath = self::getFilePath('err_file_not_exists.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_file_not_exists.svm'));
}
public function testSvmDatasetEmptyLine(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid target "".');
$filePath = self::getFilePath('err_empty_line.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_empty_line.svm'));
}
public function testSvmDatasetNoLabels(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid target "1:2.3".');
$filePath = self::getFilePath('err_no_labels.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_no_labels.svm'));
}
public function testSvmDatasetStringLabels(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid target "A".');
$filePath = self::getFilePath('err_string_labels.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_string_labels.svm'));
}
public function testSvmDatasetInvalidSpaces(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid target "".');
$filePath = self::getFilePath('err_invalid_spaces.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_invalid_spaces.svm'));
}
public function testSvmDatasetStringIndex(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid index "x".');
$filePath = self::getFilePath('err_string_index.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_string_index.svm'));
}
public function testSvmDatasetIndexZero(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid index "0".');
$filePath = self::getFilePath('err_index_zero.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_index_zero.svm'));
}
public function testSvmDatasetInvalidValue(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid value "xyz".');
$filePath = self::getFilePath('err_invalid_value.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_invalid_value.svm'));
}
public function testSvmDatasetInvalidFeature(): void
{
$this->expectException(DatasetException::class);
$this->expectExceptionMessage('Invalid value "12345".');
$filePath = self::getFilePath('err_invalid_feature.svm');
$dataset = new SvmDataset($filePath);
new SvmDataset(self::getFilePath('err_invalid_feature.svm'));
}
private static function getFilePath(string $baseName): string
{
return dirname(__FILE__).'/Resources/svm/'.$baseName;
return __DIR__.'/Resources/svm/'.$baseName;
}
}

View File

@ -54,16 +54,18 @@ class KernelPCATest extends TestCase
public function testKernelPCAThrowWhenKernelInvalid(): void
{
$this->expectException(InvalidArgumentException::class);
$kpca = new KernelPCA(0, null, 1, 15);
$this->expectExceptionMessage('KernelPCA can be initialized with the following kernels only: Linear, RBF, Sigmoid and Laplacian');
new KernelPCA(0, null, 1, 15.);
}
public function testTransformThrowWhenNotFitted(): void
{
$samples = [1, 0];
$kpca = new KernelPCA(KernelPCA::KERNEL_RBF, null, 1, 15);
$kpca = new KernelPCA(KernelPCA::KERNEL_RBF, null, 1, 15.);
$this->expectException(InvalidOperationException::class);
$this->expectExceptionMessage('KernelPCA has not been fitted with respect to original dataset, please run KernelPCA::fit() first');
$kpca->transform($samples);
}
@ -74,10 +76,11 @@ class KernelPCATest extends TestCase
[1, 1],
];
$kpca = new KernelPCA(KernelPCA::KERNEL_RBF, null, 1, 15);
$kpca = new KernelPCA(KernelPCA::KERNEL_RBF, null, 1, 15.);
$kpca->fit($samples);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('KernelPCA::transform() accepts only one-dimensional arrays');
$kpca->transform($samples);
}
}

View File

@ -68,25 +68,29 @@ class LDATest extends TestCase
public function testLDAThrowWhenTotalVarianceOutOfRange(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new LDA(0, null);
$this->expectExceptionMessage('Total variance can be a value between 0.1 and 0.99');
new LDA(0., null);
}
public function testLDAThrowWhenNumFeaturesOutOfRange(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new LDA(null, 0);
$this->expectExceptionMessage('Number of features to be preserved should be greater than 0');
new LDA(null, 0);
}
public function testLDAThrowWhenParameterNotSpecified(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new LDA();
$this->expectExceptionMessage('Either totalVariance or numFeatures should be specified in order to run the algorithm');
new LDA();
}
public function testLDAThrowWhenBothParameterSpecified(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new LDA(0.9, 1);
$this->expectExceptionMessage('Either totalVariance or numFeatures should be specified in order to run the algorithm');
new LDA(0.9, 1);
}
public function testTransformThrowWhenNotFitted(): void
@ -99,6 +103,7 @@ class LDATest extends TestCase
$pca = new LDA(0.9);
$this->expectException(InvalidOperationException::class);
$this->expectExceptionMessage('LDA has not been fitted with respect to original dataset, please run LDA::fit() first');
$pca->transform($samples);
}
}

View File

@ -60,25 +60,29 @@ class PCATest extends TestCase
public function testPCAThrowWhenTotalVarianceOutOfRange(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new PCA(0, null);
$this->expectExceptionMessage('Total variance can be a value between 0.1 and 0.99');
new PCA(0., null);
}
public function testPCAThrowWhenNumFeaturesOutOfRange(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new PCA(null, 0);
$this->expectExceptionMessage('Number of features to be preserved should be greater than 0');
new PCA(null, 0);
}
public function testPCAThrowWhenParameterNotSpecified(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new PCA();
$this->expectExceptionMessage('Either totalVariance or numFeatures should be specified in order to run the algorithm');
new PCA();
}
public function testPCAThrowWhenBothParameterSpecified(): void
{
$this->expectException(InvalidArgumentException::class);
$pca = new PCA(0.9, 1);
$this->expectExceptionMessage('Either totalVariance or numFeatures should be specified in order to run the algorithm');
new PCA(0.9, 1);
}
public function testTransformThrowWhenNotFitted(): void
@ -91,6 +95,7 @@ class PCATest extends TestCase
$pca = new PCA(0.9);
$this->expectException(InvalidOperationException::class);
$this->expectExceptionMessage('PCA has not been fitted with respect to original dataset, please run PCA::fit() first');
$pca->transform($samples);
}
}

View File

@ -98,7 +98,7 @@ class ClassificationReportTest extends TestCase
$predicted = ['cat', 'cat', 'bird', 'bird', 'ant'];
$this->expectException(InvalidArgumentException::class);
$report = new ClassificationReport($labels, $predicted, 0);
new ClassificationReport($labels, $predicted, 0);
}
public function testClassificationReportMicroAverage(): void

View File

@ -197,7 +197,7 @@ SV
$svm = new SupportVectorMachine(Type::C_SVC, Kernel::LINEAR, 100.0);
$svm->train($samples, $labels);
$predictions = $svm->predictProbability([
$svm->predictProbability([
[3, 2],
[2, 3],
[4, -5],