Skip to content

Commit 0852c16

Browse files
median_absolute_deviation bug fix for non-zero center (#997)
Fix bug causing median_absolute_deviation to return incorrect values when a non-zero center (such as median which is the default) was used.
1 parent 7ce0570 commit 0852c16

File tree

3 files changed

+124
-14
lines changed

3 files changed

+124
-14
lines changed

include/boost/math/statistics/univariate_statistics.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -505,14 +505,14 @@ auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessIterator firs
505505
{
506506
auto middle = first + (num_elems - 1)/2;
507507
std::nth_element(exec, first, middle, last, comparator);
508-
return abs(*middle);
508+
return abs(*middle-center);
509509
}
510510
else
511511
{
512512
auto middle = first + num_elems/2 - 1;
513513
std::nth_element(exec, first, middle, last, comparator);
514514
std::nth_element(exec, middle, middle+1, last, comparator);
515-
return (abs(*middle) + abs(*(middle+1)))/abs(static_cast<Real>(2));
515+
return (abs(*middle-center) + abs(*(middle+1)-center))/abs(static_cast<Real>(2));
516516
}
517517
}
518518

@@ -1043,14 +1043,14 @@ Real median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator
10431043
{
10441044
auto middle = first + (num_elems - 1)/2;
10451045
std::nth_element(first, middle, last, comparator);
1046-
return abs(*middle);
1046+
return abs(*middle-center);
10471047
}
10481048
else
10491049
{
10501050
auto middle = first + num_elems/2 - 1;
10511051
std::nth_element(first, middle, last, comparator);
10521052
std::nth_element(middle, middle+1, last, comparator);
1053-
return (abs(*middle) + abs(*(middle+1)))/abs(static_cast<Real>(2));
1053+
return (abs(*middle-center) + abs(*(middle+1)-center))/abs(static_cast<Real>(2));
10541054
}
10551055
}
10561056

test/univariate_statistics_backwards_compatible_test.cpp

+60-5
Original file line numberDiff line numberDiff line change
@@ -612,11 +612,7 @@ void test_median_absolute_deviation()
612612
v = {-1, 1};
613613
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
614614
BOOST_TEST_EQ(m, 1);
615-
// The median is zero, so coincides with the default:
616-
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
617-
BOOST_TEST_EQ(m, 1);
618-
619-
m = boost::math::statistics::median_absolute_deviation(v);
615+
m = boost::math::statistics::median_absolute_deviation(v, 0);
620616
BOOST_TEST_EQ(m, 1);
621617

622618

@@ -649,6 +645,65 @@ void test_median_absolute_deviation()
649645
u[5] = -3;
650646
m = boost::math::statistics::median_absolute_deviation(u, 0);
651647
BOOST_TEST_EQ(m, 2);
648+
649+
650+
v = {-1, 2, -3, 4, -5, 6, -7};
651+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
652+
BOOST_TEST_EQ(m, 4);
653+
654+
g = std::mt19937(12);
655+
std::shuffle(v.begin(), v.end(), g);
656+
m = boost::math::statistics::median_absolute_deviation(v);
657+
BOOST_TEST_EQ(m, 4);
658+
659+
v = {1, -2, -3, 3, -4, -5};
660+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
661+
BOOST_TEST_EQ(m, 2);
662+
std::shuffle(v.begin(), v.end(), g);
663+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
664+
BOOST_TEST_EQ(m, 2);
665+
666+
v = {-1};
667+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
668+
BOOST_TEST_EQ(m, 0);
669+
670+
v = {-1, 1};
671+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
672+
BOOST_TEST_EQ(m, 1);
673+
674+
m = boost::math::statistics::median_absolute_deviation(v);
675+
BOOST_TEST_EQ(m, 1);
676+
677+
678+
v = {2, -4};
679+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
680+
BOOST_TEST_EQ(m, 3);
681+
682+
v = {1, -1, 1};
683+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
684+
BOOST_TEST_EQ(m, 0);
685+
686+
v = {1, 2, -3};
687+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
688+
BOOST_TEST_EQ(m, 1);
689+
std::shuffle(v.begin(), v.end(), g);
690+
m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
691+
BOOST_TEST_EQ(m, 1);
692+
693+
w = {1, 2, -3};
694+
m = boost::math::statistics::median_absolute_deviation(w);
695+
BOOST_TEST_EQ(m, 1);
696+
697+
// boost.ublas vector?
698+
boost::numeric::ublas::vector<Real> u2(6);
699+
u2[0] = 1;
700+
u2[1] = 2;
701+
u2[2] = -3;
702+
u2[3] = 1;
703+
u2[4] = 2;
704+
u2[5] = -3;
705+
m = boost::math::statistics::median_absolute_deviation(u2);
706+
BOOST_TEST_EQ(m, 1);
652707
}
653708

