clean up
[jalview.git] / forester / java / src / org / forester / util / BasicDescriptiveStatistics.java
1 // $Id:
2 // $
3 //
4 // FORESTER -- software libraries and applications
5 // for evolutionary biology research and applications.
6 //
7 // Copyright (C) 2008-2009 Christian M. Zmasek
8 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
9 // All rights reserved
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 //
25 // Contact: phylosoft @ gmail . com
26 // WWW: www.phylosoft.org/forester
27
28 package org.forester.util;
29
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33
34 public class BasicDescriptiveStatistics implements DescriptiveStatistics {
35
36     private List<Double> _data;
37     private double       _sum;
38     private double       _min;
39     private double       _max;
40     private double       _sigma;
41     private boolean      _recalc_sigma;
42
43     public BasicDescriptiveStatistics() {
44         init();
45     }
46
47     /* (non-Javadoc)
48      * @see org.forester.util.DescriptiveStatisticsI#addValue(double)
49      */
50     @Override
51     public void addValue( final double d ) {
52         _recalc_sigma = true;
53         _sum += d;
54         _data.add( new Double( d ) );
55         if ( d < _min ) {
56             _min = d;
57         }
58         if ( d > _max ) {
59             _max = d;
60         }
61     }
62
63     /* (non-Javadoc)
64      * @see org.forester.util.DescriptiveStatisticsI#arithmeticMean()
65      */
66     @Override
67     public double arithmeticMean() {
68         validate();
69         return getSum() / getN();
70     }
71
72     /* (non-Javadoc)
73      * @see org.forester.util.DescriptiveStatisticsI#asSummary()
74      */
75     @Override
76     public String asSummary() {
77         if ( getN() > 1 ) {
78             return arithmeticMean() + DescriptiveStatistics.PLUS_MINUS + sampleStandardDeviation() + " [" + getMin()
79                     + "..." + getMax() + "]";
80         }
81         else {
82             return "" + arithmeticMean();
83         }
84     }
85
86     /* (non-Javadoc)
87      * @see org.forester.util.DescriptiveStatisticsI#coefficientOfVariation()
88      */
89     @Override
90     public double coefficientOfVariation() {
91         validate();
92         return ( sampleStandardDeviation() / arithmeticMean() );
93     }
94
95     /* (non-Javadoc)
96      * @see org.forester.util.DescriptiveStatisticsI#getDataAsDoubleArray()
97      */
98     @Override
99     public double[] getDataAsDoubleArray() {
100         validate();
101         final double[] data_array = new double[ getN() ];
102         for( int i = 0; i < getN(); ++i ) {
103             data_array[ i ] = getValue( i );
104         }
105         return data_array;
106     }
107
108     /* (non-Javadoc)
109      * @see org.forester.util.DescriptiveStatisticsI#getMax()
110      */
111     @Override
112     public double getMax() {
113         validate();
114         return _max;
115     }
116
117     /* (non-Javadoc)
118      * @see org.forester.util.DescriptiveStatisticsI#getMin()
119      */
120     @Override
121     public double getMin() {
122         validate();
123         return _min;
124     }
125
126     /* (non-Javadoc)
127      * @see org.forester.util.DescriptiveStatisticsI#getN()
128      */
129     @Override
130     public int getN() {
131         return _data.size();
132     }
133
134     /* (non-Javadoc)
135      * @see org.forester.util.DescriptiveStatisticsI#getSum()
136      */
137     @Override
138     public double getSum() {
139         validate();
140         return _sum;
141     }
142
143     /* (non-Javadoc)
144      * @see org.forester.util.DescriptiveStatisticsI#getSummaryAsString()
145      */
146     @Override
147     public String getSummaryAsString() {
148         validate();
149         final double mean = arithmeticMean();
150         final double sd = sampleStandardDeviation();
151         return "" + mean + ( ( char ) 177 ) + sd + " [" + getMin() + "..." + getMax() + "]";
152     }
153
154     /* (non-Javadoc)
155      * @see org.forester.util.DescriptiveStatisticsI#getValue(int)
156      */
157     @Override
158     public double getValue( final int index ) {
159         validate();
160         return ( ( ( _data.get( index ) ) ).doubleValue() );
161     }
162
163     private void init() {
164         _data = new ArrayList<Double>();
165         _sum = 0.0;
166         _min = Double.MAX_VALUE;
167         _max = -Double.MAX_VALUE;
168         _sigma = 0.0;
169         _recalc_sigma = true;
170     }
171
172     /* (non-Javadoc)
173      * @see org.forester.util.DescriptiveStatisticsI#median()
174      */
175     @Override
176     public double median() {
177         validate();
178         double median = 0.0;
179         if ( getN() == 1 ) {
180             median = getValue( 0 );
181         }
182         else {
183             final int index = ( getN() / 2 );
184             final double[] data_array = getDataAsDoubleArray();
185             Arrays.sort( data_array );
186             if ( ( ( data_array.length ) % 2 ) == 0 ) {
187                 // even number of data values
188                 median = ( data_array[ index - 1 ] + data_array[ index ] ) / 2.0;
189             }
190             else {
191                 median = data_array[ index ];
192             }
193         }
194         return median;
195     }
196
197     /* (non-Javadoc)
198      * @see org.forester.util.DescriptiveStatisticsI#midrange()
199      */
200     @Override
201     public double midrange() {
202         validate();
203         return ( _min + _max ) / 2.0;
204     }
205
206     /* (non-Javadoc)
207      * @see org.forester.util.DescriptiveStatisticsI#pearsonianSkewness()
208      */
209     @Override
210     public double pearsonianSkewness() {
211         validate();
212         final double mean = arithmeticMean();
213         final double median = median();
214         final double sd = sampleStandardDeviation();
215         return ( ( 3 * ( mean - median ) ) / sd );
216     }
217
218     /* (non-Javadoc)
219      * @see org.forester.util.DescriptiveStatisticsI#sampleStandardDeviation()
220      */
221     @Override
222     public double sampleStandardDeviation() {
223         return Math.sqrt( sampleVariance() );
224     }
225
226     /* (non-Javadoc)
227      * @see org.forester.util.DescriptiveStatisticsI#sampleStandardUnit(double)
228      */
229     @Override
230     public double sampleStandardUnit( final double value ) {
231         validate();
232         return BasicDescriptiveStatistics.sampleStandardUnit( value, arithmeticMean(), sampleStandardDeviation() );
233     }
234
235     /* (non-Javadoc)
236      * @see org.forester.util.DescriptiveStatisticsI#sampleVariance()
237      */
238     @Override
239     public double sampleVariance() {
240         validate();
241         if ( getN() < 2 ) {
242             throw new ArithmeticException( "attempt to calculate sample variance for less then two values" );
243         }
244         return ( sumDeviations() / ( getN() - 1 ) );
245     }
246
247     /* (non-Javadoc)
248      * @see org.forester.util.DescriptiveStatisticsI#standardErrorOfMean()
249      */
250     @Override
251     public double standardErrorOfMean() {
252         validate();
253         return ( sampleStandardDeviation() / Math.sqrt( getN() ) );
254     }
255
256     /* (non-Javadoc)
257      * @see org.forester.util.DescriptiveStatisticsI#sumDeviations()
258      */
259     @Override
260     public double sumDeviations() {
261         validate();
262         if ( _recalc_sigma ) {
263             _recalc_sigma = false;
264             _sigma = 0.0;
265             final double mean = arithmeticMean();
266             for( int i = 0; i < getN(); ++i ) {
267                 _sigma += Math.pow( ( getValue( i ) - mean ), 2 );
268             }
269         }
270         return _sigma;
271     }
272
273     /* (non-Javadoc)
274      * @see org.forester.util.DescriptiveStatisticsI#toString()
275      */
276     @Override
277     public String toString() {
278         if ( getN() < 1 ) {
279             return "empty data set statistics";
280         }
281         final StringBuffer sb = new StringBuffer();
282         sb.append( "Descriptive statistics:" );
283         sb.append( ForesterUtil.getLineSeparator() );
284         sb.append( "n                       : " + getN() );
285         if ( getN() > 1 ) {
286             sb.append( ForesterUtil.getLineSeparator() );
287             sb.append( "min                     : " + getMin() );
288             sb.append( ForesterUtil.getLineSeparator() );
289             sb.append( "max                     : " + getMax() );
290             sb.append( ForesterUtil.getLineSeparator() );
291             sb.append( "midrange                : " + midrange() );
292             sb.append( ForesterUtil.getLineSeparator() );
293             sb.append( "median                  : " + median() );
294             sb.append( ForesterUtil.getLineSeparator() );
295             sb.append( "mean                    : " + arithmeticMean() );
296             sb.append( ForesterUtil.getLineSeparator() );
297             sb.append( "sd                      : " + sampleStandardDeviation() );
298             sb.append( ForesterUtil.getLineSeparator() );
299             sb.append( "variance                : " + sampleVariance() );
300             sb.append( ForesterUtil.getLineSeparator() );
301             sb.append( "standard error of mean  : " + standardErrorOfMean() );
302             sb.append( ForesterUtil.getLineSeparator() );
303             sb.append( "coefficient of variation: " + coefficientOfVariation() );
304             sb.append( ForesterUtil.getLineSeparator() );
305             sb.append( "pearsonian skewness     : " + pearsonianSkewness() );
306         }
307         return sb.toString();
308     }
309
310     private void validate() throws ArithmeticException {
311         if ( getN() < 1 ) {
312             throw new ArithmeticException( "attempt to get a result from empty data set statistics" );
313         }
314     }
315
316     public static int[] performBinning( final double[] values,
317                                         final double min,
318                                         final double max,
319                                         final int number_of_bins ) {
320         if ( min >= max ) {
321             throw new IllegalArgumentException( "min [" + min + "] is larger than or equal to max [" + max + "]" );
322         }
323         if ( number_of_bins < 3 ) {
324             throw new IllegalArgumentException( "number of bins is smaller than 3" );
325         }
326         final int[] bins = new int[ number_of_bins ];
327         final double binning_factor = number_of_bins / ( max - min );
328         final int last_index = number_of_bins - 1;
329         for( final double d : values ) {
330             if ( !( ( d > max ) || ( d < min ) ) ) {
331                 final int bin = ( int ) ( ( d - min ) * binning_factor );
332                 if ( bin > last_index ) {
333                     ++bins[ last_index ];
334                 }
335                 else {
336                     ++bins[ bin ];
337                 }
338             }
339         }
340         return bins;
341     }
342
343     /**
344      * Computes the sample standard unit (z-score). Used to compute 'value' in
345      * terms of standard units. Note that 'value', 'mean' and 'sd' must be all
346      * from the same sample data.
347      * 
348      * @param value
349      *            a double in the sample for which
350      * @param mean
351      *            the mean of the sample.
352      * @param sd
353      *            The standard deviation of the sample.
354      * @return 'value' in terms of standard units
355      */
356     public static double sampleStandardUnit( final double value, final double mean, final double sd ) {
357         return ( value - mean ) / sd;
358     }
359 }