View Javadoc

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