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

OneVsRest   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 0
dl 0
loc 110
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
B train() 0 25 3
A binarizeTargets() 0 10 3
A predictSample() 0 15 3
trainBinary() 0 1 ?
predictProbability() 0 1 ?
predictSampleBinary() 0 1 ?
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpml\Helper;
6
7
trait OneVsRest
8
{
9
    /**
10
     * @var array
11
     */
12
    protected $classifiers;
13
14
    /**
15
     * @var array
16
     */
17
    protected $labels;
18
19
    /**
20
     * Train a binary classifier in the OvR style
21
     *
22
     * @param array $samples
23
     * @param array $targets
24
     */
25
    public function train(array $samples, array $targets)
26
    {
27
        // Clone the current classifier, so that
28
        // we don't mess up its variables while training
29
        // multiple instances of this classifier
30
        $classifier = clone $this;
31
        $this->classifiers = [];
32
33
        // If there are only two targets, then there is no need to perform OvR
34
        $this->labels = array_keys(array_count_values($targets));
35
        if (count($this->labels) == 2) {
36
            $classifier->trainBinary($samples, $targets);
37
            $this->classifiers[] = $classifier;
38
        } else {
39
            // Train a separate classifier for each label and memorize them
40
            $this->samples = $samples;
0 ignored issues
show
Bug introduced by
The property samples does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
41
            $this->targets = $targets;
0 ignored issues
show
Bug introduced by
The property targets does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
42
            foreach ($this->labels as $label) {
43
                $predictor = clone $classifier;
44
                $targets = $this->binarizeTargets($label);
45
                $predictor->trainBinary($samples, $targets);
46
                $this->classifiers[$label] = $predictor;
47
            }
48
        }
49
    }
50
51
    /**
52
     * Groups all targets into two groups: Targets equal to
53
     * the given label and the others
54
     *
55
     * @param mixed $label
56
     */
57
    private function binarizeTargets($label)
58
    {
59
        $targets = [];
60
61
        foreach ($this->targets as $target) {
62
            $targets[] = $target == $label ? $label : "not_$label";
63
        }
64
65
        return $targets;
66
    }
67
68
69
    /**
70
     * @param array $sample
71
     *
72
     * @return mixed
73
     */
74
    protected function predictSample(array $sample)
75
    {
76
        if (count($this->labels) == 2) {
77
            return $this->classifiers[0]->predictSampleBinary($sample);
78
        }
79
80
        $probs = [];
81
82
        foreach ($this->classifiers as $label => $predictor) {
83
            $probs[$label] = $predictor->predictProbability($sample, $label);
84
        }
85
86
        arsort($probs, SORT_NUMERIC);
87
        return key($probs);
88
    }
89
90
    /**
91
     * Each classifier should implement this method instead of train(samples, targets)
92
     *
93
     * @param array $samples
94
     * @param array $targets
95
     */
96
    abstract protected function trainBinary(array $samples, array $targets);
97
98
    /**
99
     * Each classifier that make use of OvR approach should be able to
100
     * return a probability for a sample to belong to the given label.
101
     *
102
     * @param array $sample
103
     *
104
     * @return mixed
105
     */
106
    abstract protected function predictProbability(array $sample, string $label);
107
108
    /**
109
     * Each classifier should implement this method instead of predictSample()
110
     *
111
     * @param array $sample
112
     *
113
     * @return mixed
114
     */
115
    abstract protected function predictSampleBinary(array $sample);
116
}
117