QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
33 void QgsStatisticalSummary::setStatistics( QgsStatisticalSummary::Statistics stats )
34 {
35  mStatistics = stats;
36  reset();
37 }
38 
40 {
41  mCount = 0;
42  mMissing = 0;
43  mSum = 0;
44  mMean = 0;
45  mMedian = 0;
46  mMin = std::numeric_limits<double>::max();
47  mMax = -std::numeric_limits<double>::max();
48  mStdev = 0;
49  mSampleStdev = 0;
50  mMinority = 0;
51  mMajority = 0;
52  mFirstQuartile = 0;
53  mThirdQuartile = 0;
54  mValueCount.clear();
55  mValues.clear();
56 
57  mRequiresHisto = mStatistics & QgsStatisticalSummary::Majority || mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Variety;
58 
59  mRequiresAllValueStorage = mStatistics & QgsStatisticalSummary::StDev || mStatistics & QgsStatisticalSummary::StDevSample ||
62 }
63 
64 /***************************************************************************
65  * This class is considered CRITICAL and any change MUST be accompanied with
66  * full unit tests in testqgsstatisticalsummary.cpp.
67  * See details in QEP #17
68  ****************************************************************************/
69 
70 void QgsStatisticalSummary::calculate( const QList<double> &values )
71 {
72  reset();
73 
74  Q_FOREACH ( double value, values )
75  {
76  addValue( value );
77  }
78 
79  finalize();
80 }
81 
82 void QgsStatisticalSummary::addValue( double value )
83 {
84  mCount++;
85  mSum += value;
86  mMin = std::min( mMin, value );
87  mMax = std::max( mMax, value );
88 
89  if ( mRequiresHisto )
90  mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
91 
92  if ( mRequiresAllValueStorage )
93  mValues << value;
94 }
95 
96 void QgsStatisticalSummary::addVariant( const QVariant &value )
97 {
98  bool convertOk = false;
99  if ( !value.isValid() || value.isNull() )
100  mMissing++;
101  else
102  {
103  double val = value.toDouble( &convertOk );
104  if ( convertOk )
105  addValue( val );
106  else
107  mMissing++;
108  }
109 }
110 
112 {
113  if ( mCount == 0 )
114  {
115  mMin = std::numeric_limits<double>::quiet_NaN();
116  mMax = std::numeric_limits<double>::quiet_NaN();
117  mMean = std::numeric_limits<double>::quiet_NaN();
118  mMedian = std::numeric_limits<double>::quiet_NaN();
119  mStdev = std::numeric_limits<double>::quiet_NaN();
120  mSampleStdev = std::numeric_limits<double>::quiet_NaN();
121  mMinority = std::numeric_limits<double>::quiet_NaN();
122  mMajority = std::numeric_limits<double>::quiet_NaN();
123  mFirstQuartile = std::numeric_limits<double>::quiet_NaN();
124  mThirdQuartile = std::numeric_limits<double>::quiet_NaN();
125  return;
126  }
127 
128  mMean = mSum / mCount;
129 
130  if ( mStatistics & QgsStatisticalSummary::StDev || mStatistics & QgsStatisticalSummary::StDevSample )
131  {
132  double sumSquared = 0;
133  Q_FOREACH ( double value, mValues )
134  {
135  double diff = value - mMean;
136  sumSquared += diff * diff;
137  }
138  mStdev = std::pow( sumSquared / mValues.count(), 0.5 );
139  mSampleStdev = std::pow( sumSquared / ( mValues.count() - 1 ), 0.5 );
140  }
141 
142  if ( mStatistics & QgsStatisticalSummary::Median
143  || mStatistics & QgsStatisticalSummary::FirstQuartile
144  || mStatistics & QgsStatisticalSummary::ThirdQuartile
146  {
147  std::sort( mValues.begin(), mValues.end() );
148  bool even = ( mCount % 2 ) < 1;
149  if ( even )
150  {
151  mMedian = ( mValues[mCount / 2 - 1] + mValues[mCount / 2] ) / 2.0;
152  }
153  else //odd
154  {
155  mMedian = mValues[( mCount + 1 ) / 2 - 1];
156  }
157  }
158 
159  if ( mStatistics & QgsStatisticalSummary::FirstQuartile
160  || mStatistics & QgsStatisticalSummary::InterQuartileRange )
161  {
162  if ( ( mCount % 2 ) < 1 )
163  {
164  int halfCount = mCount / 2;
165  bool even = ( halfCount % 2 ) < 1;
166  if ( even )
167  {
168  mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
169  }
170  else //odd
171  {
172  mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
173  }
174  }
175  else
176  {
177  int halfCount = mCount / 2 + 1;
178  bool even = ( halfCount % 2 ) < 1;
179  if ( even )
180  {
181  mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
182  }
183  else //odd
184  {
185  mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
186  }
187  }
188  }
189 
190  if ( mStatistics & QgsStatisticalSummary::ThirdQuartile
191  || mStatistics & QgsStatisticalSummary::InterQuartileRange )
192  {
193  if ( ( mCount % 2 ) < 1 )
194  {
195  int halfCount = mCount / 2;
196  bool even = ( halfCount % 2 ) < 1;
197  if ( even )
198  {
199  mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 1] + mValues[ halfCount + halfCount / 2] ) / 2.0;
200  }
201  else //odd
202  {
203  mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 1 + halfCount ];
204  }
205  }
206  else
207  {
208  int halfCount = mCount / 2 + 1;
209  bool even = ( halfCount % 2 ) < 1;
210  if ( even )
211  {
212  mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 2 ] + mValues[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
213  }
214  else //odd
215  {
216  mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 2 + halfCount ];
217  }
218  }
219  }
220 
221  if ( mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Majority )
222  {
223  QList<int> valueCounts = mValueCount.values();
224  std::sort( valueCounts.begin(), valueCounts.end() );
225  if ( mStatistics & QgsStatisticalSummary::Minority )
226  {
227  mMinority = mValueCount.key( valueCounts.first() );
228  }
229  if ( mStatistics & QgsStatisticalSummary::Majority )
230  {
231  mMajority = mValueCount.key( valueCounts.last() );
232  }
233  }
234 
235 }
236 
237 /***************************************************************************
238  * This class is considered CRITICAL and any change MUST be accompanied with
239  * full unit tests in testqgsstatisticalsummary.cpp.
240  * See details in QEP #17
241  ****************************************************************************/
242 
244 {
245  switch ( stat )
246  {
247  case Count:
248  return mCount;
249  case CountMissing:
250  return mMissing;
251  case Sum:
252  return mSum;
253  case Mean:
254  return mMean;
255  case Median:
256  return mMedian;
257  case StDev:
258  return mStdev;
259  case StDevSample:
260  return mSampleStdev;
261  case Min:
262  return mMin;
263  case Max:
264  return mMax;
265  case Range:
266  return mMax - mMin;
267  case Minority:
268  return mMinority;
269  case Majority:
270  return mMajority;
271  case Variety:
272  return mValueCount.count();
273  case FirstQuartile:
274  return mFirstQuartile;
275  case ThirdQuartile:
276  return mThirdQuartile;
277  case InterQuartileRange:
278  return mThirdQuartile - mFirstQuartile;
279  case All:
280  return 0;
281  }
282  return 0;
283 }
284 
286 {
287  switch ( statistic )
288  {
289  case Count:
290  return QObject::tr( "Count" );
291  case CountMissing:
292  return QObject::tr( "Count (missing)" );
293  case Sum:
294  return QObject::tr( "Sum" );
295  case Mean:
296  return QObject::tr( "Mean" );
297  case Median:
298  return QObject::tr( "Median" );
299  case StDev:
300  return QObject::tr( "St dev (pop)" );
301  case StDevSample:
302  return QObject::tr( "St dev (sample)" );
303  case Min:
304  return QObject::tr( "Minimum" );
305  case Max:
306  return QObject::tr( "Maximum" );
307  case Range:
308  return QObject::tr( "Range" );
309  case Minority:
310  return QObject::tr( "Minority" );
311  case Majority:
312  return QObject::tr( "Majority" );
313  case Variety:
314  return QObject::tr( "Variety" );
315  case FirstQuartile:
316  return QObject::tr( "Q1" );
317  case ThirdQuartile:
318  return QObject::tr( "Q3" );
319  case InterQuartileRange:
320  return QObject::tr( "IQR" );
321  case All:
322  return QString();
323  }
324  return QString();
325 }
326 
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.
double statistic(QgsStatisticalSummary::Statistic stat) const
Returns the value of a specified statistic.
QgsStatisticalSummary(QgsStatisticalSummary::Statistics stats=QgsStatisticalSummary::All)
Constructor for QgsStatisticalSummary.
static QString displayName(QgsStatisticalSummary::Statistic statistic)
Returns the friendly display name for a statistic.
void setStatistics(QgsStatisticalSummary::Statistics stats)
Sets flags which specify which statistics will be calculated.
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.