Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
RegressionAbstract
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
6 / 6
11
100.00% covered (success)
100.00%
1 / 1
 getRegression
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getStandardErrorOfRegressionPopulation
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getStandardErrorOfRegressionSample
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getPredictionIntervalMSE
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getBeta1
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 getBeta0
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSlope
n/a
0 / 0
n/a
0 / 0
0
 getElasticity
n/a
0 / 0
n/a
0 / 0
0
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Math\Statistic\Forecast\Regression
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Math\Statistic\Forecast\Regression;
16
17use phpOMS\Math\Matrix\Exception\InvalidDimensionException;
18use phpOMS\Math\Statistic\Average;
19
20/**
21 * Regression abstract class.
22 *
23 * @package phpOMS\Math\Statistic\Forecast\Regression
24 * @license OMS License 2.0
25 * @link    https://jingga.app
26 * @since   1.0.0
27 */
28abstract class RegressionAbstract
29{
30    /**
31     * Get linear regression based on scatter plot.
32     *
33     * @latex y = b_{0} + b_{1} \cdot x
34     *
35     * @param array<int|float> $x Obersved x values
36     * @param array<int|float> $y Observed y values
37     *
38     * @return array [b0 => ?, b1 => ?]
39     *
40     * @throws InvalidDimensionException throws this exception if the dimension of both arrays is not equal
41     *
42     * @since 1.0.0
43     */
44    public static function getRegression(array $x, array $y) : array
45    {
46        if (\count($x) !== \count($y)) {
47            throw new InvalidDimensionException(\count($x) . 'x' . \count($y));
48        }
49
50        $b1 = self::getBeta1($x, $y);
51
52        return ['b0' => self::getBeta0($x, $y, $b1), 'b1' => $b1];
53    }
54
55    /**
56     * Standard error of the regression for a population
57     *
58     * Used in order to evaluate the performance of the linear regression
59     *
60     * @latex s_{e} = \sqrt{\frac{1}{N - 2}\sum_{i = 1}^{N} e_{i}^{2}}
61     *
62     * @param array<int|float> $errors Errors (e = y - y_forecasted)
63     *
64     * @return float
65     *
66     * @since 1.0.0
67     */
68    public static function getStandardErrorOfRegressionPopulation(array $errors) : float
69    {
70        $count = \count($errors);
71        $sum   = 0.0;
72
73        for ($i = 0; $i < $count; ++$i) {
74            $sum += $errors[$i] ** 2;
75        }
76
77        return \sqrt($sum / $count);
78    }
79
80    /**
81     * Standard error of the regression for a sample
82     *
83     * Used in order to evaluate the performance of the linear regression
84     *
85     * @latex s_{e} = \sqrt{\frac{1}{N - 2}\sum_{i = 1}^{N} e_{i}^{2}}
86     *
87     * @param array<int|float> $errors Errors (e = y - y_forecasted)
88     *
89     * @return float
90     *
91     * @since 1.0.0
92     */
93    public static function getStandardErrorOfRegressionSample(array $errors) : float
94    {
95        $count = \count($errors);
96        $sum   = 0.0;
97
98        for ($i = 0; $i < $count; ++$i) {
99            $sum += $errors[$i] ** 2;
100        }
101
102        return \sqrt($sum / ($count - 2));
103    }
104
105    /**
106     * Get predictional interval for linear regression.
107     *
108     * @latex
109     *
110     * @param float            $fX         Forecasted at x value
111     * @param float            $fY         Forecasted y value
112     * @param array<int|float> $x          observex x values
113     * @param float            $mse        Errors for y values (y - y_forecasted)
114     * @param float            $multiplier Multiplier for interval
115     *
116     * @return array<int|float>
117     *
118     * @since 1.0.0
119     */
120    public static function getPredictionIntervalMSE(float $fX, float $fY, array $x, float $mse, float $multiplier = 1.96) : array
121    {
122        $count = \count($x);
123        $meanX = Average::arithmeticMean($x);
124        $sum   = 0.0;
125
126        for ($i = 0; $i < $count; ++$i) {
127            $sum += ($x[$i] - $meanX) ** 2;
128        }
129
130        $interval = $multiplier * \sqrt($mse + $mse / $count + $mse * ($fX - $meanX) ** 2 / $sum);
131
132        return [$fY - $interval, $fY + $interval];
133    }
134
135    /**
136     * Get linear regression parameter beta 1.
137     *
138     * @latex \beta_{1} = \frac{\sum_{i=1}^{N} \left(y_{i} - \bar{y}\right)\left(x_{i} - \bar{x}\right)}{\sum_{i=1}^{N} \left(x_{i} - \bar{x}\right)^{2}}
139     *
140     * @param array<int|float> $x Obersved x values
141     * @param array<int|float> $y Observed y values
142     *
143     * @return float
144     *
145     * @since 1.0.0
146     */
147    private static function getBeta1(array $x, array $y) : float
148    {
149        $count = \count($x);
150        $meanX = Average::arithmeticMean($x);
151        $meanY = Average::arithmeticMean($y);
152
153        $sum1 = 0;
154        $sum2 = 0;
155
156        for ($i = 0; $i < $count; ++$i) {
157            $sum1 += ($y[$i] - $meanY) * ($x[$i] - $meanX);
158            $sum2 += ($x[$i] - $meanX) ** 2;
159        }
160
161        return $sum1 / $sum2;
162    }
163
164    /**
165     * Get linear regression parameter beta 0.
166     *
167     * @latex \beta_{0} = \bar{x} - b_{1} \cdot \bar{x}
168     *
169     * @param array<int|float> $x  Obersved x values
170     * @param array<int|float> $y  Observed y values
171     * @param float            $b1 Beta 1
172     *
173     * @return float
174     *
175     * @since 1.0.0
176     */
177    private static function getBeta0(array $x, array $y, float $b1) : float
178    {
179        return Average::arithmeticMean($y) - $b1 * Average::arithmeticMean($x);
180    }
181
182    /**
183     * Get slope
184     *
185     * @param float $b1 Beta 1
186     * @param float $x  Obersved x values
187     * @param float $y  Observed y values
188     *
189     * @return float
190     *
191     * @since 1.0.0
192     */
193    abstract public static function getSlope(float $b1, float $x, float $y) : float;
194
195    /**
196     * Get elasticity
197     *
198     * @param float $b1 Beta 1
199     * @param float $x  Obersved x values
200     * @param float $y  Observed y values
201     *
202     * @return float
203     *
204     * @since 1.0.0
205     */
206    abstract public static function getElasticity(float $b1, float $x, float $y) : float;
207}