Como calcular a variação de uma partição de variáveis

15

Estou executando um experimento em que estou coletando amostras (independentes) em paralelo, calculo a variação de cada grupo de amostras e agora quero combinar tudo para encontrar a variação total de todas as amostras.

Estou tendo dificuldade em encontrar uma derivação para isso, pois não tenho certeza da terminologia. Eu penso nisso como uma partição de um RV.

Então, eu quero encontrar de V a r ( X 1 ) , V a r ( X 2 ) , ... e V a r ( X n ) , onde X = [ X 1 , X 2 , , X n ] .Var(X)Var(X1)Var(X2)Var(Xn)X[X1,X2,,Xn]

EDIT: As partições não têm o mesmo tamanho / cardinalidade, mas a soma dos tamanhos das partições é igual ao número de amostras no conjunto geral de amostras.

EDIT 2: Existe uma fórmula para uma computação paralela aqui , mas cobre apenas o caso de uma partição em dois conjuntos, não em conjuntos.n

galamina
fonte
É o mesmo que a minha pergunta aqui: mathoverflow.net/questions/64120/…
O que significa esse último colchete? E o que você quer dizer com "variação total"? É outra coisa senão a variação do conjunto de dados combinado?
whuber
@whuber qual último suporte? "variação total" significa a variação do conjunto total de dados.
gallamine
A expressão poderia significar muitas coisas (embora convencionalmente fosse um vetor): eu estava procurando um esclarecimento. [X1,X2,,Xn]
whuber

Respostas:

22

A fórmula é bastante direta se todas as subamostras tiverem o mesmo tamanho de amostra. Se tivesse sub-amostras de tamanho k (para um total de g k amostras), em seguida a variância da amostra combinada depende da média E j e variância V j de cada sub-amostra: V uma r ( X 1 , , X g k ) = k - 1gkgkEjVjonde porVar(Ej)significa a variação da média da amostra.

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

Uma demonstração em 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

Se os tamanhos das amostras não forem iguais, a fórmula não será tão boa.

EDIT: fórmula para tamanhos de amostra desiguais

gkj,j=1,,gn=kj

Var(X1,,Xn)=1n1(j=1g(kj1)Vj+j=1gkj(X¯jX¯)2),
X¯=(j=1gkjX¯j)/n

Mais uma vez, uma demonstração:

> 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
fonte
obrigado. Infelizmente, não posso garantir que minhas partições sejam do mesmo tamanho. Estou executando um processo paralelo em que preciso calcular as variações de cada partição em paralelo e depois combinar no final, mas os resultados / amostras de cada processo paralelo não são iguais (é uma simulação de Monte Carlo dos fótons recebidos).
gallamine
3
Eu não posso +1 este bastante, fórmula super útil para a computação paralela em um ambiente de data warehouse
Noah Yetter
1

Isso é simplesmente um complemento para a resposta do aniko com um esboço da derivação e algum código python, para que todos os créditos sejam do aniko.

derivação

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

Ej=E[Xj]=1kjEu=1kjXjEuVj=Vumar[Xj]=1kj-1Eu=1kj(XjEu-Ej)2
respectivamente. Se definirmosn=j=1gkj, a variação do conjunto total de dados é dada por:
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
fonte