Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
<?php

declare(strict_types=1);

namespace Phpml\Classification\DecisionTree;

use Phpml\Math\Comparison;

class DecisionTreeLeaf
{
    /**
     * @var string|int
     */
    public $value;

    /**
     * @var float
     */
    public $numericValue;

    /**
     * @var string
     */
    public $operator;

    /**
     * @var int
     */
    public $columnIndex;

    /**
     * @var DecisionTreeLeaf|null
     */
    public $leftLeaf;

    /**
     * @var DecisionTreeLeaf|null
     */
    public $rightLeaf;

    /**
     * @var array
     */
    public $records = [];

    /**
     * Class value represented by the leaf, this value is non-empty
     * only for terminal leaves
     *
     * @var string
     */
    public $classValue = '';

    /**
     * @var bool
     */
    public $isTerminal = false;

    /**
     * @var bool
     */
    public $isContinuous = false;

    /**
     * @var float
     */
    public $giniIndex = 0;

    /**
     * @var int
     */
    public $level = 0;

    /**
     * HTML representation of the tree without column names
     */
    public function __toString(): string
    {
        return $this->getHTML();
    }

    public function evaluate(array $record): bool
    {
        $recordField = $record[$this->columnIndex];

        if ($this->isContinuous) {
            return Comparison::compare((string) $recordField, $this->numericValue, $this->operator);
        }

        return $recordField == $this->value;
    }

    /**
     * Returns Mean Decrease Impurity (MDI) in the node.
     * For terminal nodes, this value is equal to 0
     */
    public function getNodeImpurityDecrease(int $parentRecordCount): float
    {
        if ($this->isTerminal) {
            return 0.0;
        }

        $nodeSampleCount = (float) count($this->records);
        $iT = $this->giniIndex;

        if ($this->leftLeaf !== null) {
            $pL = count($this->leftLeaf->records) / $nodeSampleCount;
            $iT -= $pL * $this->leftLeaf->giniIndex;
        }

        if ($this->rightLeaf !== null) {
            $pR = count($this->rightLeaf->records) / $nodeSampleCount;
            $iT -= $pR * $this->rightLeaf->giniIndex;
        }

        return $iT * $nodeSampleCount / $parentRecordCount;
    }

    /**
     * Returns HTML representation of the node including children nodes
     */
    public function getHTML(?array $columnNames = null): string
    {
        if ($this->isTerminal) {
< $value = "<b>${this}->classValue</b>";
> $value = "<b>{$this}->classValue</b>";
} else { $value = $this->value; if ($columnNames !== null) { $col = $columnNames[$this->columnIndex]; } else { $col = "col_$this->columnIndex"; } if ((bool) preg_match('/^[<>=]{1,2}/', (string) $value) === false) {
< $value = "=${value}";
> $value = "={$value}";
}
< $value = "<b>${col} ${value}</b><br>Gini: ".number_format($this->giniIndex, 2);
> $value = "<b>{$col} {$value}</b><br>Gini: ".number_format($this->giniIndex, 2);
}
< $str = "<table ><tr><td colspan=3 align=center style='border:1px solid;'>${value}</td></tr>";
> $str = "<table ><tr><td colspan=3 align=center style='border:1px solid;'>{$value}</td></tr>";
if ($this->leftLeaf !== null || $this->rightLeaf !== null) { $str .= '<tr>'; if ($this->leftLeaf !== null) { $str .= '<td valign=top><b>| Yes</b><br>'.$this->leftLeaf->getHTML($columnNames).'</td>'; } else { $str .= '<td></td>'; } $str .= '<td>&nbsp;</td>'; if ($this->rightLeaf !== null) { $str .= '<td valign=top align=right><b>No |</b><br>'.$this->rightLeaf->getHTML($columnNames).'</td>'; } else { $str .= '<td></td>'; } $str .= '</tr>'; } $str .= '</table>'; return $str; } }