001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.math3.stat.descriptive; 018 019import java.io.Serializable; 020import java.lang.reflect.InvocationTargetException; 021import java.util.Arrays; 022 023import org.apache.commons.math3.exception.MathIllegalArgumentException; 024import org.apache.commons.math3.exception.NullArgumentException; 025import org.apache.commons.math3.exception.MathIllegalStateException; 026import org.apache.commons.math3.exception.util.LocalizedFormats; 027import org.apache.commons.math3.stat.descriptive.moment.GeometricMean; 028import org.apache.commons.math3.stat.descriptive.moment.Kurtosis; 029import org.apache.commons.math3.stat.descriptive.moment.Mean; 030import org.apache.commons.math3.stat.descriptive.moment.Skewness; 031import org.apache.commons.math3.stat.descriptive.moment.Variance; 032import org.apache.commons.math3.stat.descriptive.rank.Max; 033import org.apache.commons.math3.stat.descriptive.rank.Min; 034import org.apache.commons.math3.stat.descriptive.rank.Percentile; 035import org.apache.commons.math3.stat.descriptive.summary.Sum; 036import org.apache.commons.math3.stat.descriptive.summary.SumOfSquares; 037import org.apache.commons.math3.util.MathUtils; 038import org.apache.commons.math3.util.ResizableDoubleArray; 039import org.apache.commons.math3.util.FastMath; 040 041 042/** 043 * Maintains a dataset of values of a single variable and computes descriptive 044 * statistics based on stored data. The {@link #getWindowSize() windowSize} 045 * property sets a limit on the number of values that can be stored in the 046 * dataset. The default value, INFINITE_WINDOW, puts no limit on the size of 047 * the dataset. This value should be used with caution, as the backing store 048 * will grow without bound in this case. For very large datasets, 049 * {@link SummaryStatistics}, which does not store the dataset, should be used 050 * instead of this class. If <code>windowSize</code> is not INFINITE_WINDOW and 051 * more values are added than can be stored in the dataset, new values are 052 * added in a "rolling" manner, with new values replacing the "oldest" values 053 * in the dataset. 054 * 055 * <p>Note: this class is not threadsafe. Use 056 * {@link SynchronizedDescriptiveStatistics} if concurrent access from multiple 057 * threads is required.</p> 058 * 059 */ 060public class DescriptiveStatistics implements StatisticalSummary, Serializable { 061 062 /** 063 * Represents an infinite window size. When the {@link #getWindowSize()} 064 * returns this value, there is no limit to the number of data values 065 * that can be stored in the dataset. 066 */ 067 public static final int INFINITE_WINDOW = -1; 068 069 /** Serialization UID */ 070 private static final long serialVersionUID = 4133067267405273064L; 071 072 /** Name of the setQuantile method. */ 073 private static final String SET_QUANTILE_METHOD_NAME = "setQuantile"; 074 075 /** hold the window size **/ 076 protected int windowSize = INFINITE_WINDOW; 077 078 /** 079 * Stored data values 080 */ 081 private ResizableDoubleArray eDA = new ResizableDoubleArray(); 082 083 /** Mean statistic implementation - can be reset by setter. */ 084 private UnivariateStatistic meanImpl = new Mean(); 085 086 /** Geometric mean statistic implementation - can be reset by setter. */ 087 private UnivariateStatistic geometricMeanImpl = new GeometricMean(); 088 089 /** Kurtosis statistic implementation - can be reset by setter. */ 090 private UnivariateStatistic kurtosisImpl = new Kurtosis(); 091 092 /** Maximum statistic implementation - can be reset by setter. */ 093 private UnivariateStatistic maxImpl = new Max(); 094 095 /** Minimum statistic implementation - can be reset by setter. */ 096 private UnivariateStatistic minImpl = new Min(); 097 098 /** Percentile statistic implementation - can be reset by setter. */ 099 private UnivariateStatistic percentileImpl = new Percentile(); 100 101 /** Skewness statistic implementation - can be reset by setter. */ 102 private UnivariateStatistic skewnessImpl = new Skewness(); 103 104 /** Variance statistic implementation - can be reset by setter. */ 105 private UnivariateStatistic varianceImpl = new Variance(); 106 107 /** Sum of squares statistic implementation - can be reset by setter. */ 108 private UnivariateStatistic sumsqImpl = new SumOfSquares(); 109 110 /** Sum statistic implementation - can be reset by setter. */ 111 private UnivariateStatistic sumImpl = new Sum(); 112 113 /** 114 * Construct a DescriptiveStatistics instance with an infinite window 115 */ 116 public DescriptiveStatistics() { 117 } 118 119 /** 120 * Construct a DescriptiveStatistics instance with the specified window 121 * 122 * @param window the window size. 123 * @throws MathIllegalArgumentException if window size is less than 1 but 124 * not equal to {@link #INFINITE_WINDOW} 125 */ 126 public DescriptiveStatistics(int window) throws MathIllegalArgumentException { 127 setWindowSize(window); 128 } 129 130 /** 131 * Construct a DescriptiveStatistics instance with an infinite window 132 * and the initial data values in double[] initialDoubleArray. 133 * If initialDoubleArray is null, then this constructor corresponds to 134 * DescriptiveStatistics() 135 * 136 * @param initialDoubleArray the initial double[]. 137 */ 138 public DescriptiveStatistics(double[] initialDoubleArray) { 139 if (initialDoubleArray != null) { 140 eDA = new ResizableDoubleArray(initialDoubleArray); 141 } 142 } 143 144 /** 145 * Copy constructor. Construct a new DescriptiveStatistics instance that 146 * is a copy of original. 147 * 148 * @param original DescriptiveStatistics instance to copy 149 * @throws NullArgumentException if original is null 150 */ 151 public DescriptiveStatistics(DescriptiveStatistics original) throws NullArgumentException { 152 copy(original, this); 153 } 154 155 /** 156 * Adds the value to the dataset. If the dataset is at the maximum size 157 * (i.e., the number of stored elements equals the currently configured 158 * windowSize), the first (oldest) element in the dataset is discarded 159 * to make room for the new value. 160 * 161 * @param v the value to be added 162 */ 163 public void addValue(double v) { 164 if (windowSize != INFINITE_WINDOW) { 165 if (getN() == windowSize) { 166 eDA.addElementRolling(v); 167 } else if (getN() < windowSize) { 168 eDA.addElement(v); 169 } 170 } else { 171 eDA.addElement(v); 172 } 173 } 174 175 /** 176 * Removes the most recent value from the dataset. 177 * 178 * @throws MathIllegalStateException if there are no elements stored 179 */ 180 public void removeMostRecentValue() throws MathIllegalStateException { 181 try { 182 eDA.discardMostRecentElements(1); 183 } catch (MathIllegalArgumentException ex) { 184 throw new MathIllegalStateException(LocalizedFormats.NO_DATA); 185 } 186 } 187 188 /** 189 * Replaces the most recently stored value with the given value. 190 * There must be at least one element stored to call this method. 191 * 192 * @param v the value to replace the most recent stored value 193 * @return replaced value 194 * @throws MathIllegalStateException if there are no elements stored 195 */ 196 public double replaceMostRecentValue(double v) throws MathIllegalStateException { 197 return eDA.substituteMostRecentElement(v); 198 } 199 200 /** 201 * Returns the <a href="http://www.xycoon.com/arithmetic_mean.htm"> 202 * arithmetic mean </a> of the available values 203 * @return The mean or Double.NaN if no values have been added. 204 */ 205 public double getMean() { 206 return apply(meanImpl); 207 } 208 209 /** 210 * Returns the <a href="http://www.xycoon.com/geometric_mean.htm"> 211 * geometric mean </a> of the available values 212 * @return The geometricMean, Double.NaN if no values have been added, 213 * or if the product of the available values is less than or equal to 0. 214 */ 215 public double getGeometricMean() { 216 return apply(geometricMeanImpl); 217 } 218 219 /** 220 * Returns the (sample) variance of the available values. 221 * 222 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in 223 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected 224 * population variance.</p> 225 * 226 * @return The variance, Double.NaN if no values have been added 227 * or 0.0 for a single value set. 228 */ 229 public double getVariance() { 230 return apply(varianceImpl); 231 } 232 233 /** 234 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance"> 235 * population variance</a> of the available values. 236 * 237 * @return The population variance, Double.NaN if no values have been added, 238 * or 0.0 for a single value set. 239 */ 240 public double getPopulationVariance() { 241 return apply(new Variance(false)); 242 } 243 244 /** 245 * Returns the standard deviation of the available values. 246 * @return The standard deviation, Double.NaN if no values have been added 247 * or 0.0 for a single value set. 248 */ 249 public double getStandardDeviation() { 250 double stdDev = Double.NaN; 251 if (getN() > 0) { 252 if (getN() > 1) { 253 stdDev = FastMath.sqrt(getVariance()); 254 } else { 255 stdDev = 0.0; 256 } 257 } 258 return stdDev; 259 } 260 261 /** 262 * Returns the quadratic mean, a.k.a. 263 * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html"> 264 * root-mean-square</a> of the available values 265 * @return The quadratic mean or {@code Double.NaN} if no values 266 * have been added. 267 */ 268 public double getQuadraticMean() { 269 final long n = getN(); 270 return n > 0 ? FastMath.sqrt(getSumsq() / n) : Double.NaN; 271 } 272 273 /** 274 * Returns the skewness of the available values. Skewness is a 275 * measure of the asymmetry of a given distribution. 276 * @return The skewness, Double.NaN if no values have been added 277 * or 0.0 for a value set <=2. 278 */ 279 public double getSkewness() { 280 return apply(skewnessImpl); 281 } 282 283 /** 284 * Returns the Kurtosis of the available values. Kurtosis is a 285 * measure of the "peakedness" of a distribution 286 * @return The kurtosis, Double.NaN if no values have been added, or 0.0 287 * for a value set <=3. 288 */ 289 public double getKurtosis() { 290 return apply(kurtosisImpl); 291 } 292 293 /** 294 * Returns the maximum of the available values 295 * @return The max or Double.NaN if no values have been added. 296 */ 297 public double getMax() { 298 return apply(maxImpl); 299 } 300 301 /** 302 * Returns the minimum of the available values 303 * @return The min or Double.NaN if no values have been added. 304 */ 305 public double getMin() { 306 return apply(minImpl); 307 } 308 309 /** 310 * Returns the number of available values 311 * @return The number of available values 312 */ 313 public long getN() { 314 return eDA.getNumElements(); 315 } 316 317 /** 318 * Returns the sum of the values that have been added to Univariate. 319 * @return The sum or Double.NaN if no values have been added 320 */ 321 public double getSum() { 322 return apply(sumImpl); 323 } 324 325 /** 326 * Returns the sum of the squares of the available values. 327 * @return The sum of the squares or Double.NaN if no 328 * values have been added. 329 */ 330 public double getSumsq() { 331 return apply(sumsqImpl); 332 } 333 334 /** 335 * Resets all statistics and storage 336 */ 337 public void clear() { 338 eDA.clear(); 339 } 340 341 342 /** 343 * Returns the maximum number of values that can be stored in the 344 * dataset, or INFINITE_WINDOW (-1) if there is no limit. 345 * 346 * @return The current window size or -1 if its Infinite. 347 */ 348 public int getWindowSize() { 349 return windowSize; 350 } 351 352 /** 353 * WindowSize controls the number of values that contribute to the 354 * reported statistics. For example, if windowSize is set to 3 and the 355 * values {1,2,3,4,5} have been added <strong> in that order</strong> then 356 * the <i>available values</i> are {3,4,5} and all reported statistics will 357 * be based on these values. If {@code windowSize} is decreased as a result 358 * of this call and there are more than the new value of elements in the 359 * current dataset, values from the front of the array are discarded to 360 * reduce the dataset to {@code windowSize} elements. 361 * 362 * @param windowSize sets the size of the window. 363 * @throws MathIllegalArgumentException if window size is less than 1 but 364 * not equal to {@link #INFINITE_WINDOW} 365 */ 366 public void setWindowSize(int windowSize) throws MathIllegalArgumentException { 367 if (windowSize < 1 && windowSize != INFINITE_WINDOW) { 368 throw new MathIllegalArgumentException( 369 LocalizedFormats.NOT_POSITIVE_WINDOW_SIZE, windowSize); 370 } 371 372 this.windowSize = windowSize; 373 374 // We need to check to see if we need to discard elements 375 // from the front of the array. If the windowSize is less than 376 // the current number of elements. 377 if (windowSize != INFINITE_WINDOW && windowSize < eDA.getNumElements()) { 378 eDA.discardFrontElements(eDA.getNumElements() - windowSize); 379 } 380 } 381 382 /** 383 * Returns the current set of values in an array of double primitives. 384 * The order of addition is preserved. The returned array is a fresh 385 * copy of the underlying data -- i.e., it is not a reference to the 386 * stored data. 387 * 388 * @return returns the current set of numbers in the order in which they 389 * were added to this set 390 */ 391 public double[] getValues() { 392 return eDA.getElements(); 393 } 394 395 /** 396 * Returns the current set of values in an array of double primitives, 397 * sorted in ascending order. The returned array is a fresh 398 * copy of the underlying data -- i.e., it is not a reference to the 399 * stored data. 400 * @return returns the current set of 401 * numbers sorted in ascending order 402 */ 403 public double[] getSortedValues() { 404 double[] sort = getValues(); 405 Arrays.sort(sort); 406 return sort; 407 } 408 409 /** 410 * Returns the element at the specified index 411 * @param index The Index of the element 412 * @return return the element at the specified index 413 */ 414 public double getElement(int index) { 415 return eDA.getElement(index); 416 } 417 418 /** 419 * Returns an estimate for the pth percentile of the stored values. 420 * <p> 421 * The implementation provided here follows the first estimation procedure presented 422 * <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm">here.</a> 423 * </p><p> 424 * <strong>Preconditions</strong>:<ul> 425 * <li><code>0 < p ≤ 100</code> (otherwise an 426 * <code>MathIllegalArgumentException</code> is thrown)</li> 427 * <li>at least one value must be stored (returns <code>Double.NaN 428 * </code> otherwise)</li> 429 * </ul></p> 430 * 431 * @param p the requested percentile (scaled from 0 - 100) 432 * @return An estimate for the pth percentile of the stored data 433 * @throws MathIllegalStateException if percentile implementation has been 434 * overridden and the supplied implementation does not support setQuantile 435 * @throws MathIllegalArgumentException if p is not a valid quantile 436 */ 437 public double getPercentile(double p) throws MathIllegalStateException, MathIllegalArgumentException { 438 if (percentileImpl instanceof Percentile) { 439 ((Percentile) percentileImpl).setQuantile(p); 440 } else { 441 try { 442 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, 443 new Class[] {Double.TYPE}).invoke(percentileImpl, 444 new Object[] {Double.valueOf(p)}); 445 } catch (NoSuchMethodException e1) { // Setter guard should prevent 446 throw new MathIllegalStateException( 447 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD, 448 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME); 449 } catch (IllegalAccessException e2) { 450 throw new MathIllegalStateException( 451 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD, 452 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName()); 453 } catch (InvocationTargetException e3) { 454 throw new IllegalStateException(e3.getCause()); 455 } 456 } 457 return apply(percentileImpl); 458 } 459 460 /** 461 * Generates a text report displaying univariate statistics from values 462 * that have been added. Each statistic is displayed on a separate 463 * line. 464 * 465 * @return String with line feeds displaying statistics 466 */ 467 @Override 468 public String toString() { 469 StringBuilder outBuffer = new StringBuilder(); 470 String endl = "\n"; 471 outBuffer.append("DescriptiveStatistics:").append(endl); 472 outBuffer.append("n: ").append(getN()).append(endl); 473 outBuffer.append("min: ").append(getMin()).append(endl); 474 outBuffer.append("max: ").append(getMax()).append(endl); 475 outBuffer.append("mean: ").append(getMean()).append(endl); 476 outBuffer.append("std dev: ").append(getStandardDeviation()) 477 .append(endl); 478 try { 479 // No catch for MIAE because actual parameter is valid below 480 outBuffer.append("median: ").append(getPercentile(50)).append(endl); 481 } catch (MathIllegalStateException ex) { 482 outBuffer.append("median: unavailable").append(endl); 483 } 484 outBuffer.append("skewness: ").append(getSkewness()).append(endl); 485 outBuffer.append("kurtosis: ").append(getKurtosis()).append(endl); 486 return outBuffer.toString(); 487 } 488 489 /** 490 * Apply the given statistic to the data associated with this set of statistics. 491 * @param stat the statistic to apply 492 * @return the computed value of the statistic. 493 */ 494 public double apply(UnivariateStatistic stat) { 495 // No try-catch or advertised exception here because arguments are guaranteed valid 496 return eDA.compute(stat); 497 } 498 499 // Implementation getters and setter 500 501 /** 502 * Returns the currently configured mean implementation. 503 * 504 * @return the UnivariateStatistic implementing the mean 505 * @since 1.2 506 */ 507 public synchronized UnivariateStatistic getMeanImpl() { 508 return meanImpl; 509 } 510 511 /** 512 * <p>Sets the implementation for the mean.</p> 513 * 514 * @param meanImpl the UnivariateStatistic instance to use 515 * for computing the mean 516 * @since 1.2 517 */ 518 public synchronized void setMeanImpl(UnivariateStatistic meanImpl) { 519 this.meanImpl = meanImpl; 520 } 521 522 /** 523 * Returns the currently configured geometric mean implementation. 524 * 525 * @return the UnivariateStatistic implementing the geometric mean 526 * @since 1.2 527 */ 528 public synchronized UnivariateStatistic getGeometricMeanImpl() { 529 return geometricMeanImpl; 530 } 531 532 /** 533 * <p>Sets the implementation for the gemoetric mean.</p> 534 * 535 * @param geometricMeanImpl the UnivariateStatistic instance to use 536 * for computing the geometric mean 537 * @since 1.2 538 */ 539 public synchronized void setGeometricMeanImpl( 540 UnivariateStatistic geometricMeanImpl) { 541 this.geometricMeanImpl = geometricMeanImpl; 542 } 543 544 /** 545 * Returns the currently configured kurtosis implementation. 546 * 547 * @return the UnivariateStatistic implementing the kurtosis 548 * @since 1.2 549 */ 550 public synchronized UnivariateStatistic getKurtosisImpl() { 551 return kurtosisImpl; 552 } 553 554 /** 555 * <p>Sets the implementation for the kurtosis.</p> 556 * 557 * @param kurtosisImpl the UnivariateStatistic instance to use 558 * for computing the kurtosis 559 * @since 1.2 560 */ 561 public synchronized void setKurtosisImpl(UnivariateStatistic kurtosisImpl) { 562 this.kurtosisImpl = kurtosisImpl; 563 } 564 565 /** 566 * Returns the currently configured maximum implementation. 567 * 568 * @return the UnivariateStatistic implementing the maximum 569 * @since 1.2 570 */ 571 public synchronized UnivariateStatistic getMaxImpl() { 572 return maxImpl; 573 } 574 575 /** 576 * <p>Sets the implementation for the maximum.</p> 577 * 578 * @param maxImpl the UnivariateStatistic instance to use 579 * for computing the maximum 580 * @since 1.2 581 */ 582 public synchronized void setMaxImpl(UnivariateStatistic maxImpl) { 583 this.maxImpl = maxImpl; 584 } 585 586 /** 587 * Returns the currently configured minimum implementation. 588 * 589 * @return the UnivariateStatistic implementing the minimum 590 * @since 1.2 591 */ 592 public synchronized UnivariateStatistic getMinImpl() { 593 return minImpl; 594 } 595 596 /** 597 * <p>Sets the implementation for the minimum.</p> 598 * 599 * @param minImpl the UnivariateStatistic instance to use 600 * for computing the minimum 601 * @since 1.2 602 */ 603 public synchronized void setMinImpl(UnivariateStatistic minImpl) { 604 this.minImpl = minImpl; 605 } 606 607 /** 608 * Returns the currently configured percentile implementation. 609 * 610 * @return the UnivariateStatistic implementing the percentile 611 * @since 1.2 612 */ 613 public synchronized UnivariateStatistic getPercentileImpl() { 614 return percentileImpl; 615 } 616 617 /** 618 * Sets the implementation to be used by {@link #getPercentile(double)}. 619 * The supplied <code>UnivariateStatistic</code> must provide a 620 * <code>setQuantile(double)</code> method; otherwise 621 * <code>IllegalArgumentException</code> is thrown. 622 * 623 * @param percentileImpl the percentileImpl to set 624 * @throws MathIllegalArgumentException if the supplied implementation does not 625 * provide a <code>setQuantile</code> method 626 * @since 1.2 627 */ 628 public synchronized void setPercentileImpl(UnivariateStatistic percentileImpl) 629 throws MathIllegalArgumentException { 630 try { 631 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, 632 new Class[] {Double.TYPE}).invoke(percentileImpl, 633 new Object[] {Double.valueOf(50.0d)}); 634 } catch (NoSuchMethodException e1) { 635 throw new MathIllegalArgumentException( 636 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD, 637 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME); 638 } catch (IllegalAccessException e2) { 639 throw new MathIllegalArgumentException( 640 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD, 641 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName()); 642 } catch (InvocationTargetException e3) { 643 throw new IllegalArgumentException(e3.getCause()); 644 } 645 this.percentileImpl = percentileImpl; 646 } 647 648 /** 649 * Returns the currently configured skewness implementation. 650 * 651 * @return the UnivariateStatistic implementing the skewness 652 * @since 1.2 653 */ 654 public synchronized UnivariateStatistic getSkewnessImpl() { 655 return skewnessImpl; 656 } 657 658 /** 659 * <p>Sets the implementation for the skewness.</p> 660 * 661 * @param skewnessImpl the UnivariateStatistic instance to use 662 * for computing the skewness 663 * @since 1.2 664 */ 665 public synchronized void setSkewnessImpl( 666 UnivariateStatistic skewnessImpl) { 667 this.skewnessImpl = skewnessImpl; 668 } 669 670 /** 671 * Returns the currently configured variance implementation. 672 * 673 * @return the UnivariateStatistic implementing the variance 674 * @since 1.2 675 */ 676 public synchronized UnivariateStatistic getVarianceImpl() { 677 return varianceImpl; 678 } 679 680 /** 681 * <p>Sets the implementation for the variance.</p> 682 * 683 * @param varianceImpl the UnivariateStatistic instance to use 684 * for computing the variance 685 * @since 1.2 686 */ 687 public synchronized void setVarianceImpl( 688 UnivariateStatistic varianceImpl) { 689 this.varianceImpl = varianceImpl; 690 } 691 692 /** 693 * Returns the currently configured sum of squares implementation. 694 * 695 * @return the UnivariateStatistic implementing the sum of squares 696 * @since 1.2 697 */ 698 public synchronized UnivariateStatistic getSumsqImpl() { 699 return sumsqImpl; 700 } 701 702 /** 703 * <p>Sets the implementation for the sum of squares.</p> 704 * 705 * @param sumsqImpl the UnivariateStatistic instance to use 706 * for computing the sum of squares 707 * @since 1.2 708 */ 709 public synchronized void setSumsqImpl(UnivariateStatistic sumsqImpl) { 710 this.sumsqImpl = sumsqImpl; 711 } 712 713 /** 714 * Returns the currently configured sum implementation. 715 * 716 * @return the UnivariateStatistic implementing the sum 717 * @since 1.2 718 */ 719 public synchronized UnivariateStatistic getSumImpl() { 720 return sumImpl; 721 } 722 723 /** 724 * <p>Sets the implementation for the sum.</p> 725 * 726 * @param sumImpl the UnivariateStatistic instance to use 727 * for computing the sum 728 * @since 1.2 729 */ 730 public synchronized void setSumImpl(UnivariateStatistic sumImpl) { 731 this.sumImpl = sumImpl; 732 } 733 734 /** 735 * Returns a copy of this DescriptiveStatistics instance with the same internal state. 736 * 737 * @return a copy of this 738 */ 739 public DescriptiveStatistics copy() { 740 DescriptiveStatistics result = new DescriptiveStatistics(); 741 // No try-catch or advertised exception because parms are guaranteed valid 742 copy(this, result); 743 return result; 744 } 745 746 /** 747 * Copies source to dest. 748 * <p>Neither source nor dest can be null.</p> 749 * 750 * @param source DescriptiveStatistics to copy 751 * @param dest DescriptiveStatistics to copy to 752 * @throws NullArgumentException if either source or dest is null 753 */ 754 public static void copy(DescriptiveStatistics source, DescriptiveStatistics dest) 755 throws NullArgumentException { 756 MathUtils.checkNotNull(source); 757 MathUtils.checkNotNull(dest); 758 // Copy data and window size 759 dest.eDA = source.eDA.copy(); 760 dest.windowSize = source.windowSize; 761 762 // Copy implementations 763 dest.maxImpl = source.maxImpl.copy(); 764 dest.meanImpl = source.meanImpl.copy(); 765 dest.minImpl = source.minImpl.copy(); 766 dest.sumImpl = source.sumImpl.copy(); 767 dest.varianceImpl = source.varianceImpl.copy(); 768 dest.sumsqImpl = source.sumsqImpl.copy(); 769 dest.geometricMeanImpl = source.geometricMeanImpl.copy(); 770 dest.kurtosisImpl = source.kurtosisImpl; 771 dest.skewnessImpl = source.skewnessImpl; 772 dest.percentileImpl = source.percentileImpl; 773 } 774}