EigenTransformerBase   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 6
eloc 28
dl 0
loc 77
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A reduce() 0 6 1
A eigenDecomposition() 0 31 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpml\DimensionReduction;
6
7
use Phpml\Math\LinearAlgebra\EigenvalueDecomposition;
8
use Phpml\Math\Matrix;
9
10
/**
11
 * Class to compute eigen pairs (values & vectors) of a given matrix
12
 * with the consideration of numFeatures or totalVariance to be preserved
13
 *
14
 * @author hp
15
 */
16
abstract class EigenTransformerBase
17
{
18
    /**
19
     * Total variance to be conserved after the reduction
20
     *
21
     * @var float
22
     */
23
    public $totalVariance = 0.9;
24
25
    /**
26
     * Number of features to be preserved after the reduction
27
     *
28
     * @var int
29
     */
30
    public $numFeatures = null;
31
32
    /**
33
     * Top eigenvectors of the matrix
34
     *
35
     * @var array
36
     */
37
    protected $eigVectors = [];
38
39
    /**
40
     * Top eigenValues of the matrix
41
     *
42
     * @var array
43
     */
44
    protected $eigValues = [];
45
46
    /**
47
     * Calculates eigenValues and eigenVectors of the given matrix. Returns
48
     * top eigenVectors along with the largest eigenValues. The total explained variance
49
     * of these eigenVectors will be no less than desired $totalVariance value
50
     */
51
    protected function eigenDecomposition(array $matrix): void
52
    {
53
        $eig = new EigenvalueDecomposition($matrix);
54
        $eigVals = $eig->getRealEigenvalues();
55
        $eigVects = $eig->getEigenvectors();
56
57
        $totalEigVal = array_sum($eigVals);
58
        // Sort eigenvalues in descending order
59
        arsort($eigVals);
60
61
        $explainedVar = 0.0;
62
        $vectors = [];
63
        $values = [];
64
        foreach ($eigVals as $i => $eigVal) {
65
            $explainedVar += $eigVal / $totalEigVal;
66
            $vectors[] = $eigVects[$i];
67
            $values[] = $eigVal;
68
69
            if ($this->numFeatures !== null) {
70
                if (count($vectors) == $this->numFeatures) {
71
                    break;
72
                }
73
            } else {
74
                if ($explainedVar >= $this->totalVariance) {
75
                    break;
76
                }
77
            }
78
        }
79
80
        $this->eigValues = $values;
81
        $this->eigVectors = $vectors;
82
    }
83
84
    /**
85
     * Returns the reduced data
86
     */
87
    protected function reduce(array $data): array
88
    {
89
        $m1 = new Matrix($data);
90
        $m2 = new Matrix($this->eigVectors);
91
92
        return $m1->multiply($m2->transpose())->toArray();
93
    }
94
}
95