Pergunta

Eu realmente não tenho usado determinação de desvio que muito, e eu não sei bem o que esperar. Na verdade eu não sou muito bom com a matemática em tudo.

I têm uma uma matriz de 1000000 de valores numéricos aleatórios no intervalo de 0-10000.

A matriz pode crescer ainda mais, então eu uso 64 bits int por soma.

Eu tentei encontrar o código sobre como variância calc, mas eu não sei se eu ficar saída correta.

A média é de 4692 e mediana é 4533. Eu recebo variância 1.483.780,469308 usando o seguinte 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)) );

Am I a obtenção de um valor razoável?

Tem alguma coisa errada com o cálculo?

Foi útil?

Solução

Nota:. Não olha como você está calculando a variância

desvio é calculado subtraindo-se a média de cada elemento e o cálculo da soma ponderada destas diferenças.

Então, o que você precisa fazer é:

// 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;

Note que esta é a variância da amostra, e é usado quando a distribuição subjacente é desconhecido (então assumimos uma distribuição uniforme).

Além disso, após algumas escavações ao redor, eu achei que este não é um estimador imparcial. Wolfram Alpha tem algo a dizer sobre isso, mas como um exemplo, quando MATLAB calcula a variância, ele retorna o 'variância da amostra corrigida-polarização' .

A variância corrigido de polarização pode ser obtido dividindo por cada elemento por size-1, ou:

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

Observe também que, o valor de mean continua o mesmo.

Outras dicas

Em primeiro lugar, se você está olhando apenas para obter uma alça sobre o que é uma variação "razoável", tenha em mente que a variância é o desvio basicamente padrão quadrado. desvio padrão aproximadamente mede a distância típica de um ponto de dados para o seu valor esperado.

Então, se seus dados tem média 4692, e sua variância calculada está saindo para 1.483.780, significa que o desvio padrão é de cerca de 1218, o que sugeriria seus números tendem a ser em algum lugar perto do intervalo 3474 - 5910. Então, que a variância na verdade parece um pouco baixo para mim se a gama de seus números é 0-10000; mas, obviamente, depende da distribuição dos seus dados.

Como para o próprio cálculo: Você pode calcular a variância usando um cálculo em execução como você está lendo os dados da primeira vez (você não tem que saber a média de antecedência) usando Método de Welford:

Inicializar M1 = x1 e S1 = 0.

Para posterior x de, use a recorrência fórmulas

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

Para 2 = k = n, a estimativa do k-ésimo variância é s2 = Sk / (k - 1).

Apenas por diversão, uma rota um pouco diferente para o mesmo resultado, usando std :: valarray em vez de std :: vector e (vários) 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 Jacob deu a entender, há realmente duas possíveis versões de uma determinação de desvio. Tal como está, este assume suas entradas são o "universo". Se você tiver tomado apenas uma amostra do universo geral, a última linha deve usar:. (diffs.size()-1) vez de diffs.size()

Use uma fórmula diferente, talvez?

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

Saídas: média = 5036,71 variância = 3.16806e + 07

A determinação de desvio da amostra:

#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);
}

Uma vez que você está trabalhando com grandes números e, em seguida, fazendo operações de ponto flutuante sobre eles, você pode querer fazer tudo em dobro; que lhe poupar uma grande quantidade de moldes.

Usando pow .. 2 para calcular um quadrado parece um pouco estranho. Você pode calcular o seu primeiro número, em seguida, multiplicá-lo por si mesmo para obter um quadrado.

Se você está fazendo a divisão e sentir a necessidade de fundido, o operandos (ou seja, o numerador e / ou denominador) para dobrar e não o resultado. Você está perdendo a precisão se você dividir inteiros.

Eu não tenho certeza se a sua fórmula de variância é correta. Você pode querer olhar para a explicação na Wikipedia, por exemplo. Mas eu não sou nenhum perito matemática ou, então, não tenho certeza que você tem um erro.

Uma vez que a variância é o quadrado do desvio padrão, as respostas para SO 1.174.984 deve ajudar. O curto diagnóstico é que você precisa para calcular a soma dos quadrados dos valores, bem como a soma dos valores, e você não parecem estar fazendo isso.

Uma vez que você tem 10 6 valores, eo quadrado de qualquer valor pode ser de até 10 8 , você pode acabar com uma soma dos quadrados até 10 < sup> 14 ; seus inteiros de 64 bits pode armazenar até 10 18 , então você ainda pode lidar com dez mil vezes mais entradas, ou valores que vão até um milhão em vez de apenas dez mil, sem entrar em excessos. Não há necessidade urgente, portanto, para se deslocar para computações duplas puros.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top