QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
17#include "qgsvariantutils.h"
18#include <limits>
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 mStatistics = stats;
37 reset();
38}
39
41{
42 mFirst = std::numeric_limits<double>::quiet_NaN();
43 mLast = std::numeric_limits<double>::quiet_NaN();
44 mCount = 0;
45 mMissing = 0;
46 mSum = 0;
47 mMean = 0;
48 mMedian = 0;
49 mMin = std::numeric_limits<double>::max();
50 mMax = -std::numeric_limits<double>::max();
51 mStdev = 0;
52 mSampleStdev = 0;
53 mMinority = 0;
54 mMajority = 0;
55 mFirstQuartile = 0;
56 mThirdQuartile = 0;
57 mValueCount.clear();
58 mValues.clear();
59
60 mRequiresHisto = mStatistics & Qgis::Statistic::Majority || mStatistics & Qgis::Statistic::Minority || mStatistics & Qgis::Statistic::Variety;
61
62 mRequiresAllValueStorage = mStatistics & Qgis::Statistic::StDev || mStatistics & Qgis::Statistic::StDevSample ||
63 mStatistics & Qgis::Statistic::Median || mStatistics & Qgis::Statistic::FirstQuartile ||
65}
66
67/***************************************************************************
68 * This class is considered CRITICAL and any change MUST be accompanied with
69 * full unit tests in testqgsstatisticalsummary.cpp.
70 * See details in QEP #17
71 ****************************************************************************/
72
73void QgsStatisticalSummary::calculate( const QList<double> &values )
74{
75 reset();
76
77 for ( const double value : values )
78 {
79 addValue( value );
80 }
81
82 finalize();
83}
84
86{
87 if ( mCount == 0 )
88 mFirst = value;
89 mCount++;
90 mSum += value;
91 mMin = std::min( mMin, value );
92 mMax = std::max( mMax, value );
93 mLast = value;
94
95 if ( mRequiresHisto )
96 mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
97
98 if ( mRequiresAllValueStorage )
99 mValues << value;
100}
101
102void QgsStatisticalSummary::addVariant( const QVariant &value )
103{
104 bool convertOk = false;
105 if ( QgsVariantUtils::isNull( value ) )
106 mMissing++;
107 else
108 {
109 const double val = value.toDouble( &convertOk );
110 if ( convertOk )
111 addValue( val );
112 else
113 mMissing++;
114 }
115}
116
118{
119 if ( mCount == 0 )
120 {
121 mFirst = std::numeric_limits<double>::quiet_NaN();
122 mLast = std::numeric_limits<double>::quiet_NaN();
123 mMin = std::numeric_limits<double>::quiet_NaN();
124 mMax = std::numeric_limits<double>::quiet_NaN();
125 mMean = std::numeric_limits<double>::quiet_NaN();
126 mMedian = std::numeric_limits<double>::quiet_NaN();
127 mStdev = std::numeric_limits<double>::quiet_NaN();
128 mSampleStdev = std::numeric_limits<double>::quiet_NaN();
129 mMinority = std::numeric_limits<double>::quiet_NaN();
130 mMajority = std::numeric_limits<double>::quiet_NaN();
131 mFirstQuartile = std::numeric_limits<double>::quiet_NaN();
132 mThirdQuartile = std::numeric_limits<double>::quiet_NaN();
133 return;
134 }
135
136 mMean = mSum / mCount;
137
138 if ( mStatistics & Qgis::Statistic::StDev || mStatistics & Qgis::Statistic::StDevSample )
139 {
140 double sumSquared = 0;
141 const auto constMValues = mValues;
142 for ( const double value : constMValues )
143 {
144 const double diff = value - mMean;
145 sumSquared += diff * diff;
146 }
147 mStdev = std::pow( sumSquared / mValues.count(), 0.5 );
148 mSampleStdev = std::pow( sumSquared / ( mValues.count() - 1 ), 0.5 );
149 }
150
151 if ( mStatistics & Qgis::Statistic::Median
152 || mStatistics & Qgis::Statistic::FirstQuartile
153 || mStatistics & Qgis::Statistic::ThirdQuartile
154 || mStatistics & Qgis::Statistic::InterQuartileRange )
155 {
156 std::sort( mValues.begin(), mValues.end() );
157 const bool even = ( mCount % 2 ) < 1;
158 if ( even )
159 {
160 mMedian = ( mValues[mCount / 2 - 1] + mValues[mCount / 2] ) / 2.0;
161 }
162 else //odd
163 {
164 mMedian = mValues[( mCount + 1 ) / 2 - 1];
165 }
166 }
167
168 if ( mStatistics & Qgis::Statistic::FirstQuartile
169 || mStatistics & Qgis::Statistic::InterQuartileRange )
170 {
171 if ( ( mCount % 2 ) < 1 )
172 {
173 const int halfCount = mCount / 2;
174 const 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 else
185 {
186 const int halfCount = mCount / 2 + 1;
187 const bool even = ( halfCount % 2 ) < 1;
188 if ( even )
189 {
190 mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
191 }
192 else //odd
193 {
194 mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
195 }
196 }
197 }
198
199 if ( mStatistics & Qgis::Statistic::ThirdQuartile
200 || mStatistics & Qgis::Statistic::InterQuartileRange )
201 {
202 if ( ( mCount % 2 ) < 1 )
203 {
204 const int halfCount = mCount / 2;
205 const bool even = ( halfCount % 2 ) < 1;
206 if ( even )
207 {
208 mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 1] + mValues[ halfCount + halfCount / 2] ) / 2.0;
209 }
210 else //odd
211 {
212 mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 1 + halfCount ];
213 }
214 }
215 else
216 {
217 const int halfCount = mCount / 2 + 1;
218 const bool even = ( halfCount % 2 ) < 1;
219 if ( even )
220 {
221 mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 2 ] + mValues[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
222 }
223 else //odd
224 {
225 mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 2 + halfCount ];
226 }
227 }
228 }
229
230 if ( mStatistics & Qgis::Statistic::Minority || mStatistics & Qgis::Statistic::Majority )
231 {
232 QList<int> valueCounts = mValueCount.values();
233
234 if ( mStatistics & Qgis::Statistic::Minority )
235 {
236 mMinority = mValueCount.key( *std::min_element( valueCounts.begin(), valueCounts.end() ) );
237 }
238 if ( mStatistics & Qgis::Statistic::Majority )
239 {
240 mMajority = mValueCount.key( *std::max_element( valueCounts.begin(), valueCounts.end() ) );
241 }
242 }
243
244}
245
246/***************************************************************************
247 * This class is considered CRITICAL and any change MUST be accompanied with
248 * full unit tests in testqgsstatisticalsummary.cpp.
249 * See details in QEP #17
250 ****************************************************************************/
251
253{
254 switch ( stat )
255 {
257 return mCount;
259 return mMissing;
261 return mSum;
263 return mMean;
265 return mMedian;
267 return mStdev;
269 return mSampleStdev;
271 return mMin;
273 return mMax;
275 return mMax - mMin;
277 return mMinority;
279 return mMajority;
281 return mValueCount.count();
283 return mFirstQuartile;
285 return mThirdQuartile;
287 return mThirdQuartile - mFirstQuartile;
289 return mFirst;
291 return mLast;
293 return 0;
294 }
295 return 0;
296}
297
299{
300 switch ( statistic )
301 {
303 return QObject::tr( "Count" );
305 return QObject::tr( "Count (missing)" );
307 return QObject::tr( "Sum" );
309 return QObject::tr( "Mean" );
311 return QObject::tr( "Median" );
313 return QObject::tr( "St dev (pop)" );
315 return QObject::tr( "St dev (sample)" );
317 return QObject::tr( "Minimum" );
319 return QObject::tr( "Maximum" );
321 return QObject::tr( "Range" );
323 return QObject::tr( "Minority" );
325 return QObject::tr( "Majority" );
327 return QObject::tr( "Variety" );
329 return QObject::tr( "Q1" );
331 return QObject::tr( "Q3" );
333 return QObject::tr( "IQR" );
335 return QObject::tr( "First" );
337 return QObject::tr( "Last" );
339 return QString();
340 }
341 return QString();
342}
343
345{
346 switch ( statistic )
347 {
349 return QStringLiteral( "count" );
351 return QStringLiteral( "countmissing" );
353 return QStringLiteral( "sum" );
355 return QStringLiteral( "mean" );
357 return QStringLiteral( "median" );
359 return QStringLiteral( "stdev" );
361 return QStringLiteral( "stdevsample" );
363 return QStringLiteral( "min" );
365 return QStringLiteral( "max" );
367 return QStringLiteral( "range" );
369 return QStringLiteral( "minority" );
371 return QStringLiteral( "majority" );
373 return QStringLiteral( "variety" );
375 return QStringLiteral( "q1" );
377 return QStringLiteral( "q3" );
379 return QStringLiteral( "iqr" );
381 return QStringLiteral( "first" );
383 return QStringLiteral( "last" );
385 return QString();
386 }
387 return QString();
388}
389
Statistic
Available generic statistics.
Definition: qgis.h:4747
@ StDev
Standard deviation of values.
@ FirstQuartile
First quartile.
@ Mean
Mean of values.
@ Median
Median of values.
@ Max
Max of values.
@ Min
Min of values.
@ First
First value (since QGIS 3.6)
@ Range
Range of values (max - min)
@ Sum
Sum of values.
@ Minority
Minority of values.
@ CountMissing
Number of missing (null) values.
@ All
All statistics.
@ Majority
Majority of values.
@ Variety
Variety (count of distinct) values.
@ StDevSample
Sample standard deviation of values.
@ Last
Last value (since QGIS 3.6)
@ ThirdQuartile
Third quartile.
@ InterQuartileRange
Inter quartile range (IQR)
QFlags< Statistic > Statistics
Statistics to be calculated for generic values.
Definition: qgis.h:4775
void addVariant(const QVariant &value)
Adds a single value to the statistics calculation.
static QString displayName(Qgis::Statistic statistic)
Returns the friendly display name for a statistic.
static QString shortName(Qgis::Statistic statistic)
Returns a short, friendly display name for a statistic, suitable for use in a field name.
void calculate(const QList< double > &values)
Calculates summary statistics for a list of values.
void addValue(double value)
Adds a single value to the statistics calculation.
QgsStatisticalSummary(Qgis::Statistics stats=Qgis::Statistic::All)
Constructor for QgsStatisticalSummary.
void reset()
Resets the calculated values.
double statistic(Qgis::Statistic stat) const
Returns the value of a specified statistic.
void finalize()
Must be called after adding all values with addValues() and before retrieving any calculated statisti...
void setStatistics(Qgis::Statistics stats)
Sets flags which specify which statistics will be calculated.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.