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: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
38   */
39  public class Skewness extends AbstractStorelessUnivariateStatistic implements Serializable {
40  
41      /** Serializable version identifier */
42      private 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          if (variance < 10E-20) {
95              return 0.0d;
96          } else {
97              double n0 = (double) moment.getN();
98              return  (n0 * moment.m3) /
99              ((n0 - 1) * (n0 -2) * Math.sqrt(variance) * variance);
100         }
101     }
102 
103     /**
104      * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getN()
105      */
106     public long getN() {
107         return moment.getN();
108     }
109     
110     /**
111      * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#clear()
112      */
113     public void clear() {
114         if (incMoment) {
115             moment.clear();
116         }
117     }
118 
119     /**
120      * Returns the Skewness of the entries in the specifed portion of the
121      * input array.
122      * <p>
123      * See {@link Skewness} for the definition used in the computation.
124      * <p>
125      * Throws <code>IllegalArgumentException</code> if the array is null.
126      * 
127      * @param values the input array
128      * @param begin the index of the first array element to include
129      * @param length the number of elements to include
130      * @return the skewness of the values or Double.NaN if length is less than
131      * 3
132      * @throws IllegalArgumentException if the array is null or the array index
133      *  parameters are not valid
134      */
135     public double evaluate(final double[] values,final int begin, 
136             final int length) {
137 
138         // Initialize the skewness
139         double skew = Double.NaN;
140 
141         if (test(values, begin, length) && length > 2 ){
142             Mean mean = new Mean();
143             // Get the mean and the standard deviation
144             double m = mean.evaluate(values, begin, length);
145             
146             // Calc the std, this is implemented here instead
147             // of using the standardDeviation method eliminate
148             // a duplicate pass to get the mean
149             double accum = 0.0;
150             double accum2 = 0.0;
151             for (int i = begin; i < begin + length; i++) {
152                 accum += Math.pow((values[i] - m), 2.0);
153                 accum2 += (values[i] - m);
154             }
155             double stdDev = Math.sqrt((accum - (Math.pow(accum2, 2) / ((double) length))) /
156                     (double) (length - 1));
157             
158             double accum3 = 0.0;
159             for (int i = begin; i < begin + length; i++) {
160                 accum3 += Math.pow(values[i] - m, 3.0d);
161             }
162             accum3 /= Math.pow(stdDev, 3.0d);
163             
164             // Get N
165             double n0 = length;
166             
167             // Calculate skewness
168             skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3;
169         }
170         return skew;
171     }
172 }