1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.stat.descriptive;
23
24 import java.io.Serializable;
25 import java.util.function.DoubleConsumer;
26
27 import org.hipparchus.exception.NullArgumentException;
28 import org.hipparchus.random.RandomGenerator;
29 import org.hipparchus.stat.descriptive.moment.GeometricMean;
30 import org.hipparchus.stat.descriptive.moment.Mean;
31 import org.hipparchus.stat.descriptive.moment.SecondMoment;
32 import org.hipparchus.stat.descriptive.moment.Variance;
33 import org.hipparchus.stat.descriptive.rank.Max;
34 import org.hipparchus.stat.descriptive.rank.Min;
35 import org.hipparchus.stat.descriptive.rank.RandomPercentile;
36 import org.hipparchus.stat.descriptive.summary.Sum;
37 import org.hipparchus.stat.descriptive.summary.SumOfLogs;
38 import org.hipparchus.stat.descriptive.summary.SumOfSquares;
39 import org.hipparchus.util.FastMath;
40 import org.hipparchus.util.MathUtils;
41 import org.hipparchus.util.Precision;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class StreamingStatistics
60 implements StatisticalSummary, AggregatableStatistic<StreamingStatistics>,
61 DoubleConsumer, Serializable {
62
63
64 private static final long serialVersionUID = 20160422L;
65
66
67 private long n;
68
69
70 private final SecondMoment secondMoment;
71
72 private final Min minImpl;
73
74 private final Max maxImpl;
75
76 private final Sum sumImpl;
77
78 private final SumOfSquares sumOfSquaresImpl;
79
80 private final SumOfLogs sumOfLogsImpl;
81
82 private final Mean meanImpl;
83
84 private final Variance varianceImpl;
85
86 private final GeometricMean geoMeanImpl;
87
88 private final Variance populationVariance;
89
90 private final RandomPercentile randomPercentile;
91
92
93 private final boolean computeMoments;
94
95 private final boolean computeSumOfSquares;
96
97 private final boolean computeSumOfLogs;
98
99 private final boolean computeExtrema;
100
101
102
103
104
105 public StreamingStatistics() {
106 this(Double.NaN, null);
107 }
108
109
110
111
112
113
114
115
116
117 public StreamingStatistics(final double epsilon, final RandomGenerator randomGenerator) {
118 this(true, true, true, true, epsilon, randomGenerator);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132 private StreamingStatistics(final boolean computeMoments,
133 final boolean computeSumOfLogs, final boolean computeSumOfSquares,
134 final boolean computeExtrema,
135 final double epsilon, final RandomGenerator randomGenerator) {
136 this.computeMoments = computeMoments;
137 this.computeSumOfLogs = computeSumOfLogs;
138 this.computeSumOfSquares = computeSumOfSquares;
139 this.computeExtrema = computeExtrema;
140
141 this.secondMoment = computeMoments ? new SecondMoment() : null;
142 this.maxImpl = computeExtrema ? new Max() : null;
143 this.minImpl = computeExtrema ? new Min() : null;
144 this.sumImpl = computeMoments ? new Sum() : null;
145 this.sumOfSquaresImpl = computeSumOfSquares ? new SumOfSquares() : null;
146 this.sumOfLogsImpl = computeSumOfLogs ? new SumOfLogs() : null;
147 this.meanImpl = computeMoments ? new Mean(this.secondMoment) : null;
148 this.varianceImpl = computeMoments ? new Variance(this.secondMoment) : null;
149 this.geoMeanImpl = computeSumOfLogs ? new GeometricMean(this.sumOfLogsImpl) : null;
150 this.populationVariance = computeMoments ? new Variance(false, this.secondMoment) : null;
151 this.randomPercentile = randomGenerator == null ? null : new RandomPercentile(epsilon, randomGenerator);
152 }
153
154
155
156
157
158
159
160 StreamingStatistics(StreamingStatistics original) throws NullArgumentException {
161 MathUtils.checkNotNull(original);
162
163 this.n = original.n;
164 this.secondMoment = original.computeMoments ? original.secondMoment.copy() : null;
165 this.maxImpl = original.computeExtrema ? original.maxImpl.copy() : null;
166 this.minImpl = original.computeExtrema ? original.minImpl.copy() : null;
167 this.sumImpl = original.computeMoments ? original.sumImpl.copy() : null;
168 this.sumOfLogsImpl = original.computeSumOfLogs ? original.sumOfLogsImpl.copy() : null;
169 this.sumOfSquaresImpl = original.computeSumOfSquares ? original.sumOfSquaresImpl.copy() : null;
170
171
172 this.meanImpl = original.computeMoments ? new Mean(this.secondMoment) : null;
173 this.varianceImpl = original.computeMoments ? new Variance(this.secondMoment) : null;
174 this.geoMeanImpl = original.computeSumOfLogs ? new GeometricMean(this.sumOfLogsImpl) : null;
175 this.populationVariance = original.computeMoments ? new Variance(false, this.secondMoment) : null;
176 this.randomPercentile = original.randomPercentile != null ? original.randomPercentile.copy() : null;
177
178 this.computeMoments = original.computeMoments;
179 this.computeSumOfLogs = original.computeSumOfLogs;
180 this.computeSumOfSquares = original.computeSumOfSquares;
181 this.computeExtrema = original.computeExtrema;
182 }
183
184
185
186
187
188
189 public StreamingStatistics copy() {
190 return new StreamingStatistics(this);
191 }
192
193
194
195
196
197
198 public StatisticalSummary getSummary() {
199 return new StatisticalSummaryValues(getMean(), getVariance(), getN(),
200 getMax(), getMin(), getSum());
201 }
202
203
204
205
206
207 public void addValue(double value) {
208 if (computeMoments) {
209 secondMoment.increment(value);
210 sumImpl.increment(value);
211 }
212 if (computeExtrema) {
213 minImpl.increment(value);
214 maxImpl.increment(value);
215 }
216 if (computeSumOfSquares) {
217 sumOfSquaresImpl.increment(value);
218 }
219 if (computeSumOfLogs) {
220 sumOfLogsImpl.increment(value);
221 }
222 if (randomPercentile != null) {
223 randomPercentile.increment(value);
224 }
225 n++;
226 }
227
228
229 @Override
230 public void accept(double value) {
231 addValue(value);
232 }
233
234
235
236
237 public void clear() {
238 this.n = 0;
239 if (computeExtrema) {
240 minImpl.clear();
241 maxImpl.clear();
242 }
243 if (computeMoments) {
244 sumImpl.clear();
245 secondMoment.clear();
246 }
247 if (computeSumOfLogs) {
248 sumOfLogsImpl.clear();
249 }
250 if (computeSumOfSquares) {
251 sumOfSquaresImpl.clear();
252 }
253 if (randomPercentile != null) {
254 randomPercentile.clear();
255 }
256 }
257
258
259 @Override
260 public long getN() {
261 return n;
262 }
263
264
265 @Override
266 public double getMax() {
267 return computeExtrema ? maxImpl.getResult() : Double.NaN;
268 }
269
270
271 @Override
272 public double getMin() {
273 return computeExtrema ? minImpl.getResult() : Double.NaN;
274 }
275
276
277 @Override
278 public double getSum() {
279 return computeMoments ? sumImpl.getResult() : Double.NaN;
280 }
281
282
283
284
285
286
287
288
289 public double getSumOfSquares() {
290 return computeSumOfSquares ? sumOfSquaresImpl.getResult() : Double.NaN;
291 }
292
293
294 @Override
295 public double getMean() {
296 return computeMoments ? meanImpl.getResult() : Double.NaN;
297 }
298
299
300 @Override
301 public double getVariance() {
302 return computeMoments ? varianceImpl.getResult() : Double.NaN;
303 }
304
305
306
307
308
309
310
311
312
313 public double getPopulationVariance() {
314 return computeMoments ? populationVariance.getResult() : Double.NaN;
315 }
316
317
318
319
320
321
322
323
324 public double getGeometricMean() {
325 return computeSumOfLogs ? geoMeanImpl.getResult() : Double.NaN;
326 }
327
328
329
330
331
332
333
334
335 public double getSumOfLogs() {
336 return computeSumOfLogs ? sumOfLogsImpl.getResult() : Double.NaN;
337 }
338
339
340
341
342
343
344
345
346
347
348
349 public double getSecondMoment() {
350 return computeMoments ? secondMoment.getResult() : Double.NaN;
351 }
352
353
354
355
356
357
358
359
360
361 public double getQuadraticMean() {
362 if (computeSumOfSquares) {
363 long size = getN();
364 return size > 0 ? FastMath.sqrt(getSumOfSquares() / size) : Double.NaN;
365 } else {
366 return Double.NaN;
367 }
368 }
369
370
371
372
373
374
375
376
377 @Override
378 public double getStandardDeviation() {
379 long size = getN();
380 if (computeMoments) {
381 if (size > 0) {
382 return size > 1 ? FastMath.sqrt(getVariance()) : 0.0;
383 } else {
384 return Double.NaN;
385 }
386 } else {
387 return Double.NaN;
388 }
389 }
390
391
392
393
394
395
396
397
398 public double getMedian() {
399 return randomPercentile != null ? randomPercentile.getResult(50d) : Double.NaN;
400 }
401
402
403
404
405
406
407
408
409
410 public double getPercentile(double percentile) {
411 return randomPercentile == null ? Double.NaN : randomPercentile.getResult(percentile);
412 }
413
414
415
416
417
418
419
420 @Override
421 public void aggregate(StreamingStatistics other) {
422 MathUtils.checkNotNull(other);
423
424 if (other.n > 0) {
425 this.n += other.n;
426 if (computeMoments && other.computeMoments) {
427 this.secondMoment.aggregate(other.secondMoment);
428 this.sumImpl.aggregate(other.sumImpl);
429 }
430 if (computeExtrema && other.computeExtrema) {
431 this.minImpl.aggregate(other.minImpl);
432 this.maxImpl.aggregate(other.maxImpl);
433 }
434 if (computeSumOfLogs && other.computeSumOfLogs) {
435 this.sumOfLogsImpl.aggregate(other.sumOfLogsImpl);
436 }
437 if (computeSumOfSquares && other.computeSumOfSquares) {
438 this.sumOfSquaresImpl.aggregate(other.sumOfSquaresImpl);
439 }
440 if (randomPercentile != null && other.randomPercentile != null) {
441 this.randomPercentile.aggregate(other.randomPercentile);
442 }
443 }
444 }
445
446
447
448
449
450
451
452 @Override
453 public String toString() {
454 StringBuilder outBuffer = new StringBuilder(200);
455 String endl = "\n";
456 outBuffer.append("StreamingStatistics:").append(endl).
457 append("n: ").append(getN()).append(endl).
458 append("min: ").append(getMin()).append(endl).
459 append("max: ").append(getMax()).append(endl).
460 append("sum: ").append(getSum()).append(endl).
461 append("mean: ").append(getMean()).append(endl).
462 append("variance: ").append(getVariance()).append(endl).
463 append("population variance: ").append(getPopulationVariance()).append(endl).
464 append("standard deviation: ").append(getStandardDeviation()).append(endl).
465 append("geometric mean: ").append(getGeometricMean()).append(endl).
466 append("second moment: ").append(getSecondMoment()).append(endl).
467 append("sum of squares: ").append(getSumOfSquares()).append(endl).
468 append("sum of logs: ").append(getSumOfLogs()).append(endl);
469 return outBuffer.toString();
470 }
471
472
473
474
475
476
477
478
479 @Override
480 public boolean equals(Object object) {
481 if (object == this) {
482 return true;
483 }
484 if (!(object instanceof StreamingStatistics)) {
485 return false;
486 }
487 StreamingStatistics other = (StreamingStatistics)object;
488 return other.getN() == getN() &&
489 Precision.equalsIncludingNaN(other.getMax(), getMax()) &&
490 Precision.equalsIncludingNaN(other.getMin(), getMin()) &&
491 Precision.equalsIncludingNaN(other.getSum(), getSum()) &&
492 Precision.equalsIncludingNaN(other.getGeometricMean(), getGeometricMean()) &&
493 Precision.equalsIncludingNaN(other.getMean(), getMean()) &&
494 Precision.equalsIncludingNaN(other.getSumOfSquares(), getSumOfSquares()) &&
495 Precision.equalsIncludingNaN(other.getSumOfLogs(), getSumOfLogs()) &&
496 Precision.equalsIncludingNaN(other.getVariance(), getVariance()) &&
497 Precision.equalsIncludingNaN(other.getMedian(), getMedian());
498 }
499
500
501
502
503
504 @Override
505 public int hashCode() {
506 int result = 31 + MathUtils.hash(getN());
507 result = result * 31 + MathUtils.hash(getMax());
508 result = result * 31 + MathUtils.hash(getMin());
509 result = result * 31 + MathUtils.hash(getSum());
510 result = result * 31 + MathUtils.hash(getGeometricMean());
511 result = result * 31 + MathUtils.hash(getMean());
512 result = result * 31 + MathUtils.hash(getSumOfSquares());
513 result = result * 31 + MathUtils.hash(getSumOfLogs());
514 result = result * 31 + MathUtils.hash(getVariance());
515 result = result * 31 + MathUtils.hash(getMedian());
516 return result;
517 }
518
519
520
521
522
523
524
525 public static StreamingStatisticsBuilder builder() {
526 return new StreamingStatisticsBuilder();
527 }
528
529
530
531
532 public static class StreamingStatisticsBuilder {
533
534 private boolean computeMoments;
535
536 private boolean computeSumOfSquares;
537
538 private boolean computeSumOfLogs;
539
540 private boolean computeExtrema;
541
542
543
544 private double epsilon;
545
546
547
548 private RandomGenerator randomGenerator;
549
550
551
552 public StreamingStatisticsBuilder() {
553 computeMoments = true;
554 computeSumOfSquares = true;
555 computeSumOfLogs = true;
556 computeExtrema = true;
557 percentiles(Double.NaN, null);
558 }
559
560
561
562
563
564
565
566
567 public StreamingStatisticsBuilder moments(boolean arg) {
568 this.computeMoments = arg;
569 return this;
570 }
571
572
573
574
575
576
577
578
579 public StreamingStatisticsBuilder sumOfLogs(boolean arg) {
580 this.computeSumOfLogs = arg;
581 return this;
582 }
583
584
585
586
587
588
589
590
591 public StreamingStatisticsBuilder sumOfSquares(boolean arg) {
592 this.computeSumOfSquares = arg;
593 return this;
594 }
595
596
597
598
599
600
601
602
603 public StreamingStatisticsBuilder percentiles(final double epsilonBound, final RandomGenerator generator) {
604 this.epsilon = epsilonBound;
605 this.randomGenerator = generator;
606 return this;
607 }
608
609
610
611
612
613
614
615
616 public StreamingStatisticsBuilder extrema(boolean arg) {
617 this.computeExtrema = arg;
618 return this;
619 }
620
621
622
623
624
625
626 public StreamingStatistics build() {
627 return new StreamingStatistics(computeMoments,
628 computeSumOfLogs, computeSumOfSquares,
629 computeExtrema,
630 epsilon, randomGenerator);
631 }
632 }
633 }