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 org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
19
20 /**
21 * Computes the Kurtosis of the available values.
22 * <p>
23 * We use the following (unbiased) formula to define kurtosis:
24 * <p>
25 * 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)]
26 * <p>
27 * where n is the number of values, mean is the {@link Mean} and std is the
28 * {@link StandardDeviation}
29 * <p>
30 * Note that this statistic is undefined for n < 4. <code>Double.Nan</code>
31 * is returned when there is not sufficient data to compute the statistic.
32 * <p>
33 * <strong>Note that this implementation is not synchronized.</strong> If
34 * multiple threads access an instance of this class concurrently, and at least
35 * one of the threads invokes the <code>increment()</code> or
36 * <code>clear()</code> method, it must be synchronized externally.
37 *
38 * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
39 */
40 public class Kurtosis extends AbstractStorelessUnivariateStatistic {
41
42 /** Serializable version identifier */
43 private static final long serialVersionUID = 2784465764798260919L;
44
45 /**Fourth Moment on which this statistic is based */
46 protected FourthMoment moment;
47
48 /**
49 * Determines whether or not this statistic can be incremented or cleared.
50 * <p>
51 * Statistics based on (constructed from) external moments cannot
52 * be incremented or cleared.
53 */
54 protected boolean incMoment;
55
56 /**
57 * Construct a Kurtosis
58 */
59 public Kurtosis() {
60 incMoment = true;
61 moment = new FourthMoment();
62 }
63
64 /**
65 * Construct a Kurtosis from an external moment
66 *
67 * @param m4 external Moment
68 */
69 public Kurtosis(final FourthMoment m4) {
70 incMoment = false;
71 this.moment = m4;
72 }
73
74 /**
75 * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#increment(double)
76 */
77 public void increment(final double d) {
78 if (incMoment) {
79 moment.increment(d);
80 } else {
81 throw new IllegalStateException
82 ("Statistics constructed from external moments cannot be incremented");
83 }
84 }
85
86 /**
87 * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getResult()
88 */
89 public double getResult() {
90 double kurtosis = Double.NaN;
91 if (moment.getN() > 3) {
92 double variance = moment.m2 / (double) (moment.n - 1);
93 if (moment.n <= 3 || variance < 10E-20) {
94 kurtosis = 0.0;
95 } else {
96 double n = (double) moment.n;
97 kurtosis =
98 (n * (n + 1) * moment.m4 -
99 3 * moment.m2 * moment.m2 * (n - 1)) /
100 ((n - 1) * (n -2) * (n -3) * variance * variance);
101 }
102 }
103 return kurtosis;
104 }
105
106 /**
107 * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#clear()
108 */
109 public void clear() {
110 if (incMoment) {
111 moment.clear();
112 } else {
113 throw new IllegalStateException
114 ("Statistics constructed from external moments cannot be cleared");
115 }
116 }
117
118 /**
119 * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getN()
120 */
121 public long getN() {
122 return moment.getN();
123 }
124
125
126
127 /**
128 * Returns the kurtosis of the entries in the specified portion of the
129 * input array.
130 * <p>
131 * See {@link Kurtosis} for details on the computing algorithm.
132 * <p>
133 * Throws <code>IllegalArgumentException</code> if the array is null.
134 *
135 * @param values the input array
136 * @param begin index of the first array element to include
137 * @param length the number of elements to include
138 * @return the kurtosis of the values or Double.NaN if length is less than
139 * 4
140 * @throws IllegalArgumentException if the input array is null or the array
141 * index parameters are not valid
142 */
143 public double evaluate(final double[] values,final int begin, final int length) {
144
145 double kurt = Double.NaN;
146
147 if (test(values, begin, length) && length > 3) {
148
149
150 Variance variance = new Variance();
151 variance.incrementAll(values, begin, length);
152 double mean = variance.moment.m1;
153 double stdDev = Math.sqrt(variance.getResult());
154
155
156
157 double accum3 = 0.0;
158 for (int i = begin; i < begin + length; i++) {
159 accum3 += Math.pow((values[i] - mean), 4.0);
160 }
161 accum3 /= Math.pow(stdDev, 4.0d);
162
163
164 double n0 = length;
165
166 double coefficientOne =
167 (n0 * (n0 + 1)) / ((n0 - 1) * (n0 - 2) * (n0 - 3));
168 double termTwo =
169 ((3 * Math.pow(n0 - 1, 2.0)) / ((n0 - 2) * (n0 - 3)));
170
171
172 kurt = (coefficientOne * accum3) - termTwo;
173 }
174 return kurt;
175 }
176
177 }