Calcolare Media e Varianza con la Libreria STL

Gli oggetti funzione di STL sono delle classi template con l’operatore “()“, che può essere anche definito inline. Nella libreria ci sono varie funzioni numeriche come accumulate o inner_product o ancora adiacent_difference, ma ne manca una per fare la media degli elementi di un contenitore, vediamo di colmare questa lacuna.

#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

template <class Iterator, class T>
T average(Iterator first, Iterator last, T t0)
{
   return accumulate(first, last, t0) / distance(first, last);
}

int main(int argc, char** args)
{
   int k;

   vector<int> v(7);
   v[0] = 12;
   v[1] = 6;
   v[2] = 4;
   v[3] = 13;
   v[4] = 15;
   v[5] = 5;
   v[6] = 18;

   // Calcolo la media
   cout << "La media del vettore è: "
      << average(v.begin(), v.end(), 0.0)
      << endl;

   cout << endl;    cin >> k;

   return 0;
}

Nel richiamare la funzione ho inserito un valore double ( 0.0 ) perché voglio che ritorni un valore di questo tipo, se ad esempio inseriamo un intero allora avremo il risultato dello stesso tipo e quindi troncato. La nostra funzione average calcola la media  da due iteratori di input forward, con altri tipi farebbe due passate sulla sequenza di valori perché richiamata una volta per accumulate ed una per distance. Per ovviare a questo problema dobbiamo calcolare la media della lista di valori con questo nuovo metodo:

...
int n = 0;
for (; first != last; n++)
{
   t0 += *first;
   ++first;
}

return t0 / n;
...

Ecco la nuova implementazione della funzione average che questa volta potrà funzionare con ogni contenitore di STL.
Vediamo ora qualcosa di più stimolante, il calcolo dello scarto quadratico medio o varianza che in statistica riveste un ruolo molto importante e si calcola con la formula: V(X) = E(X2) – E(X)2, da questa poi è possibile calcolare la radice quadrata ed avere la deviazione standard.

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

template <class Iterator, class T>
T average2(Iterator first, Iterator last, T t0)
{
   int n = 0;
   for (; first != last; n++)
   {
      T temp = *first;
      t0 += (temp * temp);
      ++first;
   }

   return t0 / n;
}

template <class Iterator, class T>
T average(Iterator first, Iterator last, T t0)
{
   int n = 0;
   for (; first != last; n++)
   {
      t0 += *first;
      ++first;
   }

   return t0 / n;
}

int main(int argc, char** args)
{
   int k;

   vector v(7);
   v[0] = 12;
   v[1] = 6;
   v[2] = 4;
   v[3] = 13;
   v[4] = 15;
   v[5] = 5;
   v[6] = 18;

   double m1 = average(v.begin(), v.end(), 0.0);
   m1 *= m1;
   double m2 = average2(v.begin(), v.end(), 0.0);

   // Calcolo la media
   cout << "La varianza del vettore è: " << m2 - m1 << endl;
   cout << "La deviazione standard del vettore é: "
      << sqrt(m2 - m1) << endl;

   cout << endl;    cin >> k;

   return 0;
}

Come potete notare le funzioni sono migliorabili, ma sono anche un buon punto di partenza per crearsi una libreria di statistica utilizzando funzioni generiche basate su STL.

Pubblicato
Categorie: VC/C++ Taggato

Di Giampaolo Rossi

Sviluppatore software da oltre 16 anni.