|
|
|
|
|
#pragma once
|
|
|
|
|
|
/*!\brief calculates mean, min, max, etc. as running values.
|
|
|
|
|
|
The idea is that you simply add values and ask for a stat whenever needed.
|
|
|
The clear() method resets the object and makes it able to work with new data.
|
|
|
|
|
|
Adding values can be doing with weight (addValue) or without (operator +=).
|
|
|
You can remove a value; for Min or Max this has no effect as this would
|
|
|
require buffering all data.
|
|
|
|
|
|
The mostFrequent assumes the data contains integer classes. Then the class
|
|
|
that is found most often will be the output. Weighting, again, assumes integer
|
|
|
values. Beware that if you pass data that is not really class-data, the
|
|
|
memory consumption can become large (and the result will be rather
|
|
|
uninteresting).
|
|
|
|
|
|
The variance won't take the decreasing degrees of freedom into consideration
|
|
|
when weights are provided.
|
|
|
|
|
|
|
|
|
The object is ready to use with int, float and double types. If other types
|
|
|
are needed, you may need to specialise an isZero function for each new type.
|
|
|
|
|
|
-*/
|
|
|
#include "QuickSort.h"
|
|
|
#include "TInterval.h"
|
|
|
|
|
|
namespace NSet
|
|
|
{
|
|
|
|
|
|
/* Average used to be 'Mean' but that does not sound positive enough */
|
|
|
enum EStatType
|
|
|
{
|
|
|
stCount = 0,
|
|
|
stAverage,
|
|
|
stMedian,
|
|
|
stRMS,
|
|
|
stStdDev,
|
|
|
stVariance,
|
|
|
stNormVariance,
|
|
|
stMin,
|
|
|
stMax,
|
|
|
stExtreme,
|
|
|
stSum,
|
|
|
stSqSum
|
|
|
};
|
|
|
|
|
|
template <class T>
|
|
|
class TStatValue
|
|
|
{
|
|
|
public:
|
|
|
TStatValue( bool bWeighted = false) { weighted_ = bWeighted; clear(); }
|
|
|
inline void clear();
|
|
|
|
|
|
inline TStatValue<T>& addValue(T data,T weight=1);
|
|
|
inline TStatValue<T>& addValues(int sz,const T* data,const T* weights=0);
|
|
|
inline TStatValue<T>& replaceValue(T olddata,T newdata,T wt=1);
|
|
|
inline TStatValue<T>& removeValue(T data,T weight=1);
|
|
|
|
|
|
inline double getValue(EStatType, double wt = 1) const;
|
|
|
inline int getIndex(EStatType) const; //!< only for Median, Min and Max
|
|
|
|
|
|
inline TStatValue<T>& operator +=( T t ) { return addValue(t); }
|
|
|
inline int size() const { return nrused_; }
|
|
|
inline bool isEmpty() const { return size() == 0; }
|
|
|
bool isWeighted() const { return weighted_; }
|
|
|
|
|
|
inline double sum() const;
|
|
|
inline double sqSum() const;
|
|
|
inline T minValue(int* index_of_min=0) const;
|
|
|
inline T maxValue(int* index_of_max=0) const;
|
|
|
inline T extreme(int* index_of_extr=0) const;
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>nPolicyΪ<79><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊż<CEAA><C5BC>ʱ<EFBFBD><CAB1>ȡֵ<C8A1><D6B5>ʽ=-1<><31><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD>ֵ<EFBFBD><D6B5>0:ƽ<><C6BD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>1<EFBFBD><31><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD>ֵ
|
|
|
inline T median(int* index_of_median=0) const;
|
|
|
inline double rms(double wt = 1) const;
|
|
|
inline double stdDev() const;
|
|
|
inline double average() const;
|
|
|
inline double variance() const;
|
|
|
inline double normVariance() const;
|
|
|
|
|
|
inline T clipVal(float ratio,bool upper) const;
|
|
|
//!< require median; 0 <= ratio <= 1
|
|
|
|
|
|
TTypeSet<T> vals_;
|
|
|
|
|
|
protected:
|
|
|
|
|
|
int nrused_;
|
|
|
int minidx_;
|
|
|
int maxidx_;
|
|
|
T minval_;
|
|
|
T maxval_;
|
|
|
double sum_x;
|
|
|
double sum_xx;
|
|
|
double sum_w;
|
|
|
double sum_wx;
|
|
|
double sum_wxx;
|
|
|
|
|
|
bool weighted_;
|
|
|
|
|
|
inline bool IsZero( const T& t ) const;
|
|
|
|
|
|
mutable int curmedidx_;
|
|
|
inline bool findMedIdx(T) const;
|
|
|
inline bool addExceptMed(T,T);
|
|
|
inline bool remExceptMed(T,T);
|
|
|
|
|
|
};
|
|
|
|
|
|
inline bool isZero( const float& val )
|
|
|
{
|
|
|
return fabs(val) < 1e-6 ? true:false;
|
|
|
}
|
|
|
|
|
|
inline bool isZero( const double& val )
|
|
|
{
|
|
|
return fabs(val) < 1e-10 ? true:false;
|
|
|
}
|
|
|
template <class T>
|
|
|
inline bool TStatValue<T>::IsZero( const T& val ) const
|
|
|
{
|
|
|
return fabs(val) < 1e-6 ? true:false;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
void TStatValue<T>::clear()
|
|
|
{
|
|
|
sum_x = sum_w = sum_xx = sum_wx = sum_wxx = 0;
|
|
|
nrused_ = minidx_ = maxidx_ = curmedidx_ = 0;
|
|
|
minval_ = maxval_ = 0;
|
|
|
vals_.erase();
|
|
|
}
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::rms(double wt /*= 1*/) const
|
|
|
{
|
|
|
if ( !isWeighted() )
|
|
|
return sqrt( ((double)sum_xx * wt) / nrused_ );
|
|
|
|
|
|
return isZero(sum_w) ? 0 : sqrt( ((double)sum_wxx * wt)/sum_w );
|
|
|
}
|
|
|
|
|
|
template <class T> inline
|
|
|
bool TStatValue<T>::addExceptMed( T val, T wt )
|
|
|
{
|
|
|
if ( nrused_ == 0 )
|
|
|
minval_ = maxval_ = val;
|
|
|
else
|
|
|
{
|
|
|
if ( val < minval_ ) minval_ = val;
|
|
|
if ( val > maxval_ ) maxval_ = val;
|
|
|
}
|
|
|
|
|
|
sum_x += val;
|
|
|
sum_xx += val * val;
|
|
|
if ( isWeighted() )
|
|
|
{
|
|
|
sum_w += wt;
|
|
|
sum_wx += wt * val;
|
|
|
sum_wxx += wt * val * val;
|
|
|
}
|
|
|
|
|
|
nrused_++;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
bool TStatValue<T>::remExceptMed( T val, T wt )
|
|
|
{
|
|
|
if(nrused_ <= 0) return false;
|
|
|
|
|
|
sum_x -= val;
|
|
|
sum_xx -= val * val;
|
|
|
if ( isWeighted() )
|
|
|
{
|
|
|
sum_w -= wt;
|
|
|
sum_wx -= wt * val;
|
|
|
sum_wxx -= wt * val * val;
|
|
|
}
|
|
|
|
|
|
nrused_--;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
TStatValue<T>& TStatValue<T>::addValue( T val, T wt )
|
|
|
{
|
|
|
if ( !addExceptMed(val, wt) )
|
|
|
return *this;
|
|
|
vals_ += val;
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
TStatValue<T>& TStatValue<T>::addValues( int sz, const T* data, const T* weights )
|
|
|
{
|
|
|
for ( int idx=0; idx<sz; idx++ )
|
|
|
addValue( data[idx], weights ? weights[idx] : 1 );
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
bool TStatValue<T>::findMedIdx( T val ) const
|
|
|
{
|
|
|
if ( curmedidx_ >= vals_.size() )
|
|
|
curmedidx_ = 0;
|
|
|
|
|
|
if ( vals_[curmedidx_] != val ) // oh well, need to search anyway
|
|
|
{
|
|
|
curmedidx_ = vals_.indexOf( val );
|
|
|
if ( curmedidx_ < 0 )
|
|
|
{
|
|
|
curmedidx_ = 0;
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
TStatValue<T>& TStatValue<T>::replaceValue( T oldval, T newval, T wt )
|
|
|
{
|
|
|
while( findMedIdx(oldval) )
|
|
|
{
|
|
|
remExceptMed( oldval, wt );
|
|
|
addExceptMed( newval, wt );
|
|
|
|
|
|
if ( vals_.isEmpty() )
|
|
|
break;
|
|
|
|
|
|
vals_[curmedidx_] = newval;
|
|
|
curmedidx_++;
|
|
|
}
|
|
|
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
TStatValue<T>& TStatValue<T>::removeValue( T val, T wt )
|
|
|
{
|
|
|
while ( findMedIdx(val) )
|
|
|
{
|
|
|
remExceptMed( val, wt );
|
|
|
|
|
|
if ( vals_.isEmpty() )
|
|
|
break;
|
|
|
|
|
|
vals_.remove( curmedidx_ );
|
|
|
}
|
|
|
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
double TStatValue<T>::getValue( EStatType t, double wt ) const
|
|
|
{
|
|
|
switch ( t )
|
|
|
{
|
|
|
case stCount: return size();
|
|
|
case stAverage: return average();
|
|
|
case stMedian: return median();
|
|
|
case stRMS: return rms(wt);
|
|
|
case stStdDev: return stdDev();
|
|
|
case stVariance: return variance();
|
|
|
case stNormVariance:return normVariance();
|
|
|
case stMin: return minValue();
|
|
|
case stMax: return maxValue();
|
|
|
case stExtreme: return extreme();
|
|
|
case stSum: return sum();
|
|
|
case stSqSum: return sqSum();
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T> inline
|
|
|
int TStatValue<T>::getIndex( EStatType t ) const
|
|
|
{
|
|
|
int ret;
|
|
|
switch ( t )
|
|
|
{
|
|
|
case stMin: minValue( &ret ); break;
|
|
|
case stMax: maxValue( &ret ); break;
|
|
|
case stExtreme: extreme( &ret ); break;
|
|
|
case stMedian: median( &ret ); break;
|
|
|
default: ret = 0; break;
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::stdDev() const
|
|
|
{
|
|
|
double v = variance();
|
|
|
return v > 0 ? ::sqrt( v ) : 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::average() const
|
|
|
{
|
|
|
if ( nrused_==0 ) return 0;
|
|
|
|
|
|
if(!isWeighted())
|
|
|
return ((double)sum_x) / nrused_;
|
|
|
|
|
|
return isZero(sum_w) ? 0 : ((double)sum_wx) / sum_w;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline T TStatValue<T>::median( int* idx_of_med ) const
|
|
|
{
|
|
|
if ( idx_of_med ) *idx_of_med = 0;
|
|
|
|
|
|
const int sz = vals_.size();
|
|
|
if ( sz < 2 )
|
|
|
return sz < 1 ? 0 : vals_[0];
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭʼ<D4AD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
int* m_pSourceIndex=NULL;
|
|
|
|
|
|
int mididx = sz / 2;
|
|
|
T* valarr = const_cast<T*>( vals_.arr() );
|
|
|
if ( !idx_of_med )
|
|
|
CQuickSort<T>::quickSort( valarr, sz );
|
|
|
else
|
|
|
{
|
|
|
if(m_pSourceIndex==NULL)
|
|
|
m_pSourceIndex = new int[sz];
|
|
|
for(int i=0; i<sz; i++) m_pSourceIndex[i]=i;
|
|
|
CQuickSort<T>::quickSort( valarr, m_pSourceIndex, sz );
|
|
|
*idx_of_med = m_pSourceIndex[ mididx ];
|
|
|
}
|
|
|
|
|
|
if ( sz%2 == 0 )
|
|
|
{
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>nPolicyΪ<79><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊż<CEAA><C5BC>ʱ<EFBFBD><CAB1>ȡֵ<C8A1><D6B5>ʽ=-1<><31><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD>ֵ<EFBFBD><D6B5>0:ƽ<><C6BD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>1<EFBFBD><31><EFBFBD>ϸ<EFBFBD><CFB8><EFBFBD>ֵ
|
|
|
const int policy = 0;
|
|
|
if ( policy == 0 )
|
|
|
{
|
|
|
if(m_pSourceIndex)
|
|
|
delete[] m_pSourceIndex;
|
|
|
|
|
|
return (vals_[mididx] + vals_[mididx-1]) / 2;
|
|
|
}
|
|
|
else if ( policy == -1 )
|
|
|
{
|
|
|
mididx--;
|
|
|
if ( idx_of_med && m_pSourceIndex!=NULL )
|
|
|
*idx_of_med = m_pSourceIndex[ mididx ];
|
|
|
}
|
|
|
}
|
|
|
if(m_pSourceIndex)
|
|
|
delete[] m_pSourceIndex;
|
|
|
|
|
|
return vals_[ mididx ];
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::sum() const
|
|
|
{
|
|
|
return sum_x;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::sqSum() const
|
|
|
{
|
|
|
return sum_xx;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::variance() const
|
|
|
{
|
|
|
if ( nrused_ < 2 ) return 0;
|
|
|
|
|
|
if ( !isWeighted() )
|
|
|
return ( sum_xx - (sum_x * ((double)sum_x) / nrused_) ) / (nrused_ - 1);
|
|
|
|
|
|
return (sum_wxx - (sum_wx * ((double)sum_wx) / sum_w) ) / ( (nrused_-1) * ((double)sum_w) / nrused_ );
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline double TStatValue<T>::normVariance() const
|
|
|
{
|
|
|
if ( nrused_ < 2 ) return 0;
|
|
|
|
|
|
double fact = 0.1;
|
|
|
double avg = average();
|
|
|
double var = variance();
|
|
|
return var / (avg*avg + fact*var);
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline T TStatValue<T>::minValue( int* index_of_min ) const
|
|
|
{
|
|
|
if ( index_of_min ) *index_of_min = minidx_;
|
|
|
return minval_;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline T TStatValue<T>::maxValue( int* index_of_max ) const
|
|
|
{
|
|
|
if ( index_of_max ) *index_of_max = maxidx_;
|
|
|
return maxval_;
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline T TStatValue<T>::extreme( int* index_of_extr ) const
|
|
|
{
|
|
|
if ( index_of_extr ) *index_of_extr = 0;
|
|
|
|
|
|
const T maxcmp = maxval_ < 0 ? -maxval_ : maxval_;
|
|
|
const T mincmp = minval_ < 0 ? -minval_ : minval_;
|
|
|
if ( maxcmp < mincmp )
|
|
|
{
|
|
|
if ( index_of_extr ) *index_of_extr = minidx_;
|
|
|
return minval_;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if ( index_of_extr ) *index_of_extr = maxidx_;
|
|
|
return maxval_;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
inline T TStatValue<T>::clipVal( float ratio, bool upper ) const
|
|
|
{
|
|
|
median();
|
|
|
const int lastidx = vals_.size();
|
|
|
const float fidx = ratio * lastidx;
|
|
|
const int idx = fidx <= 0 ? 0 : (fidx > lastidx ? lastidx : (int)fidx);
|
|
|
return vals_[upper ? lastidx - idx : idx];
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}//namespace
|
|
|
|