QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsstatisticalsummary.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsstatisticalsummary.cpp
3  --------------------------------------
4  Date : May 2015
5  Copyright : (C) 2015 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsstatisticalsummary.h"
17 #include <limits>
18 #include <QString>
19 #include <QObject>
20 
21 /***************************************************************************
22  * This class is considered CRITICAL and any change MUST be accompanied with
23  * full unit tests in testqgsstatisticalsummary.cpp.
24  * See details in QEP #17
25  ****************************************************************************/
26 
28  : mStatistics( stats )
29 {
30  reset();
31 }
32 
34 {
35  mCount = 0;
36  mMissing = 0;
37  mSum = 0;
38  mMean = 0;
39  mMedian = 0;
40  mMin = std::numeric_limits<double>::max();
41  mMax = -std::numeric_limits<double>::max();
42  mStdev = 0;
43  mSampleStdev = 0;
44  mMinority = 0;
45  mMajority = 0;
46  mFirstQuartile = 0;
47  mThirdQuartile = 0;
48  mValueCount.clear();
49  mValues.clear();
50 }
51 
52 /***************************************************************************
53  * This class is considered CRITICAL and any change MUST be accompanied with
54  * full unit tests in testqgsstatisticalsummary.cpp.
55  * See details in QEP #17
56  ****************************************************************************/
57 
58 void QgsStatisticalSummary::calculate( const QList<double> &values )
59 {
60  reset();
61 
62  Q_FOREACH ( double value, values )
63  {
64  addValue( value );
65  }
66 
67  finalize();
68 }
69 
70 void QgsStatisticalSummary::addValue( double value )
71 {
72  mCount++;
73  mSum += value;
74  mMin = std::min( mMin, value );
75  mMax = std::max( mMax, value );
76 
77  if ( mStatistics & QgsStatisticalSummary::Majority || mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Variety )
78  mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
79 
80  if ( mStatistics & QgsStatisticalSummary::StDev || mStatistics & QgsStatisticalSummary::StDevSample ||
83  mValues << value;
84 }
85 
86 void QgsStatisticalSummary::addVariant( const QVariant &value )
87 {
88  bool convertOk = false;
89  if ( !value.isValid() || value.isNull() )
90  mMissing++;
91  else
92  {
93  double val = value.toDouble( &convertOk );
94  if ( convertOk )
95  addValue( val );
96  else
97  mMissing++;
98  }
99 }
100 
102 {
103  if ( mCount == 0 )
104  {
105  mMin = std::numeric_limits<double>::quiet_NaN();
106  mMax = std::numeric_limits<double>::quiet_NaN();
107  mMean = std::numeric_limits<double>::quiet_NaN();
108  mMedian = std::numeric_limits<double>::quiet_NaN();
109  mStdev = std::numeric_limits<double>::quiet_NaN();
110  mSampleStdev = std::numeric_limits<double>::quiet_NaN();
111  mMinority = std::numeric_limits<double>::quiet_NaN();
112  mMajority = std::numeric_limits<double>::quiet_NaN();
113  mFirstQuartile = std::numeric_limits<double>::quiet_NaN();
114  mThirdQuartile = std::numeric_limits<double>::quiet_NaN();
115  return;
116  }
117 
118  mMean = mSum / mCount;
119 
120  if ( mStatistics & QgsStatisticalSummary::StDev || mStatistics & QgsStatisticalSummary::StDevSample )
121  {
122  double sumSquared = 0;
123  Q_FOREACH ( double value, mValues )
124  {
125  double diff = value - mMean;
126  sumSquared += diff * diff;
127  }
128  mStdev = std::pow( sumSquared / mValues.count(), 0.5 );
129  mSampleStdev = std::pow( sumSquared / ( mValues.count() - 1 ), 0.5 );
130  }
131 
132  if ( mStatistics & QgsStatisticalSummary::Median
133  || mStatistics & QgsStatisticalSummary::FirstQuartile
134  || mStatistics & QgsStatisticalSummary::ThirdQuartile
136  {
137  std::sort( mValues.begin(), mValues.end() );
138  bool even = ( mCount % 2 ) < 1;
139  if ( even )
140  {
141  mMedian = ( mValues[mCount / 2 - 1] + mValues[mCount / 2] ) / 2.0;
142  }
143  else //odd
144  {
145  mMedian = mValues[( mCount + 1 ) / 2 - 1];
146  }
147  }
148 
149  if ( mStatistics & QgsStatisticalSummary::FirstQuartile
150  || mStatistics & QgsStatisticalSummary::InterQuartileRange )
151  {
152  if ( ( mCount % 2 ) < 1 )
153  {
154  int halfCount = mCount / 2;
155  bool even = ( halfCount % 2 ) < 1;
156  if ( even )
157  {
158  mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
159  }
160  else //odd
161  {
162  mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
163  }
164  }
165  else
166  {
167  int halfCount = mCount / 2 + 1;
168  bool even = ( halfCount % 2 ) < 1;
169  if ( even )
170  {
171  mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
172  }
173  else //odd
174  {
175  mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
176  }
177  }
178  }
179 
180  if ( mStatistics & QgsStatisticalSummary::ThirdQuartile
181  || mStatistics & QgsStatisticalSummary::InterQuartileRange )
182  {
183  if ( ( mCount % 2 ) < 1 )
184  {
185  int halfCount = mCount / 2;
186  bool even = ( halfCount % 2 ) < 1;
187  if ( even )
188  {
189  mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 1] + mValues[ halfCount + halfCount / 2] ) / 2.0;
190  }
191  else //odd
192  {
193  mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 1 + halfCount ];
194  }
195  }
196  else
197  {
198  int halfCount = mCount / 2 + 1;
199  bool even = ( halfCount % 2 ) < 1;
200  if ( even )
201  {
202  mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 2 ] + mValues[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
203  }
204  else //odd
205  {
206  mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 2 + halfCount ];
207  }
208  }
209  }
210 
211  if ( mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Majority )
212  {
213  QList<int> valueCounts = mValueCount.values();
214  std::sort( valueCounts.begin(), valueCounts.end() );
215  if ( mStatistics & QgsStatisticalSummary::Minority )
216  {
217  mMinority = mValueCount.key( valueCounts.first() );
218  }
219  if ( mStatistics & QgsStatisticalSummary::Majority )
220  {
221  mMajority = mValueCount.key( valueCounts.last() );
222  }
223  }
224 
225 }
226 
227 /***************************************************************************
228  * This class is considered CRITICAL and any change MUST be accompanied with
229  * full unit tests in testqgsstatisticalsummary.cpp.
230  * See details in QEP #17
231  ****************************************************************************/
232 
234 {
235  switch ( stat )
236  {
237  case Count:
238  return mCount;
239  case CountMissing:
240  return mMissing;
241  case Sum:
242  return mSum;
243  case Mean:
244  return mMean;
245  case Median:
246  return mMedian;
247  case StDev:
248  return mStdev;
249  case StDevSample:
250  return mSampleStdev;
251  case Min:
252  return mMin;
253  case Max:
254  return mMax;
255  case Range:
256  return mMax - mMin;
257  case Minority:
258  return mMinority;
259  case Majority:
260  return mMajority;
261  case Variety:
262  return mValueCount.count();
263  case FirstQuartile:
264  return mFirstQuartile;
265  case ThirdQuartile:
266  return mThirdQuartile;
267  case InterQuartileRange:
268  return mThirdQuartile - mFirstQuartile;
269  case All:
270  return 0;
271  }
272  return 0;
273 }
274 
276 {
277  switch ( statistic )
278  {
279  case Count:
280  return QObject::tr( "Count" );
281  case CountMissing:
282  return QObject::tr( "Count (missing)" );
283  case Sum:
284  return QObject::tr( "Sum" );
285  case Mean:
286  return QObject::tr( "Mean" );
287  case Median:
288  return QObject::tr( "Median" );
289  case StDev:
290  return QObject::tr( "St dev (pop)" );
291  case StDevSample:
292  return QObject::tr( "St dev (sample)" );
293  case Min:
294  return QObject::tr( "Minimum" );
295  case Max:
296  return QObject::tr( "Maximum" );
297  case Range:
298  return QObject::tr( "Range" );
299  case Minority:
300  return QObject::tr( "Minority" );
301  case Majority:
302  return QObject::tr( "Majority" );
303  case Variety:
304  return QObject::tr( "Variety" );
305  case FirstQuartile:
306  return QObject::tr( "Q1" );
307  case ThirdQuartile:
308  return QObject::tr( "Q3" );
309  case InterQuartileRange:
310  return QObject::tr( "IQR" );
311  case All:
312  return QString();
313  }
314  return QString();
315 }
316 
void reset()
Resets the calculated values.
Statistic
Enumeration of flags that specify statistics to be calculated.
Variety (count of distinct) values.
void finalize()
Must be called after adding all values with addValues() and before retrieving any calculated statisti...
void addVariant(const QVariant &value)
Adds a single value to the statistics calculation.
Sample standard deviation of values.
Number of missing (null) values.
QgsStatisticalSummary(QgsStatisticalSummary::Statistics stats=QgsStatisticalSummary::All)
Constructor for QgsStatisticalSummary.
double statistic(QgsStatisticalSummary::Statistic stat) const
Returns the value of a specified statistic.
static QString displayName(QgsStatisticalSummary::Statistic statistic)
Returns the friendly display name for a statistic.
void calculate(const QList< double > &values)
Calculates summary statistics for a list of values.
Standard deviation of values.
Range of values (max - min)
void addValue(double value)
Adds a single value to the statistics calculation.