mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Add quartiles and IQR to QgsStatisticalSummary calculations
This commit is contained in:
parent
154468bd84
commit
31e8611230
@ -33,6 +33,9 @@ class QgsStatisticalSummary
|
||||
Minority, //!< Minority of values
|
||||
Majority, //!< Majority of values
|
||||
Variety, //!< Variety (count of distinct) values
|
||||
FirstQuartile, //!< First quartile
|
||||
ThirdQuartile, //!< Third quartile
|
||||
InterQuartileRange, //!< Inter quartile range (IQR)
|
||||
All
|
||||
};
|
||||
|
||||
@ -127,6 +130,27 @@ class QgsStatisticalSummary
|
||||
* @see minority
|
||||
*/
|
||||
double majority() const;
|
||||
|
||||
/** Returns the first quartile of the values. The quartile is calculated using the
|
||||
* "Tukey's hinges" method.
|
||||
* @see thirdQuartile
|
||||
* @see interQuartileRange
|
||||
*/
|
||||
double firstQuartile() const;
|
||||
|
||||
/** Returns the third quartile of the values. The quartile is calculated using the
|
||||
* "Tukey's hinges" method.
|
||||
* @see firstQuartile
|
||||
* @see interQuartileRange
|
||||
*/
|
||||
double thirdQuartile() const;
|
||||
|
||||
/** Returns the inter quartile range of the values. The quartiles are calculated using the
|
||||
* "Tukey's hinges" method.
|
||||
* @see firstQuartile
|
||||
* @see thirdQuartile
|
||||
*/
|
||||
double interQuartileRange() const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -41,6 +41,8 @@ void QgsStatisticalSummary::reset()
|
||||
mSampleStdev = 0;
|
||||
mMinority = 0;
|
||||
mMajority = 0;
|
||||
mFirstQuartile = 0;
|
||||
mThirdQuartile = 0;
|
||||
mValueCount.clear();
|
||||
}
|
||||
|
||||
@ -76,9 +78,13 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
|
||||
mSampleStdev = qPow( sumSquared / ( values.count() - 1 ), 0.5 );
|
||||
}
|
||||
|
||||
if ( mStatistics & QgsStatisticalSummary::Median )
|
||||
QList<double> sorted;
|
||||
if ( mStatistics & QgsStatisticalSummary::Median
|
||||
|| mStatistics & QgsStatisticalSummary::FirstQuartile
|
||||
|| mStatistics & QgsStatisticalSummary::ThirdQuartile
|
||||
|| mStatistics & QgsStatisticalSummary::InterQuartileRange )
|
||||
{
|
||||
QList<double> sorted = values;
|
||||
sorted = values;
|
||||
qSort( sorted.begin(), sorted.end() );
|
||||
bool even = ( mCount % 2 ) < 1;
|
||||
if ( even )
|
||||
@ -91,6 +97,68 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
|
||||
}
|
||||
}
|
||||
|
||||
if ( mStatistics & QgsStatisticalSummary::FirstQuartile
|
||||
|| mStatistics & QgsStatisticalSummary::InterQuartileRange )
|
||||
{
|
||||
if (( mCount % 2 ) < 1 )
|
||||
{
|
||||
int halfCount = mCount / 2;
|
||||
bool even = ( halfCount % 2 ) < 1;
|
||||
if ( even )
|
||||
{
|
||||
mFirstQuartile = ( sorted[halfCount / 2 - 1] + sorted[halfCount / 2] ) / 2.0;
|
||||
}
|
||||
else //odd
|
||||
{
|
||||
mFirstQuartile = sorted[( halfCount + 1 ) / 2 - 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int halfCount = mCount / 2 + 1;
|
||||
bool even = ( halfCount % 2 ) < 1;
|
||||
if ( even )
|
||||
{
|
||||
mFirstQuartile = ( sorted[halfCount / 2 - 1] + sorted[halfCount / 2] ) / 2.0;
|
||||
}
|
||||
else //odd
|
||||
{
|
||||
mFirstQuartile = sorted[( halfCount + 1 ) / 2 - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( mStatistics & QgsStatisticalSummary::ThirdQuartile
|
||||
|| mStatistics & QgsStatisticalSummary::InterQuartileRange )
|
||||
{
|
||||
if (( mCount % 2 ) < 1 )
|
||||
{
|
||||
int halfCount = mCount / 2;
|
||||
bool even = ( halfCount % 2 ) < 1;
|
||||
if ( even )
|
||||
{
|
||||
mThirdQuartile = ( sorted[ halfCount + halfCount / 2 - 1] + sorted[ halfCount + halfCount / 2] ) / 2.0;
|
||||
}
|
||||
else //odd
|
||||
{
|
||||
mThirdQuartile = sorted[( halfCount + 1 ) / 2 - 1 + halfCount ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int halfCount = mCount / 2 + 1;
|
||||
bool even = ( halfCount % 2 ) < 1;
|
||||
if ( even )
|
||||
{
|
||||
mThirdQuartile = ( sorted[ halfCount + halfCount / 2 - 2 ] + sorted[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
|
||||
}
|
||||
else //odd
|
||||
{
|
||||
mThirdQuartile = sorted[( halfCount + 1 ) / 2 - 2 + halfCount ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Majority )
|
||||
{
|
||||
QList<int> valueCounts = mValueCount.values();
|
||||
|
@ -49,7 +49,10 @@ class CORE_EXPORT QgsStatisticalSummary
|
||||
Minority = 512, //!< Minority of values
|
||||
Majority = 1024, //!< Majority of values
|
||||
Variety = 2048, //!< Variety (count of distinct) values
|
||||
All = Count | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety
|
||||
FirstQuartile = 4096, //!< First quartile
|
||||
ThirdQuartile = 8192, //!< Third quartile
|
||||
InterQuartileRange = 16384, //!< Inter quartile range (IQR)
|
||||
All = Count | Sum | Mean | Median | StDev | Max | Min | Range | Minority | Majority | Variety | FirstQuartile | ThirdQuartile | InterQuartileRange
|
||||
};
|
||||
Q_DECLARE_FLAGS( Statistics, Statistic )
|
||||
|
||||
@ -143,6 +146,27 @@ class CORE_EXPORT QgsStatisticalSummary
|
||||
*/
|
||||
double majority() const { return mMajority; }
|
||||
|
||||
/** Returns the first quartile of the values. The quartile is calculated using the
|
||||
* "Tukey's hinges" method.
|
||||
* @see thirdQuartile
|
||||
* @see interQuartileRange
|
||||
*/
|
||||
double firstQuartile() const { return mFirstQuartile; }
|
||||
|
||||
/** Returns the third quartile of the values. The quartile is calculated using the
|
||||
* "Tukey's hinges" method.
|
||||
* @see firstQuartile
|
||||
* @see interQuartileRange
|
||||
*/
|
||||
double thirdQuartile() const { return mThirdQuartile; }
|
||||
|
||||
/** Returns the inter quartile range of the values. The quartiles are calculated using the
|
||||
* "Tukey's hinges" method.
|
||||
* @see firstQuartile
|
||||
* @see thirdQuartile
|
||||
*/
|
||||
double interQuartileRange() const { return mThirdQuartile - mFirstQuartile; }
|
||||
|
||||
private:
|
||||
|
||||
Statistics mStatistics;
|
||||
@ -157,6 +181,8 @@ class CORE_EXPORT QgsStatisticalSummary
|
||||
double mSampleStdev;
|
||||
double mMinority;
|
||||
double mMajority;
|
||||
double mFirstQuartile;
|
||||
double mThirdQuartile;
|
||||
QMap< double, int > mValueCount;
|
||||
};
|
||||
|
||||
|
@ -84,6 +84,39 @@ void TestQgsStatisticSummary::stats()
|
||||
QCOMPARE( s.variety(), 7 );
|
||||
QCOMPARE( s.minority(), 3.0 );
|
||||
QCOMPARE( s.majority(), 12.0 );
|
||||
|
||||
//test quartiles. lots of possibilities here, involving odd/even/divisible by 4 counts
|
||||
values.clear();
|
||||
values << 7 << 15 << 36 << 39 << 40 << 41;
|
||||
s.calculate( values );
|
||||
QCOMPARE( s.median(), 37.5 );
|
||||
QCOMPARE( s.firstQuartile(), 15.0 );
|
||||
QCOMPARE( s.thirdQuartile(), 40.0 );
|
||||
QCOMPARE( s.interQuartileRange(), 25.0 );
|
||||
|
||||
values.clear();
|
||||
values << 7 << 15 << 36 << 39 << 40 << 41 << 43 << 49;
|
||||
s.calculate( values );
|
||||
QCOMPARE( s.median(), 39.5 );
|
||||
QCOMPARE( s.firstQuartile(), 25.5 );
|
||||
QCOMPARE( s.thirdQuartile(), 42.0 );
|
||||
QCOMPARE( s.interQuartileRange(), 16.5 );
|
||||
|
||||
values.clear();
|
||||
values << 6 << 7 << 15 << 36 << 39 << 40 << 41 << 42 << 43 << 47 << 49;
|
||||
s.calculate( values );
|
||||
QCOMPARE( s.median(), 40.0 );
|
||||
QCOMPARE( s.firstQuartile(), 25.5 );
|
||||
QCOMPARE( s.thirdQuartile(), 42.5 );
|
||||
QCOMPARE( s.interQuartileRange(), 17.0 );
|
||||
|
||||
values.clear();
|
||||
values << 6 << 7 << 15 << 36 << 39 << 40 << 41 << 42 << 43 << 47 << 49 << 50 << 58;
|
||||
s.calculate( values );
|
||||
QCOMPARE( s.median(), 41.0 );
|
||||
QCOMPARE( s.firstQuartile(), 36.0 );
|
||||
QCOMPARE( s.thirdQuartile(), 47.0 );
|
||||
QCOMPARE( s.interQuartileRange(), 11.0 );
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsStatisticSummary )
|
||||
|
Loading…
x
Reference in New Issue
Block a user