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