Test Failed
Pull Request — master (#54)
by
unknown
02:33
created

KNearestNeighbors::train()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpml\Classification;
6
7
use Phpml\Helper\Predictable;
8
use Phpml\Helper\Trainable;
9
use Phpml\Math\Distance;
10
use Phpml\Math\Distance\Euclidean;
11
12
class KNearestNeighbors implements Classifier
13
{
14
    use Trainable, Predictable;
15
16
    /**
17
     * @var int
18
     */
19
    private $k;
20
21
    /**
22
     * @var Distance
23
     */
24
    private $distanceMetric;
25
26
    /**
27
     * @param int           $k
28
     * @param Distance|null $distanceMetric (if null then Euclidean distance as default)
29
     */
30
    public function __construct(int $k = 3, Distance $distanceMetric = null)
31
    {
32
        if (null === $distanceMetric) {
33
            $distanceMetric = new Euclidean();
34
        }
35
36
        $this->k = $k;
37
        $this->samples = [];
38
        $this->targets = [];
39
        $this->distanceMetric = $distanceMetric;
40
    }
41
42
    /**
43
     * @param array $samples
44
     * @param array $targets
45
     */
46
    public function train(array $samples, array $targets)
47
    {
48
        $this->samples = array_merge($this->samples, $samples);
49
        $this->targets = array_merge($this->targets, $targets);
50
    }
51
52
    /**
53
     * @param array $sample
54
     *
55
     * @return mixed
56
     */
57
    protected function predictSample(array $sample)
58
    {
59
        $distances = $this->kNeighborsDistances($sample);
60
61
        $predictions = array_combine(array_values($this->targets), array_fill(0, count($this->targets), 0));
62
63
        foreach ($distances as $index => $distance) {
64
            ++$predictions[$this->targets[$index]];
65
        }
66
67
        arsort($predictions);
68
        reset($predictions);
69
70
        return key($predictions);
71
    }
72
73
    /**
74
     * @param array $sample
75
     *
76
     * @return array
77
     *
78
     * @throws \Phpml\Exception\InvalidArgumentException
79
     */
80
    private function kNeighborsDistances(array $sample)
81
    {
82
        $distances = [];
83
84
        foreach ($this->samples as $index => $neighbor) {
85
            $distances[$index] = $this->distanceMetric->distance($sample, $neighbor);
86
        }
87
88
        asort($distances);
89
90
        return array_slice($distances, 0, $this->k, true);
91
    }
92
}
93