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 }