QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
25using namespace Qt::StringLiterals;
26
27/***************************************************************************
28 * This class is considered CRITICAL and any change MUST be accompanied with
29 * full unit tests in testqgsstatisticalsummary.cpp.
30 * See details in QEP #17
31 ****************************************************************************/
32
34 : mStatistics( stats )
35{
36 reset();
37}
38
40{
41 mStatistics = stats;
42 reset();
43}
44
46{
47 mFirst = std::numeric_limits<double>::quiet_NaN();
48 mLast = std::numeric_limits<double>::quiet_NaN();
49 mCount = 0;
50 mMissing = 0;
51 mSum = 0;
52 mMean = 0;
53 mMedian = 0;
54 mMin = std::numeric_limits<double>::max();
55 mMax = -std::numeric_limits<double>::max();
56 mStdev = 0;
57 mSampleStdev = 0;
58 mMinority = 0;
59 mMajority = 0;
60 mFirstQuartile = 0;
61 mThirdQuartile = 0;
62 mValueCount.clear();
63 mValues.clear();
64
65 mRequiresHisto = mStatistics & Qgis::Statistic::Majority || mStatistics & Qgis::Statistic::Minority || mStatistics & Qgis::Statistic::Variety;
66
67 mRequiresAllValueStorage = mStatistics & Qgis::Statistic::StDev
68 || mStatistics & Qgis::Statistic::StDevSample
69 || mStatistics & Qgis::Statistic::Median
70 || mStatistics & Qgis::Statistic::FirstQuartile
71 || mStatistics & Qgis::Statistic::ThirdQuartile
73}
74
75/***************************************************************************
76 * This class is considered CRITICAL and any change MUST be accompanied with
77 * full unit tests in testqgsstatisticalsummary.cpp.
78 * See details in QEP #17
79 ****************************************************************************/
80
81void QgsStatisticalSummary::calculate( const QList<double> &values )
82{
83 reset();
84
85 for ( const double value : values )
86 {
87 addValue( value );
88 }
89
90 finalize();
91}
92
94{
95 if ( mCount == 0 )
96 mFirst = value;
97 mCount++;
98 mSum += value;
99 mMin = std::min( mMin, value );
100 mMax = std::max( mMax, value );
101 mLast = value;
102
103 if ( mRequiresHisto )
104 mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
105
106 if ( mRequiresAllValueStorage )
107 mValues << value;
108}
109
110void QgsStatisticalSummary::addVariant( const QVariant &value )
111{
112 bool convertOk = false;
113 if ( QgsVariantUtils::isNull( value ) )
114 mMissing++;
115 else
116 {
117 const double val = value.toDouble( &convertOk );
118 if ( convertOk )
119 addValue( val );
120 else
121 mMissing++;
122 }
123}
124
126{
127 if ( mCount == 0 )
128 {
129 mFirst = std::numeric_limits<double>::quiet_NaN();
130 mLast = std::numeric_limits<double>::quiet_NaN();
131 mMin = std::numeric_limits<double>::quiet_NaN();
132 mMax = std::numeric_limits<double>::quiet_NaN();
133 mMean = std::numeric_limits<double>::quiet_NaN();
134 mMedian = std::numeric_limits<double>::quiet_NaN();
135 mStdev = std::numeric_limits<double>::quiet_NaN();
136 mSampleStdev = std::numeric_limits<double>::quiet_NaN();
137 mMinority = std::numeric_limits<double>::quiet_NaN();
138 mMajority = std::numeric_limits<double>::quiet_NaN();
139 mFirstQuartile = std::numeric_limits<double>::quiet_NaN();
140 mThirdQuartile = std::numeric_limits<double>::quiet_NaN();
141 return;
142 }
143
144 mMean = mSum / mCount;
145
146 if ( mStatistics & Qgis::Statistic::StDev || mStatistics & Qgis::Statistic::StDevSample )
147 {
148 double sumSquared = 0;
149 const auto constMValues = mValues;
150 for ( const double value : constMValues )
151 {
152 const double diff = value - mMean;
153 sumSquared += diff * diff;
154 }
155 mStdev = std::pow( sumSquared / mValues.count(), 0.5 );
156 mSampleStdev = std::pow( sumSquared / ( mValues.count() - 1 ), 0.5 );
157 }
158
159 if ( mStatistics & Qgis::Statistic::Median || mStatistics & Qgis::Statistic::FirstQuartile || mStatistics & Qgis::Statistic::ThirdQuartile || mStatistics & Qgis::Statistic::InterQuartileRange )
160 {
161 std::sort( mValues.begin(), mValues.end() );
162 const bool even = ( mCount % 2 ) < 1;
163 if ( even )
164 {
165 mMedian = ( mValues[mCount / 2 - 1] + mValues[mCount / 2] ) / 2.0;
166 }
167 else //odd
168 {
169 mMedian = mValues[( mCount + 1 ) / 2 - 1];
170 }
171 }
172
173 if ( mStatistics & Qgis::Statistic::FirstQuartile || mStatistics & Qgis::Statistic::InterQuartileRange )
174 {
175 if ( ( mCount % 2 ) < 1 )
176 {
177 const int halfCount = mCount / 2;
178 const 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 else
189 {
190 const int halfCount = mCount / 2 + 1;
191 const bool even = ( halfCount % 2 ) < 1;
192 if ( even )
193 {
194 mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
195 }
196 else //odd
197 {
198 mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
199 }
200 }
201 }
202
203 if ( mStatistics & Qgis::Statistic::ThirdQuartile || 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 * This class is considered CRITICAL and any change MUST be accompanied with
250 * full unit tests in testqgsstatisticalsummary.cpp.
251 * See details in QEP #17
252 ****************************************************************************/
253
255{
256 switch ( stat )
257 {
259 return mCount;
261 return mMissing;
263 return mSum;
265 return mMean;
267 return mMedian;
269 return mStdev;
271 return mSampleStdev;
273 return mMin;
275 return mMax;
277 return mMax - mMin;
279 return mMinority;
281 return mMajority;
283 return mValueCount.count();
285 return mFirstQuartile;
287 return mThirdQuartile;
289 return mThirdQuartile - mFirstQuartile;
291 return mFirst;
293 return mLast;
295 return 0;
296 }
297 return 0;
298}
299
301{
302 switch ( statistic )
303 {
305 return QObject::tr( "Count" );
307 return QObject::tr( "Count (missing)" );
309 return QObject::tr( "Sum" );
311 return QObject::tr( "Mean" );
313 return QObject::tr( "Median" );
315 return QObject::tr( "St dev (pop)" );
317 return QObject::tr( "St dev (sample)" );
319 return QObject::tr( "Minimum" );
321 return QObject::tr( "Maximum" );
323 return QObject::tr( "Range" );
325 return QObject::tr( "Minority" );
327 return QObject::tr( "Majority" );
329 return QObject::tr( "Variety" );
331 return QObject::tr( "Q1" );
333 return QObject::tr( "Q3" );
335 return QObject::tr( "IQR" );
337 return QObject::tr( "First" );
339 return QObject::tr( "Last" );
341 return QString();
342 }
343 return QString();
344}
345
347{
348 switch ( statistic )
349 {
351 return u"count"_s;
353 return u"countmissing"_s;
355 return u"sum"_s;
357 return u"mean"_s;
359 return u"median"_s;
361 return u"stdev"_s;
363 return u"stdevsample"_s;
365 return u"min"_s;
367 return u"max"_s;
369 return u"range"_s;
371 return u"minority"_s;
373 return u"majority"_s;
375 return u"variety"_s;
377 return u"q1"_s;
379 return u"q3"_s;
381 return u"iqr"_s;
383 return u"first"_s;
385 return u"last"_s;
387 return QString();
388 }
389 return QString();
390}
Statistic
Available generic statistics.
Definition qgis.h:6206
@ StDev
Standard deviation of values.
Definition qgis.h:6212
@ FirstQuartile
First quartile.
Definition qgis.h:6220
@ Mean
Mean of values.
Definition qgis.h:6210
@ Median
Median of values.
Definition qgis.h:6211
@ Max
Max of values.
Definition qgis.h:6215
@ Min
Min of values.
Definition qgis.h:6214
@ First
First value.
Definition qgis.h:6223
@ Range
Range of values (max - min).
Definition qgis.h:6216
@ Sum
Sum of values.
Definition qgis.h:6209
@ Minority
Minority of values.
Definition qgis.h:6217
@ CountMissing
Number of missing (null) values.
Definition qgis.h:6208
@ All
All statistics.
Definition qgis.h:6225
@ Majority
Majority of values.
Definition qgis.h:6218
@ Variety
Variety (count of distinct) values.
Definition qgis.h:6219
@ StDevSample
Sample standard deviation of values.
Definition qgis.h:6213
@ Last
Last value.
Definition qgis.h:6224
@ Count
Count.
Definition qgis.h:6207
@ ThirdQuartile
Third quartile.
Definition qgis.h:6221
@ InterQuartileRange
Inter quartile range (IQR).
Definition qgis.h:6222
QFlags< Statistic > Statistics
Statistics to be calculated for generic values.
Definition qgis.h:6234
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.