Skip to content
Permalink
Browse files

Add methods to stats calculators to accept values one at a time

This can be more efficient for large quantities of values, since
it avoids the need to create a list of all values in advance
  • Loading branch information
nyalldawson committed May 15, 2016
1 parent 2bbd5ca commit 4dea723caeac3ec144ac0fe779c000482a6b15ac
@@ -53,12 +53,33 @@ class QgsDateTimeStatisticalSummary
*/
void reset();

/** Calculates summary statistics for a list of variants. Any non-string variants will be
/** Calculates summary statistics for a list of variants. Any non-datetime variants will be
* ignored.
* @param values list of variants
* @see addValue()
*/
void calculate( const QVariantList& values );

/** Adds a single datetime to the statistics calculation. Calling this method
* allows datetimes to be added to the calculation one at a time. For large
* quantities of dates this may be more efficient then first adding all the
* variants to a list and calling calculate().
* @param value datetime to add. Any non-datetime variants will be ignored.
* @note call reset() before adding the first datetime using this method
* to clear the results from any previous calculations
* @note finalize() must be called after adding the final value and before
* retrieving calculated statistics.
* @see calculate()
* @see finalize()
*/
void addValue( const QVariant& value );

/** Must be called after adding all datetimes with addValue() and before retrieving
* any calculated datetime statistics.
* @see addValue()
*/
void finalize();

/** Returns the value of a specified statistic
* @param stat statistic to return
* @returns calculated value of statistic
@@ -69,6 +69,25 @@ class QgsStatisticalSummary
*/
void calculate( const QList<double>& values );

/** Adds a single value to the statistics calculation. Calling this method
* allows values to be added to the calculation one at a time. For large
* quantities of values this may be more efficient then first adding all the
* values to a list and calling calculate().
* @param value value to add
* @note call reset() before adding the first value using this method
* to clear the results from any previous calculations
* @note finalize() must be called after adding the final value and before
* retrieving calculated statistics.
* @see calculate()
* @see finalize()
*/
void addValue( double value );

/** Must be called after adding all values with addValues() and before retrieving
* any calculated statistics.
* @see addValue()
*/
void finalize();
/** Returns the value of a specified statistic
* @param stat statistic to return
* @returns calculated value of statistic
@@ -57,19 +57,56 @@ class QgsStringStatisticalSummary
*/
void reset();

/** Calculates summary statistics for a list of strings.
/** Calculates summary statistics for an entire list of strings at once.
* @param values list of strings
* @see calculateFromVariants()
* @see addString()
*/
void calculate( const QStringList& values );

/** Calculates summary statistics for a list of variants. Any non-string variants will be
* ignored.
/** Calculates summary statistics for an entire list of variants at once. Any
* non-string variants will be ignored.
* @param values list of variants
* @see calculate()
* @see addValue()
*/
void calculateFromVariants( const QVariantList& values );

/** Adds a single string to the statistics calculation. Calling this method
* allows strings to be added to the calculation one at a time. For large
* quantities of strings this may be more efficient then first adding all the
* strings to a list and calling calculate().
* @param string string to add
* @note call reset() before adding the first string using this method
* to clear the results from any previous calculations
* @note finalize() must be called after adding the final string and before
* retrieving calculated statistics.
* @see calculate()
* @see addValue()
* @see finalize()
*/
void addString( const QString& string );

/** Adds a single variant to the statistics calculation. Calling this method
* allows variants to be added to the calculation one at a time. For large
* quantities of variants this may be more efficient then first adding all the
* variants to a list and calling calculateFromVariants().
* @param value variant to add
* @note call reset() before adding the first string using this method
* to clear the results from any previous calculations
* @note finalize() must be called after adding the final value and before
* retrieving calculated statistics.
* @see calculateFromVariants()
* @see finalize()
*/
void addValue( const QVariant& value );

/** Must be called after adding all strings with addString() and before retrieving
* any calculated string statistics.
* @see addString()
*/
void finalize();

