cannam@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@0
|
2
|
cannam@0
|
3 // Histogram.h: interface for the THistogram class.
|
cannam@0
|
4 //
|
cannam@0
|
5 //////////////////////////////////////////////////////////////////////
|
cannam@0
|
6
|
cannam@0
|
7
|
cannam@0
|
8 #ifndef HISTOGRAM_H
|
cannam@0
|
9 #define HISTOGRAM_H
|
cannam@0
|
10
|
cannam@0
|
11
|
cannam@0
|
12 #include <valarray>
|
cannam@0
|
13
|
cannam@0
|
14 /*! \brief A histogram class
|
cannam@0
|
15
|
cannam@0
|
16 This class computes the histogram of a vector.
|
cannam@0
|
17
|
cannam@0
|
18 \par Template parameters
|
cannam@0
|
19
|
cannam@0
|
20 - T type of input data (can be any: float, double, int, UINT, etc...)
|
cannam@0
|
21 - TOut type of output data: float or double. (default is double)
|
cannam@0
|
22
|
cannam@0
|
23 \par Moments:
|
cannam@0
|
24
|
cannam@0
|
25 The moments (average, standard deviation, skewness, etc.) are computed using
|
cannam@0
|
26 the algorithm of the Numerical recipies (see Numerical recipies in C, Chapter 14.1, pg 613).
|
cannam@0
|
27
|
cannam@0
|
28 \par Example:
|
cannam@0
|
29
|
cannam@0
|
30 This example shows the typical use of the class:
|
cannam@0
|
31 \code
|
cannam@0
|
32 // a vector containing the data
|
cannam@0
|
33 vector<float> data;
|
cannam@0
|
34 // Creating histogram using float data and with 101 containers,
|
cannam@0
|
35 THistogram<float> histo(101);
|
cannam@0
|
36 // computing the histogram
|
cannam@0
|
37 histo.compute(data);
|
cannam@0
|
38 \endcode
|
cannam@0
|
39
|
cannam@0
|
40 Once this is done, you can get a vector with the histogram or the normalized histogram (such that it's area is 1):
|
cannam@0
|
41 \code
|
cannam@0
|
42 // getting normalized histogram
|
cannam@0
|
43 vector<float> v=histo.getNormalizedHistogram();
|
cannam@0
|
44 \endcode
|
cannam@0
|
45
|
cannam@0
|
46 \par Reference
|
cannam@0
|
47
|
cannam@0
|
48 Equally spaced acsissa function integration (used in #GetArea): Numerical Recipies in C, Chapter 4.1, pg 130.
|
cannam@0
|
49
|
cannam@0
|
50 \author Jonathan de Halleux, dehalleux@auto.ucl.ac.be, 2002
|
cannam@0
|
51 */
|
cannam@0
|
52
|
cannam@0
|
53 template<class T, class TOut = double>
|
cannam@0
|
54 class THistogram
|
cannam@0
|
55 {
|
cannam@0
|
56 public:
|
cannam@0
|
57 //! \name Constructors
|
cannam@0
|
58 //@{
|
cannam@0
|
59 /*! Default constructor
|
cannam@0
|
60 \param counters the number of histogram containers (default value is 10)
|
cannam@0
|
61 */
|
cannam@0
|
62 THistogram(unsigned int counters = 10);
|
cannam@0
|
63 virtual ~THistogram() { clear();};
|
cannam@0
|
64 //@}
|
cannam@0
|
65
|
cannam@0
|
66 //! \name Histogram computation, update
|
cannam@0
|
67 //@{
|
cannam@0
|
68 /*! Computes histogram of vector v
|
cannam@0
|
69 \param v vector to compute histogram
|
cannam@0
|
70 \param computeMinMax set to true if min/max of v have to be used to get the histogram limits
|
cannam@0
|
71
|
cannam@0
|
72 This function computes the histogram of v and stores it internally.
|
cannam@0
|
73 \sa Update, GeTHistogram
|
cannam@0
|
74 */
|
cannam@0
|
75 void compute( const std::vector<T>& v, bool computeMinMax = true);
|
cannam@0
|
76 //! Update histogram with the vector v
|
cannam@0
|
77 void update( const std::vector<T>& v);
|
cannam@0
|
78 //! Update histogram with t
|
cannam@0
|
79 void update( const T& t);
|
cannam@0
|
80 //@}
|
cannam@0
|
81
|
cannam@0
|
82 //! \name Resetting functions
|
cannam@0
|
83 //@{
|
cannam@0
|
84 //! Resize the histogram. Warning this function clear the histogram.
|
cannam@0
|
85 void resize( unsigned int counters );
|
cannam@0
|
86 //! Clears the histogram
|
cannam@0
|
87 void clear() { m_counters.clear();};
|
cannam@0
|
88 //@}
|
cannam@0
|
89
|
cannam@0
|
90 //! \name Setters
|
cannam@0
|
91 //@{
|
cannam@0
|
92 /*! This function sets the minimum of the histogram spectrum.
|
cannam@0
|
93 The spectrum is not recomputed, use it with care
|
cannam@0
|
94 */
|
cannam@0
|
95 void setMinSpectrum( const T& min ) { m_min = min; computeStep();};
|
cannam@0
|
96 /*! This function sets the minimum of the histogram spectrum.
|
cannam@0
|
97 The spectrum is not recomputed, use it with care
|
cannam@0
|
98 */
|
cannam@0
|
99 void setMaxSpectrum( const T& max ) { m_max = max; computeStep();};
|
cannam@0
|
100 //@}
|
cannam@0
|
101 //! \name Getters
|
cannam@0
|
102 //@{
|
cannam@0
|
103 //! return minimum of histogram spectrum
|
cannam@0
|
104 const T& getMinSpectrum() const { return m_min;};
|
cannam@0
|
105 //! return maximum of histogram spectrum
|
cannam@0
|
106 const T& getMaxSpectrum() const { return m_max;};
|
cannam@0
|
107 //! return step size of histogram containers
|
cannam@0
|
108 TOut getStep() const { return m_step;};
|
cannam@0
|
109 //! return number of points in histogram
|
cannam@0
|
110 unsigned int getSum() const;
|
cannam@0
|
111 /*! \brief returns area under the histogram
|
cannam@0
|
112
|
cannam@0
|
113 The Simpson rule is used to integrate the histogram.
|
cannam@0
|
114 */
|
cannam@0
|
115 TOut getArea() const;
|
cannam@0
|
116
|
cannam@0
|
117 /*! \brief Computes the moments of the histogram
|
cannam@0
|
118
|
cannam@0
|
119 \param data dataset
|
cannam@0
|
120 \param ave mean
|
cannam@0
|
121 \f[ \bar x = \frac{1}{N} \sum_{j=1}^N x_j\f]
|
cannam@0
|
122 \param adev mean absolute deviation
|
cannam@0
|
123 \f[ adev(X) = \frac{1}{N} \sum_{j=1}^N | x_j - \bar x |\f]
|
cannam@0
|
124 \param var average deviation:
|
cannam@0
|
125 \f[ \mbox{Var}(X) = \frac{1}{N-1} \sum_{j=1}^N (x_j - \bar x)^2\f]
|
cannam@0
|
126 \param sdev standard deviation:
|
cannam@0
|
127 \f[ \sigma(X) = \sqrt{var(\bar x) }\f]
|
cannam@0
|
128 \param skew skewness
|
cannam@0
|
129 \f[ \mbox{Skew}(X) = \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^3\f]
|
cannam@0
|
130 \param kurt kurtosis
|
cannam@0
|
131 \f[ \mbox{Kurt}(X) = \left\{ \frac{1}{N}\sum_{j=1}^N \left[ \frac{x_j - \bar x}{\sigma}\right]^4 \right\} - 3\f]
|
cannam@0
|
132
|
cannam@0
|
133 */
|
cannam@0
|
134 static void getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt);
|
cannam@0
|
135
|
cannam@0
|
136 //! return number of containers
|
cannam@0
|
137 unsigned int getSize() const { return m_counters.size();};
|
cannam@0
|
138 //! returns i-th counter
|
cannam@0
|
139 unsigned int operator [] (unsigned int i) const { ASSERT( i < m_counters.size() ); return m_counters[i];};
|
cannam@0
|
140 //! return the computed histogram
|
cannam@0
|
141 const std::vector<unsigned int>& geTHistogram() const { return m_counters;};
|
cannam@0
|
142 //! return the computed histogram, in TOuts
|
cannam@0
|
143 std::vector<TOut> geTHistogramD() const;
|
cannam@0
|
144 /*! return the normalized computed histogram
|
cannam@0
|
145
|
cannam@0
|
146 \return the histogram such that the area is equal to 1
|
cannam@0
|
147 */
|
cannam@0
|
148 std::vector<TOut> getNormalizedHistogram() const;
|
cannam@0
|
149 //! returns left containers position
|
cannam@0
|
150 std::vector<TOut> getLeftContainers() const;
|
cannam@0
|
151 //! returns center containers position
|
cannam@0
|
152 std::vector<TOut> getCenterContainers() const;
|
cannam@0
|
153 //@}
|
cannam@0
|
154 protected:
|
cannam@0
|
155 //! Computes the step
|
cannam@0
|
156 void computeStep() { m_step = (TOut)(((TOut)(m_max-m_min)) / (m_counters.size()-1));};
|
cannam@0
|
157 //! Data accumulators
|
cannam@0
|
158 std::vector<unsigned int> m_counters;
|
cannam@0
|
159 //! minimum of dataset
|
cannam@0
|
160 T m_min;
|
cannam@0
|
161 //! maximum of dataset
|
cannam@0
|
162 T m_max;
|
cannam@0
|
163 //! width of container
|
cannam@0
|
164 TOut m_step;
|
cannam@0
|
165 };
|
cannam@0
|
166
|
cannam@0
|
167 template<class T, class TOut>
|
cannam@0
|
168 THistogram<T,TOut>::THistogram(unsigned int counters)
|
cannam@0
|
169 : m_counters(counters,0), m_min(0), m_max(0), m_step(0)
|
cannam@0
|
170 {
|
cannam@0
|
171
|
cannam@0
|
172 }
|
cannam@0
|
173
|
cannam@0
|
174 template<class T, class TOut>
|
cannam@0
|
175 void THistogram<T,TOut>::resize( unsigned int counters )
|
cannam@0
|
176 {
|
cannam@0
|
177 clear();
|
cannam@0
|
178
|
cannam@0
|
179 m_counters.resize(counters,0);
|
cannam@0
|
180
|
cannam@0
|
181 computeStep();
|
cannam@0
|
182 }
|
cannam@0
|
183
|
cannam@0
|
184 template<class T, class TOut>
|
cannam@0
|
185 void THistogram<T,TOut>::compute( const std::vector<T>& v, bool computeMinMax)
|
cannam@0
|
186 {
|
cannam@0
|
187 using namespace std;
|
cannam@0
|
188 unsigned int i;
|
cannam@0
|
189 int index;
|
cannam@0
|
190
|
cannam@0
|
191 if (m_counters.empty())
|
cannam@0
|
192 return;
|
cannam@0
|
193
|
cannam@0
|
194 if (computeMinMax)
|
cannam@0
|
195 {
|
cannam@0
|
196 m_max = m_min = v[0];
|
cannam@0
|
197 for (i=1;i<v.size();i++)
|
cannam@0
|
198 {
|
cannam@0
|
199 m_max = std::max( m_max, v[i]);
|
cannam@0
|
200 m_min = std::min( m_min, v[i]);
|
cannam@0
|
201 }
|
cannam@0
|
202 }
|
cannam@0
|
203
|
cannam@0
|
204 computeStep();
|
cannam@0
|
205
|
cannam@0
|
206 for (i = 0;i < v.size() ; i++)
|
cannam@0
|
207 {
|
cannam@0
|
208 index=(int) floor( ((TOut)(v[i]-m_min))/m_step ) ;
|
cannam@0
|
209
|
cannam@0
|
210 if (index >= m_counters.size() || index < 0)
|
cannam@0
|
211 return;
|
cannam@0
|
212
|
cannam@0
|
213 m_counters[index]++;
|
cannam@0
|
214 }
|
cannam@0
|
215 }
|
cannam@0
|
216
|
cannam@0
|
217 template<class T, class TOut>
|
cannam@0
|
218 void THistogram<T,TOut>::update( const std::vector<T>& v)
|
cannam@0
|
219 {
|
cannam@0
|
220 if (m_counters.empty())
|
cannam@0
|
221 return;
|
cannam@0
|
222
|
cannam@0
|
223 computeStep();
|
cannam@0
|
224
|
cannam@0
|
225 TOut size = m_counters.size();
|
cannam@0
|
226
|
cannam@0
|
227 int index;
|
cannam@0
|
228 for (unsigned int i = 0;i < size ; i++)
|
cannam@0
|
229 {
|
cannam@0
|
230 index = (int)floor(((TOut)(v[i]-m_min))/m_step);
|
cannam@0
|
231
|
cannam@0
|
232 if (index >= m_counters.size() || index < 0)
|
cannam@0
|
233 return;
|
cannam@0
|
234
|
cannam@0
|
235 m_counters[index]++;
|
cannam@0
|
236 }
|
cannam@0
|
237 }
|
cannam@0
|
238
|
cannam@0
|
239 template<class T, class TOut>
|
cannam@0
|
240 void THistogram<T,TOut>::update( const T& t)
|
cannam@0
|
241 {
|
cannam@0
|
242 int index=(int) floor( ((TOut)(t-m_min))/m_step ) ;
|
cannam@0
|
243
|
cannam@0
|
244 if (index >= m_counters.size() || index < 0)
|
cannam@0
|
245 return;
|
cannam@0
|
246
|
cannam@0
|
247 m_counters[index]++;
|
cannam@0
|
248 };
|
cannam@0
|
249
|
cannam@0
|
250 template<class T, class TOut>
|
cannam@0
|
251 std::vector<TOut> THistogram<T,TOut>::geTHistogramD() const
|
cannam@0
|
252 {
|
cannam@0
|
253 std::vector<TOut> v(m_counters.size());
|
cannam@0
|
254 for (unsigned int i = 0;i<m_counters.size(); i++)
|
cannam@0
|
255 v[i]=(TOut)m_counters[i];
|
cannam@0
|
256
|
cannam@0
|
257 return v;
|
cannam@0
|
258 }
|
cannam@0
|
259
|
cannam@0
|
260 template <class T, class TOut>
|
cannam@0
|
261 std::vector<TOut> THistogram<T,TOut>::getLeftContainers() const
|
cannam@0
|
262 {
|
cannam@0
|
263 std::vector<TOut> x( m_counters.size());
|
cannam@0
|
264
|
cannam@0
|
265 for (unsigned int i = 0;i<m_counters.size(); i++)
|
cannam@0
|
266 x[i]= m_min + i*m_step;
|
cannam@0
|
267
|
cannam@0
|
268 return x;
|
cannam@0
|
269 }
|
cannam@0
|
270
|
cannam@0
|
271 template <class T, class TOut>
|
cannam@0
|
272 std::vector<TOut> THistogram<T,TOut>::getCenterContainers() const
|
cannam@0
|
273 {
|
cannam@0
|
274 std::vector<TOut> x( m_counters.size());
|
cannam@0
|
275
|
cannam@0
|
276 for (unsigned int i = 0;i<m_counters.size(); i++)
|
cannam@0
|
277 x[i]= m_min + (i+0.5)*m_step;
|
cannam@0
|
278
|
cannam@0
|
279 return x;
|
cannam@0
|
280 }
|
cannam@0
|
281
|
cannam@0
|
282 template <class T, class TOut>
|
cannam@0
|
283 unsigned int THistogram<T,TOut>::getSum() const
|
cannam@0
|
284 {
|
cannam@0
|
285 unsigned int sum = 0;
|
cannam@0
|
286 for (unsigned int i = 0;i<m_counters.size(); i++)
|
cannam@0
|
287 sum+=m_counters[i];
|
cannam@0
|
288
|
cannam@0
|
289 return sum;
|
cannam@0
|
290 }
|
cannam@0
|
291
|
cannam@0
|
292 template <class T, class TOut>
|
cannam@0
|
293 TOut THistogram<T,TOut>::getArea() const
|
cannam@0
|
294 {
|
cannam@0
|
295 const size_t n=m_counters.size();
|
cannam@0
|
296 TOut area=0;
|
cannam@0
|
297
|
cannam@0
|
298 if (n>6)
|
cannam@0
|
299 {
|
cannam@0
|
300 area=3.0/8.0*(m_counters[0]+m_counters[n-1])
|
cannam@0
|
301 +7.0/6.0*(m_counters[1]+m_counters[n-2])
|
cannam@0
|
302 +23.0/24.0*(m_counters[2]+m_counters[n-3]);
|
cannam@0
|
303 for (unsigned int i=3;i<n-3;i++)
|
cannam@0
|
304 {
|
cannam@0
|
305 area+=m_counters[i];
|
cannam@0
|
306 }
|
cannam@0
|
307 }
|
cannam@0
|
308 else if (n>4)
|
cannam@0
|
309 {
|
cannam@0
|
310 area=5.0/12.0*(m_counters[0]+m_counters[n-1])
|
cannam@0
|
311 +13.0/12.0*(m_counters[1]+m_counters[n-2]);
|
cannam@0
|
312 for (unsigned int i=2;i<n-2;i++)
|
cannam@0
|
313 {
|
cannam@0
|
314 area+=m_counters[i];
|
cannam@0
|
315 }
|
cannam@0
|
316 }
|
cannam@0
|
317 else if (n>1)
|
cannam@0
|
318 {
|
cannam@0
|
319 area=1/2.0*(m_counters[0]+m_counters[n-1]);
|
cannam@0
|
320 for (unsigned int i=1;i<n-1;i++)
|
cannam@0
|
321 {
|
cannam@0
|
322 area+=m_counters[i];
|
cannam@0
|
323 }
|
cannam@0
|
324 }
|
cannam@0
|
325 else
|
cannam@0
|
326 area=0;
|
cannam@0
|
327
|
cannam@0
|
328 return area*m_step;
|
cannam@0
|
329 }
|
cannam@0
|
330
|
cannam@0
|
331 template <class T, class TOut>
|
cannam@0
|
332 std::vector<TOut> THistogram<T,TOut>::getNormalizedHistogram() const
|
cannam@0
|
333 {
|
cannam@0
|
334 std::vector<TOut> normCounters( m_counters.size());
|
cannam@0
|
335 TOut area = (TOut)getArea();
|
cannam@0
|
336
|
cannam@0
|
337 for (unsigned int i = 0;i<m_counters.size(); i++)
|
cannam@0
|
338 {
|
cannam@0
|
339 normCounters[i]= (TOut)m_counters[i]/area;
|
cannam@0
|
340 }
|
cannam@0
|
341
|
cannam@0
|
342 return normCounters;
|
cannam@0
|
343 };
|
cannam@0
|
344
|
cannam@0
|
345 template <class T, class TOut>
|
cannam@0
|
346 void THistogram<T,TOut>::getMoments(const std::vector<T>& data, TOut& ave, TOut& adev, TOut& sdev, TOut& var, TOut& skew, TOut& kurt)
|
cannam@0
|
347 {
|
cannam@0
|
348 int j;
|
cannam@0
|
349 double ep=0.0,s,p;
|
cannam@0
|
350 const size_t n = data.size();
|
cannam@0
|
351
|
cannam@0
|
352 if (n <= 1)
|
cannam@0
|
353 // nrerror("n must be at least 2 in moment");
|
cannam@0
|
354 return;
|
cannam@0
|
355
|
cannam@0
|
356 s=0.0; // First pass to get the mean.
|
cannam@0
|
357 for (j=0;j<n;j++)
|
cannam@0
|
358 s += data[j];
|
cannam@0
|
359
|
cannam@0
|
360 ave=s/(n);
|
cannam@0
|
361 adev=var=skew=kurt=0.0;
|
cannam@0
|
362 /* Second pass to get the first (absolute), second,
|
cannam@0
|
363 third, and fourth moments of the
|
cannam@0
|
364 deviation from the mean. */
|
cannam@0
|
365
|
cannam@0
|
366 for (j=0;j<n;j++)
|
cannam@0
|
367 {
|
cannam@0
|
368 adev += fabs(s=data[j]-(ave));
|
cannam@0
|
369 ep += s;
|
cannam@0
|
370 var += (p=s*s);
|
cannam@0
|
371 skew += (p *= s);
|
cannam@0
|
372 kurt += (p *= s);
|
cannam@0
|
373 }
|
cannam@0
|
374
|
cannam@0
|
375
|
cannam@0
|
376 adev /= n;
|
cannam@0
|
377 var=(var-ep*ep/n)/(n-1); // Corrected two-pass formula.
|
cannam@0
|
378 sdev=sqrt(var); // Put the pieces together according to the conventional definitions.
|
cannam@0
|
379 if (var)
|
cannam@0
|
380 {
|
cannam@0
|
381 skew /= (n*(var)*(sdev));
|
cannam@0
|
382 kurt=(kurt)/(n*(var)*(var))-3.0;
|
cannam@0
|
383 }
|
cannam@0
|
384 else
|
cannam@0
|
385 //nrerror("No skew/kurtosis when variance = 0 (in moment)");
|
cannam@0
|
386 return;
|
cannam@0
|
387 }
|
cannam@0
|
388
|
cannam@0
|
389 #endif
|
cannam@0
|
390
|