Comment calculer la variance d'une partition de variables

15

J'exécute une expérience où je collecte des échantillons (indépendants) en parallèle, je calcule la variance de chaque groupe d'échantillons et maintenant je veux combiner ensuite tout pour trouver la variance totale de tous les échantillons.

J'ai du mal à trouver une dérivation pour cela car je ne suis pas sûr de la terminologie. Je pense à cela comme une partition d'un VR.

Je veux donc trouver Var(X) partir de Var(X1) , Var(X2) , ..., et Var(Xn) , où X = [X1,X2,,Xn] .

EDIT: les partitions ne sont pas de la même taille / cardinalité, mais la somme des tailles de partition est égale au nombre d'échantillons dans l'ensemble d'échantillons global.

EDIT 2: Il existe une formule pour un calcul parallèle ici , mais elle ne couvre que le cas d'une partition en deux ensembles, pas ensembles.n

gallamine
la source
Est-ce la même que ma question ici: mathoverflow.net/questions/64120/…
Que signifie cette dernière tranche? Et qu'entendez-vous par "variance totale"? Est-ce autre chose que la variance de l'ensemble de données combiné?
whuber
@whuber quelle dernière tranche? "variance totale" signifie la variance de l'ensemble de données total.
gallamine
L'expression pourrait signifier beaucoup de choses (bien que ce soit classiquement un vecteur): je cherchais une clarification. [X1,X2,,Xn]
whuber

Réponses:

22

La formule est assez simple si tous les sous-échantillons ont la même taille d'échantillon. Si vous aviez sous-échantillons de taille k (pour un total de g k échantillons), alors la variance de l'échantillon combiné dépend de la moyenne E j et de la variance V j de chaque sous-échantillon: V a r ( X 1 , , X g k ) = k - 1gkgkEjVjoù parVar(Ej)signifie la variance des moyennes de l'échantillon.

Var(X1,,Xgk)=k1gk1(j=1gVj+k(g1)k1Var(Ej)),
Var(Ej)

Une démonstration en R:

> x <- rnorm(100)
> g <- gl(10,10)
> mns <- tapply(x, g, mean)
> vs <- tapply(x, g, var)
> 9/99*(sum(vs) + 10*var(mns))
[1] 1.033749
> var(x)
[1] 1.033749

Si les tailles d'échantillon ne sont pas égales, la formule n'est pas si agréable.

EDIT: formule pour des tailles d'échantillon inégales

S'il y a sous-échantillons, chacun avec k j , j = 1 , , g éléments pour un total de n = k j valeurs, alors V a r ( X 1 , , X n ) = 1gkj,j=1,,gn=kj ˉ X =( g j = 1 kj ˉ X

Var(X1,,Xn)=1n1(j=1g(kj1)Vj+j=1gkj(X¯jX¯)2),
est la moyenne pondérée de toutes les moyennes (et égale à la moyenne de toutes les valeurs).X¯=(j=1gkjX¯j)/n

Encore une fois, une démonstration:

> k <- rpois(10, lambda=10)
> n <- sum(k)
> g <- factor(rep(1:10, k))
> x <- rnorm(n)
> mns <- tapply(x, g, mean)
> vs <- tapply(x, g, var)
> 1/(n-1)*(sum((k-1)*vs) + sum(k*(mns-weighted.mean(mns,k))^2))
[1] 1.108966
> var(x)
[1] 1.108966

(XjiX¯)2X¯j[(XjiX¯j)(X¯jX¯)]2

Aniko
la source
Merci. Malheureusement, je ne peux pas garantir que mes partitions sont toutes de la même taille. J'exécute un processus massivement parallèle où je dois calculer les variances de chaque partition en parallèle puis les combiner à la fin, mais les résultats / échantillons de chaque processus parallèle ne sont pas égaux (c'est une simulation Monte Carlo des photons reçus).
gallamine
3
Je ne peux pas attribuer +1 à cette formule super utile pour le calcul parallèle dans un environnement d'entrepôt de données
Noah Yetter
1

Il s'agit simplement d'un complément à la réponse d'aniko avec un aperçu approximatif de la dérivation et du code python, donc tous les crédits vont à aniko.

dérivation

XjX={X1,X2,,Xg}gkj=|Xj|

Ej=E[Xj]=1kji=1kjXjiVj=Var[Xj]=1kj1i=1kj(XjiEj)2
respectively. If we set n=j=1gkj, the variance of the total dataset is given by:
Var[X]=1n1j=1gi=1kj(XjiE[X])2=1n1j=1gi=1kj((XjiEj)(E[X]Ej))2=1n1j=1gi=1kj(XjiEj)22(XjiEj)(E[X]Ej)+(E[X]Ej)2=1n1j=1g(kj1)Vj+kj(E[X]Ej)2.
If we have the same size k for each part, i.e. j:kj=k, above formula simplifies to
Var[X]=1n1j=1g(k1)Vj+k(g1)Var[Ej]=k1n1j=1gVj+k(g1)k1Var[Ej]

python code

The following python function works for arrays that have been splitted along the first dimension and implements the "more complex" formula for differently sized parts.

import numpy as np

def combine(averages, variances, counts, size=None):
    """
    Combine averages and variances to one single average and variance.

    # Arguments
        averages: List of averages for each part.
        variances: List of variances for each part.
        counts: List of number of elements in each part.
        size: Total number of elements in all of the parts.
    # Returns
        average: Average over all parts.
        variance: Variance over all parts.
    """
    average = np.average(averages, weights=counts)

    # necessary for correct variance in case of multidimensional arrays
    if size is not None:
        counts = counts * size // np.sum(counts, dtype='int')

    squares = (counts - 1) * variances + counts * (averages - average)**2
    return average, np.sum(squares) / (size - 1)

It can be used as follows:

# sizes k_j and n
ks = np.random.poisson(10, 10)
n = np.sum(ks)

# create data
x = np.random.randn(n, 20)
parts = np.split(x, np.cumsum(ks[:-1]))

# compute statistics on parts
ms = [np.mean(p) for p in parts]
vs = [np.var(p, ddof=1) for p in parts]

# combine and compare
combined = combine(ms, vs, ks, x.size)
numpied = np.mean(x), np.var(x, ddof=1)
distance = np.abs(np.array(combined) - np.array(numpied))
print('combined --- mean:{: .9f} - var:{: .9f}'.format(*combined))
print('numpied  --- mean:{: .9f} - var:{: .9f}'.format(*numpied))
print('distance --- mean:{: .5e} - var:{: .5e}'.format(*distance))
Mr Tsjolder
la source