QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
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
18#include <limits>
19
20#include "qgsvariantutils.h"
21
22#include <QObject>
23#include <QString>
24
25/***************************************************************************
26 * This class is considered CRITICAL and any change MUST be accompanied with
27 * full unit tests in testqgsstatisticalsummary.cpp.
28 * See details in QEP #17
29 ****************************************************************************/
30
32 : mStatistics( stats )
33{
34 reset();
35}
36
38{
39 mStatistics = stats;
40 reset();
41}
42
44{
45 mFirst = std::numeric_limits<double>::quiet_NaN();
46 mLast = std::numeric_limits<double>::quiet_NaN();
47 mCount = 0;
48 mMissing = 0;
49 mSum = 0;
50 mMean = 0;
51 mMedian = 0;
52 mMin = std::numeric_limits<double>::max();
53 mMax = -std::numeric_limits<double>::max();
54 mStdev = 0;
55 mSampleStdev = 0;
56 mMinority = 0;
57 mMajority = 0;
58 mFirstQuartile = 0;
59 mThirdQuartile = 0;
60 mValueCount.clear();
61 mValues.clear();
62
63 mRequiresHisto = mStatistics & Qgis::Statistic::Majority || mStatistics & Qgis::Statistic::Minority || mStatistics & Qgis::Statistic::Variety;
64
65 mRequiresAllValueStorage = mStatistics & Qgis::Statistic::StDev || mStatistics & Qgis::Statistic::StDevSample ||
66 mStatistics & Qgis::Statistic::Median || mStatistics & Qgis::Statistic::FirstQuartile ||
68}
69
70/***************************************************************************
71 * This class is considered CRITICAL and any change MUST be accompanied with
72 * full unit tests in testqgsstatisticalsummary.cpp.
73 * See details in QEP #17
74 ****************************************************************************/
75
76void QgsStatisticalSummary::calculate( const QList<double> &values )
77{
78 reset();
79
80 for ( const double value : values )
81 {
82 addValue( value );
83 }
84
85 finalize();
86}
87
89{
90 if ( mCount == 0 )
91 mFirst = value;
92 mCount++;
93 mSum += value;
94 mMin = std::min( mMin, value );
95 mMax = std::max( mMax, value );
96 mLast = value;
97
98 if ( mRequiresHisto )
99 mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
100
101 if ( mRequiresAllValueStorage )
102 mValues << value;
103}
104
105void QgsStatisticalSummary::addVariant( const QVariant &value )
106{
107 bool convertOk = false;
108 if ( QgsVariantUtils::isNull( value ) )
109 mMissing++;
110 else
111 {
112 const double val = value.toDouble( &convertOk );
113 if ( convertOk )
114 addValue( val );
115 else
116 mMissing++;
117 }
118}
119
121{
122 if ( mCount == 0 )
123 {
124 mFirst = std::numeric_limits<double>::quiet_NaN();
125 mLast = std::numeric_limits<double>::quiet_NaN();
126 mMin = std::numeric_limits<double>::quiet_NaN();
127 mMax = std::numeric_limits<double>::quiet_NaN();
128 mMean = std::numeric_limits<double>::quiet_NaN();
129 mMedian = std::numeric_limits<double>::quiet_NaN();
130 mStdev = std::numeric_limits<double>::quiet_NaN();
131 mSampleStdev = std::numeric_limits<double>::quiet_NaN();
132 mMinority = std::numeric_limits<double>::quiet_NaN();
133 mMajority = std::numeric_limits<double>::quiet_NaN();
134 mFirstQuartile = std::numeric_limits<double>::quiet_NaN();
135 mThirdQuartile = std::numeric_limits<double>::quiet_NaN();
136 return;
137 }
138
139 mMean = mSum / mCount;
140
141 if ( mStatistics & Qgis::Statistic::StDev || mStatistics & Qgis::Statistic::StDevSample )
142 {
143 double sumSquared = 0;
144 const auto constMValues = mValues;
145 for ( const double value : constMValues )
146 {
147 const double diff = value - mMean;
148 sumSquared += diff * diff;
149 }
150 mStdev = std::pow( sumSquared / mValues.count(), 0.5 );
151 mSampleStdev = std::pow( sumSquared / ( mValues.count() - 1 ), 0.5 );
152 }
153
154 if ( mStatistics & Qgis::Statistic::Median
155 || mStatistics & Qgis::Statistic::FirstQuartile
156 || mStatistics & Qgis::Statistic::ThirdQuartile
157 || mStatistics & Qgis::Statistic::InterQuartileRange )
158 {
159 std::sort( mValues.begin(), mValues.end() );
160 const bool even = ( mCount % 2 ) < 1;
161 if ( even )
162 {
163 mMedian = ( mValues[mCount / 2 - 1] + mValues[mCount / 2] ) / 2.0;
164 }
165 else //odd
166 {
167 mMedian = mValues[( mCount + 1 ) / 2 - 1];
168 }
169 }
170
171 if ( mStatistics & Qgis::Statistic::FirstQuartile
172 || mStatistics & Qgis::Statistic::InterQuartileRange )
173 {
174 if ( ( mCount % 2 ) < 1 )
175 {
176 const int halfCount = mCount / 2;
177 const bool even = ( halfCount % 2 ) < 1;
178 if ( even )
179 {
180 mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
181 }
182 else //odd
183 {
184 mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
185 }
186 }
187 else
188 {
189 const int halfCount = mCount / 2 + 1;
190 const bool even = ( halfCount % 2 ) < 1;
191 if ( even )
192 {
193 mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
194 }
195 else //odd
196 {
197 mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
198 }
199 }
200 }
201
202 if ( mStatistics & Qgis::Statistic::ThirdQuartile
203 || mStatistics & Qgis::Statistic::InterQuartileRange )
204 {
205 if ( ( mCount % 2 ) < 1 )
206 {
207 const int halfCount = mCount / 2;
208 const bool even = ( halfCount % 2 ) < 1;
209 if ( even )
210 {
211 mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 1] + mValues[ halfCount + halfCount / 2] ) / 2.0;
212 }
213 else //odd
214 {
215 mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 1 + halfCount ];
216 }
217 }
218 else
219 {
220 const int halfCount = mCount / 2 + 1;
221 const bool even = ( halfCount % 2 ) < 1;
222 if ( even )
223 {
224 mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 2 ] + mValues[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
225 }
226 else //odd
227 {
228 mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 2 + halfCount ];
229 }
230 }
231 }
232
233 if ( mStatistics & Qgis::Statistic::Minority || mStatistics & Qgis::Statistic::Majority )
234 {
235 QList<int> valueCounts = mValueCount.values();
236
237 if ( mStatistics & Qgis::Statistic::Minority )
238 {
239 mMinority = mValueCount.key( *std::min_element( valueCounts.begin(), valueCounts.end() ) );
240 }
241 if ( mStatistics & Qgis::Statistic::Majority )
242 {
243 mMajority = mValueCount.key( *std::max_element( valueCounts.begin(), valueCounts.end() ) );
244 }
245 }
246
247}
248
249/***************************************************************************
250 * This class is considered CRITICAL and any change MUST be accompanied with
251 * full unit tests in testqgsstatisticalsummary.cpp.
252 * See details in QEP #17
253 ****************************************************************************/
254
256{
257 switch ( stat )
258 {
260 return mCount;
262 return mMissing;
264 return mSum;
266 return mMean;
268 return mMedian;
270 return mStdev;
272 return mSampleStdev;
274 return mMin;
276 return mMax;
278 return mMax - mMin;
280 return mMinority;
282 return mMajority;
284 return mValueCount.count();
286 return mFirstQuartile;
288 return mThirdQuartile;
290 return mThirdQuartile - mFirstQuartile;
292 return mFirst;
294 return mLast;
296 return 0;
297 }
298 return 0;
299}
300
302{
303 switch ( statistic )
304 {
306 return QObject::tr( "Count" );
308 return QObject::tr( "Count (missing)" );
310 return QObject::tr( "Sum" );
312 return QObject::tr( "Mean" );
314 return QObject::tr( "Median" );
316 return QObject::tr( "St dev (pop)" );
318 return QObject::tr( "St dev (sample)" );
320 return QObject::tr( "Minimum" );
322 return QObject::tr( "Maximum" );
324 return QObject::tr( "Range" );
326 return QObject::tr( "Minority" );
328 return QObject::tr( "Majority" );
330 return QObject::tr( "Variety" );
332 return QObject::tr( "Q1" );
334 return QObject::tr( "Q3" );
336 return QObject::tr( "IQR" );
338 return QObject::tr( "First" );
340 return QObject::tr( "Last" );
342 return QString();
343 }
344 return QString();
345}
346
348{
349 switch ( statistic )
350 {
352 return QStringLiteral( "count" );
354 return QStringLiteral( "countmissing" );
356 return QStringLiteral( "sum" );
358 return QStringLiteral( "mean" );
360 return QStringLiteral( "median" );
362 return QStringLiteral( "stdev" );
364 return QStringLiteral( "stdevsample" );
366 return QStringLiteral( "min" );
368 return QStringLiteral( "max" );
370 return QStringLiteral( "range" );
372 return QStringLiteral( "minority" );
374 return QStringLiteral( "majority" );
376 return QStringLiteral( "variety" );
378 return QStringLiteral( "q1" );
380 return QStringLiteral( "q3" );
382 return QStringLiteral( "iqr" );
384 return QStringLiteral( "first" );
386 return QStringLiteral( "last" );
388 return QString();
389 }
390 return QString();
391}
392
Statistic
Available generic statistics.
Definition qgis.h:5848
@ StDev
Standard deviation of values.
Definition qgis.h:5854
@ FirstQuartile
First quartile.
Definition qgis.h:5862
@ Mean
Mean of values.
Definition qgis.h:5852
@ Median
Median of values.
Definition qgis.h:5853
@ Max
Max of values.
Definition qgis.h:5857
@ Min
Min of values.
Definition qgis.h:5856
@ First
First value.
Definition qgis.h:5865
@ Range
Range of values (max - min).
Definition qgis.h:5858
@ Sum
Sum of values.
Definition qgis.h:5851
@ Minority
Minority of values.
Definition qgis.h:5859
@ CountMissing
Number of missing (null) values.
Definition qgis.h:5850
@ All
All statistics.
Definition qgis.h:5867
@ Majority
Majority of values.
Definition qgis.h:5860
@ Variety
Variety (count of distinct) values.
Definition qgis.h:5861
@ StDevSample
Sample standard deviation of values.
Definition qgis.h:5855
@ Last
Last value.
Definition qgis.h:5866
@ Count
Count.
Definition qgis.h:5849
@ ThirdQuartile
Third quartile.
Definition qgis.h:5863
@ InterQuartileRange
Inter quartile range (IQR).
Definition qgis.h:5864
QFlags< Statistic > Statistics
Statistics to be calculated for generic values.
Definition qgis.h:5876
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.