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