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 * <p> 213 * See {@link GeometricMean} for details on the computing algorithm.</p> 214 * 215 * @return The geometricMean, Double.NaN if no values have been added, 216 * or if any negative values have been added. 217 */ 218 public double getGeometricMean() { 219 return apply(geometricMeanImpl); 220 } 221 222 /** 223 * Returns the (sample) variance of the available values. 224 * 225 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in 226 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected 227 * population variance.</p> 228 * 229 * @return The variance, Double.NaN if no values have been added 230 * or 0.0 for a single value set. 231 */ 232 public double getVariance() { 233 return apply(varianceImpl); 234 } 235 236 /** 237 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance"> 238 * population variance</a> of the available values. 239 * 240 * @return The population variance, Double.NaN if no values have been added, 241 * or 0.0 for a single value set. 242 */ 243 public double getPopulationVariance() { 244 return apply(new Variance(false)); 245 } 246 247 /** 248 * Returns the standard deviation of the available values. 249 * @return The standard deviation, Double.NaN if no values have been added 250 * or 0.0 for a single value set. 251 */ 252 public double getStandardDeviation() { 253 double stdDev = Double.NaN; 254 if (getN() > 0) { 255 if (getN() > 1) { 256 stdDev = FastMath.sqrt(getVariance()); 257 } else { 258 stdDev = 0.0; 259 } 260 } 261 return stdDev; 262 } 263 264 /** 265 * Returns the quadratic mean, a.k.a. 266 * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html"> 267 * root-mean-square</a> of the available values 268 * @return The quadratic mean or {@code Double.NaN} if no values 269 * have been added. 270 */ 271 public double getQuadraticMean() { 272 final long n = getN(); 273 return n > 0 ? FastMath.sqrt(getSumsq() / n) : Double.NaN; 274 } 275 276 /** 277 * Returns the skewness of the available values. Skewness is a 278 * measure of the asymmetry of a given distribution. 279 * 280 * @return The skewness, Double.NaN if less than 3 values have been added. 281 */ 282 public double getSkewness() { 283 return apply(skewnessImpl); 284 } 285 286 /** 287 * Returns the Kurtosis of the available values. Kurtosis is a 288 * measure of the "peakedness" of a distribution. 289 * 290 * @return The kurtosis, Double.NaN if less than 4 values have been added. 291 */ 292 public double getKurtosis() { 293 return apply(kurtosisImpl); 294 } 295 296 /** 297 * Returns the maximum of the available values 298 * @return The max or Double.NaN if no values have been added. 299 */ 300 public double getMax() { 301 return apply(maxImpl); 302 } 303 304 /** 305 * Returns the minimum of the available values 306 * @return The min or Double.NaN if no values have been added. 307 */ 308 public double getMin() { 309 return apply(minImpl); 310 } 311 312 /** 313 * Returns the number of available values 314 * @return The number of available values 315 */ 316 public long getN() { 317 return eDA.getNumElements(); 318 } 319 320 /** 321 * Returns the sum of the values that have been added to Univariate. 322 * @return The sum or Double.NaN if no values have been added 323 */ 324 public double getSum() { 325 return apply(sumImpl); 326 } 327 328 /** 329 * Returns the sum of the squares of the available values. 330 * @return The sum of the squares or Double.NaN if no 331 * values have been added. 332 */ 333 public double getSumsq() { 334 return apply(sumsqImpl); 335 } 336 337 /** 338 * Resets all statistics and storage 339 */ 340 public void clear() { 341 eDA.clear(); 342 } 343 344 345 /** 346 * Returns the maximum number of values that can be stored in the 347 * dataset, or INFINITE_WINDOW (-1) if there is no limit. 348 * 349 * @return The current window size or -1 if its Infinite. 350 */ 351 public int getWindowSize() { 352 return windowSize; 353 } 354 355 /** 356 * WindowSize controls the number of values that contribute to the 357 * reported statistics. For example, if windowSize is set to 3 and the 358 * values {1,2,3,4,5} have been added <strong> in that order</strong> then 359 * the <i>available values</i> are {3,4,5} and all reported statistics will 360 * be based on these values. If {@code windowSize} is decreased as a result 361 * of this call and there are more than the new value of elements in the 362 * current dataset, values from the front of the array are discarded to 363 * reduce the dataset to {@code windowSize} elements. 364 * 365 * @param windowSize sets the size of the window. 366 * @throws MathIllegalArgumentException if window size is less than 1 but 367 * not equal to {@link #INFINITE_WINDOW} 368 */ 369 public void setWindowSize(int windowSize) throws MathIllegalArgumentException { 370 if (windowSize < 1 && windowSize != INFINITE_WINDOW) { 371 throw new MathIllegalArgumentException( 372 LocalizedFormats.NOT_POSITIVE_WINDOW_SIZE, windowSize); 373 } 374 375 this.windowSize = windowSize; 376 377 // We need to check to see if we need to discard elements 378 // from the front of the array. If the windowSize is less than 379 // the current number of elements. 380 if (windowSize != INFINITE_WINDOW && windowSize < eDA.getNumElements()) { 381 eDA.discardFrontElements(eDA.getNumElements() - windowSize); 382 } 383 } 384 385 /** 386 * Returns the current set of values in an array of double primitives. 387 * The order of addition is preserved. The returned array is a fresh 388 * copy of the underlying data -- i.e., it is not a reference to the 389 * stored data. 390 * 391 * @return returns the current set of numbers in the order in which they 392 * were added to this set 393 */ 394 public double[] getValues() { 395 return eDA.getElements(); 396 } 397 398 /** 399 * Returns the current set of values in an array of double primitives, 400 * sorted in ascending order. The returned array is a fresh 401 * copy of the underlying data -- i.e., it is not a reference to the 402 * stored data. 403 * @return returns the current set of 404 * numbers sorted in ascending order 405 */ 406 public double[] getSortedValues() { 407 double[] sort = getValues(); 408 Arrays.sort(sort); 409 return sort; 410 } 411 412 /** 413 * Returns the element at the specified index 414 * @param index The Index of the element 415 * @return return the element at the specified index 416 */ 417 public double getElement(int index) { 418 return eDA.getElement(index); 419 } 420 421 /** 422 * Returns an estimate for the pth percentile of the stored values. 423 * <p> 424 * The implementation provided here follows the first estimation procedure presented 425 * <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm">here.</a> 426 * </p><p> 427 * <strong>Preconditions</strong>:<ul> 428 * <li><code>0 < p ≤ 100</code> (otherwise an 429 * <code>MathIllegalArgumentException</code> is thrown)</li> 430 * <li>at least one value must be stored (returns <code>Double.NaN 431 * </code> otherwise)</li> 432 * </ul></p> 433 * 434 * @param p the requested percentile (scaled from 0 - 100) 435 * @return An estimate for the pth percentile of the stored data 436 * @throws MathIllegalStateException if percentile implementation has been 437 * overridden and the supplied implementation does not support setQuantile 438 * @throws MathIllegalArgumentException if p is not a valid quantile 439 */ 440 public double getPercentile(double p) throws MathIllegalStateException, MathIllegalArgumentException { 441 if (percentileImpl instanceof Percentile) { 442 ((Percentile) percentileImpl).setQuantile(p); 443 } else { 444 try { 445 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, 446 new Class[] {Double.TYPE}).invoke(percentileImpl, 447 new Object[] {Double.valueOf(p)}); 448 } catch (NoSuchMethodException e1) { // Setter guard should prevent 449 throw new MathIllegalStateException( 450 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD, 451 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME); 452 } catch (IllegalAccessException e2) { 453 throw new MathIllegalStateException( 454 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD, 455 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName()); 456 } catch (InvocationTargetException e3) { 457 throw new IllegalStateException(e3.getCause()); 458 } 459 } 460 return apply(percentileImpl); 461 } 462 463 /** 464 * Generates a text report displaying univariate statistics from values 465 * that have been added. Each statistic is displayed on a separate 466 * line. 467 * 468 * @return String with line feeds displaying statistics 469 */ 470 @Override 471 public String toString() { 472 StringBuilder outBuffer = new StringBuilder(); 473 String endl = "\n"; 474 outBuffer.append("DescriptiveStatistics:").append(endl); 475 outBuffer.append("n: ").append(getN()).append(endl); 476 outBuffer.append("min: ").append(getMin()).append(endl); 477 outBuffer.append("max: ").append(getMax()).append(endl); 478 outBuffer.append("mean: ").append(getMean()).append(endl); 479 outBuffer.append("std dev: ").append(getStandardDeviation()) 480 .append(endl); 481 try { 482 // No catch for MIAE because actual parameter is valid below 483 outBuffer.append("median: ").append(getPercentile(50)).append(endl); 484 } catch (MathIllegalStateException ex) { 485 outBuffer.append("median: unavailable").append(endl); 486 } 487 outBuffer.append("skewness: ").append(getSkewness()).append(endl); 488 outBuffer.append("kurtosis: ").append(getKurtosis()).append(endl); 489 return outBuffer.toString(); 490 } 491 492 /** 493 * Apply the given statistic to the data associated with this set of statistics. 494 * @param stat the statistic to apply 495 * @return the computed value of the statistic. 496 */ 497 public double apply(UnivariateStatistic stat) { 498 // No try-catch or advertised exception here because arguments are guaranteed valid 499 return eDA.compute(stat); 500 } 501 502 // Implementation getters and setter 503 504 /** 505 * Returns the currently configured mean implementation. 506 * 507 * @return the UnivariateStatistic implementing the mean 508 * @since 1.2 509 */ 510 public synchronized UnivariateStatistic getMeanImpl() { 511 return meanImpl; 512 } 513 514 /** 515 * <p>Sets the implementation for the mean.</p> 516 * 517 * @param meanImpl the UnivariateStatistic instance to use 518 * for computing the mean 519 * @since 1.2 520 */ 521 public synchronized void setMeanImpl(UnivariateStatistic meanImpl) { 522 this.meanImpl = meanImpl; 523 } 524 525 /** 526 * Returns the currently configured geometric mean implementation. 527 * 528 * @return the UnivariateStatistic implementing the geometric mean 529 * @since 1.2 530 */ 531 public synchronized UnivariateStatistic getGeometricMeanImpl() { 532 return geometricMeanImpl; 533 } 534 535 /** 536 * <p>Sets the implementation for the gemoetric mean.</p> 537 * 538 * @param geometricMeanImpl the UnivariateStatistic instance to use 539 * for computing the geometric mean 540 * @since 1.2 541 */ 542 public synchronized void setGeometricMeanImpl( 543 UnivariateStatistic geometricMeanImpl) { 544 this.geometricMeanImpl = geometricMeanImpl; 545 } 546 547 /** 548 * Returns the currently configured kurtosis implementation. 549 * 550 * @return the UnivariateStatistic implementing the kurtosis 551 * @since 1.2 552 */ 553 public synchronized UnivariateStatistic getKurtosisImpl() { 554 return kurtosisImpl; 555 } 556 557 /** 558 * <p>Sets the implementation for the kurtosis.</p> 559 * 560 * @param kurtosisImpl the UnivariateStatistic instance to use 561 * for computing the kurtosis 562 * @since 1.2 563 */ 564 public synchronized void setKurtosisImpl(UnivariateStatistic kurtosisImpl) { 565 this.kurtosisImpl = kurtosisImpl; 566 } 567 568 /** 569 * Returns the currently configured maximum implementation. 570 * 571 * @return the UnivariateStatistic implementing the maximum 572 * @since 1.2 573 */ 574 public synchronized UnivariateStatistic getMaxImpl() { 575 return maxImpl; 576 } 577 578 /** 579 * <p>Sets the implementation for the maximum.</p> 580 * 581 * @param maxImpl the UnivariateStatistic instance to use 582 * for computing the maximum 583 * @since 1.2 584 */ 585 public synchronized void setMaxImpl(UnivariateStatistic maxImpl) { 586 this.maxImpl = maxImpl; 587 } 588 589 /** 590 * Returns the currently configured minimum implementation. 591 * 592 * @return the UnivariateStatistic implementing the minimum 593 * @since 1.2 594 */ 595 public synchronized UnivariateStatistic getMinImpl() { 596 return minImpl; 597 } 598 599 /** 600 * <p>Sets the implementation for the minimum.</p> 601 * 602 * @param minImpl the UnivariateStatistic instance to use 603 * for computing the minimum 604 * @since 1.2 605 */ 606 public synchronized void setMinImpl(UnivariateStatistic minImpl) { 607 this.minImpl = minImpl; 608 } 609 610 /** 611 * Returns the currently configured percentile implementation. 612 * 613 * @return the UnivariateStatistic implementing the percentile 614 * @since 1.2 615 */ 616 public synchronized UnivariateStatistic getPercentileImpl() { 617 return percentileImpl; 618 } 619 620 /** 621 * Sets the implementation to be used by {@link #getPercentile(double)}. 622 * The supplied <code>UnivariateStatistic</code> must provide a 623 * <code>setQuantile(double)</code> method; otherwise 624 * <code>IllegalArgumentException</code> is thrown. 625 * 626 * @param percentileImpl the percentileImpl to set 627 * @throws MathIllegalArgumentException if the supplied implementation does not 628 * provide a <code>setQuantile</code> method 629 * @since 1.2 630 */ 631 public synchronized void setPercentileImpl(UnivariateStatistic percentileImpl) 632 throws MathIllegalArgumentException { 633 try { 634 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, 635 new Class[] {Double.TYPE}).invoke(percentileImpl, 636 new Object[] {Double.valueOf(50.0d)}); 637 } catch (NoSuchMethodException e1) { 638 throw new MathIllegalArgumentException( 639 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD, 640 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME); 641 } catch (IllegalAccessException e2) { 642 throw new MathIllegalArgumentException( 643 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD, 644 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName()); 645 } catch (InvocationTargetException e3) { 646 throw new IllegalArgumentException(e3.getCause()); 647 } 648 this.percentileImpl = percentileImpl; 649 } 650 651 /** 652 * Returns the currently configured skewness implementation. 653 * 654 * @return the UnivariateStatistic implementing the skewness 655 * @since 1.2 656 */ 657 public synchronized UnivariateStatistic getSkewnessImpl() { 658 return skewnessImpl; 659 } 660 661 /** 662 * <p>Sets the implementation for the skewness.</p> 663 * 664 * @param skewnessImpl the UnivariateStatistic instance to use 665 * for computing the skewness 666 * @since 1.2 667 */ 668 public synchronized void setSkewnessImpl( 669 UnivariateStatistic skewnessImpl) { 670 this.skewnessImpl = skewnessImpl; 671 } 672 673 /** 674 * Returns the currently configured variance implementation. 675 * 676 * @return the UnivariateStatistic implementing the variance 677 * @since 1.2 678 */ 679 public synchronized UnivariateStatistic getVarianceImpl() { 680 return varianceImpl; 681 } 682 683 /** 684 * <p>Sets the implementation for the variance.</p> 685 * 686 * @param varianceImpl the UnivariateStatistic instance to use 687 * for computing the variance 688 * @since 1.2 689 */ 690 public synchronized void setVarianceImpl( 691 UnivariateStatistic varianceImpl) { 692 this.varianceImpl = varianceImpl; 693 } 694 695 /** 696 * Returns the currently configured sum of squares implementation. 697 * 698 * @return the UnivariateStatistic implementing the sum of squares 699 * @since 1.2 700 */ 701 public synchronized UnivariateStatistic getSumsqImpl() { 702 return sumsqImpl; 703 } 704 705 /** 706 * <p>Sets the implementation for the sum of squares.</p> 707 * 708 * @param sumsqImpl the UnivariateStatistic instance to use 709 * for computing the sum of squares 710 * @since 1.2 711 */ 712 public synchronized void setSumsqImpl(UnivariateStatistic sumsqImpl) { 713 this.sumsqImpl = sumsqImpl; 714 } 715 716 /** 717 * Returns the currently configured sum implementation. 718 * 719 * @return the UnivariateStatistic implementing the sum 720 * @since 1.2 721 */ 722 public synchronized UnivariateStatistic getSumImpl() { 723 return sumImpl; 724 } 725 726 /** 727 * <p>Sets the implementation for the sum.</p> 728 * 729 * @param sumImpl the UnivariateStatistic instance to use 730 * for computing the sum 731 * @since 1.2 732 */ 733 public synchronized void setSumImpl(UnivariateStatistic sumImpl) { 734 this.sumImpl = sumImpl; 735 } 736 737 /** 738 * Returns a copy of this DescriptiveStatistics instance with the same internal state. 739 * 740 * @return a copy of this 741 */ 742 public DescriptiveStatistics copy() { 743 DescriptiveStatistics result = new DescriptiveStatistics(); 744 // No try-catch or advertised exception because parms are guaranteed valid 745 copy(this, result); 746 return result; 747 } 748 749 /** 750 * Copies source to dest. 751 * <p>Neither source nor dest can be null.</p> 752 * 753 * @param source DescriptiveStatistics to copy 754 * @param dest DescriptiveStatistics to copy to 755 * @throws NullArgumentException if either source or dest is null 756 */ 757 public static void copy(DescriptiveStatistics source, DescriptiveStatistics dest) 758 throws NullArgumentException { 759 MathUtils.checkNotNull(source); 760 MathUtils.checkNotNull(dest); 761 // Copy data and window size 762 dest.eDA = source.eDA.copy(); 763 dest.windowSize = source.windowSize; 764 765 // Copy implementations 766 dest.maxImpl = source.maxImpl.copy(); 767 dest.meanImpl = source.meanImpl.copy(); 768 dest.minImpl = source.minImpl.copy(); 769 dest.sumImpl = source.sumImpl.copy(); 770 dest.varianceImpl = source.varianceImpl.copy(); 771 dest.sumsqImpl = source.sumsqImpl.copy(); 772 dest.geometricMeanImpl = source.geometricMeanImpl.copy(); 773 dest.kurtosisImpl = source.kurtosisImpl; 774 dest.skewnessImpl = source.skewnessImpl; 775 dest.percentileImpl = source.percentileImpl; 776 } 777}