Ticket #6128: RollingVariance.hpp

File RollingVariance.hpp, 4.6 KB (added by Pieter Ober <jaapaap@…>, 11 years ago)
Line 
1///////////////////////////////////////////////////////////////////////////////
2// rolling_variance.hpp
3// Copyright (C) 2005 Eric Niebler
4// Copyright (C) 2011 Pieter Bastiaan Ober (Integricom). Distributed under the Boost
5// Software License, Version 1.0. (See accompanying file
6// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8#ifndef BOOST_ACCUMULATORS_STATISTICS_ROLLING_VARIANCE_HPP_EAN_15_11_2011
9#define BOOST_ACCUMULATORS_STATISTICS_ROLLING_VARIANCE_HPP_EAN_15_11_2011
10
11#include <boost/accumulators/accumulators.hpp>
12#include <boost/accumulators/statistics/stats.hpp>
13
14#include <boost/mpl/placeholders.hpp>
15#include <boost/accumulators/framework/accumulator_base.hpp>
16#include <boost/accumulators/framework/extractor.hpp>
17#include <boost/accumulators/numeric/functional.hpp>
18#include <boost/accumulators/framework/parameters/sample.hpp>
19#include <boost/accumulators/framework/depends_on.hpp>
20#include <boost/accumulators/statistics_fwd.hpp>
21#include <boost/accumulators/statistics/rolling_window.hpp>
22#include <boost/accumulators/statistics/rolling_count.hpp>
23
24#include <RollingMean.hpp>
25
26// See: Chan, Tony F.; Golub, Gene H.; LeVeque, Randall J. (1983).
27// Algorithms for Computing the Sample Variance: Analysis and Recommendations.
28// The American Statistician 37, 242-247.
29//
30// Variance(x[1:N]):
31// {
32// M[1] = x[1]
33// S[1] = 0.0
34//
35// j=2:N
36// {
37// M[j] = M[j-1] + (1/j)*(x[j]-M[j]-1)
38// S[j] = S[j-1] + ((j-1)/j)*(x[j]-M[j-1])^2
39// Variance = S[j]/j or
40// Variance = S[j]/(j-1)
41// }
42// }
43//
44// When the buffer of size N is full, not only points are added but points are dropped as well.
45// from the window over which the variance is computed. Adaptation to a rolling window gives
46// for j=N+1,...:
47// {
48// M[j] = M[j-1] + (1/N)*(x[j]-x[j-N])
49// S[j] = S[j-1] + (N/(N+1))*(x[j]-M[j-1])^2 - (N/(N+1))*(x[j-N]-M[j])^2
50// Variance = S[j]/N or
51// Variance = S[j]/(N-1)
52// }
53
54
55namespace boost { namespace accumulators
56{
57namespace impl
58{
59 ///////////////////////////////////////////////////////////////////////////////
60 // rolling_variance_impl
61 //
62 template<typename Sample>
63 struct rolling_variance_impl
64 : accumulator_base
65 {
66 typedef Sample result_type;
67
68 template<typename Args>
69 rolling_variance_impl(Args const &args)
70 : previous_mean_(0.0)
71 , sum_of_squares_(0.0)
72 {
73 // VOID;
74 }
75
76 template<typename Args>
77 void operator()(Args const &args)
78 {
79 Sample added_sample = args[sample];
80 size_t nr_samples = rolling_count(args);
81
82 Sample mean = rolling_mean(args);
83
84 if(is_rolling_window_plus1_full(args))
85 {
86 Sample weight = static_cast<Sample>(nr_samples)/static_cast<Sample>(nr_samples+1);
87 Sample removed_sample = rolling_window_plus1(args).front();
88 sum_of_squares_ += weight*(
89 (added_sample-previous_mean_)*(added_sample-previous_mean_) -
90 (removed_sample-mean)*(removed_sample-mean)
91 );
92 if (sum_of_squares_ < 0.0) sum_of_squares_ = 0.0;
93 }
94 else
95 {
96 Sample weight = static_cast<Sample>(nr_samples-1)/static_cast<Sample>(nr_samples);
97 sum_of_squares_ += weight*(added_sample-previous_mean_)*(added_sample-previous_mean_);
98 }
99 previous_mean_ = mean;
100 }
101
102 template<typename Args>
103 result_type result(Args const &args) const
104 {
105 size_t nr_samples = rolling_count(args);
106 if (nr_samples < 2) return 0;
107 return sum_of_squares_/(nr_samples-1);
108 }
109
110 private:
111
112 Sample previous_mean_;
113 Sample sum_of_squares_;
114 };
115} // namespace impl
116
117///////////////////////////////////////////////////////////////////////////////
118// tag:: rolling_variance
119//
120namespace tag
121{
122 struct rolling_variance
123 : depends_on< rolling_window_plus1, rolling_count, rolling_mean>
124 {
125 /// INTERNAL ONLY
126 ///
127 typedef accumulators::impl::rolling_variance_impl< mpl::_1 > impl;
128
129 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
130 /// tag::rolling_window::window_size named parameter
131 static boost::parameter::keyword<tag::rolling_window_size> const window_size;
132 #endif
133 };
134} // namespace tag
135
136///////////////////////////////////////////////////////////////////////////////
137// extract::rolling_variance
138//
139namespace extract
140{
141 extractor<tag::rolling_variance> const rolling_variance = {};
142
143 BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_variance)
144}
145
146using extract::rolling_variance;
147
148}} // namespace boost::accumulators
149
150#endif