Pregunta

la determinación de desviaciones

No he utilizado realmente mucho, y no sé muy bien qué esperar. En realidad no soy demasiado bueno con las matemáticas en absoluto.

Tengo un una matriz de 1000000 valores numéricos aleatorios en el rango 0-10000.

La matriz podría crecer aún más grande, así que usar 64 bits para int suma.

He tratado de encontrar el código en la forma de calc varianza, pero no sé si me da salida correcta.

La media es de 4692 y la mediana es 4533. consigo varianza 1,483,780.469308 usando el siguiente código:

// size is the element count, in this case 1000000
// value_sum is __int64

double p2 = pow( (double)(value_sum - (value_sum/size)), (double)2.0 );
double variance = sqrt( (double)(p2 / (size-1)) );

¿Me estoy poniendo un valor razonable?

¿Hay algo malo en el cálculo?

¿Fue útil?

Solución

Nota:. No se ve como si estuviera calculando la varianza

varianza se calcula restando la media de cada elemento y el cálculo de la suma ponderada de estas diferencias.

Así que lo que hay que hacer es:

// Get mean
double mean = static_cast<double>(value_sum)/size;

// Calculate variance
double variance = 0;
for(int i = 0;i<size;++i) 
{
  variance += (MyArray[i]-mean)*(MyArray[i]-mean)/size;
}

// Display
cout<<variance;

Tenga en cuenta que esta es la varianza de la muestra, y se utiliza cuando la distribución subyacente es desconocida (por lo que suponemos una distribución uniforme).

Además, después de algo de investigación en todo, he encontrado que esto no es un estimador insesgado. Wolfram Alpha tiene algo que decir acerca de esto, pero como ejemplo, cuando MATLAB calcula la varianza, devuelve la 'varianza de la muestra sesgo corregido' .

La varianza sesgo corregido se puede obtener dividiendo por cada elemento por size-1, o:

//Please check that size > 1
variance += (MyArray[i]-mean)*(MyArray[i]-mean)/(size-1); 

Tenga en cuenta también que, el valor de mean sigue siendo el mismo.

Otros consejos

En primer lugar, si usted está buscando para tener una idea de lo que es una variación de "razonable", tenga en cuenta que la varianza es básicamente desviación estándar al cuadrado. La desviación estándar mide aproximadamente la distancia típica de un punto de datos a su valor esperado.

Así que si los datos tienen media de 4692, y su varianza calculada está saliendo a 1.483.780, que significa que su desviación estándar es de 1218, lo que sugeriría sus números tienden a estar en algún lugar en las proximidades de la gama 3474 - 5910. Así varianza que en realidad parece un poco baja para mí si el rango de sus números: 0 - 10000; pero, obviamente, depende de la distribución de los datos.

En cuanto al cálculo mismo: Se puede calcular la varianza utilizando un cálculo funcionando como usted está leyendo los datos de la primera vez (que no tienen que saber de antemano la media) utilizando de Welford Método :

  

Inicializar M1 = x1 y S1 = 0.

     

Para sucesivos de x, utilice la recurrencia   fórmulas

     

Mc = Mk-1 + (xk - Mk-1) / k Sk = Sk-1 +   (Xk - Mk-1) * (xk - Mc).

     

Para 2 ≤ k ≤ n, la estimación de orden k de la   varianza es s2 = Sk / (k - 1).

Sólo por diversión, una ruta ligeramente diferente para el mismo resultado, utilizando std :: valarray en lugar de std :: vector y (varios) algoritmos:

template <class T>
T const variance(std::valarray<T> const &v) {
    if (v.size() == 0)
        return T(0.0);
    T average = v.sum() / v.size();
    std::valarray<T> diffs = v-average;
    diffs *= diffs;
    return diffs.sum()/diffs.size();
}

Como dio a entender Jacob, en realidad hay dos versiones posibles de una determinación de desviaciones. En la actualidad, esto supone que las entradas son el "universo". Si ha tomado solamente una muestra del universo en general, la última línea debe utilizar:. (diffs.size()-1) en lugar de diffs.size()

Utilice una fórmula diferente, tal vez?

#include <functional>
#include <algorithm>
#include <iostream>
int main()
{
 using namespace std;

 vector<double> num( 3 );
 num[ 0 ] = 4000.9, num[ 1 ] = 11111.221, num[ 2 ] = -2;


 double mean = std::accumulate(num.begin(), num.end(), 0.0) / num.size();
 vector<double> diff(num.size());
 std::transform(num.begin(), num.end(), diff.begin(), 
                std::bind2nd(std::minus<double>(), mean));
 double variance = std::inner_product(diff.begin(), diff.end(), 
                                     diff.begin(), 0.0) / (num.size() - 1);
 cout << "mean = " << mean << endl
      << "variance = " << variance << endl;
}

Salidas:     media = 5036,71     varianza = 3.16806e + 07

La determinación de desviaciones de la muestra:

#include <math.h>
#include <vector>

double Variance(std::vector<double>);

int main()
{
     std::vector<double> samples;
     samples.push_back(2.0);
     samples.push_back(3.0);
     samples.push_back(4.0);
     samples.push_back(5.0);
     samples.push_back(6.0);
     samples.push_back(7.0);

     double variance = Variance(samples);
     return 0;
}

double Variance(std::vector<double> samples)
{
     int size = samples.size();

     double variance = 0;
     double t = samples[0];
     for (int i = 1; i < size; i++)
     {
          t += samples[i];
          double diff = ((i + 1) * samples[i]) - t;
          variance += (diff * diff) / ((i + 1.0) *i);
     }

     return variance / (size - 1);
}

Dado que se trabaja con grandes números y luego haciendo operaciones de punto flotante en ellos, es posible que desee hacer todo en dobles; que ahorraría una gran cantidad de moldes.

El uso de pow .. 2 para calcular una plaza parece un poco incómodo. Se podría calcular su número primero, y luego multiplicarlo por sí mismo para obtener una plaza.

Si estás haciendo división y sentir la necesidad de emitir, emitir el operandos (es decir, el numerador y / o el denominador) para doblar y no el resultado. Estás perdiendo exactitud si se divide números enteros.

No estoy seguro de si su fórmula de la varianza es correcta. Es posible que desee ver en la explicación en Wikipedia, por ejemplo. Pero no soy un experto en matemáticas tampoco, así que no estoy seguro de que tiene un error.

Dado que la varianza es el cuadrado de la desviación estándar, las respuestas a SO 1174984 debería ayudar. El diagnóstico corta es que se necesita para calcular la suma de los cuadrados de los valores, así como la suma de los valores, y que no parecen estar haciendo eso.

Dado que usted tiene 10 6 valores, y el cuadrado de cualquier valor puede ser de hasta 10 8 , que podría terminar con una suma de cuadrados hasta 10 < sup> 14 ; sus números enteros de 64 bits pueden almacenar hasta 10 18 , por lo que aún podía manejar diez mil veces más entradas o valores que van hasta un millón en vez de solamente diez mil, sin caer en los desbordamientos. No hay necesidad urgente, por tanto, para mover a los cómputos dobles puros.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top