средний выход Boost :: аккумуляторы :: статистика сбивает с толку - PullRequest
2 голосов
/ 17 марта 2019

Когда для вычисления медианы массива я использовал boost :: аккумуляторы :: статистику, я получил следующий код и результат:

    accumulator_set< double, features< tag::mean, tag::median > > acc;
    acc(2);
    acc(1); 
    acc(3);
    value = mean( acc );   //output is 2, expected
    value = median( acc ); //output is 3, unexpected

Я думаю, что результат для value = median( acc ) должен быть 2.

1 Ответ

0 голосов
/ 17 марта 2019

accumulator_set на самом деле не хранит все значения.Каждый вызов acc(double) фактически вызывает что-то вроде acc.mean_accumulator(double); acc.median_accumulator(double), и он пытается не сохранить все значения.

Для median, P ^2 квантиль оценки.( См. Здесь ) Это только оценка, и если вы сделаете:

acc(4);
acc(1);
acc(2);
acc(0);
acc(3);

, то она вернет ожидаемое 2.

Если вам нужно точное значениеи иметь небольшое количество значений данных, используйте такую ​​функцию:

#include <algorithm>
#include <vector>

// Warning: Will swap elements in the range.
// `It` needs to be a non-const random access iterator
// (Like `T*`)
template<class It>
auto median(It first, It last) {
    auto size = last - first;
    if (size % 2 == 1U) {
        std::nth_element(first, first + (size / 2U), last);
        return *(first + (size / 2U));
    }
    std::nth_element(first, first + (size / 2U), last);
    auto&& high = first + (size / 2U);
    auto&& low = std::max(first, first + (size / 2U - 1U));
    return (*low + *high) / 2;
}

// Copies the range and modifies the copy instead
template<class It>
auto const_median(It first, It last) {
    std::vector<decltype(*first)> v(first, last);
    return median(v.begin(), v.end());
}

int main() {
    std::vector<double> v{2, 1, 3};
    std::cout << median(v.begin(), v.end()) << '\n';
}
...