]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - vendor/wikimedia/running-stat/src/RunningStat.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / vendor / wikimedia / running-stat / src / RunningStat.php
1 <?php
2 /**
3  * RunningStat
4  *
5  * Compute running mean, variance, and extrema of a stream of numbers.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  * http://www.gnu.org/copyleft/gpl.html
21  *
22  * @file
23  * @author Ori Livneh <ori@wikimedia.org>
24  */
25
26 namespace RunningStat;
27
28 // Needed due to PHP non-bug <https://bugs.php.net/bug.php?id=49828>.
29 define( 'RUNNINGSTAT_NEGATIVE_INF', -INF );
30
31 /**
32  * Represents a running summary of a stream of numbers.
33  *
34  * RunningStat instances are accumulator-like objects that provide a set of
35  * continuously-updated summary statistics for a stream of numbers, without
36  * requiring that each value be stored. The measures it provides are the
37  * arithmetic mean, variance, standard deviation, and extrema (min and max);
38  * together they describe the central tendency and statistical dispersion of a
39  * set of values.
40  *
41  * One RunningStat instance can be merged into another; the resultant
42  * RunningStat has the state it would have had if it had accumulated each
43  * individual point. This allows data to be summarized in parallel and in
44  * stages without loss of fidelity.
45  *
46  * Based on a C++ implementation by John D. Cook:
47  *  <http://www.johndcook.com/standard_deviation.html>
48  *  <http://www.johndcook.com/skewness_kurtosis.html>
49  *
50  * The in-line documentation for this class incorporates content from the
51  * English Wikipedia articles "Variance", "Algorithms for calculating
52  * variance", and "Standard deviation".
53  */
54 class RunningStat {
55
56         /** @var int Number of samples. **/
57         public $n = 0;
58
59         /** @var float The first moment (or mean, or expected value). **/
60         public $m1 = 0.0;
61
62         /** @var float The second central moment (or variance). **/
63         public $m2 = 0.0;
64
65         /** @var float The least value in the set. **/
66         public $min = INF;
67
68         /** @var float The greatest value in the set. **/
69         public $max = RUNNINGSTAT_NEGATIVE_INF;
70
71         /**
72          * Count the number of accumulated values.
73          * @return int
74          */
75         public function getCount() {
76                 return $this->n;
77         }
78
79         /**
80          * Add a number to the data set.
81          * @param int|float $x Value to add
82          */
83         public function addObservation( $x ) {
84                 $x = (float) $x;
85
86                 $this->min = min( $this->min, $x );
87                 $this->max = max( $this->max, $x );
88
89                 $n1 = $this->n;
90                 $this->n += 1;
91                 $delta = $x - $this->m1;
92                 $delta_n = $delta / $this->n;
93                 $this->m1 += $delta_n;
94                 $this->m2 += $delta * $delta_n * $n1;
95         }
96
97         /**
98          * Get the mean, or expected value.
99          *
100          * The arithmetic mean is the sum of all measurements divided by the number
101          * of observations in the data set.
102          *
103          * @return float
104          */
105         public function getMean() {
106                 return $this->m1;
107         }
108
109         /**
110          * Get the estimated variance.
111          *
112          * Variance measures how far a set of numbers is spread out. A small
113          * variance indicates that the data points tend to be very close to the
114          * mean (and hence to each other), while a high variance indicates that the
115          * data points are very spread out from the mean and from each other.
116          *
117          * @return float Estimated variance
118          */
119         public function getVariance() {
120                 if ( $this->n === 0 ) {
121                         // The variance of the empty set is undefined.
122                         return NAN;
123                 } elseif ( $this->n === 1 ) {
124                         return 0.0;
125                 } else {
126                         return $this->m2 / ( $this->n - 1.0 );
127                 }
128         }
129
130         /**
131          * Get the estimated standard deviation.
132          *
133          * The standard deviation of a statistical population is the square root of
134          * its variance. It shows how much variation from the mean exists. In
135          * addition to expressing the variability of a population, the standard
136          * deviation is commonly used to measure confidence in statistical conclusions.
137          *
138          * @return float Estimated standard deviation
139          */
140         public function getStdDev() {
141                 return sqrt( $this->getVariance() );
142         }
143
144         /**
145          * Merge another RunningStat instance into this instance.
146          *
147          * This instance then has the state it would have had if all the data had
148          * been accumulated by it alone.
149          *
150          * @param RunningStat RunningStat instance to merge into this one
151          */
152         public function merge( RunningStat $other ) {
153                 // If the other RunningStat is empty, there's nothing to do.
154                 if ( $other->n === 0 ) {
155                         return;
156                 }
157
158                 // If this RunningStat is empty, copy values from other RunningStat.
159                 if ( $this->n === 0 ) {
160                         $this->n = $other->n;
161                         $this->m1 = $other->m1;
162                         $this->m2 = $other->m2;
163                         $this->min = $other->min;
164                         $this->max = $other->max;
165                         return;
166                 }
167
168                 $n = $this->n + $other->n;
169                 $delta = $other->m1 - $this->m1;
170                 $delta2 = $delta * $delta;
171
172                 $this->m1 = ( ( $this->n * $this->m1 ) + ( $other->n * $other->m1 ) ) / $n;
173                 $this->m2 = $this->m2 + $other->m2 + ( $delta2 * $this->n * $other->n / $n );
174                 $this->min = min( $this->min, $other->min );
175                 $this->max = max( $this->max, $other->max );
176                 $this->n = $n;
177         }
178 }