in progress
[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     private String       _desc;
43
44     public BasicDescriptiveStatistics() {
45         init();
46     }
47
48     /* (non-Javadoc)
49      * @see org.forester.util.DescriptiveStatisticsI#addValue(double)
50      */
51     @Override
52     public void addValue( final double d ) {
53         _recalc_sigma = true;
54         _sum += d;
55         _data.add( new Double( d ) );
56         if ( d < _min ) {
57             _min = d;
58         }
59         if ( d > _max ) {
60             _max = d;
61         }
62     }
63
64     /* (non-Javadoc)
65      * @see org.forester.util.DescriptiveStatisticsI#arithmeticMean()
66      */
67     @Override
68     public double arithmeticMean() {
69         validate();
70         return getSum() / getN();
71     }
72
73     /* (non-Javadoc)
74      * @see org.forester.util.DescriptiveStatisticsI#asSummary()
75      */
76     @Override
77     public String asSummary() {
78         if ( getN() > 1 ) {
79             return arithmeticMean() + DescriptiveStatistics.PLUS_MINUS + sampleStandardDeviation() + " [" + getMin()
80                     + "..." + getMax() + "]";
81         }
82         else {
83             return "" + arithmeticMean();
84         }
85     }
86
87     /* (non-Javadoc)
88      * @see org.forester.util.DescriptiveStatisticsI#coefficientOfVariation()
89      */
90     @Override
91     public double coefficientOfVariation() {
92         validate();
93         return ( sampleStandardDeviation() / arithmeticMean() );
94     }
95
96     /* (non-Javadoc)
97      * @see org.forester.util.DescriptiveStatisticsI#getDataAsDoubleArray()
98      */
99     @Override
100     public double[] getDataAsDoubleArray() {
101         validate();
102         final double[] data_array = new double[ getN() ];
103         for( int i = 0; i < getN(); ++i ) {
104             data_array[ i ] = getValue( i );
105         }
106         return data_array;
107     }
108
109     /* (non-Javadoc)
110      * @see org.forester.util.DescriptiveStatisticsI#getMax()
111      */
112     @Override
113     public double getMax() {
114         validate();
115         return _max;
116     }
117
118     /* (non-Javadoc)
119      * @see org.forester.util.DescriptiveStatisticsI#getMin()
120      */
121     @Override
122     public double getMin() {
123         validate();
124         return _min;
125     }
126
127     /* (non-Javadoc)
128      * @see org.forester.util.DescriptiveStatisticsI#getN()
129      */
130     @Override
131     public int getN() {
132         return _data.size();
133     }
134
135     /* (non-Javadoc)
136      * @see org.forester.util.DescriptiveStatisticsI#getSum()
137      */
138     @Override
139     public double getSum() {
140         validate();
141         return _sum;
142     }
143
144     /* (non-Javadoc)
145      * @see org.forester.util.DescriptiveStatisticsI#getSummaryAsString()
146      */
147     @Override
148     public String getSummaryAsString() {
149         validate();
150         final double mean = arithmeticMean();
151         final double sd = sampleStandardDeviation();
152         return "" + mean + ( ( char ) 177 ) + sd + " [" + getMin() + "..." + getMax() + "]";
153     }
154
155     /* (non-Javadoc)
156      * @see org.forester.util.DescriptiveStatisticsI#getValue(int)
157      */
158     @Override
159     public double getValue( final int index ) {
160         validate();
161         return ( ( ( _data.get( index ) ) ).doubleValue() );
162     }
163
164     private void init() {
165         _data = new ArrayList<Double>();
166         _sum = 0.0;
167         _min = Double.MAX_VALUE;
168         _max = -Double.MAX_VALUE;
169         _sigma = 0.0;
170         _recalc_sigma = true;
171         _desc = "";
172     }
173
174     /* (non-Javadoc)
175      * @see org.forester.util.DescriptiveStatisticsI#median()
176      */
177     @Override
178     public double median() {
179         validate();
180         double median = 0.0;
181         if ( getN() == 1 ) {
182             median = getValue( 0 );
183         }
184         else {
185             final int index = ( getN() / 2 );
186             final double[] data_array = getDataAsDoubleArray();
187             Arrays.sort( data_array );
188             if ( ( ( data_array.length ) % 2 ) == 0 ) {
189                 // even number of data values
190                 median = ( data_array[ index - 1 ] + data_array[ index ] ) / 2.0;
191             }
192             else {
193                 median = data_array[ index ];
194             }
195         }
196         return median;
197     }
198
199     /* (non-Javadoc)
200      * @see org.forester.util.DescriptiveStatisticsI#midrange()
201      */
202     @Override
203     public double midrange() {
204         validate();
205         return ( _min + _max ) / 2.0;
206     }
207
208     /* (non-Javadoc)
209      * @see org.forester.util.DescriptiveStatisticsI#pearsonianSkewness()
210      */
211     @Override
212     public double pearsonianSkewness() {
213         validate();
214         final double mean = arithmeticMean();
215         final double median = median();
216         final double sd = sampleStandardDeviation();
217         return ( ( 3 * ( mean - median ) ) / sd );
218     }
219
220     /* (non-Javadoc)
221      * @see org.forester.util.DescriptiveStatisticsI#sampleStandardDeviation()
222      */
223     @Override
224     public double sampleStandardDeviation() {
225         return Math.sqrt( sampleVariance() );
226     }
227
228     /* (non-Javadoc)
229      * @see org.forester.util.DescriptiveStatisticsI#sampleStandardUnit(double)
230      */
231     @Override
232     public double sampleStandardUnit( final double value ) {
233         validate();
234         return BasicDescriptiveStatistics.sampleStandardUnit( value, arithmeticMean(), sampleStandardDeviation() );
235     }
236
237     /* (non-Javadoc)
238      * @see org.forester.util.DescriptiveStatisticsI#sampleVariance()
239      */
240     @Override
241     public double sampleVariance() {
242         validate();
243         if ( getN() < 2 ) {
244             throw new ArithmeticException( "attempt to calculate sample variance for less then two values" );
245         }
246         return ( sumDeviations() / ( getN() - 1 ) );
247     }
248
249     /* (non-Javadoc)
250      * @see org.forester.util.DescriptiveStatisticsI#standardErrorOfMean()
251      */
252     @Override
253     public double standardErrorOfMean() {
254         validate();
255         return ( sampleStandardDeviation() / Math.sqrt( getN() ) );
256     }
257
258     /* (non-Javadoc)
259      * @see org.forester.util.DescriptiveStatisticsI#sumDeviations()
260      */
261     @Override
262     public double sumDeviations() {
263         validate();
264         if ( _recalc_sigma ) {
265             _recalc_sigma = false;
266             _sigma = 0.0;
267             final double mean = arithmeticMean();
268             for( int i = 0; i < getN(); ++i ) {
269                 _sigma += Math.pow( ( getValue( i ) - mean ), 2 );
270             }
271         }
272         return _sigma;
273     }
274
275     /* (non-Javadoc)
276      * @see org.forester.util.DescriptiveStatisticsI#toString()
277      */
278     @Override
279     public String toString() {
280         if ( getN() < 1 ) {
281             return "empty data set statistics";
282         }
283         final StringBuffer sb = new StringBuffer();
284         sb.append( "Descriptive statistics:" );
285         sb.append( ForesterUtil.getLineSeparator() );
286         sb.append( "n                       : " + getN() );
287         if ( getN() > 1 ) {
288             sb.append( ForesterUtil.getLineSeparator() );
289             sb.append( "min                     : " + getMin() );
290             sb.append( ForesterUtil.getLineSeparator() );
291             sb.append( "max                     : " + getMax() );
292             sb.append( ForesterUtil.getLineSeparator() );
293             sb.append( "midrange                : " + midrange() );
294             sb.append( ForesterUtil.getLineSeparator() );
295             sb.append( "median                  : " + median() );
296             sb.append( ForesterUtil.getLineSeparator() );
297             sb.append( "mean                    : " + arithmeticMean() );
298             sb.append( ForesterUtil.getLineSeparator() );
299             sb.append( "sd                      : " + sampleStandardDeviation() );
300             sb.append( ForesterUtil.getLineSeparator() );
301             sb.append( "variance                : " + sampleVariance() );
302             sb.append( ForesterUtil.getLineSeparator() );
303             sb.append( "standard error of mean  : " + standardErrorOfMean() );
304             sb.append( ForesterUtil.getLineSeparator() );
305             sb.append( "coefficient of variation: " + coefficientOfVariation() );
306             sb.append( ForesterUtil.getLineSeparator() );
307             sb.append( "pearsonian skewness     : " + pearsonianSkewness() );
308         }
309         return sb.toString();
310     }
311
312     private void validate() throws ArithmeticException {
313         if ( getN() < 1 ) {
314             throw new ArithmeticException( "attempt to get a result from empty data set statistics" );
315         }
316     }
317
318     public static int[] performBinning( final double[] values,
319                                         final double min,
320                                         final double max,
321                                         final int number_of_bins ) {
322         if ( min >= max ) {
323             throw new IllegalArgumentException( "min [" + min + "] is larger than or equal to max [" + max + "]" );
324         }
325         if ( number_of_bins < 3 ) {
326             throw new IllegalArgumentException( "number of bins is smaller than 3" );
327         }
328         final int[] bins = new int[ number_of_bins ];
329         final double binning_factor = number_of_bins / ( max - min );
330         final int last_index = number_of_bins - 1;
331         for( final double d : values ) {
332             if ( !( ( d > max ) || ( d < min ) ) ) {
333                 final int bin = ( int ) ( ( d - min ) * binning_factor );
334                 if ( bin > last_index ) {
335                     ++bins[ last_index ];
336                 }
337                 else {
338                     ++bins[ bin ];
339                 }
340             }
341         }
342         return bins;
343     }
344
345     /**
346      * Computes the sample standard unit (z-score). Used to compute 'value' in
347      * terms of standard units. Note that 'value', 'mean' and 'sd' must be all
348      * from the same sample data.
349      * 
350      * @param value
351      *            a double in the sample for which
352      * @param mean
353      *            the mean of the sample.
354      * @param sd
355      *            The standard deviation of the sample.
356      * @return 'value' in terms of standard units
357      */
358     public static double sampleStandardUnit( final double value, final double mean, final double sd ) {
359         return ( value - mean ) / sd;
360     }
361
362     @Override
363     public List<Double> getData() {
364         return _data;
365     }
366
367     @Override
368     public void setDescription( final String desc ) {
369         _desc = desc;
370     }
371
372     @Override
373     public String getDescription() {
374         return _desc;
375     }
376 }