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