QGIS API Documentation 3.99.0-Master (d270888f95f)
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 || mStatistics & Qgis::Statistic::StDevSample ||
68 mStatistics & Qgis::Statistic::Median || mStatistics & Qgis::Statistic::FirstQuartile ||
70}
71
72/***************************************************************************
73 * This class is considered CRITICAL and any change MUST be accompanied with
74 * full unit tests in testqgsstatisticalsummary.cpp.
75 * See details in QEP #17
76 ****************************************************************************/
77
78void QgsStatisticalSummary::calculate( const QList<double> &values )
79{
80 reset();
81
82 for ( const double value : values )
83 {
84 addValue( value );
85 }
86
87 finalize();
88}
89
91{
92 if ( mCount == 0 )
93 mFirst = value;
94 mCount++;
95 mSum += value;
96 mMin = std::min( mMin, value );
97 mMax = std::max( mMax, value );
98 mLast = value;
99
100 if ( mRequiresHisto )
101 mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
102
103 if ( mRequiresAllValueStorage )
104 mValues << value;
105}
106
107void QgsStatisticalSummary::addVariant( const QVariant &value )
108{
109 bool convertOk = false;
110 if ( QgsVariantUtils::isNull( value ) )
111 mMissing++;
112 else
113 {
114 const double val = value.toDouble( &convertOk );
115 if ( convertOk )
116 addValue( val );
117 else
118 mMissing++;
119 }
120}
121
123{
124 if ( mCount == 0 )
125 {
126 mFirst = std::numeric_limits<double>::quiet_NaN();
127 mLast = std::numeric_limits<double>::quiet_NaN();
128 mMin = std::numeric_limits<double>::quiet_NaN();
129 mMax = std::numeric_limits<double>::quiet_NaN();
130 mMean = std::numeric_limits<double>::quiet_NaN();
131 mMedian = std::numeric_limits<double>::quiet_NaN();
132 mStdev = std::numeric_limits<double>::quiet_NaN();
133 mSampleStdev = std::numeric_limits<double>::quiet_NaN();
134 mMinority = std::numeric_limits<double>::quiet_NaN();
135 mMajority = std::numeric_limits<double>::quiet_NaN();
136 mFirstQuartile = std::numeric_limits<double>::quiet_NaN();
137 mThirdQuartile = std::numeric_limits<double>::quiet_NaN();
138 return;
139 }
140
141 mMean = mSum / mCount;
142
143 if ( mStatistics & Qgis::Statistic::StDev || mStatistics & Qgis::Statistic::StDevSample )
144 {
145 double sumSquared = 0;
146 const auto constMValues = mValues;
147 for ( const double value : constMValues )
148 {
149 const double diff = value - mMean;
150 sumSquared += diff * diff;
151 }
152 mStdev = std::pow( sumSquared / mValues.count(), 0.5 );
153 mSampleStdev = std::pow( sumSquared / ( mValues.count() - 1 ), 0.5 );
154 }
155
156 if ( mStatistics & Qgis::Statistic::Median
157 || mStatistics & Qgis::Statistic::FirstQuartile
158 || mStatistics & Qgis::Statistic::ThirdQuartile
159 || 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
174 || mStatistics & Qgis::Statistic::InterQuartileRange )
175 {
176 if ( ( mCount % 2 ) < 1 )
177 {
178 const int halfCount = mCount / 2;
179 const bool even = ( halfCount % 2 ) < 1;
180 if ( even )
181 {
182 mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
183 }
184 else //odd
185 {
186 mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
187 }
188 }
189 else
190 {
191 const int halfCount = mCount / 2 + 1;
192 const bool even = ( halfCount % 2 ) < 1;
193 if ( even )
194 {
195 mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
196 }
197 else //odd
198 {
199 mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
200 }
201 }
202 }
203
204 if ( mStatistics & Qgis::Statistic::ThirdQuartile
205 || mStatistics & Qgis::Statistic::InterQuartileRange )
206 {
207 if ( ( mCount % 2 ) < 1 )
208 {
209 const int halfCount = mCount / 2;
210 const bool even = ( halfCount % 2 ) < 1;
211 if ( even )
212 {
213 mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 1] + mValues[ halfCount + halfCount / 2] ) / 2.0;
214 }
215 else //odd
216 {
217 mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 1 + halfCount ];
218 }
219 }
220 else
221 {
222 const int halfCount = mCount / 2 + 1;
223 const bool even = ( halfCount % 2 ) < 1;
224 if ( even )
225 {
226 mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 2 ] + mValues[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
227 }
228 else //odd
229 {
230 mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 2 + halfCount ];
231 }
232 }
233 }
234
235 if ( mStatistics & Qgis::Statistic::Minority || mStatistics & Qgis::Statistic::Majority )
236 {
237 QList<int> valueCounts = mValueCount.values();
238
239 if ( mStatistics & Qgis::Statistic::Minority )
240 {
241 mMinority = mValueCount.key( *std::min_element( valueCounts.begin(), valueCounts.end() ) );
242 }
243 if ( mStatistics & Qgis::Statistic::Majority )
244 {
245 mMajority = mValueCount.key( *std::max_element( valueCounts.begin(), valueCounts.end() ) );
246 }
247 }
248
249}
250
251/***************************************************************************
252 * This class is considered CRITICAL and any change MUST be accompanied with
253 * full unit tests in testqgsstatisticalsummary.cpp.
254 * See details in QEP #17
255 ****************************************************************************/
256
258{
259 switch ( stat )
260 {
262 return mCount;
264 return mMissing;
266 return mSum;
268 return mMean;
270 return mMedian;
272 return mStdev;
274 return mSampleStdev;
276 return mMin;
278 return mMax;
280 return mMax - mMin;
282 return mMinority;
284 return mMajority;
286 return mValueCount.count();
288 return mFirstQuartile;
290 return mThirdQuartile;
292 return mThirdQuartile - mFirstQuartile;
294 return mFirst;
296 return mLast;
298 return 0;
299 }
300 return 0;
301}
302
304{
305 switch ( statistic )
306 {
308 return QObject::tr( "Count" );
310 return QObject::tr( "Count (missing)" );
312 return QObject::tr( "Sum" );
314 return QObject::tr( "Mean" );
316 return QObject::tr( "Median" );
318 return QObject::tr( "St dev (pop)" );
320 return QObject::tr( "St dev (sample)" );
322 return QObject::tr( "Minimum" );
324 return QObject::tr( "Maximum" );
326 return QObject::tr( "Range" );
328 return QObject::tr( "Minority" );
330 return QObject::tr( "Majority" );
332 return QObject::tr( "Variety" );
334 return QObject::tr( "Q1" );
336 return QObject::tr( "Q3" );
338 return QObject::tr( "IQR" );
340 return QObject::tr( "First" );
342 return QObject::tr( "Last" );
344 return QString();
345 }
346 return QString();
347}
348
350{
351 switch ( statistic )
352 {
354 return u"count"_s;
356 return u"countmissing"_s;
358 return u"sum"_s;
360 return u"mean"_s;
362 return u"median"_s;
364 return u"stdev"_s;
366 return u"stdevsample"_s;
368 return u"min"_s;
370 return u"max"_s;
372 return u"range"_s;
374 return u"minority"_s;
376 return u"majority"_s;
378 return u"variety"_s;
380 return u"q1"_s;
382 return u"q3"_s;
384 return u"iqr"_s;
386 return u"first"_s;
388 return u"last"_s;
390 return QString();
391 }
392 return QString();
393}
394
Statistic
Available generic statistics.
Definition qgis.h:6114
@ StDev
Standard deviation of values.
Definition qgis.h:6120
@ FirstQuartile
First quartile.
Definition qgis.h:6128
@ Mean
Mean of values.
Definition qgis.h:6118
@ Median
Median of values.
Definition qgis.h:6119
@ Max
Max of values.
Definition qgis.h:6123
@ Min
Min of values.
Definition qgis.h:6122
@ First
First value.
Definition qgis.h:6131
@ Range
Range of values (max - min).
Definition qgis.h:6124
@ Sum
Sum of values.
Definition qgis.h:6117
@ Minority
Minority of values.
Definition qgis.h:6125
@ CountMissing
Number of missing (null) values.
Definition qgis.h:6116
@ All
All statistics.
Definition qgis.h:6133
@ Majority
Majority of values.
Definition qgis.h:6126
@ Variety
Variety (count of distinct) values.
Definition qgis.h:6127
@ StDevSample
Sample standard deviation of values.
Definition qgis.h:6121
@ Last
Last value.
Definition qgis.h:6132
@ Count
Count.
Definition qgis.h:6115
@ ThirdQuartile
Third quartile.
Definition qgis.h:6129
@ InterQuartileRange
Inter quartile range (IQR).
Definition qgis.h:6130
QFlags< Statistic > Statistics
Statistics to be calculated for generic values.
Definition qgis.h:6142
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.