boost — C ++ аккумуляторная библиотека с возможностью удаления старых образцов

В Boost.Accumulator вы можете добавить выборки в аккумулятор и затем извлечь из него статистические величины. например:

acc(1.)
acc(2.)
acc(3.)
cout << mean; // 2

В библиотеке есть много более сложных статистических величин, таких как skewness, kurtosis, или же p_square_cumulative_distribution,

Я хотел бы сделать что-то вроде этого:

acc(1.)
acc(2.)
acc(3.)
std::cout << mean(acc); // 2
acc.pop() // withdraw the first value (1.)
std::cout << mean(acc); // 2.5

pop() будет работать в режиме FIFO (First In First Out). То, что я пытаюсь сделать, — это вычислять статистику по моим данным в режиме онлайн (инкрементно) в скользящем временном окне.

Аккумулятор должен был бы внутренне хранить все значения.

Я мог бы сделать это самостоятельно, но я всегда хотел бы сначала проверить наличие существующих библиотек, и, возможно, существует алгоритм, которого я не знаю, который умно вычисляет количества, когда данные поступают или исходят.

4

Решение

Поскольку вы упомянули «скользящее временное окно», одним из вариантов является использование скользящего среднего (есть также скользящая сумма и скользящий счет), которое является средним значением последнего N образцы. В зависимости от ваших потребностей вы можете создать отдельные аккумуляторы с разными размерами окон.

typedef accumulator_set<double,
stats<tag::rolling_mean>
> my_accumulator;

my_accumulator acc(tag::rolling_window::window_size = 3);
acc(1.);
acc(2.);
acc(3.);
std::cout << rolling_mean(acc);
// Reset accumulator and use different window size
acc = my_accumulator(tag::rolling_window::window_size = 2);
acc(2.);
acc(3.);
std::cout << rolling_mean(acc);

Кроме того, если вы посмотрите на реализацию этих, они используют boost/circular_buffer.hpp,

9

Другие решения

Вам, вероятно, нужно будет просто сохранить все свои выборки в векторе, а затем накапливать их из вектора для каждого расчета. Что-то вроде этого: https://stackoverflow.com/a/7616783/219136

1

Вы, вероятно, хотите сохранить данные в std::deque вместо вектора, поэтому ваша вставка и удаление могут иметь постоянную сложность. Если вы используете вектор, он неизбежно будет линейным.

Кроме этого, довольно просто применить алгоритм к коллекции. Странно, однако, что я не знаю коллекцию таких алгоритмов, уже написанных и протестированных, несмотря на то, что набор доступных алгоритмов кажется довольно очевидным.

Для чего бы это ни стоило, довольно просто создать адаптер для подачи данных из коллекции в накопитель для вычисления статистики, которую вы можете получить. В некоторых случаях аккумулятору, вероятно, придется проделать дополнительную работу, чтобы постепенно вычислять результаты, но я думаю, что довольно редко можно потерять достаточную эффективность, чтобы о ней заботиться.

1