Los algoritmos para calcular la varianza desempeñan un papel fundamental en la estadística computacional . Una dificultad clave en el diseño de buenos algoritmos para este problema radica en que las fórmulas para la varianza pueden incluir sumas de cuadrados, lo que puede provocar inestabilidad numérica y desbordamiento aritmético al trabajar con valores grandes.
Algoritmo ingenuo
Una fórmula para calcular la varianza de una población completa de tamaño N es:
Utilizando la corrección de Bessel para calcular una estimación insesgada de la varianza poblacional a partir de una muestra finita de n observaciones, la fórmula es:
Por lo tanto, un algoritmo ingenuo para calcular la varianza estimada viene dado por el siguiente:
- Sea n ← 0, Suma ← 0, SumaSq ← 0
- Para cada dato x :
- n ← n + 1
- Suma ← Suma + x
- Suma de cuadrados ← Suma de cuadrados + x × x
- Var = (SumaSq − (Suma × Suma) / n) / (n − 1)
Este algoritmo se puede adaptar fácilmente para calcular la varianza de una población finita: simplemente divida por n en lugar de n − 1 en la última línea.
Debido a que SumSq y (Sum×Sum)/ n pueden ser números muy similares, la cancelación puede provocar que la precisión del resultado sea mucho menor que la precisión inherente de la aritmética de punto flotante utilizada para realizar el cálculo. Por lo tanto, este algoritmo no debería utilizarse en la práctica, [ 1 ] [ 2 ] y se han propuesto varios algoritmos alternativos numéricamente estables. [ 3 ] Esto es particularmente problemático si la desviación estándar es pequeña en relación con la media.
Computación de datos desplazados
La varianza es invariante con respecto a los cambios en un parámetro de ubicación , una propiedad que puede usarse para evitar la cancelación catastrófica en esta fórmula.
concualquier constante, lo que lleva a la nueva fórmula
cuanto más cercacuanto más cercano al valor medio, más preciso será el resultado, pero simplemente elegir un valor dentro del rango de las muestras garantizará la estabilidad deseada. Si los valoresSi son pequeños, entonces no hay problemas con la suma de sus cuadrados; por el contrario, si son grandes, necesariamente significa que la varianza también es grande. En cualquier caso, el segundo término de la fórmula siempre es menor que el primero, por lo que no puede haber cancelación. [ 2 ]
Si solo se toma la primera muestra comoEl algoritmo se puede escribir en el lenguaje de programación Python como
def shifted_data_variance ( data ): if len ( data ) < 2 : return 0.0 K = data [ 0 ] n = Ex = Ex2 = 0.0 for x in data : n += 1 Ex += x - K Ex2 += ( x - K ) ** 2 varianza = ( Ex2 - Ex ** 2 / n ) / ( n - 1 ) # usa n en lugar de (n-1) si quieres calcular la varianza exacta de los datos dados # usa (n-1) si los datos son muestras de una población mayor return varianzaAlgoritmo de dos pasadas
Un enfoque alternativo, que utiliza una fórmula diferente para la varianza, primero calcula la media de la muestra,
y luego calcula la suma de los cuadrados de las diferencias con respecto a la media,
donde s es la desviación estándar. Esto se obtiene mediante el siguiente código:
def two_pass_variance ( data ): n = len ( data ) media = suma ( data ) / n varianza = suma (( x - media ) ** 2 para x en datos ) / ( n - 1 ) return varianzaEste fragmento de código, si se ejecuta en CPython 3.12 o posterior, siempre es numéricamente estable. Esto se debe a que estas versiones utilizan el esquema de suma compensada de Neumaier para la sum()función, lo que la hace resistente a errores de redondeo repetidos. [ 4 ] Muchos lenguajes orientados numéricamente proporcionan construcciones similares.
Este algoritmo, si se implementa con una suma ingenua sum = 0; for x in data: sum += x; mean = sum / n, solo sería numéricamente estable si n es pequeño debido a la acumulación de errores de redondeo. [ 1 ] [ 5 ]
Algoritmos incrementales
A menudo resulta útil poder calcular la varianza en una sola pasada , inspeccionando cada valor.Solo una vez; por ejemplo, cuando se recopilan datos sin suficiente espacio de almacenamiento para guardar todos los valores, o cuando los costos de acceso a la memoria superan a los de computación. Para un algoritmo en línea de este tipo , se requiere una relación de recurrencia entre las cantidades a partir de la cual se puedan calcular las estadísticas necesarias de forma numéricamente estable.
Datos desplazados incrementales
Nuestro algoritmo de datos desplazados anterior incluye la actualización simple de datos en un bucle, que es naturalmente incremental. Se puede expresar como: [ 2 ]
clase ShiftDataVariance : def __init __ ( self ) : self.K = 0.0 self.n = 0 self.Ex = 0.0 self.Ex2 = 0.0def add_variable ( self , x : float ) : if self.n == 0 : self.K = x self.n + = 1 self.Ex + = x - self.K self.Ex2 + = ( x - self.K ) ** 2def remove_variable ( self , x : float ) : self.n - = 1 self.Ex - = x - self.K self.Ex2 - = ( x - self.K ) ** 2def add_variables ( self , xs : list [ float ] ) : # Python usa el algoritmo de Neumaier para la función integrada sum(), # que es más preciso que un simple bucle . if self.n == 0 and xs : self.K = xs [ 0 ] self.n + = len ( xs ) self.Ex + = sum ( x - self.K for x in xs ) self.Ex2 + = sum ( ( x - self.K ) ** 2 for x in xs )def obtener_media ( self ) -> float : return self . K + self . Ex / self . ndef get_variance ( self ) -> float : return ( self . Ex2 - self . Ex ** 2 / self . n ) / ( self . n - 1 )El algoritmo en línea de Welford
De forma análoga al algoritmo de dos pasadas anterior, sigue siendo deseable utilizar la media real de los datos en lugar de simplemente seleccionar el primer elemento. Las siguientes fórmulas se pueden utilizar para actualizar la media y la varianza (estimada) de la secuencia, para un elemento adicional x n . Aquí,denota la media muestral de las primeras n muestras.,su varianza de muestra sesgada ysu varianza muestral insesgada .
Estas fórmulas sufren de inestabilidad numérica, ya que restan repetidamente un número pequeño de un número grande que escala con n . Una mejor cantidad para actualizar es la suma de los cuadrados de las diferencias con respecto a la media actual., aquí denotado:
El siguiente algoritmo fue hallado por Welford, [ 6 ] [ 7 ] y ha sido analizado exhaustivamente. [ 2 ] [ 8 ] También es común denotary. [ 9 ] A continuación se muestra un ejemplo de implementación en Python del algoritmo de Welford, utilizando el mismo marco que el algoritmo de "datos desplazados" anterior:
clase WelfordVariance : def __init__ ( self ): # Comparación con ShiftDataVariance: self.mean = 0.0 # = K + Ex / n self.count = 0 # = n self.M2 = 0.0 # = Ex2 - (Ex)^2 / ndef add_variable ( self , x : float ): self . count += 1 old_mean = self . mean self . mean += ( x - self . mean ) / self . count self . M2 += ( x - old_mean ) * ( x - self . mean )def remove_variable ( self , x : float ): self . count -= 1 new_mean = self . mean self . mean -= ( x - self . mean ) / self . count self . M2 -= ( x - new_mean ) * ( x - self . mean )def obtener_media ( self ) -> float : return self . mediadef obtener_varianza ( self ) -> float : return self . M2 / self . countdef get_sample_variance ( self ) -> float : return self . M2 / ( self . count - 1 )Este algoritmo es mucho menos propenso a la pérdida de precisión por cancelación catastrófica , pero podría no ser tan eficiente debido a la operación de división dentro del bucle. Para un algoritmo de dos pasadas particularmente robusto para calcular la varianza, se puede calcular primero y restar una estimación de la media, y luego aplicar este algoritmo a los residuos.
El algoritmo paralelo que se muestra a continuación ilustra cómo combinar varios conjuntos de estadísticas calculadas en línea.
Algoritmo incremental ponderado
El algoritmo puede extenderse para manejar pesos de muestra desiguales, reemplazando el contador simple n con la suma de los pesos vistos hasta ahora. West (1979) [ 10 ] sugiere este algoritmo incremental :
from collections import namedtuple WeightedVariances = namedtuple ( "WeightedVariances" , "pop freq reli" ) def weighted_incremental_variance ( data_weight_pairs ): w_sum = w_sum2 = mean = S = 0para x , w en data_weight_pairs : w_sum = w_sum + w w_sum2 = w_sum2 + w ** 2 media_antigua = media media = media_antigua + ( w / w_sum ) * ( x - media_antigua ) S = S + w * ( x - media_antigua ) * ( x - media )varianza_poblacional = S / w_sum # Corrección de Bessel para muestras ponderadas # Ponderaciones de frecuencia varianza_frecuencia_muestra = S / ( w_sum - 1 )# Pesos de confiabilidad varianza_confiabilidad_muestra = S / ( w_sum - w_sum2 / w_sum ) return VarianzasPonderadas ( varianza_población , varianza_frecuencia_muestra , varianza_confiabilidad_muestra )Algoritmo paralelo
Chan et al. [ 11 ] señalan que el algoritmo en línea de Welford detallado anteriormente es un caso especial de un algoritmo que funciona para combinar conjuntos arbitrarios.y:
- .
Esto puede resultar útil cuando, por ejemplo, se pueden asignar varias unidades de procesamiento a partes discretas de la entrada.
El método de Chan para estimar la media es numéricamente inestable cuandoy ambos son grandes, debido al error numérico enno se reduce de la misma manera que en elcaso. En tales casos, prefieraReutilizando la WelfordVarianceclase anterior, tenemos:
def merge ( a : WelfordVariance , b : WelfordVariance ) - > WelfordVariance : ab = WelfordVariance ( ) ab.count = a.count + b.count delta = b.mean - a.mean ab.mean = ( a.count * a.mean + b.count * b.mean ) / ab.count ab.M2 = a.M2 + b.M2 + delta ** 2 * a.count * b.count / ab.count return ab# ejemplo: ab = merge ( a , b ) print ( ab . get_sample_variance ())Este algoritmo permite dividir un conjunto de datos en varias partes, ejecutarlas en paralelo y luego combinar los resultados. Esto posibilita la paralelización de cualquier forma, incluyendo AVX , con GPU y clústeres de computadoras . El algoritmo también puede adaptarse para estadísticas de orden superior, así como para covarianza. [ 3 ] [ 12 ]
Ejemplo
Supongamos que todas las operaciones de punto flotante utilizan aritmética de doble precisión estándar IEEE 754. Consideremos la muestra (4, 7, 13, 16) de una población infinita. Con base en esta muestra, la media poblacional estimada es 10, y la estimación insesgada de la varianza poblacional es 30. Tanto el algoritmo ingenuo como el algoritmo de dos pasadas calculan estos valores correctamente.
A continuación, consideremos la muestra ( 10 8 + 4 , 10 8 + 7 , 10 8 + 13 , 10 8 + 16 ), que da lugar a la misma varianza estimada que la primera muestra. El algoritmo de dos pasadas calcula correctamente esta estimación de la varianza, pero el algoritmo ingenuo devuelve 29,333333333333332 en lugar de 30.
Si bien esta pérdida de precisión puede ser tolerable y considerarse un defecto menor del algoritmo ingenuo, aumentar aún más el desplazamiento hace que el error sea catastrófico. Consideremos la muestra ( 10⁹ + 4 , 10⁹ + 7 , 10⁹ + 13 , 10⁹ + 16 ) . Nuevamente , la varianza poblacional estimada de 30 se calcula correctamente mediante el algoritmo de dos pasadas, pero el algoritmo ingenuo ahora la calcula como -170,66666666666666. Este es un problema grave con el algoritmo ingenuo y se debe a la cancelación catastrófica en la resta de dos números similares en la etapa final del algoritmo.
Estadísticas de orden superior
Terriberry [ 12 ] extiende las fórmulas de Chan para calcular el tercer y cuarto momento central , necesarios, por ejemplo, para estimar la asimetría y la curtosis :
Aquí elson nuevamente las sumas de potencias de diferencias con respecto a la media, donación
Para el caso incremental (es decir,), esto se simplifica a:
Al preservar el valorSolo se necesita una operación de división y, por lo tanto, las estadísticas de orden superior se pueden calcular con un coste incremental mínimo.
Un ejemplo del algoritmo en línea para la curtosis implementado como se describe es:
def curtosis_en_línea ( datos ): n = media = M2 = M3 = M4 = 0para x en datos : n1 = n n = n + 1 delta = x - media delta_n = delta / n delta_n2 = delta_n ** 2 término1 = delta * delta_n * n1 media = media + delta_n M4 = M4 + término1 * delta_n2 * ( n ** 2 - 3 * n + 3 ) + 6 * delta_n2 * M2 - 4 * delta_n * M3 M3 = M3 + término1 * delta_n * ( n - 2 ) - 3 * delta_n * M2 M2 = M2 + término1# Nota: también puedes calcular la varianza usando M2 y la asimetría usando M3. # Precaución: si todas las entradas son iguales, M2 será 0, lo que resultará en una división por cero. curtosis = ( n * M4 ) / ( M2 ** 2 ) - 3 return curtosisPébaÿ [ 13 ] extiende aún más estos resultados a momentos centrales de orden arbitrario , para los casos incremental y por pares, y posteriormente Pébaÿ et al. [ 14 ] para momentos ponderados y compuestos. También se pueden encontrar allí fórmulas similares para la covarianza .
Choi y Sweetman [ 15 ] ofrecen dos métodos alternativos para calcular la asimetría y la curtosis, cada uno de los cuales puede ahorrar requisitos sustanciales de memoria de computadora y tiempo de CPU en ciertas aplicaciones. El primer enfoque consiste en calcular los momentos estadísticos separando los datos en intervalos y luego calculando los momentos a partir de la geometría del histograma resultante , lo que efectivamente se convierte en un algoritmo de una sola pasada para momentos de orden superior. Una ventaja es que los cálculos de los momentos estadísticos se pueden realizar con una precisión arbitraria, de modo que los cálculos se pueden ajustar a la precisión de, por ejemplo, el formato de almacenamiento de datos o el hardware de medición original. Un histograma relativo de una variable aleatoria se puede construir de la manera convencional: el rango de valores potenciales se divide en intervalos y el número de ocurrencias dentro de cada intervalo se cuenta y se grafica de manera que el área de cada rectángulo sea igual a la porción de los valores de la muestra dentro de ese intervalo:
dóndeyrepresentan la frecuencia y la frecuencia relativa en el intervaloyes el área total del histograma. Después de esta normalización, elmomentos crudos y momentos centrales dese puede calcular a partir del histograma relativo:
donde el superíndiceindica que los momentos se calculan a partir del histograma. Para un ancho de intervalo constanteEstas dos expresiones se pueden simplificar usando:
El segundo enfoque, propuesto por Choi y Sweetman [ 15 ], es una metodología analítica para combinar momentos estadísticos de segmentos individuales de una serie temporal, de manera que los momentos globales resultantes correspondan a la serie temporal completa. Esta metodología podría utilizarse para el cálculo paralelo de momentos estadísticos con su posterior combinación, o para la combinación de momentos estadísticos calculados en instantes de tiempo consecutivos.
SiSe conocen conjuntos de momentos estadísticos: para, luego cada unopuede expresarse en términos del equivalentemomentos crudos:
dóndeGeneralmente se considera que es la duración de lahistorial temporal, o el número de puntos sies constante.
El beneficio de expresar los momentos estadísticos en términos dees que elLos conjuntos se pueden combinar mediante la suma, y no hay límite superior en el valor de.
donde el subíndicerepresenta el historial temporal concatenado o combinadoEstos valores combinados deLuego se pueden transformar inversamente en momentos brutos que representan la historia temporal concatenada completa.
Relaciones conocidas entre los momentos crudos () y los momentos centrales (Luego se utilizan para calcular los momentos centrales de la historia temporal concatenada. Finalmente, los momentos estadísticos de la historia concatenada se calculan a partir de los momentos centrales:
Covarianza
Se pueden utilizar algoritmos muy similares para calcular la covarianza .
Algoritmo ingenuo
El algoritmo ingenuo es
Para el algoritmo anterior, se podría utilizar el siguiente código Python:
def naive_covariance ( data1 , data2 ): n = len ( data1 ) sum1 = sum ( data1 ) sum2 = sum ( data2 ) sum12 = sum ([ i1 * i2 for i1 , i2 in zip ( data1 , data2 )])covarianza = ( suma12 - suma1 * suma2 / n ) / n devolver covarianzaCon estimación de la media
En cuanto a la varianza, la covarianza de dos variables aleatorias también es invariante a cambios, por lo que dados cualesquiera dos valores constantesySe puede escribir:
Y nuevamente, elegir un valor dentro del rango de valores estabilizará la fórmula contra cancelaciones catastróficas, además de hacerla más robusta contra grandes sumas. Tomando el primer valor de cada conjunto de datos , el algoritmo se puede escribir como:
def shifted_data_covariance ( data_x , data_y ): n = len ( data_x ) if n < 2 : return 0 kx = data_x [ 0 ] ky = data_y [ 0 ] Ex = Ey = Exy = 0 for ix , iy in zip ( data_x , data_y ): # para mayor precisión, use sum(): Ex += ix - kx # Ex = sum(ix - kx for ix in data_x) # o sum(ix) - kx * n Ey += iy - ky # Ey = sum(iy - ky for iy in data_y) # o sum(iy) - ky * n Exy += ( ix - kx ) * ( iy - ky ) # Exy = sum((ix - kx) * (iy - ky) for ix, iy in zip(data_x, data_y)) return ( Exy - Ex * Ey / n ) / nDos pases
El algoritmo de dos pasos primero calcula las medias de las muestras y luego la covarianza:
El algoritmo de dos pasadas se puede escribir como:
def two_pass_covariance ( data1 , data2 ): n = len ( data1 ) media1 = suma ( data1 ) / n media2 = suma ( data2 ) / ncovarianza = 0 para i1 , i2 en zip ( data1 , data2 ): # para mayor precisión, usar sum(): a = i1 - media1 # covarianza = sum((i1 - media1) * (i2 - media2) para i1, i2 en zip(data1, data2)) b = i2 - media2 covarianza += a * b / n return covarianzaEn línea
Existe un algoritmo estable de una sola pasada, similar al algoritmo en línea para calcular la varianza, que calcula el co-momento.:
La aparente asimetría en esa última ecuación se debe al hecho de que, por lo que ambos términos de actualización son iguales aSe puede lograr una precisión aún mayor calculando primero las medias y luego utilizando el algoritmo estable de una sola pasada sobre los residuos.
Por lo tanto, la covarianza se puede calcular como
def covarianza_en_línea ( datos1 , datos2 ): media_x = media_y = C = n = 0 para x , y en zip ( datos1 , datos2 ): n += 1 dx = x - media_x media_x += dx / n media_y += ( y - media_y ) / n C += dx * ( y - media_y )# Covarianza y corrección de Bessel para el retorno de la muestra ( C / n , C / ( n - 1 ))También se puede realizar una pequeña modificación para calcular la covarianza ponderada:
def covarianza_ponderada_en_línea ( datos1 , datos2 , datos3 ): media_x = media_y = 0 suma_w = suma_w2 = 0 C = 0 para x , y , w en zip ( datos1 , datos2 , datos3 ): suma_w += w suma_w2 += w * w dx = x - media_x media_x += ( w / suma_w ) * dx media_y += ( w / suma_w ) * ( y - media_y ) C += w * dx * ( y - media_y )covarianza_población = C / wsum # Corrección de Bessel para la varianza de la muestra # Pesos de frecuencia covarianza_frecuencia_muestra = C / ( wsum - 1 ) # Pesos de fiabilidad covarianza_fiabilidad_muestra = C / ( wsum - wsum2 / wsum )Asimismo, existe una fórmula para combinar las covarianzas de dos conjuntos que puede utilizarse para paralelizar el cálculo: [ 3 ]
Versión ponderada por lotes
También existe una versión del algoritmo en línea ponderado que realiza actualizaciones por lotes: letdenote los pesos y escriba
La covarianza se puede calcular entonces como
(Esto se puede usar con Python sumpara mayor precisión. La actualización de bloques también está relacionada con el algoritmo paralelo/de fusión).
Véase también
Referencias
- 1 2 Einarsson, Bo (2005). Precisión y fiabilidad en la computación científica . SIAM. pág. 47. ISBN 978-0-89871-584-2.
- 1 2 3 4 Chan, Tony F. ; Golub, Gene H. ; LeVeque, Randall J. (1983). "Algoritmos para calcular la varianza muestral: análisis y recomendaciones" (PDF) . The American Statistician . 37 (3): 242– 247. doi : 10.1080/00031305.1983.10483115 . JSTOR 2683386 . Archivado (PDF) del original el 9 de octubre de 2022.
- 1 2 3 Schubert, Erich; Gertz, Michael (9 de julio de 2018). Cálculo paralelo numéricamente estable de la (co)varianza . ACM. pág. 10. doi : 10.1145/3221269.3223036 . ISBN 9781450365055. S2CID 49665540 .
- ↑
- ↑ Higham, Nicholas J. (2002). «Problema 1.10». Precisión y estabilidad de los algoritmos numéricos (2.ª ed.). Filadelfia, PA: Society for Industrial and Applied Mathematics. doi : 10.1137/1.9780898718027 . ISBN 978-0-898715-21-7ISBN 978-0-89871-802-7, 2002075848.Los metadatos también figuran en la Biblioteca Digital de ACM .
- ↑ Welford, BP (1962). "Nota sobre un método para calcular sumas de cuadrados y productos corregidos". Technometrics . 4 (3): 419– 420. doi : 10.2307/1266577 . JSTOR 1266577 .
- ↑ Donald E. Knuth (1998). El arte de la programación informática , volumen 2: Algoritmos seminuméricos , 3.ª ed., pág. 232. Boston: Addison-Wesley.
- ↑ Ling, Robert F. (1974). "Comparación de varios algoritmos para calcular medias y varianzas de muestras". Journal of the American Statistical Association . 69 (348): 859– 866. doi : 10.2307/2286154 . JSTOR 2286154 .
- ↑ Cook, John D. (30 de septiembre de 2022) [1 de noviembre de 2014]. "Cálculo preciso de la varianza muestral" . John D. Cook Consulting: Consultoría experta en matemáticas aplicadas y privacidad de datos .
- ↑ West, DHD (1979). "Actualización de las estimaciones de la media y la varianza: un método mejorado" . Communications of the ACM . 22 (9): 532– 535. doi : 10.1145/359146.359153 . S2CID 30671293 .
- ↑ Chan, Tony F. ; Golub, Gene H. ; LeVeque, Randall J. (noviembre de 1979). "Actualización de fórmulas y un algoritmo por pares para el cálculo de varianzas de muestras" (PDF) . Departamento de Ciencias de la Computación, Universidad de Stanford. Informe técnico STAN-CS-79-773, financiado en parte por el contrato del Ejército n.° DAAGEI-'EG-013.
- 1 2 Terriberry, Timothy B. (15 de octubre de 2008) [9 de diciembre de 2007]. "Cálculo de momentos de orden superior en línea" . Archivado del original el 23 de abril de 2014. Recuperado el 5 de mayo de 2008 .
- ↑ Pébay, Philippe Pierre (septiembre de 2008). "Fórmulas para el cálculo paralelo robusto de una sola pasada de covarianzas y momentos estadísticos de orden arbitrario" . Organismo patrocinador: USDOE. Albuquerque, NM y Livermore, CA (Estados Unidos): Laboratorios Nacionales Sandia (SNL). doi : 10.2172/1028931 . OSTI 1028931. Informe técnico SAND2008-6212, TRN: US201201%%57, número de contrato del DOE: AC04-94AL85000 – vía Biblioteca Digital de la UNT.
- ↑ Pébaÿ, Philippe; Terriberry, Timothy; Kolla, Hemanth; Bennett, Janine (2016). "Fórmulas numéricamente estables y escalables para el cálculo paralelo y en línea de momentos centrales multivariados de orden superior con ponderaciones arbitrarias" . Computational Statistics . 31 (4). Springer: 1305–1325 . doi : 10.1007/s00180-015-0637-z . S2CID 124570169 .
- 1 2 Choi, Myoungkeun; Sweetman, Bert (2010). "Cálculo eficiente de momentos estadísticos para el monitoreo de la salud estructural". Journal of Structural Health Monitoring . 9 (1): 13– 24. doi : 10.1177/1475921709341014 . S2CID 17534100 .
Enlaces externos
- Weisstein, Eric W. "Cálculo de la varianza muestral" . MathWorld .
- Algoritmos estadísticos
- Desviación estadística y dispersión