tail_mean.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // tail_mean.hpp
  3. //
  4. // Copyright 2006 Daniel Egloff, Olivier Gygi. 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. #ifndef BOOST_ACCUMULATORS_STATISTICS_TAIL_MEAN_HPP_DE_01_01_2006
  8. #define BOOST_ACCUMULATORS_STATISTICS_TAIL_MEAN_HPP_DE_01_01_2006
  9. #include <numeric>
  10. #include <vector>
  11. #include <limits>
  12. #include <functional>
  13. #include <sstream>
  14. #include <stdexcept>
  15. #include <boost/throw_exception.hpp>
  16. #include <boost/parameter/keyword.hpp>
  17. #include <boost/mpl/placeholders.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/accumulators/framework/accumulator_base.hpp>
  20. #include <boost/accumulators/framework/extractor.hpp>
  21. #include <boost/accumulators/numeric/functional.hpp>
  22. #include <boost/accumulators/framework/parameters/sample.hpp>
  23. #include <boost/accumulators/statistics_fwd.hpp>
  24. #include <boost/accumulators/statistics/count.hpp>
  25. #include <boost/accumulators/statistics/tail.hpp>
  26. #include <boost/accumulators/statistics/tail_quantile.hpp>
  27. #include <boost/accumulators/statistics/parameters/quantile_probability.hpp>
  28. #ifdef _MSC_VER
  29. # pragma warning(push)
  30. # pragma warning(disable: 4127) // conditional expression is constant
  31. #endif
  32. namespace boost { namespace accumulators
  33. {
  34. namespace impl
  35. {
  36. ///////////////////////////////////////////////////////////////////////////////
  37. // coherent_tail_mean_impl
  38. //
  39. /**
  40. @brief Estimation of the coherent tail mean based on order statistics (for both left and right tails)
  41. The coherent tail mean \f$\widehat{CTM}_{n,\alpha}(X)\f$ is equal to the non-coherent tail mean \f$\widehat{NCTM}_{n,\alpha}(X)\f$
  42. plus a correction term that ensures coherence in case of non-continuous distributions.
  43. \f[
  44. \widehat{CTM}_{n,\alpha}^{\mathrm{right}}(X) = \widehat{NCTM}_{n,\alpha}^{\mathrm{right}}(X) +
  45. \frac{1}{\lceil n(1-\alpha)\rceil}\hat{q}_{n,\alpha}(X)\left(1 - \alpha - \frac{1}{n}\lceil n(1-\alpha)\rceil \right)
  46. \f]
  47. \f[
  48. \widehat{CTM}_{n,\alpha}^{\mathrm{left}}(X) = \widehat{NCTM}_{n,\alpha}^{\mathrm{left}}(X) +
  49. \frac{1}{\lceil n\alpha\rceil}\hat{q}_{n,\alpha}(X)\left(\alpha - \frac{1}{n}\lceil n\alpha\rceil \right)
  50. \f]
  51. */
  52. template<typename Sample, typename LeftRight>
  53. struct coherent_tail_mean_impl
  54. : accumulator_base
  55. {
  56. typedef typename numeric::functional::fdiv<Sample, std::size_t>::result_type float_type;
  57. // for boost::result_of
  58. typedef float_type result_type;
  59. coherent_tail_mean_impl(dont_care) {}
  60. template<typename Args>
  61. result_type result(Args const &args) const
  62. {
  63. std::size_t cnt = count(args);
  64. std::size_t n = static_cast<std::size_t>(
  65. std::ceil(
  66. cnt * ( ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability] )
  67. )
  68. );
  69. extractor<tag::non_coherent_tail_mean<LeftRight> > const some_non_coherent_tail_mean = {};
  70. return some_non_coherent_tail_mean(args)
  71. + numeric::fdiv(quantile(args), n)
  72. * (
  73. ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability]
  74. - numeric::fdiv(n, count(args))
  75. );
  76. }
  77. // serialization is done by accumulators it depends on
  78. template<class Archive>
  79. void serialize(Archive & ar, const unsigned int file_version) {}
  80. };
  81. ///////////////////////////////////////////////////////////////////////////////
  82. // non_coherent_tail_mean_impl
  83. //
  84. /**
  85. @brief Estimation of the (non-coherent) tail mean based on order statistics (for both left and right tails)
  86. An estimation of the non-coherent tail mean \f$\widehat{NCTM}_{n,\alpha}(X)\f$ is given by the mean of the
  87. \f$\lceil n\alpha\rceil\f$ smallest samples (left tail) or the mean of the \f$\lceil n(1-\alpha)\rceil\f$
  88. largest samples (right tail), \f$n\f$ being the total number of samples and \f$\alpha\f$ the quantile level:
  89. \f[
  90. \widehat{NCTM}_{n,\alpha}^{\mathrm{right}}(X) = \frac{1}{\lceil n(1-\alpha)\rceil} \sum_{i=\lceil \alpha n \rceil}^n X_{i:n}
  91. \f]
  92. \f[
  93. \widehat{NCTM}_{n,\alpha}^{\mathrm{left}}(X) = \frac{1}{\lceil n\alpha\rceil} \sum_{i=1}^{\lceil \alpha n \rceil} X_{i:n}
  94. \f]
  95. It thus requires the caching of at least the \f$\lceil n\alpha\rceil\f$ smallest or the \f$\lceil n(1-\alpha)\rceil\f$
  96. largest samples.
  97. @param quantile_probability
  98. */
  99. template<typename Sample, typename LeftRight>
  100. struct non_coherent_tail_mean_impl
  101. : accumulator_base
  102. {
  103. typedef typename numeric::functional::fdiv<Sample, std::size_t>::result_type float_type;
  104. // for boost::result_of
  105. typedef float_type result_type;
  106. non_coherent_tail_mean_impl(dont_care) {}
  107. template<typename Args>
  108. result_type result(Args const &args) const
  109. {
  110. std::size_t cnt = count(args);
  111. std::size_t n = static_cast<std::size_t>(
  112. std::ceil(
  113. cnt * ( ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability] )
  114. )
  115. );
  116. // If n is in a valid range, return result, otherwise return NaN or throw exception
  117. if (n <= static_cast<std::size_t>(tail(args).size()))
  118. return numeric::fdiv(
  119. std::accumulate(
  120. tail(args).begin()
  121. , tail(args).begin() + n
  122. , Sample(0)
  123. )
  124. , n
  125. );
  126. else
  127. {
  128. if (std::numeric_limits<result_type>::has_quiet_NaN)
  129. {
  130. return std::numeric_limits<result_type>::quiet_NaN();
  131. }
  132. else
  133. {
  134. std::ostringstream msg;
  135. msg << "index n = " << n << " is not in valid range [0, " << tail(args).size() << ")";
  136. boost::throw_exception(std::runtime_error(msg.str()));
  137. return Sample(0);
  138. }
  139. }
  140. }
  141. // serialization is done by accumulators it depends on
  142. template<class Archive>
  143. void serialize(Archive & ar, const unsigned int file_version) {}
  144. };
  145. } // namespace impl
  146. ///////////////////////////////////////////////////////////////////////////////
  147. // tag::coherent_tail_mean<>
  148. // tag::non_coherent_tail_mean<>
  149. //
  150. namespace tag
  151. {
  152. template<typename LeftRight>
  153. struct coherent_tail_mean
  154. : depends_on<count, quantile, non_coherent_tail_mean<LeftRight> >
  155. {
  156. typedef accumulators::impl::coherent_tail_mean_impl<mpl::_1, LeftRight> impl;
  157. };
  158. template<typename LeftRight>
  159. struct non_coherent_tail_mean
  160. : depends_on<count, tail<LeftRight> >
  161. {
  162. typedef accumulators::impl::non_coherent_tail_mean_impl<mpl::_1, LeftRight> impl;
  163. };
  164. struct abstract_non_coherent_tail_mean
  165. : depends_on<>
  166. {
  167. };
  168. }
  169. ///////////////////////////////////////////////////////////////////////////////
  170. // extract::non_coherent_tail_mean;
  171. // extract::coherent_tail_mean;
  172. //
  173. namespace extract
  174. {
  175. extractor<tag::abstract_non_coherent_tail_mean> const non_coherent_tail_mean = {};
  176. extractor<tag::tail_mean> const coherent_tail_mean = {};
  177. BOOST_ACCUMULATORS_IGNORE_GLOBAL(non_coherent_tail_mean)
  178. BOOST_ACCUMULATORS_IGNORE_GLOBAL(coherent_tail_mean)
  179. }
  180. using extract::non_coherent_tail_mean;
  181. using extract::coherent_tail_mean;
  182. // for the purposes of feature-based dependency resolution,
  183. // coherent_tail_mean<LeftRight> provides the same feature as tail_mean
  184. template<typename LeftRight>
  185. struct feature_of<tag::coherent_tail_mean<LeftRight> >
  186. : feature_of<tag::tail_mean>
  187. {
  188. };
  189. template<typename LeftRight>
  190. struct feature_of<tag::non_coherent_tail_mean<LeftRight> >
  191. : feature_of<tag::abstract_non_coherent_tail_mean>
  192. {
  193. };
  194. // So that non_coherent_tail_mean can be automatically substituted
  195. // with weighted_non_coherent_tail_mean when the weight parameter is non-void.
  196. template<typename LeftRight>
  197. struct as_weighted_feature<tag::non_coherent_tail_mean<LeftRight> >
  198. {
  199. typedef tag::non_coherent_weighted_tail_mean<LeftRight> type;
  200. };
  201. template<typename LeftRight>
  202. struct feature_of<tag::non_coherent_weighted_tail_mean<LeftRight> >
  203. : feature_of<tag::non_coherent_tail_mean<LeftRight> >
  204. {};
  205. // NOTE that non_coherent_tail_mean cannot be feature-grouped with tail_mean,
  206. // which is the base feature for coherent tail means, since (at least for
  207. // non-continuous distributions) non_coherent_tail_mean is a different measure!
  208. }} // namespace boost::accumulators
  209. #ifdef _MSC_VER
  210. # pragma warning(pop)
  211. #endif
  212. #endif