Desviación estándar ponderada en NumPy

numpy.average() tiene una opción de pesos, pero numpy.std() no la tiene. ¿Alguien tiene sugerencias para una solución?

¿Qué tal el siguiente “cálculo manual”?

 def weighted_avg_and_std(values, weights): """ Return the weighted average and standard deviation. values, weights -- Numpy ndarrays with the same shape. """ average = numpy.average(values, weights=weights) # Fast and numerically precise: variance = numpy.average((values-average)**2, weights=weights) return (average, math.sqrt(variance)) 

Hay una clase en statsmodels que facilita el cálculo de estadísticas ponderadas: statsmodels.stats.weightstats.DescrStatsW .

Asumiendo este conjunto de datos y pesos:

 import numpy as np from statsmodels.stats.weightstats import DescrStatsW array = np.array([1,2,1,2,1,2,1,3]) weights = np.ones_like(array) weights[3] = 100 

Inicializa la clase (tenga en cuenta que debe pasar el factor de corrección, los grados de libertad delta en este punto):

 weighted_stats = DescrStatsW(array, weights=weights, ddof=0) 

Entonces puedes calcular:

  • .mean la media ponderada :

     >>> weighted_stats.mean 1.97196261682243 
  • .std la desviación estándar ponderada :

     >>> weighted_stats.std 0.21434289609681711 
  • .var la varianza ponderada :

     >>> weighted_stats.var 0.045942877107170932 
  • .std_mean el error estándar de la media ponderada:

     >>> weighted_stats.std_mean 0.020818822467555047 

    En caso de que esté interesado en la relación entre el error estándar y la desviación estándar: el error estándar se ddof == 0 (para ddof == 0 ) como la desviación estándar ponderada dividida por la raíz cuadrada de la sum de los pesos menos 1 ( fuente correspondiente para statsmodels versión 0.9 en GitHub ):

     standard_error = standard_deviation / sqrt(sum(weights) - 1) 

Aún no parece haber una función de este tipo en el número / scipy, pero hay un ticket que propone esta funcionalidad adicional. Incluido allí encontrará Statistics.py que implementa desviaciones estándar ponderadas.

Aquí hay una opción más:

 np.sqrt(np.cov(values, aweights=weights)) 

Hay un muy buen ejemplo propuesto por Gaborous :

 import pandas as pd import numpy as np # X is the dataset, as a Pandas' DataFrame mean = mean = np.ma.average(X, axis=0, weights=weights) # Computing the weighted sample mean (fast, efficient and precise) # Convert to a Pandas' Series (it's just aesthetic and more # ergonomic; no difference in computed values) mean = pd.Series(mean, index=list(X.keys())) xm = X-mean # xm = X diff to mean xm = xm.fillna(0) # fill NaN with 0 (because anyway a variance of 0 is just void, but at least it keeps the other covariance's values computed correctly)) sigma2 = 1./(w.sum()-1) * xm.mul(w, axis=0).T.dot(xm); # Compute the unbiased weighted sample covariance 

Ecuación correcta para covarianza de muestra imparcial ponderada, URL (versión: 2016-06-28)