/** Returns the value of a specified statistic
* @param stat statistic to return
* @returns calculated value of statistic
@@ -49,18 +49,30 @@ void QgsDateTimeStatisticalSummary::calculate( const QVariantList& values )

Q_FOREACH ( const QVariant& variant, values )
{
if ( variant.type() == QVariant::DateTime )
{
testDateTime( variant.toDateTime() );
}
else if ( variant.type() == QVariant::Date )
{
QDate date = variant.toDate();
testDateTime( date.isValid() ? QDateTime( date, QTime( 0, 0, 0 ) )
: QDateTime() );
}
// QTime?
addValue( variant );
}
finalize();
}

void QgsDateTimeStatisticalSummary::addValue( const QVariant& value )
{
if ( value.type() == QVariant::DateTime )
{
testDateTime( value.toDateTime() );
}
else if ( value.type() == QVariant::Date )
{
QDate date = value.toDate();
testDateTime( date.isValid() ? QDateTime( date, QTime( 0, 0, 0 ) )
: QDateTime() );
}
// QTime?
}

void QgsDateTimeStatisticalSummary::finalize()
{
//nothing to do for now - this method has been added for forward compatibility
//if statistics are implemented which require a post-calculation step
}

void QgsDateTimeStatisticalSummary::testDateTime( const QDateTime& dateTime )
@@ -79,12 +79,33 @@ class CORE_EXPORT QgsDateTimeStatisticalSummary
*/
void reset();

/** Calculates summary statistics for a list of variants. Any non-string variants will be
/** Calculates summary statistics for a list of variants. Any non-datetime variants will be
* ignored.
* @param values list of variants
* @see addValue()
*/
void calculate( const QVariantList& values );

/** Adds a single datetime to the statistics calculation. Calling this method
* allows datetimes to be added to the calculation one at a time. For large
* quantities of dates this may be more efficient then first adding all the
* variants to a list and calling calculate().
* @param value datetime to add. Any non-datetime variants will be ignored.
* @note call reset() before adding the first datetime using this method
* to clear the results from any previous calculations
* @note finalize() must be called after adding the final value and before
* retrieving calculated statistics.
* @see calculate()
* @see finalize()
*/
void addValue( const QVariant& value );

/** Must be called after adding all datetimes with addValue() and before retrieving
* any calculated datetime statistics.
* @see addValue()
*/
void finalize();

