View Javadoc

    1   /*
    2    * Copyright 2003-2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.math.stat.descriptive.moment;
    17
    18  import java.io.Serializable;
    19
    20  import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
    21
    22  /***
    23   * Computes the skewness of the available values.
    24   * <p>
    25   * We use the following (unbiased) formula to define skewness:
    26   * <p>
    27   * skewness = [n / (n -1) (n - 2)] sum[(x_i - mean)^3] / std^3
    28   * <p>
    29   * where n is the number of values, mean is the {@link Mean} and std is the
    30   * {@link StandardDeviation}
    31   * <p>
    32   * <strong>Note that this implementation is not synchronized.</strong> If
    33   * multiple threads access an instance of this class concurrently, and at least
    34   * one of the threads invokes the <code>increment()</code> or
    35   * <code>clear()</code> method, it must be synchronized externally.
    36   *
    37   * @version $Revision: 1.1 $ $Date: 2004/10/08 05:08:17 $
    38   */
    39  public class Skewness extends AbstractStorelessUnivariateStatistic implements Serializable {
    40
    41      /*** Serializable version identifier */
    42      static final long serialVersionUID = 7101857578996691352L;
    43
    44      /*** Third moment on which this statistic is based */
    45      protected ThirdMoment moment = null;
    46
    47       /***
    48       * Determines whether or not this statistic can be incremented or cleared.
    49       * <p>
    50       * Statistics based on (constructed from) external moments cannot
    51       * be incremented or cleared.
    52      */
    53      protected boolean incMoment;
    54
    55      /***
    56       * Constructs a Skewness
    57       */
    58      public Skewness() {
    59          incMoment = true;
    60          moment = new ThirdMoment();
    61      }
    62
    63      /***
    64       * Constructs a Skewness with an external moment
    65       * @param m3 external moment
    66       */
    67      public Skewness(final ThirdMoment m3) {
    68          incMoment = false;
    69          this.moment = m3;
    70      }
    71
    72      /***
    73       * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#increment(double)
    74       */
    75      public void increment(final double d) {
    76          if (incMoment) {
    77              moment.increment(d);
    78          }
    79      }
    80
    81      /***
    82       * Returns the value of the statistic based on the values that have been added.
    83       * <p>
    84       * See {@link Skewness} for the definition used in the computation.
    85       *
    86       * @return the skewness of the available values.
    87       */
    88      public double getResult() {
    89
    90          if (moment.n < 3) {
    91              return Double.NaN;
    92          }
    93          double variance = moment.m2 / (double) (moment.n - 1);
    94          double skewness = Double.NaN;
    95          if (variance < 10E-20) {
    96              skewness = 0.0;
    97          } else {
    98              double n0 = (double) moment.getN();
    99              skewness = (n0 * moment.m3) /
    100             ((n0 - 1) * (n0 -2) * Math.sqrt(variance) * variance);
    101         }
    102         return skewness;
    103     }
    104
    105     /***
    106      * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getN()
    107      */
    108     public long getN() {
    109         return moment.getN();
    110     }
    111
    112     /***
    113      * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#clear()
    114      */
    115     public void clear() {
    116         if (incMoment) {
    117             moment.clear();
    118         }
    119     }
    120
    121     /***
    122      * Returns the Skewness of the entries in the specifed portion of the
    123      * input array.
    124      * <p>
    125      * See {@link Skewness} for the definition used in the computation.
    126      * <p>
    127      * Throws <code>IllegalArgumentException</code> if the array is null.
    128      *
    129      * @param values the input array
    130      * @param begin the index of the first array element to include
    131      * @param length the number of elements to include
    132      * @return the skewness of the values or Double.NaN if length is less than
    133      * 3
    134      * @throws IllegalArgumentException if the array is null or the array index
    135      *  parameters are not valid
    136      */
    137     public double evaluate(final double[] values,final int begin,
    138             final int length) {
    139
    140         // Initialize the skewness
    141         double skew = Double.NaN;
    142
    143         if (test(values, begin, length) && length > 2 ){
    144             Mean mean = new Mean();
    145             // Get the mean and the standard deviation
    146             double m = mean.evaluate(values, begin, length);
    147
    148             // Calc the std, this is implemented here instead
    149             // of using the standardDeviation method eliminate
    150             // a duplicate pass to get the mean
    151             double accum = 0.0;
    152             double accum2 = 0.0;
    153             for (int i = begin; i < begin + length; i++) {
    154                 accum += Math.pow((values[i] - m), 2.0);
    155                 accum2 += (values[i] - m);
    156             }
    157             double stdDev = Math.sqrt((accum - (Math.pow(accum2, 2) / ((double) length))) /
    158                     (double) (length - 1));
    159
    160             double accum3 = 0.0;
    161             for (int i = begin; i < begin + length; i++) {
    162                 accum3 += Math.pow(values[i] - m, 3.0d);
    163             }
    164             accum3 /= Math.pow(stdDev, 3.0d);
    165
    166             // Get N
    167             double n0 = length;
    168
    169             // Calculate skewness
    170             skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3;
    171         }
    172         return skew;
    173     }
    174 }