2010-03-30 18 views
5

Tengo un conjunto de datos con N muestras (digamos, 13, 16, 17, 20) donde cada muestra siguiente se incrementa en algún valor (3, 1, 3 en este caso) y quiero encontrar varias estadísticas de la segunda secuencia .Muestra los deltas entre los valores usando boost :: accumulators

Las muestras son marcas de tiempo que se recopilan de forma incremental (es decir, no todas las muestras están disponibles a la vez), por lo tanto, quiero usar boost::accumulators::accumulator_set, ya que parece que encajaría en la factura.

Quiero ser capaz de hacer algo como esto:

accumulator_set< double, features<tag::mean> > acc; 
... 
acc(13); 
acc(16); 
acc(17); 
acc(20); 

... PERO el muestreo de las diferencias en lugar de los valores reales.

¿Cómo puedo hacer eso con accumulator_set sin hacer un seguimiento del último valor manualmente?

+0

¿Algo así o exactamente eso? La media de las diferencias es solo la diferencia entre la primera y la última muestra, dividida por (el número de muestras -1) ;-p –

+0

@Steve Jessop, también me gustaría calcular la desviación estándar. Por lo tanto, utilizando el marco de acumuladores. –

Respuesta

1

Esta respuesta puede ser un poco más complicada de lo que a usted le gustaría, pero al menos no es tan escandalosa como me temo que podría resultar. La idea sería comenzar creando un tipo de iterador que actúe como un adaptador de algoritmos "normales" al algoritmo de algoritmo Boost. Esta es la parte que resultó un poco más simple de lo que realmente esperaba:

#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 

Luego viene una parte que es algo desafortunado. La biblioteca estándar tiene un algoritmo adjacent_difference que se supone que produce la transmisión que desea (las diferencias entre elementos adyacentes en una colección). Sin embargo, tiene un problema serio: alguien pensó que sería útil para producir una colección de resultados que era del mismo tamaño que la colección de entrada (aunque obviamente hay una entrada más que el resultado). Para hacer eso, adjacent_difference deja el primer elemento en el resultado con algún valor no especificado, por lo que debe ignorar el primer valor para obtener algo útil de él.

para compensar eso, reimplementado un algoritmo comostd::adjacent_difference con una diferencia oh-tan-de menor importancia: ya es evidente que hay un resultado menos de entradas, sólo produce uno menos resultado que en los insumos, y no da un valor sin especificar, sin especificar en el resultado. Combinando los dos, obtenemos:

#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; 
} 
+0

Creo que debería haber dado más información en mi pregunta. Mi problema real es que continuamente estoy recolectando muestras de marcas de tiempo en un sistema sensible a la latencia y quiero medir la inestabilidad, así que idealmente necesito actualizar mis estadísticas de forma incremental. Por lo tanto, tener una colección de muestras no es deseable en este caso. –

+0

@Checkers: 'diffs' simplemente toma la entrada de un' input_iterator' y escribe los resultados en un 'output_iterator'.Para la demostración/prueba, el 'input_iterator' se conecta a una colección, pero podría fácilmente leer datos de un archivo en el disco o desde una conexión de red. –

Cuestiones relacionadas