/** Returns the value of a specified statistic
* @param stat statistic to return
* @returns calculated value of statistic
@@ -51,6 +51,7 @@ void QgsStatisticalSummary::reset()
mFirstQuartile = 0;
mThirdQuartile = 0;
mValueCount.clear();
mValues.clear();
}

/***************************************************************************
@@ -65,15 +66,30 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )

Q_FOREACH ( double value, values )
{
mCount++;
mSum += value;
mMin = qMin( mMin, value );
mMax = qMax( mMax, value );

if ( mStatistics & QgsStatisticalSummary::Majority || mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Variety )
mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );
addValue( value );
}

finalize();
}

void QgsStatisticalSummary::addValue( double value )
{
mCount++;
mSum += value;
mMin = qMin( mMin, value );
mMax = qMax( mMax, value );

if ( mStatistics & QgsStatisticalSummary::Majority || mStatistics & QgsStatisticalSummary::Minority || mStatistics & QgsStatisticalSummary::Variety )
mValueCount.insert( value, mValueCount.value( value, 0 ) + 1 );

if ( mStatistics & QgsStatisticalSummary::StDev || mStatistics & QgsStatisticalSummary::StDevSample ||
mStatistics & QgsStatisticalSummary::Median || mStatistics & QgsStatisticalSummary::FirstQuartile ||
mStatistics & QgsStatisticalSummary::ThirdQuartile || mStatistics & QgsStatisticalSummary::InterQuartileRange )
mValues << value;
}

void QgsStatisticalSummary::finalize()
{
if ( mCount == 0 )
return;

@@ -82,31 +98,29 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
if ( mStatistics & QgsStatisticalSummary::StDev || mStatistics & QgsStatisticalSummary::StDevSample )
{
double sumSquared = 0;
Q_FOREACH ( double value, values )
Q_FOREACH ( double value, mValues )
{
double diff = value - mMean;
sumSquared += diff * diff;
}
mStdev = qPow( sumSquared / values.count(), 0.5 );
mSampleStdev = qPow( sumSquared / ( values.count() - 1 ), 0.5 );
mStdev = qPow( sumSquared / mValues.count(), 0.5 );
mSampleStdev = qPow( sumSquared / ( mValues.count() - 1 ), 0.5 );
}

QList<double> sorted;
if ( mStatistics & QgsStatisticalSummary::Median
|| mStatistics & QgsStatisticalSummary::FirstQuartile
|| mStatistics & QgsStatisticalSummary::ThirdQuartile
|| mStatistics & QgsStatisticalSummary::InterQuartileRange )
{
sorted = values;
qSort( sorted.begin(), sorted.end() );
qSort( mValues.begin(), mValues.end() );
bool even = ( mCount % 2 ) < 1;
if ( even )
{
mMedian = ( sorted[mCount / 2 - 1] + sorted[mCount / 2] ) / 2.0;
mMedian = ( mValues[mCount / 2 - 1] + mValues[mCount / 2] ) / 2.0;
}
else //odd
{
mMedian = sorted[( mCount + 1 ) / 2 - 1];
mMedian = mValues[( mCount + 1 ) / 2 - 1];
}
}

@@ -119,11 +133,11 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
bool even = ( halfCount % 2 ) < 1;
if ( even )
{
mFirstQuartile = ( sorted[halfCount / 2 - 1] + sorted[halfCount / 2] ) / 2.0;
mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
}
else //odd
{
mFirstQuartile = sorted[( halfCount + 1 ) / 2 - 1];
mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
}
}
else
@@ -132,11 +146,11 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
bool even = ( halfCount % 2 ) < 1;
if ( even )
{
mFirstQuartile = ( sorted[halfCount / 2 - 1] + sorted[halfCount / 2] ) / 2.0;
mFirstQuartile = ( mValues[halfCount / 2 - 1] + mValues[halfCount / 2] ) / 2.0;
}
else //odd
{
mFirstQuartile = sorted[( halfCount + 1 ) / 2 - 1];
mFirstQuartile = mValues[( halfCount + 1 ) / 2 - 1];
}
}
}
@@ -150,11 +164,11 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
bool even = ( halfCount % 2 ) < 1;
if ( even )
{
mThirdQuartile = ( sorted[ halfCount + halfCount / 2 - 1] + sorted[ halfCount + halfCount / 2] ) / 2.0;
mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 1] + mValues[ halfCount + halfCount / 2] ) / 2.0;
}
else //odd
{
mThirdQuartile = sorted[( halfCount + 1 ) / 2 - 1 + halfCount ];
mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 1 + halfCount ];
}
}
else
@@ -163,11 +177,11 @@ void QgsStatisticalSummary::calculate( const QList<double> &values )
bool even = ( halfCount % 2 ) < 1;
if ( even )
{
mThirdQuartile = ( sorted[ halfCount + halfCount / 2 - 2 ] + sorted[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
mThirdQuartile = ( mValues[ halfCount + halfCount / 2 - 2 ] + mValues[ halfCount + halfCount / 2 - 1 ] ) / 2.0;
}
else //odd
{
mThirdQuartile = sorted[( halfCount + 1 ) / 2 - 2 + halfCount ];
mThirdQuartile = mValues[( halfCount + 1 ) / 2 - 2 + halfCount ];
}
}
}
@@ -91,6 +91,26 @@ class CORE_EXPORT QgsStatisticalSummary
*/
void calculate( const QList<double>& values );

/** Adds a single value to the statistics calculation. Calling this method
* allows values to be added to the calculation one at a time. For large
* quantities of values this may be more efficient then first adding all the
* values to a list and calling calculate().
* @param value value to add
* @note call reset() before adding the first value using this method
* to clear the results from any previous calculations
* @note finalize() must be called after adding the final value and before
* retrieving calculated statistics.
* @see calculate()
* @see finalize()
*/
void addValue( double value );

/** Must be called after adding all values with addValues() and before retrieving
* any calculated statistics.
* @see addValue()
*/
void finalize();

/** Returns the value of a specified statistic
* @param stat statistic to return
* @returns calculated value of statistic
@@ -201,6 +221,7 @@ class CORE_EXPORT QgsStatisticalSummary
double mFirstQuartile;
double mThirdQuartile;
QMap< double, int > mValueCount;
QList< double > mValues;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsStatisticalSummary::Statistics )

0 comments on commit 4dea723

Please sign in to comment.
You can’t perform that action at this time.