diff --git a/src/Phpml/Classification/DecisionTree.php b/src/Phpml/Classification/DecisionTree.php
index 6e890c9..da8b81b 100644
--- a/src/Phpml/Classification/DecisionTree.php
+++ b/src/Phpml/Classification/DecisionTree.php
@@ -102,19 +102,21 @@ class DecisionTree implements Classifier
$this->columnNames = array_slice($this->columnNames, 0, $this->featureCount);
} elseif (count($this->columnNames) < $this->featureCount) {
$this->columnNames = array_merge($this->columnNames,
- range(count($this->columnNames), $this->featureCount - 1));
+ range(count($this->columnNames), $this->featureCount - 1)
+ );
}
}
/**
* @param array $samples
+ *
* @return array
*/
public static function getColumnTypes(array $samples) : array
{
$types = [];
$featureCount = count($samples[0]);
- for ($i=0; $i < $featureCount; $i++) {
+ for ($i = 0; $i < $featureCount; ++$i) {
$values = array_column($samples, $i);
$isCategorical = self::isCategoricalColumn($values);
$types[] = $isCategorical ? self::NOMINAL : self::CONTINUOUS;
@@ -125,7 +127,8 @@ class DecisionTree implements Classifier
/**
* @param array $records
- * @param int $depth
+ * @param int $depth
+ *
* @return DecisionTreeLeaf
*/
protected function getSplitLeaf(array $records, int $depth = 0) : DecisionTreeLeaf
@@ -163,10 +166,10 @@ class DecisionTree implements Classifier
// Group remaining targets
$target = $this->targets[$recordNo];
- if (! array_key_exists($target, $remainingTargets)) {
+ if (!array_key_exists($target, $remainingTargets)) {
$remainingTargets[$target] = 1;
} else {
- $remainingTargets[$target]++;
+ ++$remainingTargets[$target];
}
}
@@ -188,6 +191,7 @@ class DecisionTree implements Classifier
/**
* @param array $records
+ *
* @return DecisionTreeLeaf
*/
protected function getBestSplit(array $records) : DecisionTreeLeaf
@@ -251,7 +255,7 @@ class DecisionTree implements Classifier
protected function getSelectedFeatures() : array
{
$allFeatures = range(0, $this->featureCount - 1);
- if ($this->numUsableFeatures === 0 && ! $this->selectedFeatures) {
+ if ($this->numUsableFeatures === 0 && !$this->selectedFeatures) {
return $allFeatures;
}
@@ -271,9 +275,10 @@ class DecisionTree implements Classifier
}
/**
- * @param $baseValue
+ * @param mixed $baseValue
* @param array $colValues
* @param array $targets
+ *
* @return float
*/
public function getGiniIndex($baseValue, array $colValues, array $targets) : float
@@ -282,13 +287,15 @@ class DecisionTree implements Classifier
foreach ($this->labels as $label) {
$countMatrix[$label] = [0, 0];
}
+
foreach ($colValues as $index => $value) {
$label = $targets[$index];
$rowIndex = $value === $baseValue ? 0 : 1;
- $countMatrix[$label][$rowIndex]++;
+ ++$countMatrix[$label][$rowIndex];
}
+
$giniParts = [0, 0];
- for ($i=0; $i<=1; $i++) {
+ for ($i = 0; $i <= 1; ++$i) {
$part = 0;
$sum = array_sum(array_column($countMatrix, $i));
if ($sum > 0) {
@@ -296,6 +303,7 @@ class DecisionTree implements Classifier
$part += pow($countMatrix[$label][$i] / floatval($sum), 2);
}
}
+
$giniParts[$i] = (1 - $part) * $sum;
}
@@ -304,6 +312,7 @@ class DecisionTree implements Classifier
/**
* @param array $samples
+ *
* @return array
*/
protected function preprocess(array $samples) : array
@@ -311,7 +320,7 @@ class DecisionTree implements Classifier
// Detect and convert continuous data column values into
// discrete values by using the median as a threshold value
$columns = [];
- for ($i=0; $i<$this->featureCount; $i++) {
+ for ($i = 0; $i < $this->featureCount; ++$i) {
$values = array_column($samples, $i);
if ($this->columnTypes[$i] == self::CONTINUOUS) {
$median = Mean::median($values);
@@ -332,6 +341,7 @@ class DecisionTree implements Classifier
/**
* @param array $columnValues
+ *
* @return bool
*/
protected static function isCategoricalColumn(array $columnValues) : bool
@@ -348,6 +358,7 @@ class DecisionTree implements Classifier
if ($floatValues) {
return false;
}
+
if (count($numericValues) !== $count) {
return true;
}
@@ -365,7 +376,9 @@ class DecisionTree implements Classifier
* randomly selected for each split operation.
*
* @param int $numFeatures
+ *
* @return $this
+ *
* @throws InvalidArgumentException
*/
public function setNumFeatures(int $numFeatures)
@@ -394,7 +407,9 @@ class DecisionTree implements Classifier
* column importances are desired to be inspected.
*
* @param array $names
+ *
* @return $this
+ *
* @throws InvalidArgumentException
*/
public function setColumnNames(array $names)
@@ -458,8 +473,9 @@ class DecisionTree implements Classifier
* Collects and returns an array of internal nodes that use the given
* column as a split criterion
*
- * @param int $column
+ * @param int $column
* @param DecisionTreeLeaf $node
+ *
* @return array
*/
protected function getSplitNodesByColumn(int $column, DecisionTreeLeaf $node) : array
@@ -478,9 +494,11 @@ class DecisionTree implements Classifier
if ($node->leftLeaf) {
$lNodes = $this->getSplitNodesByColumn($column, $node->leftLeaf);
}
+
if ($node->rightLeaf) {
$rNodes = $this->getSplitNodesByColumn($column, $node->rightLeaf);
}
+
$nodes = array_merge($nodes, $lNodes, $rNodes);
return $nodes;
@@ -488,6 +506,7 @@ class DecisionTree implements Classifier
/**
* @param array $sample
+ *
* @return mixed
*/
protected function predictSample(array $sample)
@@ -497,6 +516,7 @@ class DecisionTree implements Classifier
if ($node->isTerminal) {
break;
}
+
if ($node->evaluate($sample)) {
$node = $node->leftLeaf;
} else {
diff --git a/src/Phpml/Classification/DecisionTree/DecisionTreeLeaf.php b/src/Phpml/Classification/DecisionTree/DecisionTreeLeaf.php
index bbb3175..787108f 100644
--- a/src/Phpml/Classification/DecisionTree/DecisionTreeLeaf.php
+++ b/src/Phpml/Classification/DecisionTree/DecisionTreeLeaf.php
@@ -92,6 +92,8 @@ class DecisionTreeLeaf
* Returns Mean Decrease Impurity (MDI) in the node.
* For terminal nodes, this value is equal to 0
*
+ * @param int $parentRecordCount
+ *
* @return float
*/
public function getNodeImpurityDecrease(int $parentRecordCount)
@@ -133,7 +135,7 @@ class DecisionTreeLeaf
} else {
$col = "col_$this->columnIndex";
}
- if (! preg_match("/^[<>=]{1,2}/", $value)) {
+ if (!preg_match("/^[<>=]{1,2}/", $value)) {
$value = "=$value";
}
$value = "$col $value
Gini: ". number_format($this->giniIndex, 2);
diff --git a/src/Phpml/Classification/Ensemble/AdaBoost.php b/src/Phpml/Classification/Ensemble/AdaBoost.php
index 3d1e418..38571da 100644
--- a/src/Phpml/Classification/Ensemble/AdaBoost.php
+++ b/src/Phpml/Classification/Ensemble/AdaBoost.php
@@ -75,6 +75,7 @@ class AdaBoost implements Classifier
* improve classification performance of 'weak' classifiers such as
* DecisionStump (default base classifier of AdaBoost).
*
+ * @param int $maxIterations
*/
public function __construct(int $maxIterations = 50)
{
@@ -96,6 +97,8 @@ class AdaBoost implements Classifier
/**
* @param array $samples
* @param array $targets
+ *
+ * @throws \Exception
*/
public function train(array $samples, array $targets)
{
@@ -123,7 +126,6 @@ class AdaBoost implements Classifier
// Execute the algorithm for a maximum number of iterations
$currIter = 0;
while ($this->maxIterations > $currIter++) {
-
// Determine the best 'weak' classifier based on current weights
$classifier = $this->getBestClassifier();
$errorRate = $this->evaluateClassifier($classifier);
@@ -181,7 +183,7 @@ class AdaBoost implements Classifier
$targets = [];
foreach ($weights as $index => $weight) {
$z = (int)round(($weight - $mean) / $std) - $minZ + 1;
- for ($i=0; $i < $z; $i++) {
+ for ($i = 0; $i < $z; ++$i) {
if (rand(0, 1) == 0) {
continue;
}
@@ -197,6 +199,8 @@ class AdaBoost implements Classifier
* Evaluates the classifier and returns the classification error rate
*
* @param Classifier $classifier
+ *
+ * @return float
*/
protected function evaluateClassifier(Classifier $classifier)
{
diff --git a/src/Phpml/Classification/Ensemble/Bagging.php b/src/Phpml/Classification/Ensemble/Bagging.php
index 1bb2027..1af155d 100644
--- a/src/Phpml/Classification/Ensemble/Bagging.php
+++ b/src/Phpml/Classification/Ensemble/Bagging.php
@@ -59,13 +59,13 @@ class Bagging implements Classifier
private $samples = [];
/**
- * Creates an ensemble classifier with given number of base classifiers
- * Default number of base classifiers is 100.
+ * Creates an ensemble classifier with given number of base classifiers
+ * Default number of base classifiers is 50.
* The more number of base classifiers, the better performance but at the cost of procesing time
*
* @param int $numClassifier
*/
- public function __construct($numClassifier = 50)
+ public function __construct(int $numClassifier = 50)
{
$this->numClassifier = $numClassifier;
}
@@ -76,14 +76,17 @@ class Bagging implements Classifier
* to train each base classifier.
*
* @param float $ratio
+ *
* @return $this
- * @throws Exception
+ *
+ * @throws \Exception
*/
public function setSubsetRatio(float $ratio)
{
if ($ratio < 0.1 || $ratio > 1.0) {
throw new \Exception("Subset ratio should be between 0.1 and 1.0");
}
+
$this->subsetRatio = $ratio;
return $this;
}
@@ -98,12 +101,14 @@ class Bagging implements Classifier
*
* @param string $classifier
* @param array $classifierOptions
+ *
* @return $this
*/
public function setClassifer(string $classifier, array $classifierOptions = [])
{
$this->classifier = $classifier;
$this->classifierOptions = $classifierOptions;
+
return $this;
}
@@ -138,11 +143,12 @@ class Bagging implements Classifier
$targets = [];
srand($index);
$bootstrapSize = $this->subsetRatio * $this->numSamples;
- for ($i=0; $i < $bootstrapSize; $i++) {
+ for ($i = 0; $i < $bootstrapSize; ++$i) {
$rand = rand(0, $this->numSamples - 1);
$samples[] = $this->samples[$rand];
$targets[] = $this->targets[$rand];
}
+
return [$samples, $targets];
}
@@ -152,24 +158,25 @@ class Bagging implements Classifier
protected function initClassifiers()
{
$classifiers = [];
- for ($i=0; $i<$this->numClassifier; $i++) {
+ for ($i = 0; $i < $this->numClassifier; ++$i) {
$ref = new \ReflectionClass($this->classifier);
if ($this->classifierOptions) {
$obj = $ref->newInstanceArgs($this->classifierOptions);
} else {
$obj = $ref->newInstance();
}
- $classifiers[] = $this->initSingleClassifier($obj, $i);
+
+ $classifiers[] = $this->initSingleClassifier($obj);
}
return $classifiers;
}
/**
* @param Classifier $classifier
- * @param int $index
+ *
* @return Classifier
*/
- protected function initSingleClassifier($classifier, $index)
+ protected function initSingleClassifier($classifier)
{
return $classifier;
}
diff --git a/src/Phpml/Classification/Ensemble/RandomForest.php b/src/Phpml/Classification/Ensemble/RandomForest.php
index 273eb21..7849cd8 100644
--- a/src/Phpml/Classification/Ensemble/RandomForest.php
+++ b/src/Phpml/Classification/Ensemble/RandomForest.php
@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Phpml\Classification\Ensemble;
use Phpml\Classification\DecisionTree;
-use Phpml\Classification\Classifier;
class RandomForest extends Bagging
{
@@ -24,9 +23,9 @@ class RandomForest extends Bagging
* may increase the prediction performance while it will also substantially
* increase the processing time and the required memory
*
- * @param type $numClassifier
+ * @param int $numClassifier
*/
- public function __construct($numClassifier = 50)
+ public function __construct(int $numClassifier = 50)
{
parent::__construct($numClassifier);
@@ -43,17 +42,21 @@ class RandomForest extends Bagging
* features to be taken into consideration while selecting subspace of features
*
* @param mixed $ratio string or float should be given
+ *
* @return $this
- * @throws Exception
+ *
+ * @throws \Exception
*/
public function setFeatureSubsetRatio($ratio)
{
if (is_float($ratio) && ($ratio < 0.1 || $ratio > 1.0)) {
throw new \Exception("When a float given, feature subset ratio should be between 0.1 and 1.0");
}
+
if (is_string($ratio) && $ratio != 'sqrt' && $ratio != 'log') {
throw new \Exception("When a string given, feature subset ratio can only be 'sqrt' or 'log' ");
}
+
$this->featureSubsetRatio = $ratio;
return $this;
}
@@ -62,8 +65,11 @@ class RandomForest extends Bagging
* RandomForest algorithm is usable *only* with DecisionTree
*
* @param string $classifier
- * @param array $classifierOptions
+ * @param array $classifierOptions
+ *
* @return $this
+ *
+ * @throws \Exception
*/
public function setClassifer(string $classifier, array $classifierOptions = [])
{
@@ -125,10 +131,10 @@ class RandomForest extends Bagging
/**
* @param DecisionTree $classifier
- * @param int $index
+ *
* @return DecisionTree
*/
- protected function initSingleClassifier($classifier, $index)
+ protected function initSingleClassifier($classifier)
{
if (is_float($this->featureSubsetRatio)) {
$featureCount = (int)($this->featureSubsetRatio * $this->featureCount);
diff --git a/src/Phpml/Classification/Linear/Adaline.php b/src/Phpml/Classification/Linear/Adaline.php
index f34dc5c..b94de28 100644
--- a/src/Phpml/Classification/Linear/Adaline.php
+++ b/src/Phpml/Classification/Linear/Adaline.php
@@ -4,11 +4,8 @@ declare(strict_types=1);
namespace Phpml\Classification\Linear;
-use Phpml\Classification\Classifier;
-
class Adaline extends Perceptron
{
-
/**
* Batch training is the default Adaline training algorithm
*/
@@ -35,13 +32,17 @@ class Adaline extends Perceptron
* If normalizeInputs is set to true, then every input given to the algorithm will be standardized
* by use of standard deviation and mean calculation
*
- * @param int $learningRate
- * @param int $maxIterations
+ * @param float $learningRate
+ * @param int $maxIterations
+ * @param bool $normalizeInputs
+ * @param int $trainingType
+ *
+ * @throws \Exception
*/
public function __construct(float $learningRate = 0.001, int $maxIterations = 1000,
bool $normalizeInputs = true, int $trainingType = self::BATCH_TRAINING)
{
- if (! in_array($trainingType, [self::BATCH_TRAINING, self::ONLINE_TRAINING])) {
+ if (!in_array($trainingType, [self::BATCH_TRAINING, self::ONLINE_TRAINING])) {
throw new \Exception("Adaline can only be trained with batch and online/stochastic gradient descent algorithm");
}
diff --git a/src/Phpml/Classification/Linear/DecisionStump.php b/src/Phpml/Classification/Linear/DecisionStump.php
index 99f982f..5a3247f 100644
--- a/src/Phpml/Classification/Linear/DecisionStump.php
+++ b/src/Phpml/Classification/Linear/DecisionStump.php
@@ -87,6 +87,8 @@ class DecisionStump extends WeightedClassifier
/**
* @param array $samples
* @param array $targets
+ * @param array $labels
+ *
* @throws \Exception
*/
protected function trainBinary(array $samples, array $targets, array $labels)
@@ -237,13 +239,13 @@ class DecisionStump extends WeightedClassifier
/**
*
- * @param type $leftValue
- * @param type $operator
- * @param type $rightValue
+ * @param mixed $leftValue
+ * @param string $operator
+ * @param mixed $rightValue
*
* @return boolean
*/
- protected function evaluate($leftValue, $operator, $rightValue)
+ protected function evaluate($leftValue, string $operator, $rightValue)
{
switch ($operator) {
case '>': return $leftValue > $rightValue;
@@ -288,10 +290,10 @@ class DecisionStump extends WeightedClassifier
$wrong += $this->weights[$index];
}
- if (! isset($prob[$predicted][$target])) {
+ if (!isset($prob[$predicted][$target])) {
$prob[$predicted][$target] = 0;
}
- $prob[$predicted][$target]++;
+ ++$prob[$predicted][$target];
}
// Calculate probabilities: Proportion of labels in each leaf
diff --git a/src/Phpml/Classification/Linear/LogisticRegression.php b/src/Phpml/Classification/Linear/LogisticRegression.php
index bd56d34..bc6a3c9 100644
--- a/src/Phpml/Classification/Linear/LogisticRegression.php
+++ b/src/Phpml/Classification/Linear/LogisticRegression.php
@@ -4,21 +4,19 @@ declare(strict_types=1);
namespace Phpml\Classification\Linear;
-use Phpml\Classification\Classifier;
use Phpml\Helper\Optimizer\ConjugateGradient;
class LogisticRegression extends Adaline
{
-
/**
* Batch training: Gradient descent algorithm (default)
*/
- const BATCH_TRAINING = 1;
+ const BATCH_TRAINING = 1;
/**
* Online training: Stochastic gradient descent learning
*/
- const ONLINE_TRAINING = 2;
+ const ONLINE_TRAINING = 2;
/**
* Conjugate Batch: Conjugate Gradient algorithm
@@ -74,13 +72,13 @@ class LogisticRegression extends Adaline
string $penalty = 'L2')
{
$trainingTypes = range(self::BATCH_TRAINING, self::CONJUGATE_GRAD_TRAINING);
- if (! in_array($trainingType, $trainingTypes)) {
+ if (!in_array($trainingType, $trainingTypes)) {
throw new \Exception("Logistic regression can only be trained with " .
"batch (gradient descent), online (stochastic gradient descent) " .
"or conjugate batch (conjugate gradients) algorithms");
}
- if (! in_array($cost, ['log', 'sse'])) {
+ if (!in_array($cost, ['log', 'sse'])) {
throw new \Exception("Logistic regression cost function can be one of the following: \n" .
"'log' for log-likelihood and 'sse' for sum of squared errors");
}
@@ -126,6 +124,8 @@ class LogisticRegression extends Adaline
*
* @param array $samples
* @param array $targets
+ *
+ * @throws \Exception
*/
protected function runTraining(array $samples, array $targets)
{
@@ -140,12 +140,18 @@ class LogisticRegression extends Adaline
case self::CONJUGATE_GRAD_TRAINING:
return $this->runConjugateGradient($samples, $targets, $callback);
+
+ default:
+ throw new \Exception('Logistic regression has invalid training type: %s.', $this->trainingType);
}
}
/**
- * Executes Conjugate Gradient method to optimize the
- * weights of the LogReg model
+ * Executes Conjugate Gradient method to optimize the weights of the LogReg model
+ *
+ * @param array $samples
+ * @param array $targets
+ * @param \Closure $gradientFunc
*/
protected function runConjugateGradient(array $samples, array $targets, \Closure $gradientFunc)
{
@@ -162,6 +168,8 @@ class LogisticRegression extends Adaline
* Returns the appropriate callback function for the selected cost function
*
* @return \Closure
+ *
+ * @throws \Exception
*/
protected function getCostFunction()
{
@@ -203,7 +211,7 @@ class LogisticRegression extends Adaline
return $callback;
case 'sse':
- /**
+ /*
* Sum of squared errors or least squared errors cost function:
* J(x) = ∑ (y - h(x))^2
*
@@ -224,6 +232,9 @@ class LogisticRegression extends Adaline
};
return $callback;
+
+ default:
+ throw new \Exception(sprintf('Logistic regression has invalid cost function: %s.', $this->costFunction));
}
}
@@ -245,6 +256,7 @@ class LogisticRegression extends Adaline
* Returns the class value (either -1 or 1) for the given input
*
* @param array $sample
+ *
* @return int
*/
protected function outputClass(array $sample)
@@ -266,6 +278,8 @@ class LogisticRegression extends Adaline
*
* @param array $sample
* @param mixed $label
+ *
+ * @return float
*/
protected function predictProbability(array $sample, $label)
{
diff --git a/src/Phpml/Classification/Linear/Perceptron.php b/src/Phpml/Classification/Linear/Perceptron.php
index 91ffacf..f4a8791 100644
--- a/src/Phpml/Classification/Linear/Perceptron.php
+++ b/src/Phpml/Classification/Linear/Perceptron.php
@@ -63,22 +63,22 @@ class Perceptron implements Classifier, IncrementalEstimator
/**
* Initalize a perceptron classifier with given learning rate and maximum
- * number of iterations used while training the perceptron
+ * number of iterations used while training the perceptron
*
- * Learning rate should be a float value between 0.0(exclusive) and 1.0(inclusive)
- * Maximum number of iterations can be an integer value greater than 0
- * @param int $learningRate
- * @param int $maxIterations
+ * @param float $learningRate Value between 0.0(exclusive) and 1.0(inclusive)
+ * @param int $maxIterations Must be at least 1
+ * @param bool $normalizeInputs
+ *
+ * @throws \Exception
*/
- public function __construct(float $learningRate = 0.001, int $maxIterations = 1000,
- bool $normalizeInputs = true)
+ public function __construct(float $learningRate = 0.001, int $maxIterations = 1000, bool $normalizeInputs = true)
{
if ($learningRate <= 0.0 || $learningRate > 1.0) {
throw new \Exception("Learning rate should be a float value between 0.0(exclusive) and 1.0(inclusive)");
}
if ($maxIterations <= 0) {
- throw new \Exception("Maximum number of iterations should be an integer greater than 0");
+ throw new \Exception("Maximum number of iterations must be an integer greater than 0");
}
if ($normalizeInputs) {
@@ -96,7 +96,7 @@ class Perceptron implements Classifier, IncrementalEstimator
*/
public function partialTrain(array $samples, array $targets, array $labels = [])
{
- return $this->trainByLabel($samples, $targets, $labels);
+ $this->trainByLabel($samples, $targets, $labels);
}
/**
@@ -140,6 +140,8 @@ class Perceptron implements Classifier, IncrementalEstimator
* for $maxIterations times
*
* @param bool $enable
+ *
+ * @return $this
*/
public function setEarlyStop(bool $enable = true)
{
@@ -185,12 +187,14 @@ class Perceptron implements Classifier, IncrementalEstimator
* Executes a Gradient Descent algorithm for
* the given cost function
*
- * @param array $samples
- * @param array $targets
+ * @param array $samples
+ * @param array $targets
+ * @param \Closure $gradientFunc
+ * @param bool $isBatch
*/
protected function runGradientDescent(array $samples, array $targets, \Closure $gradientFunc, bool $isBatch = false)
{
- $class = $isBatch ? GD::class : StochasticGD::class;
+ $class = $isBatch ? GD::class : StochasticGD::class;
if (empty($this->optimizer)) {
$this->optimizer = (new $class($this->featureCount))
@@ -262,6 +266,8 @@ class Perceptron implements Classifier, IncrementalEstimator
*
* @param array $sample
* @param mixed $label
+ *
+ * @return float
*/
protected function predictProbability(array $sample, $label)
{
@@ -277,6 +283,7 @@ class Perceptron implements Classifier, IncrementalEstimator
/**
* @param array $sample
+ *
* @return mixed
*/
protected function predictSampleBinary(array $sample)
@@ -285,6 +292,6 @@ class Perceptron implements Classifier, IncrementalEstimator
$predictedClass = $this->outputClass($sample);
- return $this->labels[ $predictedClass ];
+ return $this->labels[$predictedClass];
}
}
diff --git a/src/Phpml/Classification/NaiveBayes.php b/src/Phpml/Classification/NaiveBayes.php
index af81b00..1a634da 100644
--- a/src/Phpml/Classification/NaiveBayes.php
+++ b/src/Phpml/Classification/NaiveBayes.php
@@ -89,7 +89,7 @@ class NaiveBayes implements Classifier
$this->mean[$label]= array_fill(0, $this->featureCount, 0);
$this->dataType[$label] = array_fill(0, $this->featureCount, self::CONTINUOS);
$this->discreteProb[$label] = array_fill(0, $this->featureCount, self::CONTINUOS);
- for ($i=0; $i<$this->featureCount; $i++) {
+ for ($i = 0; $i < $this->featureCount; ++$i) {
// Get the values of nth column in the samples array
// Mean::arithmetic is called twice, can be optimized
$values = array_column($samples, $i);
@@ -114,16 +114,17 @@ class NaiveBayes implements Classifier
/**
* Calculates the probability P(label|sample_n)
*
- * @param array $sample
- * @param int $feature
+ * @param array $sample
+ * @param int $feature
* @param string $label
+ *
* @return float
*/
private function sampleProbability($sample, $feature, $label)
{
$value = $sample[$feature];
if ($this->dataType[$label][$feature] == self::NOMINAL) {
- if (! isset($this->discreteProb[$label][$feature][$value]) ||
+ if (!isset($this->discreteProb[$label][$feature][$value]) ||
$this->discreteProb[$label][$feature][$value] == 0) {
return self::EPSILON;
}
@@ -145,13 +146,15 @@ class NaiveBayes implements Classifier
/**
* Return samples belonging to specific label
+ *
* @param string $label
+ *
* @return array
*/
private function getSamplesByLabel($label)
{
$samples = [];
- for ($i=0; $i<$this->sampleCount; $i++) {
+ for ($i = 0; $i < $this->sampleCount; ++$i) {
if ($this->targets[$i] == $label) {
$samples[] = $this->samples[$i];
}
@@ -171,12 +174,13 @@ class NaiveBayes implements Classifier
$predictions = [];
foreach ($this->labels as $label) {
$p = $this->p[$label];
- for ($i=0; $i<$this->featureCount; $i++) {
+ for ($i = 0; $i<$this->featureCount; ++$i) {
$Plf = $this->sampleProbability($sample, $i, $label);
$p += $Plf;
}
$predictions[$label] = $p;
}
+
arsort($predictions, SORT_NUMERIC);
reset($predictions);
return key($predictions);
diff --git a/src/Phpml/Clustering/FuzzyCMeans.php b/src/Phpml/Clustering/FuzzyCMeans.php
index 424f2f1..c6a3c46 100644
--- a/src/Phpml/Clustering/FuzzyCMeans.php
+++ b/src/Phpml/Clustering/FuzzyCMeans.php
@@ -7,6 +7,7 @@ namespace Phpml\Clustering;
use Phpml\Clustering\KMeans\Point;
use Phpml\Clustering\KMeans\Cluster;
use Phpml\Clustering\KMeans\Space;
+use Phpml\Exception\InvalidArgumentException;
use Phpml\Math\Distance\Euclidean;
class FuzzyCMeans implements Clusterer
@@ -25,10 +26,12 @@ class FuzzyCMeans implements Clusterer
* @var Space
*/
private $space;
+
/**
* @var array|float[][]
*/
private $membership;
+
/**
* @var float
*/
@@ -56,6 +59,9 @@ class FuzzyCMeans implements Clusterer
/**
* @param int $clustersNumber
+ * @param float $fuzziness
+ * @param float $epsilon
+ * @param int $maxIterations
*
* @throws InvalidArgumentException
*/
@@ -86,14 +92,15 @@ class FuzzyCMeans implements Clusterer
protected function generateRandomMembership(int $rows, int $cols)
{
$this->membership = [];
- for ($i=0; $i < $rows; $i++) {
+ for ($i = 0; $i < $rows; ++$i) {
$row = [];
$total = 0.0;
- for ($k=0; $k < $cols; $k++) {
+ for ($k = 0; $k < $cols; ++$k) {
$val = rand(1, 5) / 10.0;
$row[] = $val;
$total += $val;
}
+
$this->membership[] = array_map(function ($val) use ($total) {
return $val / $total;
}, $row);
@@ -103,21 +110,22 @@ class FuzzyCMeans implements Clusterer
protected function updateClusters()
{
$dim = $this->space->getDimension();
- if (! $this->clusters) {
+ if (!$this->clusters) {
$this->clusters = [];
- for ($i=0; $i<$this->clustersNumber; $i++) {
+ for ($i = 0; $i < $this->clustersNumber; ++$i) {
$this->clusters[] = new Cluster($this->space, array_fill(0, $dim, 0.0));
}
}
- for ($i=0; $i<$this->clustersNumber; $i++) {
+ for ($i = 0; $i < $this->clustersNumber; ++$i) {
$cluster = $this->clusters[$i];
$center = $cluster->getCoordinates();
- for ($k=0; $k<$dim; $k++) {
+ for ($k = 0; $k < $dim; ++$k) {
$a = $this->getMembershipRowTotal($i, $k, true);
$b = $this->getMembershipRowTotal($i, $k, false);
$center[$k] = $a / $b;
}
+
$cluster->setCoordinates($center);
}
}
@@ -125,20 +133,22 @@ class FuzzyCMeans implements Clusterer
protected function getMembershipRowTotal(int $row, int $col, bool $multiply)
{
$sum = 0.0;
- for ($k = 0; $k < $this->sampleCount; $k++) {
+ for ($k = 0; $k < $this->sampleCount; ++$k) {
$val = pow($this->membership[$row][$k], $this->fuzziness);
if ($multiply) {
$val *= $this->samples[$k][$col];
}
+
$sum += $val;
}
+
return $sum;
}
protected function updateMembershipMatrix()
{
- for ($i = 0; $i < $this->clustersNumber; $i++) {
- for ($k = 0; $k < $this->sampleCount; $k++) {
+ for ($i = 0; $i < $this->clustersNumber; ++$i) {
+ for ($k = 0; $k < $this->sampleCount; ++$k) {
$distCalc = $this->getDistanceCalc($i, $k);
$this->membership[$i][$k] = 1.0 / $distCalc;
}
@@ -157,11 +167,15 @@ class FuzzyCMeans implements Clusterer
$distance = new Euclidean();
$dist1 = $distance->distance(
$this->clusters[$row]->getCoordinates(),
- $this->samples[$col]);
- for ($j = 0; $j < $this->clustersNumber; $j++) {
+ $this->samples[$col]
+ );
+
+ for ($j = 0; $j < $this->clustersNumber; ++$j) {
$dist2 = $distance->distance(
$this->clusters[$j]->getCoordinates(),
- $this->samples[$col]);
+ $this->samples[$col]
+ );
+
$val = pow($dist1 / $dist2, 2.0 / ($this->fuzziness - 1));
$sum += $val;
}
@@ -177,13 +191,14 @@ class FuzzyCMeans implements Clusterer
{
$sum = 0.0;
$distance = new Euclidean();
- for ($i = 0; $i < $this->clustersNumber; $i++) {
+ for ($i = 0; $i < $this->clustersNumber; ++$i) {
$clust = $this->clusters[$i]->getCoordinates();
- for ($k = 0; $k < $this->sampleCount; $k++) {
+ for ($k = 0; $k < $this->sampleCount; ++$k) {
$point = $this->samples[$k];
$sum += $distance->distance($clust, $point);
}
}
+
return $sum;
}
@@ -210,7 +225,6 @@ class FuzzyCMeans implements Clusterer
// Our goal is minimizing the objective value while
// executing the clustering steps at a maximum number of iterations
$lastObjective = 0.0;
- $difference = 0.0;
$iterations = 0;
do {
// Update the membership matrix and cluster centers, respectively
@@ -224,7 +238,7 @@ class FuzzyCMeans implements Clusterer
} while ($difference > $this->epsilon && $iterations++ <= $this->maxIterations);
// Attach (hard cluster) each data point to the nearest cluster
- for ($k=0; $k<$this->sampleCount; $k++) {
+ for ($k = 0; $k < $this->sampleCount; ++$k) {
$column = array_column($this->membership, $k);
arsort($column);
reset($column);
@@ -238,6 +252,7 @@ class FuzzyCMeans implements Clusterer
foreach ($this->clusters as $cluster) {
$grouped[] = $cluster->getPoints();
}
+
return $grouped;
}
}
diff --git a/src/Phpml/Clustering/KMeans/Space.php b/src/Phpml/Clustering/KMeans/Space.php
index 5a4d530..0276880 100644
--- a/src/Phpml/Clustering/KMeans/Space.php
+++ b/src/Phpml/Clustering/KMeans/Space.php
@@ -156,7 +156,11 @@ class Space extends SplObjectStorage
case KMeans::INIT_KMEANS_PLUS_PLUS:
$clusters = $this->initializeKMPPClusters($clustersNumber);
break;
+
+ default:
+ return [];
}
+
$clusters[0]->attachAll($this);
return $clusters;
diff --git a/src/Phpml/Dataset/CsvDataset.php b/src/Phpml/Dataset/CsvDataset.php
index 8bcd3c4..b2e9407 100644
--- a/src/Phpml/Dataset/CsvDataset.php
+++ b/src/Phpml/Dataset/CsvDataset.php
@@ -17,6 +17,7 @@ class CsvDataset extends ArrayDataset
* @param string $filepath
* @param int $features
* @param bool $headingRow
+ * @param string $delimiter
*
* @throws FileException
*/
@@ -37,11 +38,15 @@ class CsvDataset extends ArrayDataset
$this->columnNames = range(0, $features - 1);
}
+ $samples = $targets = [];
while (($data = fgetcsv($handle, 1000, $delimiter)) !== false) {
- $this->samples[] = array_slice($data, 0, $features);
- $this->targets[] = $data[$features];
+ $samples[] = array_slice($data, 0, $features);
+ $targets[] = $data[$features];
}
+
fclose($handle);
+
+ parent::__construct($samples, $targets);
}
/**
diff --git a/src/Phpml/DimensionReduction/EigenTransformerBase.php b/src/Phpml/DimensionReduction/EigenTransformerBase.php
index b399002..6c0ef05 100644
--- a/src/Phpml/DimensionReduction/EigenTransformerBase.php
+++ b/src/Phpml/DimensionReduction/EigenTransformerBase.php
@@ -1,4 +1,6 @@
-calculateKernelMatrix($this->data, $numRows);
$matrix = $this->centerMatrix($matrix, $numRows);
- $this->eigenDecomposition($matrix, $numRows);
+ $this->eigenDecomposition($matrix);
$this->fit = true;
@@ -98,7 +98,7 @@ class KernelPCA extends PCA
* An n-by-m matrix is given and an n-by-n matrix is returned
*
* @param array $data
- * @param int $numRows
+ * @param int $numRows
*
* @return array
*/
@@ -107,8 +107,8 @@ class KernelPCA extends PCA
$kernelFunc = $this->getKernel();
$matrix = [];
- for ($i=0; $i < $numRows; $i++) {
- for ($k=0; $k < $numRows; $k++) {
+ for ($i = 0; $i < $numRows; ++$i) {
+ for ($k = 0; $k < $numRows; ++$k) {
if ($i <= $k) {
$matrix[$i][$k] = $kernelFunc($data[$i], $data[$k]);
} else {
@@ -127,7 +127,9 @@ class KernelPCA extends PCA
* K′ = K − N.K − K.N + N.K.N where N is n-by-n matrix filled with 1/n
*
* @param array $matrix
- * @param int $n
+ * @param int $n
+ *
+ * @return array
*/
protected function centerMatrix(array $matrix, int $n)
{
@@ -152,6 +154,8 @@ class KernelPCA extends PCA
* Returns the callable kernel function
*
* @return \Closure
+ *
+ * @throws \Exception
*/
protected function getKernel()
{
@@ -181,6 +185,9 @@ class KernelPCA extends PCA
return function ($x, $y) use ($dist) {
return exp(-$this->gamma * $dist->distance($x, $y));
};
+
+ default:
+ throw new \Exception(sprintf('KernelPCA initialized with invalid kernel: %d', $this->kernel));
}
}
@@ -228,6 +235,8 @@ class KernelPCA extends PCA
* @param array $sample
*
* @return array
+ *
+ * @throws \Exception
*/
public function transform(array $sample)
{
diff --git a/src/Phpml/DimensionReduction/LDA.php b/src/Phpml/DimensionReduction/LDA.php
index 28f34d6..e094c35 100644
--- a/src/Phpml/DimensionReduction/LDA.php
+++ b/src/Phpml/DimensionReduction/LDA.php
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Phpml\DimensionReduction;
-use Phpml\Math\Statistic\Mean;
use Phpml\Math\Matrix;
class LDA extends EigenTransformerBase
@@ -30,7 +29,7 @@ class LDA extends EigenTransformerBase
public $counts;
/**
- * @var float
+ * @var float[]
*/
public $overallMean;
@@ -111,12 +110,12 @@ class LDA extends EigenTransformerBase
* Calculates mean of each column for each class and returns
* n by m matrix where n is number of labels and m is number of columns
*
- * @param type $data
- * @param type $classes
+ * @param array $data
+ * @param array $classes
*
* @return array
*/
- protected function calculateMeans($data, $classes) : array
+ protected function calculateMeans(array $data, array $classes) : array
{
$means = [];
$counts= [];
@@ -126,17 +125,18 @@ class LDA extends EigenTransformerBase
$label = array_search($classes[$index], $this->labels);
foreach ($row as $col => $val) {
- if (! isset($means[$label][$col])) {
+ if (!isset($means[$label][$col])) {
$means[$label][$col] = 0.0;
}
$means[$label][$col] += $val;
$overallMean[$col] += $val;
}
- if (! isset($counts[$label])) {
+ if (!isset($counts[$label])) {
$counts[$label] = 0;
}
- $counts[$label]++;
+
+ ++$counts[$label];
}
foreach ($means as $index => $row) {
@@ -231,6 +231,8 @@ class LDA extends EigenTransformerBase
* @param array $sample
*
* @return array
+ *
+ * @throws \Exception
*/
public function transform(array $sample)
{
@@ -238,7 +240,7 @@ class LDA extends EigenTransformerBase
throw new \Exception("LDA has not been fitted with respect to original dataset, please run LDA::fit() first");
}
- if (! is_array($sample[0])) {
+ if (!is_array($sample[0])) {
$sample = [$sample];
}
diff --git a/src/Phpml/DimensionReduction/PCA.php b/src/Phpml/DimensionReduction/PCA.php
index db2110d..acaa8e0 100644
--- a/src/Phpml/DimensionReduction/PCA.php
+++ b/src/Phpml/DimensionReduction/PCA.php
@@ -6,7 +6,6 @@ namespace Phpml\DimensionReduction;
use Phpml\Math\Statistic\Covariance;
use Phpml\Math\Statistic\Mean;
-use Phpml\Math\Matrix;
class PCA extends EigenTransformerBase
{
@@ -86,7 +85,7 @@ class PCA extends EigenTransformerBase
{
// Calculate means for each dimension
$this->means = [];
- for ($i=0; $i < $n; $i++) {
+ for ($i = 0; $i < $n; ++$i) {
$column = array_column($data, $i);
$this->means[] = Mean::arithmetic($column);
}
@@ -97,7 +96,7 @@ class PCA extends EigenTransformerBase
* each dimension therefore dimensions will be centered to zero
*
* @param array $data
- * @param int $n
+ * @param int $n
*
* @return array
*/
@@ -109,7 +108,7 @@ class PCA extends EigenTransformerBase
// Normalize data
foreach ($data as $i => $row) {
- for ($k=0; $k < $n; $k++) {
+ for ($k = 0; $k < $n; ++$k) {
$data[$i][$k] -= $this->means[$k];
}
}
@@ -124,6 +123,8 @@ class PCA extends EigenTransformerBase
* @param array $sample
*
* @return array
+ *
+ * @throws \Exception
*/
public function transform(array $sample)
{
@@ -131,7 +132,7 @@ class PCA extends EigenTransformerBase
throw new \Exception("PCA has not been fitted with respect to original dataset, please run PCA::fit() first");
}
- if (! is_array($sample[0])) {
+ if (!is_array($sample[0])) {
$sample = [$sample];
}
diff --git a/src/Phpml/Exception/DatasetException.php b/src/Phpml/Exception/DatasetException.php
index 6092053..ca7b065 100644
--- a/src/Phpml/Exception/DatasetException.php
+++ b/src/Phpml/Exception/DatasetException.php
@@ -6,7 +6,6 @@ namespace Phpml\Exception;
class DatasetException extends \Exception
{
-
/**
* @param string $path
*
diff --git a/src/Phpml/Exception/FileException.php b/src/Phpml/Exception/FileException.php
index 558ae48..20b2936 100644
--- a/src/Phpml/Exception/FileException.php
+++ b/src/Phpml/Exception/FileException.php
@@ -6,7 +6,6 @@ namespace Phpml\Exception;
class FileException extends \Exception
{
-
/**
* @param string $filepath
*
diff --git a/src/Phpml/Exception/InvalidArgumentException.php b/src/Phpml/Exception/InvalidArgumentException.php
index f6b0031..bf6d8cc 100644
--- a/src/Phpml/Exception/InvalidArgumentException.php
+++ b/src/Phpml/Exception/InvalidArgumentException.php
@@ -11,7 +11,7 @@ class InvalidArgumentException extends \Exception
*/
public static function arraySizeNotMatch()
{
- return new self('Size of given arrays not match');
+ return new self('Size of given arrays does not match');
}
/**
@@ -55,7 +55,7 @@ class InvalidArgumentException extends \Exception
*/
public static function inconsistentMatrixSupplied()
{
- return new self('Inconsistent matrix applied');
+ return new self('Inconsistent matrix supplied');
}
/**
diff --git a/src/Phpml/Exception/SerializeException.php b/src/Phpml/Exception/SerializeException.php
index 70e6892..5753eb7 100644
--- a/src/Phpml/Exception/SerializeException.php
+++ b/src/Phpml/Exception/SerializeException.php
@@ -6,7 +6,6 @@ namespace Phpml\Exception;
class SerializeException extends \Exception
{
-
/**
* @param string $filepath
*
diff --git a/src/Phpml/Helper/OneVsRest.php b/src/Phpml/Helper/OneVsRest.php
index e207c46..8d71fbc 100644
--- a/src/Phpml/Helper/OneVsRest.php
+++ b/src/Phpml/Helper/OneVsRest.php
@@ -6,7 +6,6 @@ namespace Phpml\Helper;
trait OneVsRest
{
-
/**
* @var array
*/
@@ -35,18 +34,18 @@ trait OneVsRest
// Clears previous stuff.
$this->reset();
- return $this->trainBylabel($samples, $targets);
+ $this->trainBylabel($samples, $targets);
}
/**
* @param array $samples
* @param array $targets
* @param array $allLabels All training set labels
+ *
* @return void
*/
protected function trainByLabel(array $samples, array $targets, array $allLabels = [])
{
-
// Overwrites the current value if it exist. $allLabels must be provided for each partialTrain run.
if (!empty($allLabels)) {
$this->allLabels = $allLabels;
@@ -57,7 +56,6 @@ trait OneVsRest
// If there are only two targets, then there is no need to perform OvR
if (count($this->allLabels) == 2) {
-
// Init classifier if required.
if (empty($this->classifiers)) {
$this->classifiers[0] = $this->getClassifierCopy();
@@ -68,7 +66,6 @@ trait OneVsRest
// Train a separate classifier for each label and memorize them
foreach ($this->allLabels as $label) {
-
// Init classifier if required.
if (empty($this->classifiers[$label])) {
$this->classifiers[$label] = $this->getClassifierCopy();
@@ -107,7 +104,6 @@ trait OneVsRest
*/
protected function getClassifierCopy()
{
-
// Clone the current classifier, so that
// we don't mess up its variables while training
// multiple instances of this classifier
@@ -180,7 +176,8 @@ trait OneVsRest
* Each classifier that make use of OvR approach should be able to
* return a probability for a sample to belong to the given label.
*
- * @param array $sample
+ * @param array $sample
+ * @param string $label
*
* @return mixed
*/
diff --git a/src/Phpml/Helper/Optimizer/ConjugateGradient.php b/src/Phpml/Helper/Optimizer/ConjugateGradient.php
index 18ae89a..44bcd14 100644
--- a/src/Phpml/Helper/Optimizer/ConjugateGradient.php
+++ b/src/Phpml/Helper/Optimizer/ConjugateGradient.php
@@ -18,8 +18,8 @@ namespace Phpml\Helper\Optimizer;
class ConjugateGradient extends GD
{
/**
- * @param array $samples
- * @param array $targets
+ * @param array $samples
+ * @param array $targets
* @param \Closure $gradientCb
*
* @return array
@@ -34,7 +34,7 @@ class ConjugateGradient extends GD
$d = mp::muls($this->gradient($this->theta), -1);
- for ($i=0; $i < $this->maxIterations; $i++) {
+ for ($i = 0; $i < $this->maxIterations; ++$i) {
// Obtain α that minimizes f(θ + α.d)
$alpha = $this->getAlpha(array_sum($d));
@@ -68,11 +68,11 @@ class ConjugateGradient extends GD
*
* @param array $theta
*
- * @return float
+ * @return array
*/
protected function gradient(array $theta)
{
- list($_, $gradient, $_) = parent::gradient($theta);
+ list(, $gradient) = parent::gradient($theta);
return $gradient;
}
@@ -86,7 +86,7 @@ class ConjugateGradient extends GD
*/
protected function cost(array $theta)
{
- list($cost, $_, $_) = parent::gradient($theta);
+ list($cost) = parent::gradient($theta);
return array_sum($cost) / $this->sampleCount;
}
@@ -107,7 +107,7 @@ class ConjugateGradient extends GD
*
* @param float $d
*
- * @return array
+ * @return float
*/
protected function getAlpha(float $d)
{
@@ -157,14 +157,14 @@ class ConjugateGradient extends GD
* @param float $alpha
* @param array $d
*
- * return array
+ * @return array
*/
protected function getNewTheta(float $alpha, array $d)
{
$theta = $this->theta;
- for ($i=0; $i < $this->dimensions + 1; $i++) {
- if ($i == 0) {
+ for ($i = 0; $i < $this->dimensions + 1; ++$i) {
+ if ($i === 0) {
$theta[$i] += $alpha * array_sum($d);
} else {
$sum = 0.0;
@@ -266,10 +266,11 @@ class mp
*
* @param array $m1
* @param array $m2
+ * @param int $mag
*
* @return array
*/
- public static function add(array $m1, array $m2, $mag = 1)
+ public static function add(array $m1, array $m2, int $mag = 1)
{
$res = [];
foreach ($m1 as $i => $val) {
@@ -333,10 +334,11 @@ class mp
*
* @param array $m1
* @param float $m2
+ * @param int $mag
*
* @return array
*/
- public static function adds(array $m1, float $m2, $mag = 1)
+ public static function adds(array $m1, float $m2, int $mag = 1)
{
$res = [];
foreach ($m1 as $val) {
@@ -350,7 +352,7 @@ class mp
* Element-wise subtraction of a vector with a scalar
*
* @param array $m1
- * @param float $m2
+ * @param array $m2
*
* @return array
*/
diff --git a/src/Phpml/Helper/Optimizer/GD.php b/src/Phpml/Helper/Optimizer/GD.php
index 8974c8e..b88b0c7 100644
--- a/src/Phpml/Helper/Optimizer/GD.php
+++ b/src/Phpml/Helper/Optimizer/GD.php
@@ -18,8 +18,8 @@ class GD extends StochasticGD
protected $sampleCount = null;
/**
- * @param array $samples
- * @param array $targets
+ * @param array $samples
+ * @param array $targets
* @param \Closure $gradientCb
*
* @return array
@@ -75,7 +75,7 @@ class GD extends StochasticGD
list($cost, $grad, $penalty) = array_pad($result, 3, 0);
$costs[] = $cost;
- $gradient[]= $grad;
+ $gradient[] = $grad;
$totalPenalty += $penalty;
}
@@ -91,8 +91,8 @@ class GD extends StochasticGD
protected function updateWeightsWithUpdates(array $updates, float $penalty)
{
// Updates all weights at once
- for ($i=0; $i <= $this->dimensions; $i++) {
- if ($i == 0) {
+ for ($i = 0; $i <= $this->dimensions; ++$i) {
+ if ($i === 0) {
$this->theta[0] -= $this->learningRate * array_sum($updates);
} else {
$col = array_column($this->samples, $i - 1);
diff --git a/src/Phpml/Helper/Optimizer/Optimizer.php b/src/Phpml/Helper/Optimizer/Optimizer.php
index 9ef4c4d..09668a9 100644
--- a/src/Phpml/Helper/Optimizer/Optimizer.php
+++ b/src/Phpml/Helper/Optimizer/Optimizer.php
@@ -31,7 +31,7 @@ abstract class Optimizer
// Inits the weights randomly
$this->theta = [];
- for ($i=0; $i < $this->dimensions; $i++) {
+ for ($i = 0; $i < $this->dimensions; ++$i) {
$this->theta[] = rand() / (float) getrandmax();
}
}
@@ -40,6 +40,10 @@ abstract class Optimizer
* Sets the weights manually
*
* @param array $theta
+ *
+ * @return $this
+ *
+ * @throws \Exception
*/
public function setInitialTheta(array $theta)
{
@@ -56,6 +60,9 @@ abstract class Optimizer
* Executes the optimization with the given samples & targets
* and returns the weights
*
+ * @param array $samples
+ * @param array $targets
+ * @param \Closure $gradientCb
*/
abstract protected function runOptimization(array $samples, array $targets, \Closure $gradientCb);
}
diff --git a/src/Phpml/Helper/Optimizer/StochasticGD.php b/src/Phpml/Helper/Optimizer/StochasticGD.php
index e9e318a..fa2401a 100644
--- a/src/Phpml/Helper/Optimizer/StochasticGD.php
+++ b/src/Phpml/Helper/Optimizer/StochasticGD.php
@@ -166,7 +166,6 @@ class StochasticGD extends Optimizer
$currIter = 0;
$bestTheta = null;
$bestScore = 0.0;
- $bestWeightIter = 0;
$this->costValues = [];
while ($this->maxIterations > $currIter++) {
@@ -180,7 +179,6 @@ class StochasticGD extends Optimizer
if ($bestTheta == null || $cost <= $bestScore) {
$bestTheta = $theta;
$bestScore = $cost;
- $bestWeightIter = $currIter;
}
// Add the cost value for this iteration to the list
@@ -218,7 +216,7 @@ class StochasticGD extends Optimizer
$this->theta[0] -= $this->learningRate * $gradient;
// Update other values
- for ($i=1; $i <= $this->dimensions; $i++) {
+ for ($i = 1; $i <= $this->dimensions; ++$i) {
$this->theta[$i] -= $this->learningRate *
($gradient * $sample[$i - 1] + $penalty * $this->theta[$i]);
}
diff --git a/src/Phpml/Helper/Predictable.php b/src/Phpml/Helper/Predictable.php
index 097edaa..2ef9017 100644
--- a/src/Phpml/Helper/Predictable.php
+++ b/src/Phpml/Helper/Predictable.php
@@ -14,12 +14,12 @@ trait Predictable
public function predict(array $samples)
{
if (!is_array($samples[0])) {
- $predicted = $this->predictSample($samples);
- } else {
- $predicted = [];
- foreach ($samples as $index => $sample) {
- $predicted[$index] = $this->predictSample($sample);
- }
+ return $this->predictSample($samples);
+ }
+
+ $predicted = [];
+ foreach ($samples as $index => $sample) {
+ $predicted[$index] = $this->predictSample($sample);
}
return $predicted;
diff --git a/src/Phpml/IncrementalEstimator.php b/src/Phpml/IncrementalEstimator.php
index fc6912d..4a0d1cc 100644
--- a/src/Phpml/IncrementalEstimator.php
+++ b/src/Phpml/IncrementalEstimator.php
@@ -6,7 +6,6 @@ namespace Phpml;
interface IncrementalEstimator
{
-
/**
* @param array $samples
* @param array $targets
diff --git a/src/Phpml/Math/Kernel/RBF.php b/src/Phpml/Math/Kernel/RBF.php
index 8ca7d84..2cd92db 100644
--- a/src/Phpml/Math/Kernel/RBF.php
+++ b/src/Phpml/Math/Kernel/RBF.php
@@ -23,8 +23,8 @@ class RBF implements Kernel
}
/**
- * @param float $a
- * @param float $b
+ * @param array $a
+ * @param array $b
*
* @return float
*/
diff --git a/src/Phpml/Math/LinearAlgebra/EigenvalueDecomposition.php b/src/Phpml/Math/LinearAlgebra/EigenvalueDecomposition.php
index 5cbc121..7f0ec4b 100644
--- a/src/Phpml/Math/LinearAlgebra/EigenvalueDecomposition.php
+++ b/src/Phpml/Math/LinearAlgebra/EigenvalueDecomposition.php
@@ -33,7 +33,6 @@ use Phpml\Math\Matrix;
class EigenvalueDecomposition
{
-
/**
* Row and column dimension (square matrix).
* @var int
@@ -42,9 +41,9 @@ class EigenvalueDecomposition
/**
* Internal symmetry flag.
- * @var int
+ * @var bool
*/
- private $issymmetric;
+ private $symmetric;
/**
* Arrays for internal storage of eigenvalues.
@@ -78,6 +77,38 @@ class EigenvalueDecomposition
private $cdivr;
private $cdivi;
+ /**
+ * Constructor: Check for symmetry, then construct the eigenvalue decomposition
+ *
+ * @param array $Arg
+ */
+ public function __construct(array $Arg)
+ {
+ $this->A = $Arg;
+ $this->n = count($Arg[0]);
+ $this->symmetric = true;
+
+ for ($j = 0; ($j < $this->n) && $this->symmetric; ++$j) {
+ for ($i = 0; ($i < $this->n) & $this->symmetric; ++$i) {
+ $this->symmetric = ($this->A[$i][$j] == $this->A[$j][$i]);
+ }
+ }
+
+ if ($this->symmetric) {
+ $this->V = $this->A;
+ // Tridiagonalize.
+ $this->tred2();
+ // Diagonalize.
+ $this->tql2();
+ } else {
+ $this->H = $this->A;
+ $this->ort = [];
+ // Reduce to Hessenberg form.
+ $this->orthes();
+ // Reduce Hessenberg to real Schur form.
+ $this->hqr2();
+ }
+ }
/**
* Symmetric Householder reduction to tridiagonal form.
@@ -88,10 +119,10 @@ class EigenvalueDecomposition
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
- $this->d = $this->V[$this->n-1];
+ $this->d = $this->V[$this->n - 1];
// Householder reduction to tridiagonal form.
- for ($i = $this->n-1; $i > 0; --$i) {
- $i_ = $i -1;
+ for ($i = $this->n - 1; $i > 0; --$i) {
+ $i_ = $i - 1;
// Scale to avoid under/overflow.
$h = $scale = 0.0;
$scale += array_sum(array_map('abs', $this->d));
@@ -107,14 +138,17 @@ class EigenvalueDecomposition
$this->d[$k] /= $scale;
$h += pow($this->d[$k], 2);
}
+
$f = $this->d[$i_];
$g = sqrt($h);
if ($f > 0) {
$g = -$g;
}
+
$this->e[$i] = $scale * $g;
$h = $h - $f * $g;
$this->d[$i_] = $f - $g;
+
for ($j = 0; $j < $i; ++$j) {
$this->e[$j] = 0.0;
}
@@ -123,22 +157,26 @@ class EigenvalueDecomposition
$f = $this->d[$j];
$this->V[$j][$i] = $f;
$g = $this->e[$j] + $this->V[$j][$j] * $f;
- for ($k = $j+1; $k <= $i_; ++$k) {
+
+ for ($k = $j + 1; $k <= $i_; ++$k) {
$g += $this->V[$k][$j] * $this->d[$k];
$this->e[$k] += $this->V[$k][$j] * $f;
}
$this->e[$j] = $g;
}
+
$f = 0.0;
if ($h === 0 || $h < 1e-32) {
$h = 1e-32;
}
+
for ($j = 0; $j < $i; ++$j) {
$this->e[$j] /= $h;
$f += $this->e[$j] * $this->d[$j];
}
+
$hh = $f / (2 * $h);
- for ($j=0; $j < $i; ++$j) {
+ for ($j = 0; $j < $i; ++$j) {
$this->e[$j] -= $hh * $this->d[$j];
}
for ($j = 0; $j < $i; ++$j) {
@@ -147,7 +185,7 @@ class EigenvalueDecomposition
for ($k = $j; $k <= $i_; ++$k) {
$this->V[$k][$j] -= ($f * $this->e[$k] + $g * $this->d[$k]);
}
- $this->d[$j] = $this->V[$i-1][$j];
+ $this->d[$j] = $this->V[$i - 1][$j];
$this->V[$i][$j] = 0.0;
}
}
@@ -155,18 +193,18 @@ class EigenvalueDecomposition
}
// Accumulate transformations.
- for ($i = 0; $i < $this->n-1; ++$i) {
- $this->V[$this->n-1][$i] = $this->V[$i][$i];
+ for ($i = 0; $i < $this->n - 1; ++$i) {
+ $this->V[$this->n - 1][$i] = $this->V[$i][$i];
$this->V[$i][$i] = 1.0;
- $h = $this->d[$i+1];
+ $h = $this->d[$i + 1];
if ($h != 0.0) {
for ($k = 0; $k <= $i; ++$k) {
- $this->d[$k] = $this->V[$k][$i+1] / $h;
+ $this->d[$k] = $this->V[$k][$i + 1] / $h;
}
for ($j = 0; $j <= $i; ++$j) {
$g = 0.0;
for ($k = 0; $k <= $i; ++$k) {
- $g += $this->V[$k][$i+1] * $this->V[$k][$j];
+ $g += $this->V[$k][$i + 1] * $this->V[$k][$j];
}
for ($k = 0; $k <= $i; ++$k) {
$this->V[$k][$j] -= $g * $this->d[$k];
@@ -174,13 +212,13 @@ class EigenvalueDecomposition
}
}
for ($k = 0; $k <= $i; ++$k) {
- $this->V[$k][$i+1] = 0.0;
+ $this->V[$k][$i + 1] = 0.0;
}
}
- $this->d = $this->V[$this->n-1];
- $this->V[$this->n-1] = array_fill(0, $j, 0.0);
- $this->V[$this->n-1][$this->n-1] = 1.0;
+ $this->d = $this->V[$this->n - 1];
+ $this->V[$this->n - 1] = array_fill(0, $j, 0.0);
+ $this->V[$this->n - 1][$this->n - 1] = 1.0;
$this->e[0] = 0.0;
}
@@ -196,9 +234,9 @@ class EigenvalueDecomposition
private function tql2()
{
for ($i = 1; $i < $this->n; ++$i) {
- $this->e[$i-1] = $this->e[$i];
+ $this->e[$i - 1] = $this->e[$i];
}
- $this->e[$this->n-1] = 0.0;
+ $this->e[$this->n - 1] = 0.0;
$f = 0.0;
$tst1 = 0.0;
$eps = pow(2.0, -52.0);
@@ -222,14 +260,14 @@ class EigenvalueDecomposition
$iter += 1;
// Compute implicit shift
$g = $this->d[$l];
- $p = ($this->d[$l+1] - $g) / (2.0 * $this->e[$l]);
+ $p = ($this->d[$l + 1] - $g) / (2.0 * $this->e[$l]);
$r = hypot($p, 1.0);
if ($p < 0) {
$r *= -1;
}
$this->d[$l] = $this->e[$l] / ($p + $r);
- $this->d[$l+1] = $this->e[$l] * ($p + $r);
- $dl1 = $this->d[$l+1];
+ $this->d[$l + 1] = $this->e[$l] * ($p + $r);
+ $dl1 = $this->d[$l + 1];
$h = $g - $this->d[$l];
for ($i = $l + 2; $i < $this->n; ++$i) {
$this->d[$i] -= $h;
@@ -241,23 +279,23 @@ class EigenvalueDecomposition
$c2 = $c3 = $c;
$el1 = $this->e[$l + 1];
$s = $s2 = 0.0;
- for ($i = $m-1; $i >= $l; --$i) {
+ for ($i = $m - 1; $i >= $l; --$i) {
$c3 = $c2;
$c2 = $c;
$s2 = $s;
$g = $c * $this->e[$i];
$h = $c * $p;
$r = hypot($p, $this->e[$i]);
- $this->e[$i+1] = $s * $r;
+ $this->e[$i + 1] = $s * $r;
$s = $this->e[$i] / $r;
$c = $p / $r;
$p = $c * $this->d[$i] - $s * $g;
- $this->d[$i+1] = $h + $s * ($c * $g + $s * $this->d[$i]);
+ $this->d[$i + 1] = $h + $s * ($c * $g + $s * $this->d[$i]);
// Accumulate transformation.
for ($k = 0; $k < $this->n; ++$k) {
- $h = $this->V[$k][$i+1];
- $this->V[$k][$i+1] = $s * $this->V[$k][$i] + $c * $h;
- $this->V[$k][$i] = $c * $this->V[$k][$i] - $s * $h;
+ $h = $this->V[$k][$i + 1];
+ $this->V[$k][$i + 1] = $s * $this->V[$k][$i] + $c * $h;
+ $this->V[$k][$i] = $c * $this->V[$k][$i] - $s * $h;
}
}
$p = -$s * $s2 * $c3 * $el1 * $this->e[$l] / $dl1;
@@ -274,7 +312,7 @@ class EigenvalueDecomposition
for ($i = 0; $i < $this->n - 1; ++$i) {
$k = $i;
$p = $this->d[$i];
- for ($j = $i+1; $j < $this->n; ++$j) {
+ for ($j = $i + 1; $j < $this->n; ++$j) {
if ($this->d[$j] < $p) {
$k = $j;
$p = $this->d[$j];
@@ -304,19 +342,19 @@ class EigenvalueDecomposition
private function orthes()
{
$low = 0;
- $high = $this->n-1;
+ $high = $this->n - 1;
- for ($m = $low+1; $m <= $high-1; ++$m) {
+ for ($m = $low + 1; $m <= $high - 1; ++$m) {
// Scale column.
$scale = 0.0;
for ($i = $m; $i <= $high; ++$i) {
- $scale = $scale + abs($this->H[$i][$m-1]);
+ $scale = $scale + abs($this->H[$i][$m - 1]);
}
if ($scale != 0.0) {
// Compute Householder transformation.
$h = 0.0;
for ($i = $high; $i >= $m; --$i) {
- $this->ort[$i] = $this->H[$i][$m-1] / $scale;
+ $this->ort[$i] = $this->H[$i][$m - 1] / $scale;
$h += $this->ort[$i] * $this->ort[$i];
}
$g = sqrt($h);
@@ -348,7 +386,7 @@ class EigenvalueDecomposition
}
}
$this->ort[$m] = $scale * $this->ort[$m];
- $this->H[$m][$m-1] = $scale * $g;
+ $this->H[$m][$m - 1] = $scale * $g;
}
}
@@ -358,10 +396,10 @@ class EigenvalueDecomposition
$this->V[$i][$j] = ($i == $j ? 1.0 : 0.0);
}
}
- for ($m = $high-1; $m >= $low+1; --$m) {
- if ($this->H[$m][$m-1] != 0.0) {
- for ($i = $m+1; $i <= $high; ++$i) {
- $this->ort[$i] = $this->H[$i][$m-1];
+ for ($m = $high - 1; $m >= $low + 1; --$m) {
+ if ($this->H[$m][$m - 1] != 0.0) {
+ for ($i = $m + 1; $i <= $high; ++$i) {
+ $this->ort[$i] = $this->H[$i][$m - 1];
}
for ($j = $m; $j <= $high; ++$j) {
$g = 0.0;
@@ -369,7 +407,7 @@ class EigenvalueDecomposition
$g += $this->ort[$i] * $this->V[$i][$j];
}
// Double division avoids possible underflow
- $g = ($g / $this->ort[$m]) / $this->H[$m][$m-1];
+ $g = ($g / $this->ort[$m]) / $this->H[$m][$m - 1];
for ($i = $m; $i <= $high; ++$i) {
$this->V[$i][$j] += $g * $this->ort[$i];
}
@@ -378,9 +416,13 @@ class EigenvalueDecomposition
}
}
-
/**
- * Performs complex division.
+ * Performs complex division.
+ *
+ * @param int|float $xr
+ * @param int|float $xi
+ * @param int|float $yr
+ * @param int|float $yi
*/
private function cdiv($xr, $xi, $yr, $yi)
{
@@ -397,7 +439,6 @@ class EigenvalueDecomposition
}
}
-
/**
* Nonsymmetric reduction from Hessenberg to real Schur form.
*
@@ -424,7 +465,7 @@ class EigenvalueDecomposition
$this->d[$i] = $this->H[$i][$i];
$this->e[$i] = 0.0;
}
- for ($j = max($i-1, 0); $j < $nn; ++$j) {
+ for ($j = max($i - 1, 0); $j < $nn; ++$j) {
$norm = $norm + abs($this->H[$i][$j]);
}
}
@@ -435,11 +476,11 @@ class EigenvalueDecomposition
// Look for single small sub-diagonal element
$l = $n;
while ($l > $low) {
- $s = abs($this->H[$l-1][$l-1]) + abs($this->H[$l][$l]);
+ $s = abs($this->H[$l - 1][$l - 1]) + abs($this->H[$l][$l]);
if ($s == 0.0) {
$s = $norm;
}
- if (abs($this->H[$l][$l-1]) < $eps * $s) {
+ if (abs($this->H[$l][$l - 1]) < $eps * $s) {
break;
}
--$l;
@@ -453,13 +494,13 @@ class EigenvalueDecomposition
--$n;
$iter = 0;
// Two roots found
- } elseif ($l == $n-1) {
- $w = $this->H[$n][$n-1] * $this->H[$n-1][$n];
- $p = ($this->H[$n-1][$n-1] - $this->H[$n][$n]) / 2.0;
+ } elseif ($l == $n - 1) {
+ $w = $this->H[$n][$n - 1] * $this->H[$n - 1][$n];
+ $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 - 1][$n - 1] = $this->H[$n - 1][$n - 1] + $exshift;
$x = $this->H[$n][$n];
// Real pair
if ($q >= 0) {
@@ -468,14 +509,14 @@ class EigenvalueDecomposition
} else {
$z = $p - $z;
}
- $this->d[$n-1] = $x + $z;
- $this->d[$n] = $this->d[$n-1];
+ $this->d[$n - 1] = $x + $z;
+ $this->d[$n] = $this->d[$n - 1];
if ($z != 0.0) {
$this->d[$n] = $x - $w / $z;
}
- $this->e[$n-1] = 0.0;
+ $this->e[$n - 1] = 0.0;
$this->e[$n] = 0.0;
- $x = $this->H[$n][$n-1];
+ $x = $this->H[$n][$n - 1];
$s = abs($x) + abs($z);
$p = $x / $s;
$q = $z / $s;
@@ -483,29 +524,29 @@ class EigenvalueDecomposition
$p = $p / $r;
$q = $q / $r;
// Row modification
- for ($j = $n-1; $j < $nn; ++$j) {
- $z = $this->H[$n-1][$j];
- $this->H[$n-1][$j] = $q * $z + $p * $this->H[$n][$j];
+ for ($j = $n - 1; $j < $nn; ++$j) {
+ $z = $this->H[$n - 1][$j];
+ $this->H[$n - 1][$j] = $q * $z + $p * $this->H[$n][$j];
$this->H[$n][$j] = $q * $this->H[$n][$j] - $p * $z;
}
// Column modification
for ($i = 0; $i <= $n; ++$i) {
- $z = $this->H[$i][$n-1];
- $this->H[$i][$n-1] = $q * $z + $p * $this->H[$i][$n];
+ $z = $this->H[$i][$n - 1];
+ $this->H[$i][$n - 1] = $q * $z + $p * $this->H[$i][$n];
$this->H[$i][$n] = $q * $this->H[$i][$n] - $p * $z;
}
// Accumulate transformations
for ($i = $low; $i <= $high; ++$i) {
- $z = $this->V[$i][$n-1];
- $this->V[$i][$n-1] = $q * $z + $p * $this->V[$i][$n];
+ $z = $this->V[$i][$n - 1];
+ $this->V[$i][$n - 1] = $q * $z + $p * $this->V[$i][$n];
$this->V[$i][$n] = $q * $this->V[$i][$n] - $p * $z;
}
// Complex pair
} else {
- $this->d[$n-1] = $x + $p;
- $this->d[$n] = $x + $p;
- $this->e[$n-1] = $z;
- $this->e[$n] = -$z;
+ $this->d[$n - 1] = $x + $p;
+ $this->d[$n] = $x + $p;
+ $this->e[$n - 1] = $z;
+ $this->e[$n] = -$z;
}
$n = $n - 2;
$iter = 0;
@@ -516,8 +557,8 @@ class EigenvalueDecomposition
$y = 0.0;
$w = 0.0;
if ($l < $n) {
- $y = $this->H[$n-1][$n-1];
- $w = $this->H[$n][$n-1] * $this->H[$n-1][$n];
+ $y = $this->H[$n - 1][$n - 1];
+ $w = $this->H[$n][$n - 1] * $this->H[$n - 1][$n];
}
// Wilkinson's original ad hoc shift
if ($iter == 10) {
@@ -525,7 +566,7 @@ class EigenvalueDecomposition
for ($i = $low; $i <= $n; ++$i) {
$this->H[$i][$i] -= $x;
}
- $s = abs($this->H[$n][$n-1]) + abs($this->H[$n-1][$n-2]);
+ $s = abs($this->H[$n][$n - 1]) + abs($this->H[$n - 1][$n - 2]);
$x = $y = 0.75 * $s;
$w = -0.4375 * $s * $s;
}
@@ -554,9 +595,9 @@ class EigenvalueDecomposition
$z = $this->H[$m][$m];
$r = $x - $z;
$s = $y - $z;
- $p = ($r * $s - $w) / $this->H[$m+1][$m] + $this->H[$m][$m+1];
- $q = $this->H[$m+1][$m+1] - $z - $r - $s;
- $r = $this->H[$m+2][$m+1];
+ $p = ($r * $s - $w) / $this->H[$m + 1][$m] + $this->H[$m][$m + 1];
+ $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;
@@ -564,25 +605,25 @@ class EigenvalueDecomposition
if ($m == $l) {
break;
}
- if (abs($this->H[$m][$m-1]) * (abs($q) + abs($r)) <
- $eps * (abs($p) * (abs($this->H[$m-1][$m-1]) + abs($z) + abs($this->H[$m+1][$m+1])))) {
+ if (abs($this->H[$m][$m - 1]) * (abs($q) + abs($r)) <
+ $eps * (abs($p) * (abs($this->H[$m - 1][$m - 1]) + abs($z) + abs($this->H[$m + 1][$m + 1])))) {
break;
}
--$m;
}
for ($i = $m + 2; $i <= $n; ++$i) {
- $this->H[$i][$i-2] = 0.0;
- if ($i > $m+2) {
- $this->H[$i][$i-3] = 0.0;
+ $this->H[$i][$i - 2] = 0.0;
+ if ($i > $m + 2) {
+ $this->H[$i][$i - 3] = 0.0;
}
}
// Double QR step involving rows l:n and columns m:n
- for ($k = $m; $k <= $n-1; ++$k) {
- $notlast = ($k != $n-1);
+ for ($k = $m; $k <= $n - 1; ++$k) {
+ $notlast = ($k != $n - 1);
if ($k != $m) {
- $p = $this->H[$k][$k-1];
- $q = $this->H[$k+1][$k-1];
- $r = ($notlast ? $this->H[$k+2][$k-1] : 0.0);
+ $p = $this->H[$k][$k - 1];
+ $q = $this->H[$k + 1][$k - 1];
+ $r = ($notlast ? $this->H[$k + 2][$k - 1] : 0.0);
$x = abs($p) + abs($q) + abs($r);
if ($x != 0.0) {
$p = $p / $x;
@@ -599,9 +640,9 @@ class EigenvalueDecomposition
}
if ($s != 0) {
if ($k != $m) {
- $this->H[$k][$k-1] = -$s * $x;
+ $this->H[$k][$k - 1] = -$s * $x;
} elseif ($l != $m) {
- $this->H[$k][$k-1] = -$this->H[$k][$k-1];
+ $this->H[$k][$k - 1] = -$this->H[$k][$k - 1];
}
$p = $p + $s;
$x = $p / $s;
@@ -611,33 +652,33 @@ class EigenvalueDecomposition
$r = $r / $p;
// Row modification
for ($j = $k; $j < $nn; ++$j) {
- $p = $this->H[$k][$j] + $q * $this->H[$k+1][$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 = $p + $r * $this->H[$k + 2][$j];
+ $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 + 1][$j] = $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];
+ 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 = $p + $z * $this->H[$i][$k + 2];
+ $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 + 1] = $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];
+ $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 = $p + $z * $this->V[$i][$k + 2];
+ $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 + 1] = $this->V[$i][$k + 1] - $p * $q;
}
} // ($s != 0)
} // k loop
@@ -649,19 +690,20 @@ class EigenvalueDecomposition
return;
}
- for ($n = $nn-1; $n >= 0; --$n) {
+ for ($n = $nn - 1; $n >= 0; --$n) {
$p = $this->d[$n];
$q = $this->e[$n];
// Real vector
if ($q == 0) {
$l = $n;
$this->H[$n][$n] = 1.0;
- for ($i = $n-1; $i >= 0; --$i) {
+ for ($i = $n - 1; $i >= 0; --$i) {
$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];
}
+
if ($this->e[$i] < 0.0) {
$z = $w;
$s = $r;
@@ -675,15 +717,15 @@ class EigenvalueDecomposition
}
// Solve real equations
} else {
- $x = $this->H[$i][$i+1];
- $y = $this->H[$i+1][$i];
+ $x = $this->H[$i][$i + 1];
+ $y = $this->H[$i + 1][$i];
$q = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i];
$t = ($x * $s - $z * $r) / $q;
$this->H[$i][$n] = $t;
if (abs($x) > abs($z)) {
- $this->H[$i+1][$n] = (-$r - $w * $t) / $x;
+ $this->H[$i + 1][$n] = (-$r - $w * $t) / $x;
} else {
- $this->H[$i+1][$n] = (-$s - $y * $t) / $z;
+ $this->H[$i + 1][$n] = (-$s - $y * $t) / $z;
}
}
// Overflow control
@@ -697,24 +739,24 @@ class EigenvalueDecomposition
}
// Complex vector
} elseif ($q < 0) {
- $l = $n-1;
+ $l = $n - 1;
// Last vector component imaginary so matrix is triangular
- if (abs($this->H[$n][$n-1]) > abs($this->H[$n-1][$n])) {
- $this->H[$n-1][$n-1] = $q / $this->H[$n][$n-1];
- $this->H[$n-1][$n] = -($this->H[$n][$n] - $p) / $this->H[$n][$n-1];
+ if (abs($this->H[$n][$n - 1]) > abs($this->H[$n - 1][$n])) {
+ $this->H[$n - 1][$n - 1] = $q / $this->H[$n][$n - 1];
+ $this->H[$n - 1][$n] = -($this->H[$n][$n] - $p) / $this->H[$n][$n - 1];
} else {
- $this->cdiv(0.0, -$this->H[$n-1][$n], $this->H[$n-1][$n-1] - $p, $q);
- $this->H[$n-1][$n-1] = $this->cdivr;
- $this->H[$n-1][$n] = $this->cdivi;
+ $this->cdiv(0.0, -$this->H[$n - 1][$n], $this->H[$n - 1][$n - 1] - $p, $q);
+ $this->H[$n - 1][$n - 1] = $this->cdivr;
+ $this->H[$n - 1][$n] = $this->cdivi;
}
- $this->H[$n][$n-1] = 0.0;
- $this->H[$n][$n] = 1.0;
- for ($i = $n-2; $i >= 0; --$i) {
+ $this->H[$n][$n - 1] = 0.0;
+ $this->H[$n][$n] = 1.0;
+ for ($i = $n - 2; $i >= 0; --$i) {
// double ra,sa,vr,vi;
$ra = 0.0;
$sa = 0.0;
for ($j = $l; $j <= $n; ++$j) {
- $ra = $ra + $this->H[$i][$j] * $this->H[$j][$n-1];
+ $ra = $ra + $this->H[$i][$j] * $this->H[$j][$n - 1];
$sa = $sa + $this->H[$i][$j] * $this->H[$j][$n];
}
$w = $this->H[$i][$i] - $p;
@@ -726,35 +768,35 @@ class EigenvalueDecomposition
$l = $i;
if ($this->e[$i] == 0) {
$this->cdiv(-$ra, -$sa, $w, $q);
- $this->H[$i][$n-1] = $this->cdivr;
- $this->H[$i][$n] = $this->cdivi;
+ $this->H[$i][$n - 1] = $this->cdivr;
+ $this->H[$i][$n] = $this->cdivi;
} else {
// Solve complex equations
- $x = $this->H[$i][$i+1];
- $y = $this->H[$i+1][$i];
+ $x = $this->H[$i][$i + 1];
+ $y = $this->H[$i + 1][$i];
$vr = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i] - $q * $q;
$vi = ($this->d[$i] - $p) * 2.0 * $q;
if ($vr == 0.0 & $vi == 0.0) {
$vr = $eps * $norm * (abs($w) + abs($q) + abs($x) + abs($y) + abs($z));
}
$this->cdiv($x * $r - $z * $ra + $q * $sa, $x * $s - $z * $sa - $q * $ra, $vr, $vi);
- $this->H[$i][$n-1] = $this->cdivr;
- $this->H[$i][$n] = $this->cdivi;
+ $this->H[$i][$n - 1] = $this->cdivr;
+ $this->H[$i][$n] = $this->cdivi;
if (abs($x) > (abs($z) + abs($q))) {
- $this->H[$i+1][$n-1] = (-$ra - $w * $this->H[$i][$n-1] + $q * $this->H[$i][$n]) / $x;
- $this->H[$i+1][$n] = (-$sa - $w * $this->H[$i][$n] - $q * $this->H[$i][$n-1]) / $x;
+ $this->H[$i + 1][$n - 1] = (-$ra - $w * $this->H[$i][$n - 1] + $q * $this->H[$i][$n]) / $x;
+ $this->H[$i + 1][$n] = (-$sa - $w * $this->H[$i][$n] - $q * $this->H[$i][$n - 1]) / $x;
} else {
- $this->cdiv(-$r - $y * $this->H[$i][$n-1], -$s - $y * $this->H[$i][$n], $z, $q);
- $this->H[$i+1][$n-1] = $this->cdivr;
- $this->H[$i+1][$n] = $this->cdivi;
+ $this->cdiv(-$r - $y * $this->H[$i][$n - 1], -$s - $y * $this->H[$i][$n], $z, $q);
+ $this->H[$i + 1][$n - 1] = $this->cdivr;
+ $this->H[$i + 1][$n] = $this->cdivi;
}
}
// Overflow control
- $t = max(abs($this->H[$i][$n-1]), abs($this->H[$i][$n]));
+ $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] = $this->H[$j][$n - 1] / $t;
+ $this->H[$j][$n] = $this->H[$j][$n] / $t;
}
}
} // end else
@@ -772,7 +814,7 @@ class EigenvalueDecomposition
}
// Back transformation to get eigenvectors of original matrix
- for ($j = $nn-1; $j >= $low; --$j) {
+ for ($j = $nn - 1; $j >= $low; --$j) {
for ($i = $low; $i <= $high; ++$i) {
$z = 0.0;
for ($k = $low; $k <= min($j, $high); ++$k) {
@@ -783,45 +825,12 @@ class EigenvalueDecomposition
}
} // end hqr2
-
/**
- * Constructor: Check for symmetry, then construct the eigenvalue decomposition
+ * Return the eigenvector matrix
*
- * @param array $Arg
- */
- public function __construct(array $Arg)
- {
- $this->A = $Arg;
- $this->n = count($Arg[0]);
-
- $issymmetric = true;
- for ($j = 0; ($j < $this->n) & $issymmetric; ++$j) {
- for ($i = 0; ($i < $this->n) & $issymmetric; ++$i) {
- $issymmetric = ($this->A[$i][$j] == $this->A[$j][$i]);
- }
- }
-
- if ($issymmetric) {
- $this->V = $this->A;
- // Tridiagonalize.
- $this->tred2();
- // Diagonalize.
- $this->tql2();
- } else {
- $this->H = $this->A;
- $this->ort = [];
- // Reduce to Hessenberg form.
- $this->orthes();
- // Reduce Hessenberg to real Schur form.
- $this->hqr2();
- }
- }
-
- /**
- * Return the eigenvector matrix
+ * @access public
*
- * @access public
- * @return array
+ * @return array
*/
public function getEigenvectors()
{
@@ -831,20 +840,21 @@ class EigenvalueDecomposition
$vectors = new Matrix($vectors);
$vectors = array_map(function ($vect) {
$sum = 0;
- for ($i=0; $itranspose()->toArray());
return $vectors;
}
-
/**
* Return the real parts of the eigenvalues
* d = real(diag(D));
@@ -856,7 +866,6 @@ class EigenvalueDecomposition
return $this->d;
}
-
/**
* Return the imaginary parts of the eigenvalues
* d = imag(diag(D))
@@ -868,7 +877,6 @@ class EigenvalueDecomposition
return $this->e;
}
-
/**
* Return the block diagonal eigenvalue matrix
*
@@ -876,15 +884,19 @@ class EigenvalueDecomposition
*/
public function getDiagonalEigenvalues()
{
+ $D = [];
+
for ($i = 0; $i < $this->n; ++$i) {
$D[$i] = array_fill(0, $this->n, 0.0);
$D[$i][$i] = $this->d[$i];
if ($this->e[$i] == 0) {
continue;
}
+
$o = ($this->e[$i] > 0) ? $i + 1 : $i - 1;
$D[$i][$o] = $this->e[$i];
}
+
return $D;
}
} // class EigenvalueDecomposition
diff --git a/src/Phpml/Math/LinearAlgebra/LUDecomposition.php b/src/Phpml/Math/LinearAlgebra/LUDecomposition.php
index 1aeb239..de6a15d 100644
--- a/src/Phpml/Math/LinearAlgebra/LUDecomposition.php
+++ b/src/Phpml/Math/LinearAlgebra/LUDecomposition.php
@@ -1,4 +1,6 @@
-piv[$i] = $i;
}
$this->pivsign = 1;
- $LUrowi = $LUcolj = [];
+ $LUcolj = [];
// Outer loop.
for ($j = 0; $j < $this->n; ++$j) {
@@ -102,7 +105,7 @@ class LUDecomposition
}
// Find pivot and exchange if necessary.
$p = $j;
- for ($i = $j+1; $i < $this->m; ++$i) {
+ for ($i = $j + 1; $i < $this->m; ++$i) {
if (abs($LUcolj[$i]) > abs($LUcolj[$p])) {
$p = $i;
}
@@ -120,7 +123,7 @@ class LUDecomposition
}
// Compute multipliers.
if (($j < $this->m) && ($this->LU[$j][$j] != 0.0)) {
- for ($i = $j+1; $i < $this->m; ++$i) {
+ for ($i = $j + 1; $i < $this->m; ++$i) {
$this->LU[$i][$j] /= $this->LU[$j][$j];
}
}
@@ -129,9 +132,9 @@ class LUDecomposition
/**
- * Get lower triangular factor.
+ * Get lower triangular factor.
*
- * @return array Lower triangular factor
+ * @return Matrix Lower triangular factor
*/
public function getL()
{
@@ -152,9 +155,9 @@ class LUDecomposition
/**
- * Get upper triangular factor.
+ * Get upper triangular factor.
*
- * @return array Upper triangular factor
+ * @return Matrix Upper triangular factor
*/
public function getU()
{
@@ -173,9 +176,9 @@ class LUDecomposition
/**
- * Return pivot permutation vector.
+ * Return pivot permutation vector.
*
- * @return array Pivot vector
+ * @return array Pivot vector
*/
public function getPivot()
{
@@ -184,9 +187,9 @@ class LUDecomposition
/**
- * Alias for getPivot
+ * Alias for getPivot
*
- * @see getPivot
+ * @see getPivot
*/
public function getDoublePivot()
{
@@ -195,9 +198,9 @@ class LUDecomposition
/**
- * Is the matrix nonsingular?
+ * Is the matrix nonsingular?
*
- * @return true if U, and hence A, is nonsingular.
+ * @return true if U, and hence A, is nonsingular.
*/
public function isNonsingular()
{
@@ -206,31 +209,35 @@ class LUDecomposition
return false;
}
}
+
return true;
} // function isNonsingular()
/**
- * Count determinants
+ * Count determinants
*
- * @return array d matrix deterninat
+ * @return float|int d matrix determinant
+ *
+ * @throws MatrixException
*/
public function det()
{
- if ($this->m == $this->n) {
- $d = $this->pivsign;
- for ($j = 0; $j < $this->n; ++$j) {
- $d *= $this->LU[$j][$j];
- }
- return $d;
- } else {
+ if ($this->m !== $this->n) {
throw MatrixException::notSquareMatrix();
}
+
+ $d = $this->pivsign;
+ for ($j = 0; $j < $this->n; ++$j) {
+ $d *= $this->LU[$j][$j];
+ }
+
+ return $d;
} // function det()
/**
- * Solve A*X = B
+ * Solve A*X = B
*
* @param Matrix $B A Matrix with as many rows as A and any number of columns.
*
@@ -244,23 +251,23 @@ class LUDecomposition
throw MatrixException::notSquareMatrix();
}
- if (! $this->isNonsingular()) {
+ if (!$this->isNonsingular()) {
throw MatrixException::singularMatrix();
}
// Copy right hand side with pivoting
$nx = $B->getColumns();
- $X = $this->getSubMatrix($B->toArray(), $this->piv, 0, $nx-1);
+ $X = $this->getSubMatrix($B->toArray(), $this->piv, 0, $nx - 1);
// Solve L*Y = B(piv,:)
for ($k = 0; $k < $this->n; ++$k) {
- for ($i = $k+1; $i < $this->n; ++$i) {
+ for ($i = $k + 1; $i < $this->n; ++$i) {
for ($j = 0; $j < $nx; ++$j) {
$X[$i][$j] -= $X[$k][$j] * $this->LU[$i][$k];
}
}
}
// Solve U*X = Y;
- for ($k = $this->n-1; $k >= 0; --$k) {
+ for ($k = $this->n - 1; $k >= 0; --$k) {
for ($j = 0; $j < $nx; ++$j) {
$X[$k][$j] /= $this->LU[$k][$k];
}
@@ -274,9 +281,10 @@ class LUDecomposition
} // function solve()
/**
- * @param Matrix $matrix
- * @param int $j0
- * @param int $jF
+ * @param array $matrix
+ * @param array $RL
+ * @param int $j0
+ * @param int $jF
*
* @return array
*/
@@ -284,11 +292,11 @@ class LUDecomposition
{
$m = count($RL);
$n = $jF - $j0;
- $R = array_fill(0, $m, array_fill(0, $n+1, 0.0));
+ $R = array_fill(0, $m, array_fill(0, $n + 1, 0.0));
for ($i = 0; $i < $m; ++$i) {
for ($j = $j0; $j <= $jF; ++$j) {
- $R[$i][$j - $j0]= $matrix[ $RL[$i] ][$j];
+ $R[$i][$j - $j0] = $matrix[$RL[$i]][$j];
}
}
diff --git a/src/Phpml/Math/Matrix.php b/src/Phpml/Math/Matrix.php
index c996e7f..3c31052 100644
--- a/src/Phpml/Math/Matrix.php
+++ b/src/Phpml/Math/Matrix.php
@@ -139,6 +139,7 @@ class Matrix
}
$lu = new LUDecomposition($this);
+
return $this->determinant = $lu->det();
}
@@ -232,6 +233,8 @@ class Matrix
* Element-wise addition of the matrix with another one
*
* @param Matrix $other
+ *
+ * @return Matrix
*/
public function add(Matrix $other)
{
@@ -242,6 +245,8 @@ class Matrix
* Element-wise subtracting of another matrix from this one
*
* @param Matrix $other
+ *
+ * @return Matrix
*/
public function subtract(Matrix $other)
{
@@ -252,7 +257,9 @@ class Matrix
* Element-wise addition or substraction depending on the given sign parameter
*
* @param Matrix $other
- * @param type $sign
+ * @param int $sign
+ *
+ * @return Matrix
*/
protected function _add(Matrix $other, $sign = 1)
{
@@ -260,13 +267,13 @@ class Matrix
$a2 = $other->toArray();
$newMatrix = [];
- for ($i=0; $i < $this->rows; $i++) {
- for ($k=0; $k < $this->columns; $k++) {
+ for ($i = 0; $i < $this->rows; ++$i) {
+ for ($k = 0; $k < $this->columns; ++$k) {
$newMatrix[$i][$k] = $a1[$i][$k] + $sign * $a2[$i][$k];
}
}
- return new Matrix($newMatrix, false);
+ return new self($newMatrix, false);
}
/**
@@ -295,7 +302,7 @@ class Matrix
protected function getIdentity()
{
$array = array_fill(0, $this->rows, array_fill(0, $this->columns, 0));
- for ($i=0; $i < $this->rows; $i++) {
+ for ($i = 0; $i < $this->rows; ++$i) {
$array[$i][$i] = 1;
}
@@ -345,7 +352,7 @@ class Matrix
*/
public static function transposeArray(array $array)
{
- return (new Matrix($array, false))->transpose()->toArray();
+ return (new self($array, false))->transpose()->toArray();
}
/**
@@ -359,8 +366,8 @@ class Matrix
*/
public static function dot(array $array1, array $array2)
{
- $m1 = new Matrix($array1, false);
- $m2 = new Matrix($array2, false);
+ $m1 = new self($array1, false);
+ $m2 = new self($array2, false);
return $m1->multiply($m2->transpose())->toArray()[0];
}
diff --git a/src/Phpml/Math/Statistic/Covariance.php b/src/Phpml/Math/Statistic/Covariance.php
index 4a9b613..8c8781d 100644
--- a/src/Phpml/Math/Statistic/Covariance.php
+++ b/src/Phpml/Math/Statistic/Covariance.php
@@ -13,7 +13,7 @@ class Covariance
*
* @param array $x
* @param array $y
- * @param bool $sample
+ * @param bool $sample
* @param float $meanX
* @param float $meanY
*
@@ -57,14 +57,18 @@ class Covariance
* Calculates covariance of two dimensions, i and k in the given data.
*
* @param array $data
- * @param int $i
- * @param int $k
- * @param type $sample
- * @param int $n
+ * @param int $i
+ * @param int $k
+ * @param bool $sample
* @param float $meanX
* @param float $meanY
+ *
+ * @return float
+ *
+ * @throws InvalidArgumentException
+ * @throws \Exception
*/
- public static function fromDataset(array $data, int $i, int $k, $sample = true, float $meanX = null, float $meanY = null)
+ public static function fromDataset(array $data, int $i, int $k, bool $sample = true, float $meanX = null, float $meanY = null)
{
if (empty($data)) {
throw InvalidArgumentException::arrayCantBeEmpty();
@@ -123,7 +127,8 @@ class Covariance
/**
* Returns the covariance matrix of n-dimensional data
*
- * @param array $data
+ * @param array $data
+ * @param array|null $means
*
* @return array
*/
@@ -133,19 +138,20 @@ class Covariance
if ($means === null) {
$means = [];
- for ($i=0; $i < $n; $i++) {
+ for ($i = 0; $i < $n; ++$i) {
$means[] = Mean::arithmetic(array_column($data, $i));
}
}
$cov = [];
- for ($i=0; $i < $n; $i++) {
- for ($k=0; $k < $n; $k++) {
+ for ($i = 0; $i < $n; ++$i) {
+ for ($k = 0; $k < $n; ++$k) {
if ($i > $k) {
$cov[$i][$k] = $cov[$k][$i];
} else {
- $cov[$i][$k] = Covariance::fromDataset(
- $data, $i, $k, true, $means[$i], $means[$k]);
+ $cov[$i][$k] = self::fromDataset(
+ $data, $i, $k, true, $means[$i], $means[$k]
+ );
}
}
}
diff --git a/src/Phpml/Math/Statistic/Gaussian.php b/src/Phpml/Math/Statistic/Gaussian.php
index df27f07..d09edba 100644
--- a/src/Phpml/Math/Statistic/Gaussian.php
+++ b/src/Phpml/Math/Statistic/Gaussian.php
@@ -31,7 +31,7 @@ class Gaussian
*
* @param float $value
*
- * @return type
+ * @return float|int
*/
public function pdf(float $value)
{
diff --git a/src/Phpml/Math/Statistic/Mean.php b/src/Phpml/Math/Statistic/Mean.php
index 581a122..bd9657e 100644
--- a/src/Phpml/Math/Statistic/Mean.php
+++ b/src/Phpml/Math/Statistic/Mean.php
@@ -68,7 +68,7 @@ class Mean
*/
private static function checkArrayLength(array $array)
{
- if (0 == count($array)) {
+ if (empty($array)) {
throw InvalidArgumentException::arrayCantBeEmpty();
}
}
diff --git a/src/Phpml/Metric/ClassificationReport.php b/src/Phpml/Metric/ClassificationReport.php
index c7cc147..6fc026c 100644
--- a/src/Phpml/Metric/ClassificationReport.php
+++ b/src/Phpml/Metric/ClassificationReport.php
@@ -112,8 +112,8 @@ class ClassificationReport
private function computeAverage()
{
foreach (['precision', 'recall', 'f1score'] as $metric) {
- $values = array_filter($this->$metric);
- if (0 == count($values)) {
+ $values = array_filter($this->{$metric});
+ if (empty($values)) {
$this->average[$metric] = 0.0;
continue;
}
diff --git a/src/Phpml/ModelManager.php b/src/Phpml/ModelManager.php
index c03d0ed..08ab3e6 100644
--- a/src/Phpml/ModelManager.php
+++ b/src/Phpml/ModelManager.php
@@ -11,7 +11,8 @@ class ModelManager
{
/**
* @param Estimator $estimator
- * @param string $filepath
+ * @param string $filepath
+ *
* @throws FileException
* @throws SerializeException
*/
@@ -23,7 +24,7 @@ class ModelManager
$serialized = serialize($estimator);
if (empty($serialized)) {
- throw SerializeException::cantSerialize(get_type($estimator));
+ throw SerializeException::cantSerialize(gettype($estimator));
}
$result = file_put_contents($filepath, $serialized, LOCK_EX);
@@ -34,7 +35,9 @@ class ModelManager
/**
* @param string $filepath
+ *
* @return Estimator
+ *
* @throws FileException
* @throws SerializeException
*/
diff --git a/src/Phpml/NeuralNetwork/Training/Backpropagation.php b/src/Phpml/NeuralNetwork/Training/Backpropagation.php
index 136e8bf..43ac512 100644
--- a/src/Phpml/NeuralNetwork/Training/Backpropagation.php
+++ b/src/Phpml/NeuralNetwork/Training/Backpropagation.php
@@ -44,10 +44,12 @@ class Backpropagation implements Training
*/
public function train(array $samples, array $targets, float $desiredError = 0.001, int $maxIterations = 10000)
{
+ $samplesCount = count($samples);
+
for ($i = 0; $i < $maxIterations; ++$i) {
$resultsWithinError = $this->trainSamples($samples, $targets, $desiredError);
- if ($resultsWithinError == count($samples)) {
+ if ($resultsWithinError === $samplesCount) {
break;
}
}
diff --git a/src/Phpml/Preprocessing/Normalizer.php b/src/Phpml/Preprocessing/Normalizer.php
index 8392db7..c61b447 100644
--- a/src/Phpml/Preprocessing/Normalizer.php
+++ b/src/Phpml/Preprocessing/Normalizer.php
@@ -84,7 +84,7 @@ class Normalizer implements Preprocessor
$this->fit($samples);
foreach ($samples as &$sample) {
- $this->$method($sample);
+ $this->{$method}($sample);
}
}
diff --git a/src/Phpml/SupportVectorMachine/SupportVectorMachine.php b/src/Phpml/SupportVectorMachine/SupportVectorMachine.php
index 9f6da70..c6ec017 100644
--- a/src/Phpml/SupportVectorMachine/SupportVectorMachine.php
+++ b/src/Phpml/SupportVectorMachine/SupportVectorMachine.php
@@ -130,6 +130,8 @@ class SupportVectorMachine
/**
* @param string $binPath
+ *
+ * @return $this
*/
public function setBinPath(string $binPath)
{
@@ -140,6 +142,8 @@ class SupportVectorMachine
/**
* @param string $varPath
+ *
+ * @return $this
*/
public function setVarPath(string $varPath)
{
@@ -230,8 +234,8 @@ class SupportVectorMachine
}
/**
- * @param $trainingSetFileName
- * @param $modelFileName
+ * @param string $trainingSetFileName
+ * @param string $modelFileName
*
* @return string
*/