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 }