654709

test/univariate_statistics_test.cpp

+60-5
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,7 @@ void test_median_absolute_deviation(ExecutionPolicy&& exec)
577577
v = {-1, 1};
578578
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end(), 0);
579579
BOOST_TEST_EQ(m, 1);
580-
// The median is zero, so coincides with the default:
581-
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
582-
BOOST_TEST_EQ(m, 1);
583-
584-
m = boost::math::statistics::median_absolute_deviation(exec, v);
580+
m = boost::math::statistics::median_absolute_deviation(exec, v, 0);
585581
BOOST_TEST_EQ(m, 1);
586582

587583

@@ -614,6 +610,65 @@ void test_median_absolute_deviation(ExecutionPolicy&& exec)
614610
u[5] = -3;
615611
m = boost::math::statistics::median_absolute_deviation(exec, u, 0);
616612
BOOST_TEST_EQ(m, 2);
613+
614+
615+
v = {-1, 2, -3, 4, -5, 6, -7};
616+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
617+
BOOST_TEST_EQ(m, 4);
618+
619+
g = std::mt19937(12);
620+
std::shuffle(v.begin(), v.end(), g);
621+
m = boost::math::statistics::median_absolute_deviation(exec, v);
622+
BOOST_TEST_EQ(m, 4);
623+
624+
v = {1, -2, -3, 3, -4, -5};
625+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
626+
BOOST_TEST_EQ(m, 2);
627+
std::shuffle(v.begin(), v.end(), g);
628+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
629+
BOOST_TEST_EQ(m, 2);
630+
631+
v = {-1};
632+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
633+
BOOST_TEST_EQ(m, 0);
634+
635+
v = {-1, 1};
636+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
637+
BOOST_TEST_EQ(m, 1);
638+
639+
m = boost::math::statistics::median_absolute_deviation(exec, v);
640+
BOOST_TEST_EQ(m, 1);
641+
642+
643+
v = {2, -4};
644+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
645+
BOOST_TEST_EQ(m, 3);
646+
647+
v = {1, -1, 1};
648+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
649+
BOOST_TEST_EQ(m, 0);
650+
651+
v = {1, 2, -3};
652+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
653+
BOOST_TEST_EQ(m, 1);
654+
std::shuffle(v.begin(), v.end(), g);
655+
m = boost::math::statistics::median_absolute_deviation(exec, v.begin(), v.end());
656+
BOOST_TEST_EQ(m, 1);
657+
658+
w = {1, 2, -3};
659+
m = boost::math::statistics::median_absolute_deviation(exec, w);
660+
BOOST_TEST_EQ(m, 1);
661+
662+
// boost.ublas vector?
663+
boost::numeric::ublas::vector<Real> u2(6);
664+
u2[0] = 1;
665+
u2[1] = 2;
666+
u2[2] = -3;
667+
u2[3] = 1;
668+
u2[4] = 2;
669+
u2[5] = -3;
670+
m = boost::math::statistics::median_absolute_deviation(exec, u2);
671+
BOOST_TEST_EQ(m, 1);
617672
}
618673

619674

0 commit comments

Comments
 (0)