1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // weighted_variance.hpp |
3 | // |
4 | // Copyright 2005 Daniel Egloff, Eric Niebler. 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_WEIGHTED_VARIANCE_HPP_EAN_28_10_2005 |
9 | #define BOOST_ACCUMULATORS_STATISTICS_WEIGHTED_VARIANCE_HPP_EAN_28_10_2005 |
10 | |
11 | #include <boost/mpl/placeholders.hpp> |
12 | #include <boost/accumulators/framework/accumulator_base.hpp> |
13 | #include <boost/accumulators/framework/extractor.hpp> |
14 | #include <boost/accumulators/numeric/functional.hpp> |
15 | #include <boost/accumulators/framework/parameters/sample.hpp> |
16 | #include <boost/accumulators/framework/depends_on.hpp> |
17 | #include <boost/accumulators/statistics_fwd.hpp> |
18 | #include <boost/accumulators/statistics/count.hpp> |
19 | #include <boost/accumulators/statistics/variance.hpp> |
20 | #include <boost/accumulators/statistics/weighted_sum.hpp> |
21 | #include <boost/accumulators/statistics/weighted_mean.hpp> |
22 | #include <boost/accumulators/statistics/weighted_moment.hpp> |
23 | |
24 | namespace boost { namespace accumulators |
25 | { |
26 | |
27 | namespace impl |
28 | { |
29 | //! Lazy calculation of variance of weighted samples. |
30 | /*! |
31 | The default implementation of the variance of weighted samples is based on the second moment |
32 | \f$\widehat{m}_n^{(2)}\f$ (weighted_moment<2>) and the mean\f$ \hat{\mu}_n\f$ (weighted_mean): |
33 | \f[ |
34 | \hat{\sigma}_n^2 = \widehat{m}_n^{(2)}-\hat{\mu}_n^2, |
35 | \f] |
36 | where \f$n\f$ is the number of samples. |
37 | */ |
38 | template<typename Sample, typename Weight, typename MeanFeature> |
39 | struct lazy_weighted_variance_impl |
40 | : accumulator_base |
41 | { |
42 | typedef typename numeric::functional::multiplies<Sample, Weight>::result_type weighted_sample; |
43 | // for boost::result_of |
44 | typedef typename numeric::functional::fdiv<weighted_sample, Weight>::result_type result_type; |
45 | |
46 | lazy_weighted_variance_impl(dont_care) {} |
47 | |
48 | template<typename Args> |
49 | result_type result(Args const &args) const |
50 | { |
51 | extractor<MeanFeature> const some_mean = {}; |
52 | result_type tmp = some_mean(args); |
53 | return accumulators::weighted_moment<2>(args) - tmp * tmp; |
54 | } |
55 | }; |
56 | |
57 | //! Iterative calculation of variance of weighted samples. |
58 | /*! |
59 | Iterative calculation of variance of weighted samples: |
60 | \f[ |
61 | \hat{\sigma}_n^2 = |
62 | \frac{\bar{w}_n - w_n}{\bar{w}_n}\hat{\sigma}_{n - 1}^2 |
63 | + \frac{w_n}{\bar{w}_n - w_n}\left(X_n - \hat{\mu}_n\right)^2 |
64 | ,\quad n\ge2,\quad\hat{\sigma}_0^2 = 0. |
65 | \f] |
66 | where \f$\bar{w}_n\f$ is the sum of the \f$n\f$ weights \f$w_i\f$ and \f$\hat{\mu}_n\f$ |
67 | the estimate of the mean of the weighted samples. Note that the sample variance is not defined for |
68 | \f$n <= 1\f$. |
69 | */ |
70 | template<typename Sample, typename Weight, typename MeanFeature, typename Tag> |
71 | struct weighted_variance_impl |
72 | : accumulator_base |
73 | { |
74 | typedef typename numeric::functional::multiplies<Sample, Weight>::result_type weighted_sample; |
75 | // for boost::result_of |
76 | typedef typename numeric::functional::fdiv<weighted_sample, Weight>::result_type result_type; |
77 | |
78 | template<typename Args> |
79 | weighted_variance_impl(Args const &args) |
80 | : weighted_variance(numeric::fdiv(args[sample | Sample()], numeric::one<Weight>::value)) |
81 | { |
82 | } |
83 | |
84 | template<typename Args> |
85 | void operator ()(Args const &args) |
86 | { |
87 | std::size_t cnt = count(args); |
88 | |
89 | if(cnt > 1) |
90 | { |
91 | extractor<MeanFeature> const some_mean = {}; |
92 | |
93 | result_type tmp = args[parameter::keyword<Tag>::get()] - some_mean(args); |
94 | |
95 | this->weighted_variance = |
96 | numeric::fdiv(this->weighted_variance * (sum_of_weights(args) - args[weight]), sum_of_weights(args)) |
97 | + numeric::fdiv(tmp * tmp * args[weight], sum_of_weights(args) - args[weight] ); |
98 | } |
99 | } |
100 | |
101 | result_type result(dont_care) const |
102 | { |
103 | return this->weighted_variance; |
104 | } |
105 | |
106 | // make this accumulator serializeable |
107 | template<class Archive> |
108 | void serialize(Archive & ar, const unsigned int file_version) |
109 | { |
110 | ar & weighted_variance; |
111 | } |
112 | |
113 | private: |
114 | result_type weighted_variance; |
115 | }; |
116 | |
117 | } // namespace impl |
118 | |
119 | /////////////////////////////////////////////////////////////////////////////// |
120 | // tag::weighted_variance |
121 | // tag::immediate_weighted_variance |
122 | // |
123 | namespace tag |
124 | { |
125 | struct lazy_weighted_variance |
126 | : depends_on<weighted_moment<2>, weighted_mean> |
127 | { |
128 | /// INTERNAL ONLY |
129 | /// |
130 | typedef accumulators::impl::lazy_weighted_variance_impl<mpl::_1, mpl::_2, weighted_mean> impl; |
131 | }; |
132 | |
133 | struct weighted_variance |
134 | : depends_on<count, immediate_weighted_mean> |
135 | { |
136 | /// INTERNAL ONLY |
137 | /// |
138 | typedef accumulators::impl::weighted_variance_impl<mpl::_1, mpl::_2, immediate_weighted_mean, sample> impl; |
139 | }; |
140 | } |
141 | |
142 | /////////////////////////////////////////////////////////////////////////////// |
143 | // extract::weighted_variance |
144 | // extract::immediate_weighted_variance |
145 | // |
146 | namespace extract |
147 | { |
148 | extractor<tag::lazy_weighted_variance> const = {}; |
149 | extractor<tag::weighted_variance> const = {}; |
150 | |
151 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(lazy_weighted_variance) |
152 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(weighted_variance) |
153 | } |
154 | |
155 | using extract::lazy_weighted_variance; |
156 | using extract::weighted_variance; |
157 | |
158 | // weighted_variance(lazy) -> lazy_weighted_variance |
159 | template<> |
160 | struct as_feature<tag::weighted_variance(lazy)> |
161 | { |
162 | typedef tag::lazy_weighted_variance type; |
163 | }; |
164 | |
165 | // weighted_variance(immediate) -> weighted_variance |
166 | template<> |
167 | struct as_feature<tag::weighted_variance(immediate)> |
168 | { |
169 | typedef tag::weighted_variance type; |
170 | }; |
171 | |
172 | //////////////////////////////////////////////////////////////////////////// |
173 | //// droppable_accumulator<weighted_variance_impl> |
174 | //// need to specialize droppable lazy weighted_variance to cache the result at the |
175 | //// point the accumulator is dropped. |
176 | ///// INTERNAL ONLY |
177 | ///// |
178 | //template<typename Sample, typename Weight, typename MeanFeature> |
179 | //struct droppable_accumulator<impl::weighted_variance_impl<Sample, Weight, MeanFeature> > |
180 | // : droppable_accumulator_base< |
181 | // with_cached_result<impl::weighted_variance_impl<Sample, Weight, MeanFeature> > |
182 | // > |
183 | //{ |
184 | // template<typename Args> |
185 | // droppable_accumulator(Args const &args) |
186 | // : droppable_accumulator::base(args) |
187 | // { |
188 | // } |
189 | //}; |
190 | |
191 | }} // namespace boost::accumulators |
192 | |
193 | #endif |
194 | |