Clase4 DG
Clase4 DG
Modelación de distribuciones e
introducción a las relaciones entre
variables
Curso:
Estadística para ciencia de datos
Profesor
Nicolás Alvarado
© Nicolás Alvarado
Clase Nº4:
Modelación de distribuciones e introducción a las
relaciones entre variables
Contenido
Resultado de aprendizaje de la clase u objetivos 2
Tema 1: Introducción 3
Tema 2: Distribución exponencial y distribución normal 3
2.1 Distribución exponencial 3
2.2 Distribución normal 8
Tema 3: Gráficas distribución lognormal 11
3.1 Distribuciones lognormal 11
3.2 Generación de números aleatorios 13
Tema 4: Diagramas de dispersión 15
Tema 5: Correlación 19
Tema 6: Ejercicios 19
Tema 7: Conclusión 20
Referencias bibliográficas 20
© Nicolás Alvarado
1
Resultado de aprendizaje de la clase u objetivos
Los modelos son útiles si capturan los aspectos relevantes del mundo real y dejan fuera datos
innecesarios. Posterior al estudio de esta clase, el alumno será capaz de distinguir cuando estos
datos son innecesarios y, de esta manera, podrá modelar distintos tipos de situaciones mediante el
uso de distribuciones.
© Nicolás Alvarado
2
Tema 1: Introducción
La mayoría de las distribuciones que hemos usado hasta ahora son llamadas distribuciones
empíricas debido a que se basan en observaciones empíricas, que son necesariamente muestras
finitas. La alternativa a esto es usar distribuciones analíticas, que son caracterizadas por una
función de distribución acumulada. Se le llama analítica por ser una función matemática, que
usualmente goza de buenas propiedades para hacer análisis (por ejemplo, diferenciabilidad,
continuidad, etc.).
Las distribuciones analíticas pueden ser usadas para modelar distribuciones empíricas. En este
contexto, un modelo es una simplificación del comportamiento de los datos que deja fuera
detalles innecesarios. En esta clase vamos a trabajar, principalmente, con distribuciones analíticas
comunes, pero de una manera menos formal y con más relación a la programación.
𝑃(𝑋 ≤ 𝑥) = ∫ 𝜆𝑒 −𝑡𝜆 𝑑𝑡
0
𝜆 −𝑡𝜆 𝑥
𝑃(𝑋 ≤ 𝑥) = − 𝑒 |0
𝜆
𝑃(𝑋 ≤ 𝑥) = 1 − 𝑒 −𝑥𝜆
NPara graficar en Python ambas funciones podemos hacer lo siguiente. Primero importamos los
módulos necesarios para usar la distribución exponencial:
import numpy as np
from numpy import random
import seaborn as sns
Luego:
for x in [10,100,1000,10000]:
sns.distplot(random.exponential(size=x), hist=False)
plt.show()
© Nicolás Alvarado
3
Así, obtenemos lo mostrado en la siguiente figura:
thinkplot.PrePlot(5)
for x in [4,3,2,1, 0.5]:
xs, ps = thinkstats2.RenderExpoCdf(x, 0, 2.0, 50)
label = r"$\lambda=%g$" % x
thinkplot.Plot(xs, ps, label=label)
thinkplot.Config(title="Función de Distribución Acumulada Exponencial",
xlabel="x", ylabel="CDF", loc="lower right")
© Nicolás Alvarado
4
De esta forma, obtenemos:
Como ejemplo, estudiemos el tiempo entre llegadas de los nacimientos. En diciembre 18 de 1997,
44 personas nacieron en un hospital en Brisbane, Australia. El tiempo de nacimiento de los 44
infantes fue reportado y el dataset completo se encuentra en el archivo babyboom.dat disponible
en el siguiente enlace: https://github.com/AllenDowney/ThinkStats2.
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/nsfg.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/analytic.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/babyboom.dat")
import analytic
df = analytic.ReadBabyBoom()
diffs = df.minutes.diff()
cdf = thinkstats2.Cdf(diffs, label="actual")
thinkplot.Cdf(cdf)
thinkplot.Config(xlabel="Tiempo entre nacimientos (minutos)", ylabel="CDF")
© Nicolás Alvarado
5
Figura 3: CDF del tiempo entre nacimientos
Fuente: Elaboración propia
NReadBabyBoom lee el archivo de los datos y retorna un dataframe con las columnas tiempo,
género, peso y minutos, donde los minutos son el tiempo de nacimiento convertido a minutos
desde medianoche. La variable diffs está definida de tal forma de que podamos contar la
diferencia entre tiempos de nacimientos consecutivos, y la variable cdf es por supuesto la
distribución de los tiempos de llegada.
En la figura anterior podemos ver que la gráfica se parece bastante a la de la función exponencial,
pero ¿cómo podemos estar seguros? Supongamos que 𝑦 = 1 − 𝑒 −𝜆𝑥 , entonces:
𝑦 = 1 − 𝑒 −𝜆𝑥
𝑦 ≈ 𝑒 −𝜆𝑥
log 𝑦 ≈ −𝜆𝑥
Esta es la función inversa del complemento de la CDF de la exponencial. Aquí, con el complemento
de CDF(x) nos referimos a 1-CDF(x). ¿Por qué estamos haciendo este cambio de variable? El
graficar el complemento de la CDF de la exponencial nos permitirá responder a la pregunta sobre
la gráfica anterior.
Para datos de una distribución exponencial, el resultado es una línea recta (¿por qué?). Si
graficamos el complemento de la CDF exponencial de un dataset que creemos que es exponencial,
deberíamos tener una función como la anteriormente calculada. Pero notemos qué nos arroja el
siguiente código:
© Nicolás Alvarado
6
thinkplot.Cdf(cdf, complement=True)
thinkplot.Config(
xlabel="Tiempo entre nacimientos (minutos)",
ylabel="Complemento de la CDF",
yscale="log",
loc="upper right",
)
Podemos ver en la figura anterior que el resultado no es exactamente una línea recta, lo que
indica que la distribución exponencial no es un modelo perfecto para estos datos. Lo más probable
es que la suposición, de que un nacimiento es igualmente probable en cualquier momento del día,
no sea exactamente cierta. Sin embargo, podría ser razonable modelar este conjunto de datos con
una distribución exponencial. Con esa simplificación, podemos resumir la distribución con un solo
parámetro.
El parámetro λ puede ser interpretado como una razón; es decir, el número de eventos que
ocurren, en promedio, en una unidad de tiempo. En el ejemplo anterior 44 nacimientos ocurrieron
en 24 horas. Por lo tanto, podemos deducir que la media entre los nacimientos es de 32,7
minutos.
© Nicolás Alvarado
7
2.2 Distribución normal
En esta sección estudiaremos la gráfica y el comportamiento estadístico de la distribución normal
usando Python, más que su estructura teórica. Recordemos que la distribución normal es
caracterizada por dos parámetros, la media 𝜇 y la varianza 𝜎 2 . Si usamos 𝜇 = 0 y 𝜎 = 1 estamos
hablando de la distribución normal estándar. La función de distribución acumulada está definida
por:
𝑥
1 2 ⁄2
Φ(𝑥) = ∫ 𝑒 −𝑡 𝑑𝑡
√2𝜋
−∞
Existen algoritmos para evaluar Φ(𝑥), en Python, de una manera eficiente. Uno de ellos lo da
SciPy: scipy.stats.norm es un objeto que representa la distribución normal; provee un método, cdf,
que evalúa la CDF normal estándar. Por ejemplo,
Noimport scipy.stats
scipy.stats.norm.cdf(0)
arroja 0,5. Este resultado es correcto ya que la mediana de la distribución normal estandarizada es
0 (al igual que la media), y la mitad de los valores caen debajo de la media, lo que nos dice que
CDF(0) es 0,5.
mus = [0, 1, 2, 3, 4]
© Nicolás Alvarado
8
Figura 5: CDF de distribuciones normales
Fuente: Elaboración propia
import nsfg
import first
Finalmente, estimamos los parámetros recortando los outliers para producir un mejor ajuste y
graficamos.
mu, var = thinkstats2.TrimmedMeanVar(weights, p=0.01)
print("Media, Varianza", mu, var)
© Nicolás Alvarado
9
sigma = np.sqrt(var)
print("Sigma", sigma)
xs, ps = thinkstats2.RenderNormalCdf(mu, sigma, low=0, high=12.5)
thinkplot.PrePlot(1)
thinkplot.Cdf(cdf)
thinkplot.Config(title="Pesos de los nacimientos",
xlabel="Pesos en libras", ylabel="CDF")
Lo anterior nos arroja lo mostrado en la siguiente figura. Además, el output anterior nos dice que:
Notemos que bajo el percentil 10 existe una diferencia entre los datos y el modelo; una de las
curvas está por sobre la otra. Específicamente, esto nos dice que hay nacimientos más livianos de
los que podríamos esperar en una distribución normal. Si estamos interesados en los nacimientos
prematuros, sería importante mencionar esta parte de la distribución como un dato con peso. Esto
implica que podría no ser apropiado usar el modelo de la distribución normal.
© Nicolás Alvarado
10
Tema 3: Gráficas distribución lognormal
Si el logaritmo de un conjunto de valores tiene distribución normal, los valores tienen una
distribución log-normal. Su función de probabilidad es de la forma:
1 ln(𝑥 − 𝜇)2
𝑃(𝑋 = 𝑥) = exp (− )
𝑥𝜎√2𝜋 2𝜎 2
De lo anterior es posible deducir que la CDF de la log-normal es la misma que la CDF de la normal,
con la única distinción de que sustituimos 𝑥 por 𝑙𝑜𝑔 𝑥, es decir 𝑃(𝑋 ≤ 𝑥) = 𝛷(𝑙𝑛 𝑥 − 𝜇)/(𝛷(
𝑙𝑜𝑔 (𝑥) − 𝜇)/𝜎)).
import brfss
df = brfss.ReadBrfss()
weights = df.wtkg2.dropna()
Definamos una función para estimar los parámetros de una distribución normal y para graficar los
datos y un modelo normal.
def MakeNormalModel(weights):
cdf = thinkstats2.Cdf(weights, label="pesos")
mean, var = thinkstats2.TrimmedMeanVar(weights)
std = np.sqrt(var)
print("n, mean, std", len(weights), mean, std)
MakeNormalModel(weights)
thinkplot.Config(
title="Escala lineal, peso adultos",
xlabel="Peso en kilos",
ylabel="CDF",
© Nicolás Alvarado
11
loc="upper right",
)
Con el siguiente código podemos crear un gráfico normal. Usaremos el peso de los adultos.
def MakeNormalPlot(weights):
xs = [-5, 5]
xs, ys = thinkstats2.FitLine(xs, mean, std)
thinkplot.Plot(xs, ys, color="0.8", label="modelo")
xs, ys = thinkstats2.NormalProbability(weights)
thinkplot.Plot(xs, ys, label="peso")
MakeNormalPlot(log_weights)
© Nicolás Alvarado
12
thinkplot.Config(
title="Peso adultos, gráfica lognormal",
xlabel="Peso en log kg",
ylabel="CDF",
loc="upper left",
)
De la comparación anterior podemos notar la diferencia entre ambas gráficas. Es claro que el
ajuste lognormal, en este caso, es mucho más preciso que el normal.
Las funciones analíticas de distribución acumulada pueden ser usadas para generar números
aleatorios con una función de distribución dada, 𝑝 = 𝐶𝐷𝐹(𝑥).
Si existe una forma eficiente de calcular la inversa de una CDF, podemos generar valores aleatorios
con la distribución apropiada. Esto se hace escogiendo p de una distribución uniforme entre 0 y 1,
y luego tomando 𝑥 = 𝐼𝐶𝐷𝐹(𝑝). Por ejemplo, recordemos que la CDF de la distribución
exponencial está dada por 𝑝(𝑥) = 1 − 𝑒 −𝑥𝜆 . Luego, al despejar x se tiene 𝑥 = − 𝑙𝑜𝑔 (1 − 𝑝)/𝜆 .
Ahora, para usar esto en Python importamos el módulo random y numpy (as np) y luego definimos
la siguiente función
def expovariate(lam):
p = random.random()
x = -np.log(1-p)/lam
return x
© Nicolás Alvarado
13
La función expovariate toma el parámetro lambda (lam) y retorna un valor aleatorio escogido de la
distribución exponencial con parámetro lam. Por otra parte, para mostrar gráficamente que está
pasando ejecutamos el siguiente código
cdf = thinkstats2.Cdf(t)
thinkplot.Cdf(cdf, complement=True)
Por otra parte, los modelos analíticos son una forma de comprimir datos. Cuando un modelo se
ajusta a un dataset de buena manera, un conjunto pequeño de parámetros puede resumir una gran
cantidad de datos. A veces resulta sorprendente cuando los datos de un fenómeno natural se
ajustan a una distribución analítica, pero esas observaciones pueden dar información sobre los
sistemas físicos. A veces podemos explicar cuando una distribución tiene una forma en particular.
© Nicolás Alvarado
14
Por ejemplo, consideremos la siguiente función de distribución acumulada 𝐶𝐷𝐹(𝑥) = 1 −
(𝑥/𝑥𝑚 )𝛼 . En la fórmula anterior los parámetros 𝑥𝑚 y 𝛼 determinan la ubicación y la forma de la
distribución. El primer parámetro es el mínimo valor posible. Esta CDF es la función de distribución
acumulada de Pareto.
xmin = 0.65
thinkplot.PrePlot(5)
La distribución anterior se llama distribución de Pareto. Las distribuciones de Pareto son a menudo
el resultado de procesos generativos con retroalimentación positiva (los llamados procesos de
apego preferencial). También, las distribuciones analíticas nos llevan a usar herramientas de análisis
matemático, pero vale la pena recordar que todos los modelos son imperfectos. Los datos del
mundo o la vida real nunca se ajustarán a una distribución analítica de manera perfecta. Los modelos
son útiles si capturan los aspectos relevantes del mundo real y dejan fuera los detalles innecesarios.
Pero dado este punto es natural preguntarse qué es relevante o innecesario. Esto, por lo general,
depende explícitamente en que se quiera hacer con el modelo.
Hasta ahora solo hemos mirado una variable de manera simultánea. En esta sección veremos la
relación entre dos variables. Dos variables están relacionadas si conociendo una, nos proporciona
información sobre la otra. Por ejemplo, peso y altura están relacionadas; las personas que son más
altas tienden a ser más pesadas. Es claro eso sí, que no es una relación perfecta ya que existe gente
pequeña que es pesada como también personas altas que son livianas. Pero si uno quiere intentar
adivinar el peso de una persona, sería más acertado sabiendo la altura de ella.
Una de las maneras más usuales y fáciles para estudiar la relación entre dos variables es hacer
diagramas de dispersión. Lamentablemente esto no siempre es sencillo. Usemos el siguiente
© Nicolás Alvarado
15
ejemplo. Comencemos por descargar los datos del Sistema de Vigilancia de Factores de Riesgo del
Comportamiento (BRFSS).
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/brfss.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/CDBRFS08.ASC.gz")
import brfss
df = brfss.ReadBrfss(nrows=None)
return sample
Esta función nos permite tomar un subconjunto aleatorio del dataset. Ahora usando lo siguiente,
definimos las variables altura y peso:
thinkplot.Config(xlabel='Altura (cm)',
ylabel='Peso (kg)',
axis=[140, 210, 20, 200],
legend=False)
El resultado de este código se ve en la siguiente figura y podemos notar como cierta cantidad de
puntos se acumulan en una parte de la gráfica. Podemos decir de esto que de alguna manera las
variables presentan una correlación.
© Nicolás Alvarado
16
Figura 10: Correlación entre peso y altura
Fuente: Elaboración propia
© Nicolás Alvarado
17
Figura 11: Correlación entre peso y altura con mayor muestra
Fuente: Elaboración propia
¿Existe alguna relación entre las gráficas mostradas? ¿Cuál es la diferencia principal al ir
aumentando el tamaño de la muestra? Los datos se agrupan en columnas ya que están
redondeados. Se puede reducir este efecto agregando algo de ruido aleatorio a los datos. Una
opción natural es usar la función Jitter.
La función Jitter, en ThinkStats, usa ruido con una distribución uniforme. Cambiemos un poco esto
usando una distribución normal:
n = len(values)
return np.random.normal(0, jitter, n) + values
La distribución normal hace un mejor trabajo dando una visión más borrosa, en cambio la
distribución uniforme puede ser más acertada respecto a los datos.
thinkplot.Config(xlabel='Altura (cm)',
ylabel='Peso (kg)',
axis=[140, 210, 20, 200],
legend=False)
En la medida que aumentamos el ruido las columnas desaparecen. Dado esto, surge un problema
nuevo: saturación. La saturación se puede ver en los sectores donde queda una cantidad excesiva
de puntos solapados. Si graficamos lo anteriormente mencionado las gráficas no serán tan oscuras
© Nicolás Alvarado
18
como debiesen ser, lo que significa que los outliers son más oscuros de lo que deberían ser. Lo
anterior hace que pensemos en que los datos están más dispersos de lo que en realidad están.
Tema 5: Correlación
Una correlación es un estadístico que mide la relación entre dos variables. El desafío en medir una
correlación es que las variables que queremos comparar a menudo no tienen las mismas unidades.
Incluso si tienen las mismas, es altamente probable que tengan diferentes distribuciones. Hay dos
soluciones comunes para estos problemas: transformar cada valor a su puntaje estándar, que es el
número de desviaciones estándar de la media. Esta transformación nos permite definir la
correlación de Pearson. Transformar cada valor a su rango, que es indexarlo en una lista ordenada
de valores. Dado esto, podemos definir la correlación de Spearman.
Si 𝑋 es una serie de 𝑛 valores, 𝑥𝑖 , podemos convertir cada uno de ellos a sus puntajes estándar
haciendo la siguiente transformación: 𝑧 = (𝑥𝑖 − 𝜇)/𝜎. En la fórmula anterior, 𝜇 es la media y 𝜎 la
desviación estándar.
Tema 6: Ejercicios
• Las distribuciones de riqueza e ingresos son modeladas a veces usando las distribuciones
Pareto y lognormal. Compárelas usando la Current Population Survey (CPS) que se
encuentra en el repositorio del libro principal del curso.
© Nicolás Alvarado
19
Tema 7: Conclusión
En esta clase estudiamos a fondo la distribución exponencial y la distribución normal. Además, se
habló sobre la distribución lognormal y su relación con la distribución normal. Por otra parte, se
trabajó la manipulación de código para la gráfica de funciones de distribución acumulada. Además,
se introdujeron los diagramas de dispersión con el fin de comenzar a estudiar relación, y aún más,
correlación entre dos variables.
Referencias bibliográficas
© Nicolás Alvarado
20