ljung_box.hpp 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // (C) Copyright Nick Thompson 2019.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_STATISTICS_LJUNG_BOX_HPP
  6. #define BOOST_MATH_STATISTICS_LJUNG_BOX_HPP
  7. #include <cmath>
  8. #include <iterator>
  9. #include <utility>
  10. #include <boost/math/distributions/chi_squared.hpp>
  11. #include <boost/math/statistics/univariate_statistics.hpp>
  12. namespace boost::math::statistics {
  13. template<class RandomAccessIterator>
  14. auto ljung_box(RandomAccessIterator begin, RandomAccessIterator end, int64_t lags = -1, int64_t fit_dof = 0) {
  15. using Real = typename std::iterator_traits<RandomAccessIterator>::value_type;
  16. int64_t n = std::distance(begin, end);
  17. if (lags >= n) {
  18. throw std::domain_error("Number of lags must be < number of elements in array.");
  19. }
  20. if (lags == -1) {
  21. // This is the same default as Mathematica; it seems sensible enough . . .
  22. lags = static_cast<int64_t>(std::ceil(std::log(Real(n))));
  23. }
  24. if (lags <= 0) {
  25. throw std::domain_error("Must have at least one lag.");
  26. }
  27. auto mu = boost::math::statistics::mean(begin, end);
  28. std::vector<Real> r(lags + 1, Real(0));
  29. for (size_t i = 0; i < r.size(); ++i) {
  30. for (auto it = begin + i; it != end; ++it) {
  31. Real ak = *(it) - mu;
  32. Real akml = *(it-i) - mu;
  33. r[i] += ak*akml;
  34. }
  35. }
  36. Real Q = 0;
  37. for (size_t k = 1; k < r.size(); ++k) {
  38. Q += r[k]*r[k]/(r[0]*r[0]*(n-k));
  39. }
  40. Q *= n*(n+2);
  41. typedef boost::math::policies::policy<
  42. boost::math::policies::promote_float<false>,
  43. boost::math::policies::promote_double<false> >
  44. no_promote_policy;
  45. auto chi = boost::math::chi_squared_distribution<Real, no_promote_policy>(Real(lags - fit_dof));
  46. Real pvalue = 1 - boost::math::cdf(chi, Q);
  47. return std::make_pair(Q, pvalue);
  48. }
  49. template<class RandomAccessContainer>
  50. auto ljung_box(RandomAccessContainer const & v, int64_t lags = -1, int64_t fit_dof = 0) {
  51. return ljung_box(v.begin(), v.end(), lags, fit_dof);
  52. }
  53. }
  54. #endif