mirror of
https://github.com/boostorg/math.git
synced 2026-01-19 04:22:09 +00:00
Rename 'absolute_median' to 'median_absolute_deviation' [CI SKIP]
This commit is contained in:
@@ -13,13 +13,7 @@
|
||||
``
|
||||
#include <boost/math/tools/signal_statistics.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace tools {
|
||||
|
||||
template<class Container>
|
||||
auto absolute_median(Container & c);
|
||||
|
||||
template<class ForwardIterator>
|
||||
auto absolute_median(ForwardIterator first, ForwardIterator last);
|
||||
namespace boost::math::tools {
|
||||
|
||||
template<class Container>
|
||||
auto absolute_gini_coefficient(Container & c);
|
||||
@@ -57,7 +51,7 @@ namespace boost{ namespace math{ namespace tools {
|
||||
template<class Container>
|
||||
auto m2m4_snr_estimator_db(Container const & noisy_signal,typename Container::value_type estimated_signal_kurtosis=1, typename Container::value_type estimate_noise_kurtosis=3);
|
||||
|
||||
}}}
|
||||
}
|
||||
``
|
||||
|
||||
[heading Description]
|
||||
@@ -69,18 +63,6 @@ In general, you can store your data in an Eigen array, and Armadillo vector, `st
|
||||
These routines are usable in float, double, long double, and Boost.Multiprecision precision, as well as their complex extensions whenever the computation is well-defined.
|
||||
For certain operations (total variation, for example) integer inputs are supported.
|
||||
|
||||
[heading Absolute Median]
|
||||
|
||||
The absolute median is used in signal processing, where the median of the magnitude of the coefficients in some expansion are used to estimate noise variance.
|
||||
See [@https://wavelet-tour.github.io/ Mallat] for details.
|
||||
The absolute median supports both real and complex arithmetic, modifies its input, and requires random access containers.
|
||||
|
||||
std::vector<double> v{-1, 1};
|
||||
double m = boost::math::tools::absolute_median(v);
|
||||
// m = 1
|
||||
// Alternative syntax, using a subset of the container:
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.begin() + 1);
|
||||
|
||||
[heading Absolute Gini Coefficient]
|
||||
|
||||
The Gini coefficient, first used to measure wealth inequality, is also one of the best measures of the sparsity of an expansion in a basis.
|
||||
|
||||
@@ -63,6 +63,12 @@ namespace boost{ namespace math{ namespace tools {
|
||||
template<class ForwardIterator>
|
||||
auto median(ForwardIterator first, ForwardIterator last);
|
||||
|
||||
template<class RandomAccessIterator>
|
||||
auto median_absolute_deviation(ForwardIterator first, ForwardIterator last, typename std::iterator_traits<RandomAccessIterator>::value_type center=std::numeric_limits<Real>::quiet_NaN());
|
||||
|
||||
template<class RandomAccessContainer>
|
||||
auto median_absolute_deviation(RandomAccessContainer v, typename RandomAccessContainer::value_type center=std::numeric_limits<Real>::quiet_NaN());
|
||||
|
||||
template<class Container>
|
||||
auto gini_coefficient(Container & c);
|
||||
|
||||
@@ -169,7 +175,7 @@ Simultaneously computes the first four [@https://en.wikipedia.org/wiki/Central_m
|
||||
|
||||
[heading Median]
|
||||
|
||||
Compute the median of a dataset:
|
||||
Computes the median of a dataset:
|
||||
|
||||
std::vector<double> v{1,2,3,4,5};
|
||||
double m = boost::math::tools::median(v.begin(), v.end());
|
||||
@@ -179,6 +185,27 @@ The calculation of the median is a thin wrapper around the C++11 [@https://en.cp
|
||||
Therefore, all requirements of `std::nth_element` are inherited by the median calculation.
|
||||
In particular, the container must allow random access.
|
||||
|
||||
[heading Median Absolute Deviation]
|
||||
|
||||
Computes the [@https://en.wikipedia.org/wiki/Median_absolute_deviation median absolute deviation] of a dataset:
|
||||
|
||||
std::vector<double> v{1,2,3,4,5};
|
||||
double mad = boost::math::tools::median_absolute_deviation(v);
|
||||
|
||||
By default, the deviation from the median is used.
|
||||
If you have some prior that the median is zero, or wish to compute the median absolute deviation from the mean,
|
||||
use the following:
|
||||
|
||||
// prior is that center is zero:
|
||||
double center = 0;
|
||||
double mad = boost::math::tools::median_absolute_deviation(v, center);
|
||||
|
||||
// compute median absolute deviation from the mean:
|
||||
double mu = boost::math::tools::mean(v);
|
||||
double mad = boost::math::tools::median_absolute_deviation(v, mu);
|
||||
|
||||
/Nota bene:/ The input vector is modified.
|
||||
Again the vector is passed into a call to [@https://en.cppreference.com/w/cpp/algorithm/nth_element `nth_element`].
|
||||
|
||||
[heading Gini Coefficient]
|
||||
|
||||
|
||||
@@ -15,36 +15,7 @@
|
||||
#include <boost/math/tools/univariate_statistics.hpp>
|
||||
|
||||
|
||||
namespace boost{ namespace math{ namespace tools {
|
||||
|
||||
template<class RandomAccessIterator>
|
||||
auto absolute_median(RandomAccessIterator first, RandomAccessIterator last)
|
||||
{
|
||||
using std::abs;
|
||||
using RealOrComplex = typename std::iterator_traits<RandomAccessIterator>::value_type;
|
||||
size_t num_elems = std::distance(first, last);
|
||||
BOOST_ASSERT_MSG(num_elems > 0, "The median of a zero-length vector is undefined.");
|
||||
auto comparator = [](RealOrComplex a, RealOrComplex b) { return abs(a) < abs(b);};
|
||||
if (num_elems & 1)
|
||||
{
|
||||
auto middle = first + (num_elems - 1)/2;
|
||||
std::nth_element(first, middle, last, comparator);
|
||||
return abs(*middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto middle = first + num_elems/2 - 1;
|
||||
std::nth_element(first, middle, last, comparator);
|
||||
std::nth_element(middle, middle+1, last, comparator);
|
||||
return (abs(*middle) + abs(*(middle+1)))/abs(static_cast<RealOrComplex>(2));
|
||||
}
|
||||
}
|
||||
|
||||
template<class RandomAccessContainer>
|
||||
inline auto absolute_median(RandomAccessContainer & v)
|
||||
{
|
||||
return absolute_median(v.begin(), v.end());
|
||||
}
|
||||
namespace boost::math::tools {
|
||||
|
||||
template<class ForwardIterator>
|
||||
auto absolute_gini_coefficient(ForwardIterator first, ForwardIterator last)
|
||||
@@ -352,5 +323,5 @@ inline auto m2m4_snr_estimator_db(Container const & noisy_signal, typename Cont
|
||||
return 10*log10(m2m4_snr_estimator(noisy_signal, estimated_signal_kurtosis, estimated_noise_kurtosis));
|
||||
}
|
||||
|
||||
}}}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <boost/multiprecision/detail/number_base.hpp>
|
||||
|
||||
|
||||
namespace boost{ namespace math{ namespace tools {
|
||||
namespace boost::math::tools {
|
||||
|
||||
template<class ForwardIterator>
|
||||
auto mean(ForwardIterator first, ForwardIterator last)
|
||||
@@ -382,7 +382,40 @@ inline auto sample_gini_coefficient(RandomAccessContainer & v)
|
||||
return sample_gini_coefficient(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template<class RandomAccessIterator>
|
||||
auto median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator last, typename std::iterator_traits<RandomAccessIterator>::value_type center=std::numeric_limits<typename std::iterator_traits<RandomAccessIterator>::value_type>::quiet_NaN())
|
||||
{
|
||||
using std::abs;
|
||||
using Real = typename std::iterator_traits<RandomAccessIterator>::value_type;
|
||||
using std::isnan;
|
||||
if (isnan(center))
|
||||
{
|
||||
center = boost::math::tools::median(first, last);
|
||||
}
|
||||
size_t num_elems = std::distance(first, last);
|
||||
BOOST_ASSERT_MSG(num_elems > 0, "The median of a zero-length vector is undefined.");
|
||||
auto comparator = [¢er](Real a, Real b) { return abs(a-center) < abs(b-center);};
|
||||
if (num_elems & 1)
|
||||
{
|
||||
auto middle = first + (num_elems - 1)/2;
|
||||
std::nth_element(first, middle, last, comparator);
|
||||
return abs(*middle);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto middle = first + num_elems/2 - 1;
|
||||
std::nth_element(first, middle, last, comparator);
|
||||
std::nth_element(middle, middle+1, last, comparator);
|
||||
return (abs(*middle) + abs(*(middle+1)))/abs(static_cast<Real>(2));
|
||||
}
|
||||
}
|
||||
|
||||
template<class RandomAccessContainer>
|
||||
inline auto median_absolute_deviation(RandomAccessContainer & v, typename RandomAccessContainer::value_type center=std::numeric_limits<typename RandomAccessContainer::value_type>::quiet_NaN())
|
||||
{
|
||||
return median_absolute_deviation(v.begin(), v.end(), center);
|
||||
}
|
||||
|
||||
|
||||
}}}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -33,99 +33,6 @@ using boost::math::constants::two_pi;
|
||||
* 6) Does it work with integer data if sensible?
|
||||
*/
|
||||
|
||||
template<class Real>
|
||||
void test_absolute_median()
|
||||
{
|
||||
std::vector<Real> v{-1, 2, -3, 4, -5, 6, -7};
|
||||
|
||||
Real m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 4);
|
||||
|
||||
std::mt19937 g(12);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::absolute_median(v);
|
||||
BOOST_TEST_EQ(m, 4);
|
||||
|
||||
v = {1, -2, -3, 3, -4, -5};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
|
||||
v = {-1};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
v = {-1, 1};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
v = {2, -4};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
|
||||
v = {1, -1, 1};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
v = {1, 2, -3};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
|
||||
std::array<Real, 3> w{1, 2, -3};
|
||||
m = boost::math::tools::absolute_median(w);
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
|
||||
// boost.ublas vector?
|
||||
boost::numeric::ublas::vector<Real> u(6);
|
||||
u[0] = 1;
|
||||
u[1] = 2;
|
||||
u[2] = -3;
|
||||
u[3] = 1;
|
||||
u[4] = 2;
|
||||
u[5] = -3;
|
||||
m = boost::math::tools::absolute_median(u);
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
}
|
||||
|
||||
|
||||
template<class Complex>
|
||||
void test_complex_absolute_median()
|
||||
{
|
||||
typedef typename Complex::value_type Real;
|
||||
std::mt19937 g(18);
|
||||
std::vector<Complex> v{{0,1}, {0,-2},{0,3}, {0,-4}, {0,5}, {0,-6}, {0,7}};
|
||||
|
||||
Real m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 4);
|
||||
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::absolute_median(v);
|
||||
BOOST_TEST_EQ(m, 4);
|
||||
|
||||
v = {{0,1}, {0,-2}, {0,-3}, {0,3}, {0,4}, {0,-5}};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
|
||||
v = {{0, -1}};
|
||||
m = boost::math::tools::absolute_median(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
boost::numeric::ublas::vector<Complex> w(1);
|
||||
w[0] = {0, -1};
|
||||
m = boost::math::tools::absolute_median(w);
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<class Real>
|
||||
void test_hoyer_sparsity()
|
||||
{
|
||||
@@ -386,16 +293,6 @@ void test_m2m4_snr_estimator()
|
||||
|
||||
int main()
|
||||
{
|
||||
test_absolute_median<float>();
|
||||
test_absolute_median<double>();
|
||||
test_absolute_median<long double>();
|
||||
test_absolute_median<cpp_bin_float_50>();
|
||||
|
||||
test_complex_absolute_median<std::complex<float>>();
|
||||
test_complex_absolute_median<std::complex<double>>();
|
||||
test_complex_absolute_median<std::complex<long double>>();
|
||||
test_complex_absolute_median<cpp_complex_50>();
|
||||
|
||||
test_absolute_gini_coefficient<float>();
|
||||
test_absolute_gini_coefficient<double>();
|
||||
test_absolute_gini_coefficient<long double>();
|
||||
|
||||
@@ -347,6 +347,73 @@ void test_median()
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
}
|
||||
|
||||
template<class Real>
|
||||
void test_median_absolute_deviation()
|
||||
{
|
||||
std::vector<Real> v{-1, 2, -3, 4, -5, 6, -7};
|
||||
|
||||
Real m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 4);
|
||||
|
||||
std::mt19937 g(12);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::median_absolute_deviation(v, 0);
|
||||
BOOST_TEST_EQ(m, 4);
|
||||
|
||||
v = {1, -2, -3, 3, -4, -5};
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
|
||||
v = {-1};
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
v = {-1, 1};
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
// The median is zero, so coincides with the default:
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
m = boost::math::tools::median_absolute_deviation(v);
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
|
||||
v = {2, -4};
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 3);
|
||||
|
||||
v = {1, -1, 1};
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 1);
|
||||
|
||||
v = {1, 2, -3};
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
m = boost::math::tools::median_absolute_deviation(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
|
||||
std::array<Real, 3> w{1, 2, -3};
|
||||
m = boost::math::tools::median_absolute_deviation(w, 0);
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
|
||||
// boost.ublas vector?
|
||||
boost::numeric::ublas::vector<Real> u(6);
|
||||
u[0] = 1;
|
||||
u[1] = 2;
|
||||
u[2] = -3;
|
||||
u[3] = 1;
|
||||
u[4] = 2;
|
||||
u[5] = -3;
|
||||
m = boost::math::tools::median_absolute_deviation(u, 0);
|
||||
BOOST_TEST_EQ(m, 2);
|
||||
}
|
||||
|
||||
|
||||
template<class Real>
|
||||
void test_sample_gini_coefficient()
|
||||
{
|
||||
@@ -471,6 +538,11 @@ int main()
|
||||
test_median<long double>();
|
||||
test_median<cpp_bin_float_50>();
|
||||
|
||||
test_median_absolute_deviation<float>();
|
||||
test_median_absolute_deviation<double>();
|
||||
test_median_absolute_deviation<long double>();
|
||||
test_median_absolute_deviation<cpp_bin_float_50>();
|
||||
|
||||
test_gini_coefficient<float>();
|
||||
test_gini_coefficient<double>();
|
||||
test_gini_coefficient<long double>();
|
||||
|
||||
Reference in New Issue
Block a user