Completed
Push — master ( 240a22...a33d5f )
by Arkadiusz
02:53
created

DecisionTreeLeaf   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 0
dl 0
loc 153
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A evaluate() 0 12 3
A getNodeImpurityDecrease() 0 21 4
C getHTML() 0 36 8
A __toString() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpml\Classification\DecisionTree;
6
7
class DecisionTreeLeaf
8
{
9
    /**
10
     * @var string
11
     */
12
    public $value;
13
14
    /**
15
     * @var int
16
     */
17
    public $columnIndex;
18
19
    /**
20
     * @var DecisionTreeLeaf
21
     */
22
    public $leftLeaf = null;
23
24
    /**
25
     * @var DecisionTreeLeaf
26
     */
27
    public $rightLeaf= null;
28
29
    /**
30
     * @var array
31
     */
32
    public $records = [];
33
34
    /**
35
     * Class value represented by the leaf, this value is non-empty
36
     * only for terminal leaves
37
     *
38
     * @var string
39
     */
40
    public $classValue = '';
41
42
    /**
43
     * @var bool
44
     */
45
    public $isTerminal = false;
46
47
    /**
48
     * @var bool
49
     */
50
    public $isContinuous = false;
51
52
    /**
53
     * @var float
54
     */
55
    public $giniIndex = 0;
56
57
    /**
58
     * @var int
59
     */
60
    public $level = 0;
61
62
    /**
63
     * @param array $record
64
     * @return bool
65
     */
66
    public function evaluate($record)
67
    {
68
        $recordField = $record[$this->columnIndex];
69
        if ($this->isContinuous && preg_match("/^([<>=]{1,2})\s*(.*)/", strval($this->value), $matches)) {
70
            $op = $matches[1];
71
            $value= floatval($matches[2]);
72
            $recordField = strval($recordField);
73
            eval("\$result = $recordField $op $value;");
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
74
            return $result;
0 ignored issues
show
Bug introduced by
The variable $result does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
75
        }
76
        return $recordField == $this->value;
77
    }
78
79
    /**
80
     * Returns Mean Decrease Impurity (MDI) in the node.
81
     * For terminal nodes, this value is equal to 0
82
     *
83
     * @return float
84
     */
85
    public function getNodeImpurityDecrease(int $parentRecordCount)
86
    {
87
        if ($this->isTerminal) {
88
            return 0.0;
89
        }
90
91
        $nodeSampleCount = (float)count($this->records);
92
        $iT = $this->giniIndex;
93
94
        if ($this->leftLeaf) {
95
            $pL = count($this->leftLeaf->records)/$nodeSampleCount;
96
            $iT -= $pL * $this->leftLeaf->giniIndex;
97
        }
98
99
        if ($this->rightLeaf) {
100
            $pR = count($this->rightLeaf->records)/$nodeSampleCount;
101
            $iT -= $pR * $this->rightLeaf->giniIndex;
102
        }
103
104
        return $iT * $nodeSampleCount / $parentRecordCount;
105
    }
106
107
    /**
108
     * Returns HTML representation of the node including children nodes
109
     *
110
     * @param $columnNames
111
     * @return string
112
     */
113
    public function getHTML($columnNames = null)
114
    {
115
        if ($this->isTerminal) {
116
            $value = "<b>$this->classValue</b>";
117
        } else {
118
            $value = $this->value;
119
            if ($columnNames !== null) {
120
                $col = $columnNames[$this->columnIndex];
121
            } else {
122
                $col = "col_$this->columnIndex";
123
            }
124
            if (! preg_match("/^[<>=]{1,2}/", $value)) {
125
                $value = "=$value";
126
            }
127
            $value = "<b>$col $value</b><br>Gini: ". number_format($this->giniIndex, 2);
128
        }
129
        $str = "<table ><tr><td colspan=3 align=center style='border:1px solid;'>
130
				$value</td></tr>";
131
        if ($this->leftLeaf || $this->rightLeaf) {
132
            $str .='<tr>';
133
            if ($this->leftLeaf) {
134
                $str .="<td valign=top><b>| Yes</b><br>" . $this->leftLeaf->getHTML($columnNames) . "</td>";
135
            } else {
136
                $str .='<td></td>';
137
            }
138
            $str .='<td>&nbsp;</td>';
139
            if ($this->rightLeaf) {
140
                $str .="<td valign=top align=right><b>No |</b><br>" . $this->rightLeaf->getHTML($columnNames) . "</td>";
141
            } else {
142
                $str .='<td></td>';
143
            }
144
            $str .= '</tr>';
145
        }
146
        $str .= '</table>';
147
        return $str;
148
    }
149
150
    /**
151
     * HTML representation of the tree without column names
152
     *
153
     * @return string
154
     */
155
    public function __toString()
156
    {
157
        return $this->getHTML();
158
    }
159
}
160