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: 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
139 double skew = Double.NaN;
140
141 if (test(values, begin, length) && length > 2 ){
142 Mean mean = new Mean();
143
144 double m = mean.evaluate(values, begin, length);
145
146
147
148
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
165 double n0 = length;
166
167
168 skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3;
169 }
170 return skew;
171 }
172 }