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 org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
    19
    20  /***
    21   * Computes the Kurtosis of the available values.
    22   * <p>
    23   * We use the following (unbiased) formula to define kurtosis:
    24   *  <p>
    25   *  kurtosis = { [n(n+1) / (n -1)(n - 2)(n-3)] sum[(x_i - mean)^4] / std^4 } - [3(n-1)^2 / (n-2)(n-3)]
    26   *  <p>
    27   *  where n is the number of values, mean is the {@link Mean} and std is the
    28   * {@link StandardDeviation}
    29   * <p>
    30   *  Note that this statistic is undefined for n < 4.  <code>Double.Nan</code>
    31   *  is returned when there is not sufficient data to compute the statistic.
    32   * <p>
    33   * <strong>Note that this implementation is not synchronized.</strong> If
    34   * multiple threads access an instance of this class concurrently, and at least
    35   * one of the threads invokes the <code>increment()</code> or
    36   * <code>clear()</code> method, it must be synchronized externally.
    37   *
    38   * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
    39   */
    40  public class Kurtosis extends AbstractStorelessUnivariateStatistic  {
    41
    42      /*** Serializable version identifier */
    43      private static final long serialVersionUID = 2784465764798260919L;
    44
    45      /***Fourth Moment on which this statistic is based */
    46      protected FourthMoment moment;
    47
    48      /***
    49       * Determines whether or not this statistic can be incremented or cleared.
    50       * <p>
    51       * Statistics based on (constructed from) external moments cannot
    52       * be incremented or cleared.
    53      */
    54      protected boolean incMoment;
    55
    56      /***
    57       * Construct a Kurtosis
    58       */
    59      public Kurtosis() {
    60          incMoment = true;
    61          moment = new FourthMoment();
    62      }
    63
    64      /***
    65       * Construct a Kurtosis from an external moment
    66       *
    67       * @param m4 external Moment
    68       */
    69      public Kurtosis(final FourthMoment m4) {
    70          incMoment = false;
    71          this.moment = m4;
    72      }
    73
    74      /***
    75       * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#increment(double)
    76       */
    77      public void increment(final double d) {
    78          if (incMoment) {
    79              moment.increment(d);
    80          }  else  {
    81              throw new IllegalStateException
    82              ("Statistics constructed from external moments cannot be incremented");
    83          }
    84      }
    85
    86      /***
    87       * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getResult()
    88       */
    89      public double getResult() {
    90          double kurtosis = Double.NaN;
    91          if (moment.getN() > 3) {
    92              double variance = moment.m2 / (double) (moment.n - 1);
    93                  if (moment.n <= 3 || variance < 10E-20) {
    94                      kurtosis = 0.0;
    95                  } else {
    96                      double n = (double) moment.n;
    97                      kurtosis =
    98                          (n * (n + 1) * moment.m4 -
    99                                  3 * moment.m2 * moment.m2 * (n - 1)) /
    100                                 ((n - 1) * (n -2) * (n -3) * variance * variance);
    101                 }
    102         }
    103         return kurtosis;
    104     }
    105
    106     /***
    107      * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#clear()
    108      */
    109     public void clear() {
    110         if (incMoment) {
    111             moment.clear();
    112         } else  {
    113             throw new IllegalStateException
    114                 ("Statistics constructed from external moments cannot be cleared");
    115         }
    116     }
    117
    118     /***
    119      * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getN()
    120      */
    121     public long getN() {
    122         return moment.getN();
    123     }
    124
    125     /* UnvariateStatistic Approach  */
    126
    127     /***
    128      * Returns the kurtosis of the entries in the specified portion of the
    129      * input array.
    130      * <p>
    131      * See {@link Kurtosis} for details on the computing algorithm.
    132      * <p>
    133      * Throws <code>IllegalArgumentException</code> if the array is null.
    134      *
    135      * @param values the input array
    136      * @param begin index of the first array element to include
    137      * @param length the number of elements to include
    138      * @return the kurtosis of the values or Double.NaN if length is less than
    139      * 4
    140      * @throws IllegalArgumentException if the input array is null or the array
    141      * index parameters are not valid
    142      */
    143     public double evaluate(final double[] values,final int begin, final int length) {
    144         // Initialize the kurtosis
    145         double kurt = Double.NaN;
    146
    147         if (test(values, begin, length) && length > 3) {
    148
    149             // Compute the mean and standard deviation
    150             Variance variance = new Variance();
    151             variance.incrementAll(values, begin, length);
    152             double mean = variance.moment.m1;
    153             double stdDev = Math.sqrt(variance.getResult());
    154
    155             // Sum the ^4 of the distance from the mean divided by the
    156             // standard deviation
    157             double accum3 = 0.0;
    158             for (int i = begin; i < begin + length; i++) {
    159                 accum3 += Math.pow((values[i] - mean), 4.0);
    160             }
    161             accum3 /= Math.pow(stdDev, 4.0d);
    162
    163             // Get N
    164             double n0 = length;
    165
    166             double coefficientOne =
    167                 (n0 * (n0 + 1)) / ((n0 - 1) * (n0 - 2) * (n0 - 3));
    168             double termTwo =
    169                 ((3 * Math.pow(n0 - 1, 2.0)) / ((n0 - 2) * (n0 - 3)));
    170
    171             // Calculate kurtosis
    172             kurt = (coefficientOne * accum3) - termTwo;
    173         }
    174         return kurt;
    175     }
    176
    177 }