Pourquoi numpy std () donne-t-il un résultat différent à matlab std ()?

87

J'essaie de convertir le code matlab en numpy et j'ai compris que numpy avait un résultat différent avec la fonction std.

dans matlab

std([1,3,4,6])
ans =  2.0817

dans numpy

np.std([1,3,4,6])
1.8027756377319946

Est-ce normal? Et comment dois-je gérer cela?

Gustavgans
la source

Réponses:

145

La fonction NumPy np.stdprend un paramètre optionnel ddof: "Delta Degrees of Freedom". Par défaut, c'est 0. Réglez-le sur 1pour obtenir le résultat MATLAB:

>>> np.std([1,3,4,6], ddof=1)
2.0816659994661326

Pour ajouter un peu plus de contexte, dans le calcul de la variance (dont l'écart type est la racine carrée), nous divisons généralement par le nombre de valeurs que nous avons.

Mais si nous sélectionnons un échantillon aléatoire d' Néléments à partir d'une distribution plus large et calculons la variance, la division par Npeut conduire à une sous-estimation de la variance réelle. Pour résoudre ce problème, nous pouvons réduire le nombre par lequel nous divisons ( les degrés de liberté ) à un nombre inférieur à N(généralement N-1). Le ddofparamètre nous permet de changer le diviseur du montant que nous spécifions.

Sauf indication contraire, NumPy calculera l' estimateur biaisé de la variance ( ddof=0, en divisant par N). C'est ce que vous voulez si vous travaillez avec la distribution entière (et non un sous-ensemble de valeurs qui ont été choisies au hasard dans une distribution plus large). Si le ddofparamètre est donné, NumPy se divise par à la N - ddofplace.

Le comportement par défaut de MATLAB stdest de corriger le biais de la variance de l'échantillon en divisant par N-1. Cela élimine une partie (mais probablement pas la totalité) du biais de l'écart type. C'est probablement ce que vous souhaitez si vous utilisez la fonction sur un échantillon aléatoire d'une distribution plus large.

La belle réponse de @hbaderts donne d'autres détails mathématiques.

Alex Riley
la source
4
J'ajouterai que dans Matlab, std([1 3 4 6],1)équivaut à la valeur par défaut de NumPy np.std([1,3,4,6]). Tout cela est assez clairement expliqué dans la documentation de Matlab et NumPy, donc je recommande fortement que l'OP soit sûr de les lire à l'avenir.
horchler
À un moment donné, cette norme a changé: np.std () = np.std (ddof = 1), même si la documentation indique que np.std () devrait par défaut être ddof = 0 ...
ColinMac
61

L'écart type est la racine carrée de la variance. La variance d'une variable aléatoire Xest définie comme

définition de la variance

Un estimateur de la variance serait donc

estimateur biaisé

moyenne de l'échantillondésigne la moyenne de l'échantillon. Pour une sélection aléatoire xi, on peut montrer que cet estimateur ne converge pas vers la variance réelle, mais vers

estimateur sans biais

Si vous sélectionnez au hasard des échantillons et estimez la moyenne et la variance de l'échantillon, vous devrez utiliser un estimateur corrigé (sans biais)

estimateur sans biais

qui convergera vers sigma au carré. Le terme de correction n-1est également appelé correction de Bessel.

Désormais, par défaut, MATLABs stdcalcule l' estimateur sans biais avec le terme de correction n-1. Cependant, NumPy (comme @ajcr l'a expliqué) calcule l' estimateur biaisé sans terme de correction par défaut. Le paramètre ddofpermet de définir n'importe quel terme de correction n-ddof. En le mettant à 1, vous obtenez le même résultat que dans MATLAB.

De même, MATLAB permet d'ajouter un deuxième paramètre w, qui spécifie le "schéma de pesée". La valeur par défaut,, w=0donne le terme de correction n-1(estimateur sans biais), tandis que pour w=1, seul n est utilisé comme terme de correction (estimateur biaisé).

hbaderts
la source
2
Dans la formule de l'estimateur corrigé, le facteur n (dans la somme) ne doit pas être présent.
Frunobulax
3
L'intuition derrière le terme n-1 dans la variance: vous avez déjà utilisé vos échantillons pour estimer la moyenne que vous utiliserez pour approximer la variance. Cela introduit une corrélation et donc ddof doit être 1.
Matthias
@Frunobulax J'ai corrigé la faute de frappe pour la postérité. Ce qui s'est passé dans l'équation d'origine était que la limite supérieure de la somme n'était pas rendue correctement. Au lieu d' naller en haut de la notation de sommation, il est entré dans la somme.
rayryeng
4

Pour les personnes qui ne sont pas douées pour les statistiques, un guide simpliste est:

  • Inclure ddof=1si vous calculez np.std()pour un échantillon prélevé sur votre ensemble de données complet.

  • Assurez ddof=0-vous que vous calculez np.std()pour la population complète

Le DDOF est inclus pour les échantillons afin de contrebalancer le biais qui peut se produire dans les nombres.

MJM
la source