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 }