Пример дельты между значениями, используя boost :: аккумуляторы - PullRequest
5 голосов
/ 31 марта 2010

У меня есть набор данных с 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, не отслеживая последнее значение вручную?

Ответы [ 2 ]

3 голосов
/ 31 марта 2010

Аккумуляторы наддува не имеют разностной статистики. Вы можете свернуть свой собственный, хотя:

http://www.boost.org/doc/libs/1_37_0/doc/html/accumulators/user_s_guide.html#accumulators.user_s_guide.the_accumulators_framework.extending_the_accumulators_framework

На мой взгляд, лучшее решение - просто отслеживать последнюю добавленную стоимость.

1 голос
/ 31 марта 2010

Этот ответ может быть немного более сложным, чем вы хотели бы, но, по крайней мере, он не настолько возмутителен, как я боялся, что он может оказаться. Идея состояла бы в том, чтобы начать с создания типа итератора, который действует как адаптер от «обычных» алгоритмов к алгоритму в стиле аккумулятора 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

Затем приходит часть, которая несколько неудачна. Стандартная библиотека имеет алгоритм adjacent_difference, который должен генерировать нужный вам поток (различия между смежными элементами в коллекции). Однако у него есть одна серьезная проблема: кто-то подумал, что было бы полезно для него создать коллекцию результатов того же размера, что и входная коллекция (хотя очевидно, что входных данных больше, чем результата). Для этого adjacent_difference оставляет первый элемент в результате с каким-то неопределенным значением, поэтому вы должны игнорировать первое значение, чтобы получить что-нибудь полезное из него.

Чтобы восполнить это, я повторно реализовал алгоритм наподобие std::adjacent_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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...