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