Calculos estadisticos en python
Módulo statistics[editar]
Python viene con un módulo que nos ayuda a hacer cálculos estadísticos. Es el módulo statistics
. Debemos importarlo para poder usarlo
import statistics
Función mean()[editar]
La función mean()
nos da la media aritmética de la lista de números que pasamos.
>>> valores = [1,2,4,6]
>>> statistics.mean(valores)
3.25
Función fmean()[editar]
Igual que mean()
, pero convierte todos los valores a flotantes y es más rápida. A partir de la versión 3.11 de Python, también admite un segundo parámetro con los pesos de cada valor.
>>> valores = [1,2,4,6]
>>> statistics.fmean(valores)
3.25
>>> pesos = [7,1,1,1]
>>> statistics.fmean(valores, pesos)
1.9
En el ejemplo, los pesos son [7,1,1,1]
. Esto quiere decir que el valor 1 es como si apareciera 7 veces en la lista de valores
, y los valores 2, 4 y 6 una sola vez cada uno.
Función geometric_mean()[editar]
La función geometric_mean()
calcula la media geométrica de los números que se le pasan. La media calculada por mean()
es la suma de los valores dividida por el número total de valores. La media geométrica geometric_mean()
es la raíz n-sima del producto de los n valores.
>>> valores = [1,2,4,6]
>>> statistics.geometric_mean(valores)
2.6321480259049848
En el ejemplo, el resultado es la raíz cuarta (hay cuatro valores) del producto 1*2*4*6
Función harmonic_mean()[editar]
La función harmonic_mean()
calcula la media armónica de los valores. Es el inverso de la media de los inversos de los números. Es decir, si los valores son v1, v2 ... vn y hay n valores, la media es (v1+v2+...+vn)/n
, mientras que la media armónica es n / (1/v1 + 1/v2 + ... + 1/vn)
>>> valores = [1,2,4,6]
>>> statistics.harmonic_mean(valores)
2.0869565217391304
Admite como segundo parámetro una lista de pesos de los valores.
Función median(), median_low() y median_high()[editar]
La función median()
calcula la mediana de una lista de valores ordenada. Es decir, el valor que está en medio de la lista.
>>> valores = [1,10,2,3,5]
>>> statistics.median(valores)
3
En ejemplo, se ordena la lista [1,2,3,5,10]
y se devuelve el valor del medio. Si el número de valores es par, se devuelve la media de los dos valores del medio.
>>> valores = [1,10,2,3]
>>> statistics.median(valores)
2.5
El valor 2.5 devuelto es la media de 2 y 3, que son los valores que quedarían en medio de la lista al ordenarla.
Las funciones median_low()
y median_high()
se comportan igual que median()
si el número de valores es impar. Si el número de valores es par, entonces en vez de hacer la media de los dos valores que quedan en medio, devuelven el más bajo o el más alto respectivamente.
>>> valores = [1,10,2,3]
>>> statistics.median_low(valores)
2
>>> statistics.median_high(valores)
3
Función median_grouped()[editar]
La función median_grouped()
calcula la media agrupada de los datos. La explicación matemática de qué es la media agrupada es demasiado extensa para ponerla aquí, así que en el enlace tienes una explicación. Aquí también tienes la fórmula matemática que usan python para este cálculo de la media agrupada.
>>> valores = [1.1, 1.2, 1.3, 3.3, 3.4]
>>> statistics.median_grouped(valores)
1.3
Una expliación sencilla aunque no exacta, es que esta función coge la mediana (1.3). Con este valor hace un intervalo de 1 alrededor de la mediana, es decir +/- 0.5 de la mediana, que da un intervalor de 0.8 a 1.8. Con todo esto y teniendo en cuanta el total de valores y cuántos hay por debajo de la mediana, obtiene el resultado.
Función mode()[editar]
La función mode()
devuelva la moda de los datos. La moda es el valor que sale con más frecuencia. Puede haber varias modas, es decir, varios valores que salen con la misma frecuencia. Python devuelve sólo uno de ellos
>>> valores = [1,1,1,3,3,4]
>>> statistics.mode(valores)
1
>>> valores = [1,2,2,3,3]
>>> statistics.mode(valores)
2
En la primera lista el valor más repetido es el 1. En la segunda lista, se repiten el mismo número de veces el 2 y el 3.
Función multimode()[editar]
La función multimode()
devuelve una lista de valores moda en el caso de que haya varias modas que se repitan el mismo número de veces
>>> valores = [1,2,2,3,3]
>>> statistics.multimode(valores)
[2, 3]
Función pvariance()[editar]
La función pvariance()
calcula la varianza de una serie de números. El cálculo se hace sumando los cuadrados de las diferencias de cada valor con la media aritmética y dividiendo el resultado entre el número de valores. var = ( (x1 - media)^2 + (x2 - media)^2 + ... (xn - media)^2 ) / N
. Nos da una idea de cuán dispersos están los números, es decir, de cuánto se alejan de su valor medio
>>> valores = [1,2,2,3,3]
>>> statistics.pvariance(valores)
0.56
Admite un segundo parámetro que sería el valor que se use como media. Esto es útil para saber cuánto de desvían estos valores de un valor concreto que no es la media
>>> statistics.pvariance(valores,5)
8.4
Función variance()[editar]
La función variance()
hace lo mismo que pvariance()
, pero dividiendo entre el número de valores menos uno, es decir, var = ( (x1 - media)^2 + (x2 - media)^2 + ... (xn - media)^2 ) / (N-1)
. Aunque algo liado, veamos el motivo y cuando usar una u otra función.
La diferencia entre una y otra es que pvariance()
supone que la lista de números que le pasamos es la población completa posible y variance()
supone que le estamos pasando sólo unos cuantos valores de esa población completa. Veamos un ejemplo para aclararlo. Si queremos calcular la varianza de las edad de la población española, la población sería una lista con todas las edades de todos los españoles, mientras que una muestra sería elegir una serie de españoles al azar y ver sus edades. Es decir, la población sería una lista de unos 47 millones de edades mientras que la muestra podrían ser solo 1000 edades, 10000 o el número de españoles al azar que elijamos para hacer nuestro muestreo.
La pvariance()
nos da el valor exacto de la población, puesto que cuenta con todas las muestras. La variance()
nos da una aproximación, puesto que solo cogemos un número de muestras de todas la población. Según qué muestras cojamos, pueden salir valores distintos. Si preguntas a 1000 españoles al azar su edad y echas las cuentas, saldrá un valor de media y de varianza. Si repites el experimento cogiendo otros 1000 españoles al azar, puede salirte un número distinto. Teniendo esto en cuenta, se comprueba que dividiendo entre N-1 la varianza de una muestra se obtiene una mejor aproximación de la varianza total de la población. Ver Varianza Muestral
>>> valores = [1,2,2,3,3]
>>> statistics.variance(valores)
0.7
>>> statistics.variance(valores,5)
10.5
Función stdev()[editar]
La función stdev()
calcula la desviación estándar o típica. Es la raíz cuadrada de la varianza. Nos indica igual que la varianza, la dispersión de los valores respecto a su media aritmética u otro valor (segundo parámetro de la función)
>>> valores = [1,2,2,3,3]
>>> statistics.stdev(valores)
0.8366600265340756
>>> statistics.stdev(valores,5)
3.24037034920393
Función pstdev()[editar]
La función pstdev()
es la raíz cuadrada de la pvariance()
. La diferencia entre pstdev()
y stdev()
es la misma que comentamos en el apartado variance()
. Tener toda la población completa de números o tener sólo una muestra de ellos.
>>> valores = [1,2,2,3,3]
>>> statistics.pstdev(valores)
0.7483314773547883
>>> statistics.pstdev(valores,5)
2.898275349237888
Función quantiles()[editar]
La función quantiles()
permite obtener intervalos "equiprobables" que contengan los números. Por defecto obtiene 4 intervales. Veamos y expliquemos con un ejemplo
>>> valores = [1,2,3,4,5,6,7,8]
>>> statistics.quantiles(valores)
[2.25, 4.5, 6.75]
Nos da tres valores, que corresponden a 4 intervalos: Por debajo de 2.25, entre 2.25 y 4.5, entre 4.5 y 6.75 y por encima de 6.75. Estos límites se han calculado de forma que el 25% de los valores caigan dentro de cada uno de los intervalos. Como tenemos 8 valores, el 25% de 8 son 2 valores. Cada intervalo tiene dos valores dentro. Hay dos valores, el 1 y el 2, por debajo de 2.25. Hay dos valores, el 3 y el 4, entre 2.25 y 4.5. Hay dos valores, el 5 y 6, entre 4.5 y 6.75. Y hay dos valores, el 7 y 4l 8, por encima de 6.75.
También se puede interpretar de forma "acumulativa". El 25% de los valores está por debajo de 2.25. El 50% de los valores está por debajo de 4.5. El 75% de los valores está por debajo de 6.75.
La función admite un segundo parámetro, n, si queremos hacer otro número de intervalos. Por defecto es 4, pero otro valor típico sería 100, para calcular percentiles.
>>> valores = range(1,200)
>>> statistics.quantiles(valores,n=100)
[2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 38.0, 40.0, 42.0, 44.0, 46.0, 48.0, 50.0, 52.0, 54.0, 56.0, 58.0, 60.0, 62.0, 64.0, 66.0, 68.0, 70.0, 72.0, 74.0, 76.0, 78.0, 80.0, 82.0, 84.0, 86.0, 88.0, 90.0, 92.0, 94.0, 96.0, 98.0, 100.0, 102.0, 104.0, 106.0, 108.0, 110.0, 112.0, 114.0, 116.0, 118.0, 120.0, 122.0, 124.0, 126.0, 128.0, 130.0, 132.0, 134.0, 136.0, 138.0, 140.0, 142.0, 144.0, 146.0, 148.0, 150.0, 152.0, 154.0, 156.0, 158.0, 160.0, 162.0, 164.0, 166.0, 168.0, 170.0, 172.0, 174.0, 176.0, 178.0, 180.0, 182.0, 184.0, 186.0, 188.0, 190.0, 192.0, 194.0, 196.0, 198.0]
Usando la función range()
hemos creado una lista de 1 a 200. Al hacer los quantiles()
con n=100
, estamos obteniendo 100 intervalos (99 valores) con un 1% de datos dentro cada uno, es decir, 2 valores cada uno. Hay 2 valores por debajo (o igual) de 2.0, el 1 y el 2. Dos valores entre 2.0 y 4.0, el 3 y el 4. Y así sucesivamente.
Función covariance()[editar]
La función covariance()
mide la covarianza de dos series de valores. La covarianza mide de alguna manera si ambas series de valores están relacionadas la una con la otra. Una covarianza de 0 indica que ambas series de valores son independientes. Una covarianza positiva indica que si una de las series de valores crece, la otra también, por lo que parece que hay una dependencia entre ellas. Y una covarianza negativa indica que si una serie crece la otra decrece, es decir, también hay dependencia entre ellas, pero inversa.
Veamos tres ejemplos
>>> v1 = [1,2,3]
>>> v2 = [1,2,3]
>>> statistics.covariance(v1,v2)
1.0
Covarianza positiva, ambas series tienden a crecer a la vez.
>>> v1 = [1,2,3]
>>> v2 = [3,2,1]
>>> statistics.covariance(v1,v2)
-1.0
Covarianza negativa, una serie crece, la otra decrece.
>>> import random
>>> v1 = random.sample([1,2,3,4,5,6,7,8,9,10], 5)
>>> v1
[4, 8, 1, 6, 10]
>>> v2 = random.sample([1,2,3,4,5,6,7,8,9,10], 5)
>>> v2
[4, 3, 9, 6, 10]
>>> statistics.covariance(v1,v2)
-0.15000000000000016
Hemos creado dos secuencias de números aleatorios de 5 números cada una elegidos entre el 1 y el 10 usando la función random.sample()
. Al elegirlos de forma aleatoria, teóricamente ambas series no tiene relacíón ninguna entre ellas. La covarianza sale -0.15, es decir, un valor más cercano a 0 que en los casos anteriores. Si tuvieramos secuencias de núemros aleatorios más grandes, posiblemente saldrían valores más cercanos a cero.
Funcion correlation()[editar]
La función correlation()
mide lo mismo que la función covariance()
pero con un pequeño matiz. Como hemos comentado, la función covariance()
mide si dos series de números están relacionadas entre ellas, dando valores positivos si cuando una crece, la otra también. Pero el valor que da depende mucho de los números, si son números que se distancian mucho de su valor medio, la covariance()
da valores grandes mientras que si la distancia con el valor medio es pequeña, la función covariance()
da valores menores.
La función correlation()
normaliza estos resultados, dando siempre un valor entre -1 y 1, independientemente de los números que compnen la serie. Veamos un ejemplo en que se comparan ambas funciones
>>> v1 = [1,10,100]
>>> v2 = [1,10,100]
>>> statistics.covariance(v1,v2)
2997.0
>>> statistics.correlation(v1,v2)
1.0
Función linear_regression()[editar]
La función linear_regression()
nos da la recta (pendiente y ordenada en el origen) que más se aproxima a dos secuencias de valores x,y. De forma que la ecuación de la recta y = pendiente*x + ordenada
nos permitiría obtener los valores de y estimados a partir de x. Vemaos un ejemplo
>>> x = [1,2,3,4]
>>> y = [3,5,7,9]
>>> pendiente,ordenada = statistics.linear_regression(x,y)
>>> pendiente
2.0
>>> ordenada
1.0
>>> pendiente*1 + ordenada
3.0
>>> pendiente*2 + ordenada
5.0
>>> pendiente*3 + ordenada
7.0
>>> pendiente*4 + ordenada
9.0
>>> pendiente*5 + ordenada
11.0
En este ejemplo los puntos x,y se ajustan exactamente a una recta, por lo que dado un valor de x, la fórmula y = pendiente*x + ordenada
nos devuelve el valor exacto de y. Veamos un ejemplo donde esta correspondencia no es tan exacta. Los valores de y serán como los del ejemplo anterior pero con un pequeño incremento/decremento.
>>> x = [1,2,3,4]
>>> y = [3.1, 4.9, 7.2, 8.4]
>>> pendiente,ordenada = statistics.linear_regression(x,y)
>>> pendiente
1.8199999999999998
>>> ordenada
1.3500000000000005
>>> pendiente*1 + ordenada
3.1700000000000004
>>> pendiente*2 + ordenada
4.99
>>> pendiente*3 + ordenada
6.81
>>> pendiente*4 + ordenada
8.629999999999999
>>> pendiente*5 + ordenada
10.45
Vemos que la recta obtenida da valores aproximados a los originales, pero no exactos.
Clase NormalDist[editar]
La clase NormalDist
representa una distribución normal o gaussiana. En este tipo de distribuciones hay un valor medio que es el más probable y según nos alejamos de él a valores menores o mayores, la probabilidad va descendiendo, sin llegar nunca a cero. Si representamos gráficamente la distribución, tiene forma de campana.
Al instanciar la clase, podemos pasar como parámetros el valor medio que queremos y la desviación típica de la distribución. Si no ponemos dichos valores, por defecto será media 0 y desviación típica 1. Una vez creada la clase podemos obtener valores aleatorios con ella que sigan la distribución normal.
>>> normal = statistics.NormalDist()
>>> normal.mean
0.0
>>> normal.median
0.0
>>> normal.stdev
1.0
>>> normal.variance
1.0
>>> normal.samples(10)
[-0.3179461891833272, 0.4094447046095158, -1.3440839031032044, 0.1642710642348059, -0.8410726745769876, 1.3449589904688415, -0.8587488199062069, 0.33496666979221845, -0.027277334192755638, 0.3612181145439156]
En el ejemplo hemos instanciado una distribución normal por defecto (media 0, desviación típica 1). Usando mean
, median
, stdev
y variance
vemos los valores de estas estadísticas para la distribución normal creada. Y finalmente, con samples(10)
obtenemos 10 valores aleatorios que cumplen dicha distribución.
Es posible también crear una intancia de esta clase a partir de valores concretos, de forma que la clase intentará estimar cual es la distribución normal en la que estarían los valores que le hemos pasado. Usando los valores generados, intentemos reconstruir la distribución normal.
>>> valores = [-0.3179461891833272, 0.4094447046095158, -1.3440839031032044, 0.1642710642348059, -0.8410726745769876, 1.3449589904688415, -0.8587488199062069, 0.33496666979221845, -0.027277334192755638, 0.3612181145439156]
>>> normal = statistics.NormalDist.from_samples(valores)
>>> normal.mean
-0.07742693773131844
>>> normal.median
-0.07742693773131844
>>> normal.stdev
0.7845398279225592
>>> normal.variance
0.6155027415967588
Hemos usando el método from_samples()
para obtener una distribución normal que se aproxime a los valores que le pasamos como parámetro. Si verificamos mean
, median
, stdev
y variance
vemos que se parecen a los originales 0 y 1, pero no son exactamente. Si usamos más muestras, tendríamos resultados más precisos. El siguiente ejemplo lo hace con 10000 valores.
>>> normal = statistics.NormalDist()
>>> valores = normal.samples(10000)
>>> normal_calculada = statistics.NormalDist.from_samples(valores)
>>> normal_calculada.mean
0.014790650775154342
>>> normal_calculada.median
0.014790650775154342
>>> normal_calculada.stdev
1.0020430728403373
>>> normal_calculada.variance
1.0040903198273057
Vemos que ahora se aproximan bastante más a 0 y 1.