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