2017-09-03 6 views
-1

Je traite souvent certaines données par des programmes où par des données. Pour faire est simple considérons que les données sont une seule série de nombres de même ampleur. Lorsque les chiffres sont déraisonnablement élevés, il peut être utile de normaliser les données. L'une des transformations courantes consiste à soustraire la moyenne de toutes les valeurs. Après cette transformation, les données transformées auront le zéro moyen.énormes erreurs numériques lors de la tentative de normalisation des données

Une autre transformation courante qui peut être effectuée après avoir une moyenne nulle divise les données par leur écart-type. Après l'application de cette transformation, les nouvelles données ont une variance unitaire. Lorsque j'utilise des données normalisées de cette manière, je pense que les erreurs numériques devraient être plus petites. Cependant, il semble que je ne parvienne pas à faire ces transformations parce que les erreurs numériques apparaissent même lorsque j'essaie de calculer l'écart-type.

Ci-dessous est un exemple de code dans C# où j'essaie de calculer l'écart-type. On peut facilement voir même sans connaissance statistique (de la formule) que la sortie du programme devrait être nulle. (Si des données est un tableau de constantes que la moyenne des carrés des données équivaut à la case départ des moyennes.)

static double standardDeviation(double[] data) 
{ 
    double sum = 0; 
    double sumOfSquares = 0; 
    foreach (double number in data) 
    { 
     sum += number; 
     sumOfSquares += number * number; 
    } 
    double average = sum/data.Length; 
    double averageOfSquares = sumOfSquares/data.Length; 
    return Math.Sqrt(averageOfSquares - average * average); 
} 
static void Main(string[] args) 
{ 
    double bigNumber = 1478340000000; 
    double[] data = Enumerable.Repeat(bigNumber, 83283).ToArray(); 
    Console.WriteLine(standardDeviation(data)); 
} 

Au lieu de zéro, le programme fournit un grand nombre causé par des erreurs numériques: 2133383,0308878

Notez que si je omettrait Math.Sqrt (ie je calculerais la variance au lieu de l'écart-type) alors l'erreur serait beaucoup plus élevée.

Quelle est la cause et comment puis-je écrire cela avec des erreurs numériques plus smaler?

Répondre

1

Bien que la formule que vous utilisez pour la variance soit correcte mathématiquement - c.-à-d. Si vous avez une précision infinie - elle peut causer des problèmes avec une précision finie.

Une meilleure façon pour les données N X est de calculer

variance = Sum{ square(X[i] - mean) }/ N 

mean = Sum{ X[i] } /N 

Comme écrit cela nécessite deux passes à travers les données. Si cela vous gêne, vous pouvez le faire en un seul passage. Vous devez garder trois variables, n (nombre d'éléments de données vus jusqu'à présent) moyenne et variance. Ceux-ci devraient tous être initialisés à 0 (aka 0.0). Puis, quand vous obtenez le prochain élément de données x:

n = n + 1 
f = 1.0/n 
d = x-mean 
mean = mean + f*d 
variance = (1.0-f)*(variance + f*d*d) 

A chaque étape après le traitement d'un élément de données n, moyenne, la variance sont en effet le nombre, moyenne et la variance des données jusqu'à présent.

+0

Thx pour une bonne réponse. J'aime particulièrement comment vous le faites en un seul passage. Je comprends que la moyenne est correcte. Cependant, la formule de la variance me semble erronée. Qu'en est-il de la formule suivante?'vaiance = (1.0-f) * variance + f * d * d * (1.0 + f)' Cela aurait plus de sens pour moi. –

+0

Je suis sûr que ma formule est correcte. Votre ne peut pas être pour après le premier élément de données, lorsque f = 1, votre formule donne une valeur non nulle, 2 * d * d où d est la première valeur de données (parce que la moyenne est initialisée à 0). Mais la variance d'une collection de 1 choses est 0. – dmuir

+0

Votre contre-exemple est exact. Ainsi est votre formule. J'ai codé le programme avec votre formule et il renvoie les valeurs attendues. J'ai donc marqué votre réponse comme acceptée. Cependant je ne vois toujours pas pourquoi cela fonctionne. –

-1

Je pense que vous confondez le nombre max/min possible (± 5,0 × 10-324 à ± 1,7 × 10308) avec le nombre de chiffres significatifs disponibles (15 - 16) pour le double.

Dans votre cas, je dirais que vous gaspillez chiffres de ne pas échelle la première entrée, qui transforme votre valeur à 1,47834, avec un facteur d'échelle 1/10^7 pour vos calculs numériques.

+0

La mise à l'échelle n'a rien à voir ici. C'est de toute façon fait par la représentation FP et peut être factorisé ou pas. –