Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // weighted_median.hpp Chris@16: // Chris@16: // Copyright 2006 Eric Niebler, Olivier Gygi. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_ACCUMULATORS_STATISTICS_WEIGHTED_MEDIAN_HPP_EAN_28_10_2005 Chris@16: #define BOOST_ACCUMULATORS_STATISTICS_WEIGHTED_MEDIAN_HPP_EAN_28_10_2005 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace accumulators Chris@16: { Chris@16: Chris@16: namespace impl Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // weighted_median_impl Chris@16: // Chris@16: /** Chris@16: @brief Median estimation for weighted samples based on the \f$P^2\f$ quantile estimator Chris@16: Chris@16: The \f$P^2\f$ algorithm for weighted samples is invoked with a quantile probability of 0.5. Chris@16: */ Chris@16: template Chris@16: struct weighted_median_impl Chris@16: : accumulator_base Chris@16: { Chris@16: // for boost::result_of Chris@16: typedef typename numeric::functional::fdiv::result_type result_type; Chris@16: Chris@16: weighted_median_impl(dont_care) {} Chris@16: Chris@16: template Chris@16: result_type result(Args const &args) const Chris@16: { Chris@16: return weighted_p_square_quantile_for_median(args); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // with_density_weighted_median_impl Chris@16: // Chris@16: /** Chris@16: @brief Median estimation for weighted samples based on the density estimator Chris@16: Chris@16: The algorithm determines the bin in which the \f$0.5*cnt\f$-th sample lies, \f$cnt\f$ being Chris@16: the total number of samples. It returns the approximate horizontal position of this sample, Chris@16: based on a linear interpolation inside the bin. Chris@16: */ Chris@16: template Chris@16: struct with_density_weighted_median_impl Chris@16: : accumulator_base Chris@16: { Chris@16: typedef typename numeric::functional::fdiv::result_type float_type; Chris@16: typedef std::vector > histogram_type; Chris@16: typedef iterator_range range_type; Chris@16: // for boost::result_of Chris@16: typedef float_type result_type; Chris@16: Chris@16: template Chris@16: with_density_weighted_median_impl(Args const &args) Chris@16: : sum(numeric::fdiv(args[sample | Sample()], (std::size_t)1)) Chris@16: , is_dirty(true) Chris@16: { Chris@16: } Chris@16: Chris@16: void operator ()(dont_care) Chris@16: { Chris@16: this->is_dirty = true; Chris@16: } Chris@16: Chris@16: template Chris@16: result_type result(Args const &args) const Chris@16: { Chris@16: if (this->is_dirty) Chris@16: { Chris@16: this->is_dirty = false; Chris@16: Chris@16: std::size_t cnt = count(args); Chris@16: range_type histogram = weighted_density(args); Chris@16: typename range_type::iterator it = histogram.begin(); Chris@16: while (this->sum < 0.5 * cnt) Chris@16: { Chris@16: this->sum += it->second * cnt; Chris@16: ++it; Chris@16: } Chris@16: --it; Chris@16: float_type over = numeric::fdiv(this->sum - 0.5 * cnt, it->second * cnt); Chris@16: this->median = it->first * over + (it + 1)->first * ( 1. - over ); Chris@16: } Chris@16: Chris@16: return this->median; Chris@16: } Chris@16: Chris@16: private: Chris@16: mutable float_type sum; Chris@16: mutable bool is_dirty; Chris@16: mutable float_type median; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // with_p_square_cumulative_distribution_weighted_median_impl Chris@16: // Chris@16: /** Chris@16: @brief Median estimation for weighted samples based on the \f$P^2\f$ cumulative distribution estimator Chris@16: Chris@16: The algorithm determines the first (leftmost) bin with a height exceeding 0.5. It Chris@16: returns the approximate horizontal position of where the cumulative distribution Chris@16: equals 0.5, based on a linear interpolation inside the bin. Chris@16: */ Chris@16: template Chris@16: struct with_p_square_cumulative_distribution_weighted_median_impl Chris@16: : accumulator_base Chris@16: { Chris@16: typedef typename numeric::functional::multiplies::result_type weighted_sample; Chris@16: typedef typename numeric::functional::fdiv::result_type float_type; Chris@16: typedef std::vector > histogram_type; Chris@16: typedef iterator_range range_type; Chris@16: // for boost::result_of Chris@16: typedef float_type result_type; Chris@16: Chris@16: with_p_square_cumulative_distribution_weighted_median_impl(dont_care) Chris@16: : is_dirty(true) Chris@16: { Chris@16: } Chris@16: Chris@16: void operator ()(dont_care) Chris@16: { Chris@16: this->is_dirty = true; Chris@16: } Chris@16: Chris@16: template Chris@16: result_type result(Args const &args) const Chris@16: { Chris@16: if (this->is_dirty) Chris@16: { Chris@16: this->is_dirty = false; Chris@16: Chris@16: range_type histogram = weighted_p_square_cumulative_distribution(args); Chris@16: typename range_type::iterator it = histogram.begin(); Chris@16: while (it->second < 0.5) Chris@16: { Chris@16: ++it; Chris@16: } Chris@16: float_type over = numeric::fdiv(it->second - 0.5, it->second - (it - 1)->second); Chris@16: this->median = it->first * over + (it + 1)->first * ( 1. - over ); Chris@16: } Chris@16: Chris@16: return this->median; Chris@16: } Chris@16: private: Chris@16: mutable bool is_dirty; Chris@16: mutable float_type median; Chris@16: }; Chris@16: Chris@16: } // namespace impl Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // tag::weighted_median Chris@16: // tag::with_density_weighted_median Chris@16: // tag::with_p_square_cumulative_distribution_weighted_median Chris@16: // Chris@16: namespace tag Chris@16: { Chris@16: struct weighted_median Chris@16: : depends_on Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: typedef accumulators::impl::weighted_median_impl impl; Chris@16: }; Chris@16: struct with_density_weighted_median Chris@16: : depends_on Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: typedef accumulators::impl::with_density_weighted_median_impl impl; Chris@16: }; Chris@16: struct with_p_square_cumulative_distribution_weighted_median Chris@16: : depends_on Chris@16: { Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: typedef accumulators::impl::with_p_square_cumulative_distribution_weighted_median_impl impl; Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // extract::weighted_median Chris@16: // Chris@16: namespace extract Chris@16: { Chris@16: extractor const weighted_median = {}; Chris@16: Chris@16: BOOST_ACCUMULATORS_IGNORE_GLOBAL(weighted_median) Chris@16: } Chris@16: Chris@16: using extract::weighted_median; Chris@16: // weighted_median(with_p_square_quantile) -> weighted_median Chris@16: template<> Chris@16: struct as_feature Chris@16: { Chris@16: typedef tag::weighted_median type; Chris@16: }; Chris@16: Chris@16: // weighted_median(with_density) -> with_density_weighted_median Chris@16: template<> Chris@16: struct as_feature Chris@16: { Chris@16: typedef tag::with_density_weighted_median type; Chris@16: }; Chris@16: Chris@16: // weighted_median(with_p_square_cumulative_distribution) -> with_p_square_cumulative_distribution_weighted_median Chris@16: template<> Chris@16: struct as_feature Chris@16: { Chris@16: typedef tag::with_p_square_cumulative_distribution_weighted_median type; Chris@16: }; Chris@16: Chris@16: }} // namespace boost::accumulators Chris@16: Chris@16: #endif