Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
4.35% |
1 / 23 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
Forecasts | |
4.35% |
1 / 23 |
|
50.00% |
1 / 2 |
49.88 | |
0.00% |
0 / 1 |
getForecastInteval | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
simpleSeasonalForecast | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
42 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Math\Statistic\Forecast |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Math\Statistic\Forecast; |
16 | |
17 | /** |
18 | * General forecasts helper class. |
19 | * |
20 | * @package phpOMS\Math\Statistic\Forecast |
21 | * @license OMS License 2.0 |
22 | * @link https://jingga.app |
23 | * @since 1.0.0 |
24 | */ |
25 | final class Forecasts |
26 | { |
27 | /** |
28 | * Get forecast/prediction interval. |
29 | * |
30 | * @param float $forecast Forecast value |
31 | * @param float $standardDeviation Standard Deviation of forecast |
32 | * @param float $interval Forecast multiplier for prediction intervals |
33 | * |
34 | * @return array<int|float> |
35 | * |
36 | * @since 1.0.0 |
37 | */ |
38 | public static function getForecastInteval(float $forecast, float $standardDeviation, float $interval = 1.96) : array |
39 | { |
40 | return [$forecast - $interval * $standardDeviation, $forecast + $interval * $standardDeviation]; |
41 | } |
42 | |
43 | /** |
44 | * Simple seasonal forecast. |
45 | * |
46 | * @param array<int|float> $history History |
47 | * @param int $periods Number of periods to forecast |
48 | * @param int $seasonality Seasonality |
49 | * |
50 | * @return array<int|float> |
51 | * |
52 | * @since 1.0.0 |
53 | */ |
54 | public static function simpleSeasonalForecast(array $history, int $periods, int $seasonality = 1) : array |
55 | { |
56 | $size = \count($history); |
57 | $avg = \array_sum($history) / $size; |
58 | |
59 | $variance = 0; |
60 | foreach ($history as $sale) { |
61 | $variance += \pow($sale - $avg, 2); |
62 | } |
63 | |
64 | $variance /= $size; |
65 | $stdDeviation = \sqrt($variance); |
66 | |
67 | // Calculate the seasonal index for each period |
68 | $seasonalIndex = []; |
69 | for ($i = 0; $i < $seasonality; ++$i) { |
70 | $seasonalIndex[$i] = 0; |
71 | $count = 0; |
72 | |
73 | for ($j = $i; $j < $size; $j += $seasonality) { |
74 | $seasonalIndex[$i] += $history[$j]; |
75 | ++$count; |
76 | } |
77 | |
78 | if ($count > 0) { |
79 | $seasonalIndex[$i] /= $count; |
80 | $seasonalIndex[$i] /= $avg; |
81 | } |
82 | } |
83 | |
84 | // Forecast the next periods |
85 | $forecast = []; |
86 | for ($i = 1; $i <= $periods; ++$i) { |
87 | $seasonalMultiplier = $seasonalIndex[($i - 1) % $seasonality]; |
88 | $forecast[] = $avg * $seasonalMultiplier + ($stdDeviation * $i); |
89 | } |
90 | |
91 | return $forecast; |
92 | } |
93 | } |