У меня есть набор данных с образцами N (скажите, 13, 16, 17, 20), где каждый следующий образец увеличен некоторым значением (3, 1, 3 в этом случае), и я хочу найти различную статистику второй последовательности.
Образцы являются метками времени, которые собраны инкрементно (т.е. не все образцы доступны сразу), следовательно я хочу использовать boost::accumulators::accumulator_set
как похож, это - что-то, что отвечало бы всем требованиям.
Я хочу смочь сделать что-то вроде этого:
accumulator_set< double, features< tag::mean > > acc;
...
acc(13);
acc(16);
acc(17);
acc(20);
... НО выбирая различия вместо фактических значений.
Как я могу сделать это с accumulator_set
не отслеживая последнее значение вручную?
Этот ответ может быть немного сложнее, чем вам хотелось бы, но, по крайней мере, он не так возмутителен, как я боялся. Идея состоит в том, чтобы начать с создания типа итератора, который действует как переходник от «обычных» алгоритмов к алгоритмам стиля аккумуляторов Boost. Эта часть оказалась немного проще, чем я ожидал:
#ifndef ACCUM_ITERATOR_H_INCLUDED
#define ACCUM_ITERATOR_H_INCLUDED
#include <iterator>
template <class Accumulator>
class accum_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void> {
protected:
Accumulator &accumulator;
public:
typedef Accumulator accumulator_type;
explicit accum_iterator(Accumulator& x) : accumulator(x) {}
// The only part that really does anything: handle assignment by
// calling the accumulator with the value.
accum_iterator<Accumulator>&
operator=(typename Accumulator::sample_type value) {
accumulator(value);
return *this;
}
accum_iterator<Accumulator>& operator*() { return *this; }
accum_iterator<Accumulator>& operator++() { return *this; }
accum_iterator<Accumulator> operator++(int) { return *this; }
};
// A convenience function to create an accum_iterator for a given accumulator.
template <class Accumulator>
accum_iterator<Accumulator> to_accum(Accumulator &accum) {
return accum_iterator<Accumulator>(accum);
}
#endif
Затем следует часть, которая несколько неудачна. Стандартная библиотека имеет алгоритм соседнее_различие
, который должен создавать нужный вам поток (различия между соседними элементами в коллекции). Однако у него есть одна серьезная проблема: кто-то подумал, что было бы полезно создать коллекцию результатов того же размера, что и коллекция входных данных (хотя очевидно, что входных данных на один больше, чем результата). Для этого соседнее_различие
оставляет первый элемент результата с некоторым неопределенным значением, поэтому вы должны проигнорировать первое значение, чтобы получить из него что-нибудь полезное.
Чтобы компенсировать это, я повторно реализовал алгоритм наподобие std :: neighbour_difference
с одной очень незначительной разницей: поскольку очевидно, что результатов на один меньше, чем входных данных, это только дает на один результат меньше, чем входные данные, и не дает бессмысленного, неопределенного значения в результате. Комбинируя эти два, мы получаем:
#include "accum_iterator.h"
#include <iostream>
#include <vector>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/mean.hpp>
using namespace boost::accumulators;
// A re-implementation of std::adjacent_difference, but with sensible outputs.
template <class InIt, class OutIt>
void diffs(InIt in1, InIt in2, OutIt out) {
typename InIt::value_type prev = *in1;
++in1;
while (in1 != in2) {
typename InIt::value_type temp = *in1;
*out++ = temp - prev;
prev = temp;
++in1;
}
}
int main() {
// Create the accumulator.
accumulator_set<double, features< tag::mean > > acc;
// Set up the test values.
std::vector<double> values;
values.push_back(13);
values.push_back(16);
values.push_back(17);
values.push_back(20);
// Use diffs to compute the differences, and feed the results to the
// accumulator via the accum_iterator:
diffs(values.begin(), values.end(), to_accum(acc));
// And print the result from the accumulator:
std::cout << "Mean: " << mean(acc) << std::endl;
return 0;
}
Накопители ускорения не имеют статистики разницы. Однако вы можете создать свою собственную:
Лучшим решением, на мой взгляд, будет просто отслеживать последнее добавленное значение.