1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
141 double skew = Double.NaN;
142
143 if (test(values, begin, length) && length > 2 ){
144 Mean mean = new Mean();
145
146 double m = mean.evaluate(values, begin, length);
147
148
149
150
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
167 double n0 = length;
168
169
170 skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3;
171 }
172 return skew;
173 }
174 }