Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Curso:
Estadística para ciencia de datos
Profesor
Nicolás Alvarado
© Nicolás Alvarado
Clase Nº5:
Relación entre variables, correlación y una
introducción al testeo de hipótesis
Contenido
Resultado de aprendizaje de la clase u objetivos 2
Tema 1: Introducción 3
Tema 2: Covarianza 3
2.1 Correlación de Pearson y causalidad 4
2.1.1 Correlación y causalidad 6
Tema 3: Testeo de hipótesis 7
Tema 4: Diferencia de medias 10
Tema 5: Formalización 12
Tema 6: Ejercicios 14
Tema 7: Conclusión 15
Referencias bibliográficas 15
© Nicolás Alvarado
1
Resultado de aprendizaje de la clase u objetivos
Luego del estudio de esta clase, el alumno tendrá un entendimiento sobre la relación entre
variables, y podrá caracterizar algebraica y geométricamente las relaciones. A partir de esto, tendrá
nociones de inferencia estadística.
© Nicolás Alvarado
2
Tema 1: Introducción
Tema 2: Covarianza
𝑑𝑥𝑖 = 𝑥𝑖 − 𝑥
𝑑𝑦𝑖 = 𝑦𝑖 − 𝑦
Si multiplicamos las diferencias, el producto es positivo cuando las desviaciones tienen el mismo
signo y negativo en caso contrario. Entonces, al sumar los productos obtenemos una medida de la
variación conjunta. Definimos entonces la covarianza como la media de estos productos:
1
𝐶𝑜𝑣(𝑋, 𝑌) = ∑ 𝑑𝑥𝑖 𝑑𝑦𝑖
𝑛
donde 𝑛 es el largo de las series X e Y.
def download(url):
filename = basename(url)
if not exists(filename):
from urllib.request import urlretrieve
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/thinkstats2.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/thinkplot.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/brfss.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/CDBRFS08.ASC.gz")
import numpy as np
import thinkstats2
import thinkplot
import brfss
df = brfss.ReadBrfss(nrows=None)
cleaned = df.dropna(subset=['htm3', 'wtkg2'])
© Nicolás Alvarado
3
def Cov(xs, ys, meanx=None, meany=None):
xs = np.asarray(xs)
ys = np.asarray(ys)
if meanx is None:
meanx = np.mean(xs)
if meany is None:
meany = np.mean(ys)
La función Cov calcula las desviaciones de las medias muestrales. Si 𝑥𝑠 e 𝑦𝑠 son sucesiones
definidas en Python, np.asarray las convierte a NumPy arrays. Si ya son NumPy arrays,
entonces np.asarray no hace nada. Esta implementación de la covarianza pretende ser simple,
dado que se quiere explicar el concepto.
NumPy y Pandas también cuentan con implementaciones de la covarianza, pero ambas aplican
una corrección para tamaños muestrales pequeños que no han sido cubiertos aún, y np.cov
retorna una matriz de covarianza, lo que por ahora no necesitamos.
La covarianza es útil en algunos cálculos, pero se sabe que pocas veces se usa como estadístico de
resumen ya que su interpretación, por lo general, es compleja. Dentro de otros problemas, sus
unidades son el producto de las unidades de X e Y. Por ejemplo, la covarianza de los pesos y de las
alturas del BRFSS es 113kg-cm. ¿Qué significa esto? Una solución para este problema es dividir las
desviaciones por la desviación estándar y calcular el producto de los puntajes estándar:
𝐶𝑜𝑣(𝑋, 𝑌)
𝜌=
𝑆𝑋 𝑆𝑌
Corr(heights,weights)
0.5087364789734768
Este número indica que tenemos una correlación moderadamente fuerte entre los pesos y las
alturas de la BRFSS. En la función anterior, MeanVar calcula la media y la varianza levemente mejor
que np.mean y np.var.
Un aspecto importante es que el coeficiente de correlación de Pearson está entre menos y uno,
incluyéndolos. Si 𝜌 > 0, entonces diremos que la correlación es positiva, esto significa que cuando
una variable crece, la otra también. En caso contrario, 𝜌 < 0, diremos que la correlación es negativa,
lo que implica que cuando una variable aumenta su valor, la otra tiende a disminuir.
Si la correlación de Pearson está alrededor de 0, es tentador concluir que no existe una relación
entre las variables, pero esa conclusión no es válida. La correlación de Pearson sólo mide relaciones
lineales (de hecho, se puede obtener una forma circular en la distribución de los puntos cuando la
correlación es casi nula). Si existe una relación no lineal, 𝜌 indica que tan fuerte es. De hecho, se
puede tener alguna idea sobre la correlación dependiendo su forma. Como mencionamos
anteriormente, si esta tiene la forma de una recta, ya sea de pendiente positiva o negativa, entonces
está cercana a menos 1 o uno. En cambio, si es cercana a 0 esta puede deformarse y producir un
círculo, una elipse, un cuadrado, entre otros. Lo importante es que no siempre se puede obtener
toda la información a partir del diagrama de dispersión.
El coeficiente de correlación de Pearson funciona bien si la relación entre las variables es lineal y si
las variables distribuyen parecidamente a una distribución normal. Pero, no es robusto en la
presencia de outliers. El coeficiente de correlación de Spearman es una alternativa que mitiga el
efecto de los outliers y las distribuciones sesgadas.
© Nicolás Alvarado
5
Para calcular la correlación de Spearman, necesitamos calcular el rango de cada valor, que es el
índice en la muestra de la ordenada. Por ejemplo, en la muestra [1,2,5,7] el rango del valor 5 es 3,
ya que aparece tercero en la lista ordenada. Entonces, calculamos el coeficiente de correlación de
Pearson para los rangos. El módulo thinkstats2 tiene una función que nos permite calcular la
correlación de rango de Spearman. Para usarlo, hacemos lo siguiente:
import pandas as pd
SpearmanCorr(heights,weights)
0.5405846262320481
Notemos que la correlación de rango de Spearman para el BRFSS es aproximadamente 0,54, que es
un poco mayor de lo que habíamos obtenido calculando el coeficiente de correlación de Pearson
(∼ 0,51). Existen muchas razones para la diferencia, incluyendo las siguientes:
Si las variables A y B están correlacionadas, existen tres posibilidades para explicar su correlación:
• A causa a B.
• B causa a A.
• Algún otro conjunto de factores causa a ambas variables A y B.
Estas explicaciones se llaman relaciones causales. La correlación por sí sola no distingue entre estas
explicaciones, entonces no se sabe cuál de ellas es verdad.
© Nicolás Alvarado
6
se puede eliminar las relaciones espurias. Esto funciona incluso cuando no se sabe cuáles
son las variables relevantes.
Estas ideas son la motivación para los ensayos aleatorios controlados, en los que los sujetos son
asignados aleatoriamente a dos o más grupos: un grupo de tratamiento que recibe cierto tipo de
intervención, como una nueva medicina, y un grupo control que no recibe intervención o recibe
otro tratamiento cuyos efectos son conocidos.
Explorando los datos de la NSFG vimos muchos efectos aparentes, incluyendo diferencias entre los
nacimientos primerizos y otros. Hasta ahora vemos todos esos efectos como valores de fantasía; en
esta sección los pondremos a prueba.
La pregunta fundamental que queremos abordar es cuándo estos efectos que vemos en una
muestra son probables que aparezcan en toda la población. Por ejemplo, en la muestra de la NSFG
vemos una diferencia entre la media de la duración del embarazo para los nacimientos primerizos
versus los otros. Nos gustaría saber si el efecto refleja una diferencia real para mujeres en los
Estados Unidos, o si podría aparecer en la muestra por casualidad. Hay muchas formas en las que
podemos formular esta pregunta, incluyendo el test de hipótesis nula de Fisher, la teoría de decisión
de Neyman-Pearson, y la inferencia Bayesiana. Lo que presentaremos acá es un subconjunto de
estas tres opciones y lo llamaremos testeo de hipótesis clásico.
El objetivo del testeo de hipótesis clásico es, dada una muestra y un efecto aparente, responder a
la pregunta: ¿Cuál es la probabilidad de ver un efecto por casualidad? Veamos cómo responderla:
• El primer paso es cuantificar el tamaño del efecto aparente eligiendo un test estadístico. En
el ejemplo de la NSFG, el efecto aparente es una diferencia en la duración del embarazo
primerizo y otros, entonces una elección natural para el test estadístico es la diferencia en
la media entre los dos grupos.
• El segundo paso es definir una hipótesis nula, que es un modelo del sistema basado en
asumir que el efecto aparente no es real. En el ejemplo de la NSFG, la hipótesis nula es que
no existe diferencia entre los nacimientos primerizos y otros, esto es, que la duración del
embarazo para ambos grupos se distribuye de igual manera.
© Nicolás Alvarado
7
• El tercer paso es calcular un valor p, que es la probabilidad de ver el efecto aparente si la
hipótesis nula es cierta. En el ejemplo de la NSFG, podríamos calcular la diferencia real de
medias, luego calcular la probabilidad de ver una diferencia grande bajo la hipótesis nula.
• El último paso es interpretar el resultado. Si el valor p es bajo, entonces el efecto se dice que
es estadísticamente significante, lo que significa que es poco probable que haya ocurrido por
casualidad. En ese caso inferiremos que el efecto es más probable que aparezca en la
población.
La lógica de este proceso es similar a una demostración por contradicción. Para probar una
afirmación matemática, A, se asume temporalmente que A es falso. Si el hecho de asumir lleva a un
absurdo, se concluye que realmente A debe ser cierta. Similarmente, en un test de hipótesis del tipo
el efecto es real, asumimos que, temporalmente, no lo es. Esa es la hipótesis nula. Basado en lo que
se asume, calculamos la probabilidad del efecto aparente y si es baja, concluimos que la hipótesis
nula no debe ser cierta.
class HypothesisTest(object):
def MakeModel(self):
pass
def RunModel(self):
raise UnimplementedMethodException()
La clase HypothesisTest es una clase padre abstracta que da definiciones completas para algunos
métodos y fija a otros. Las clases hijas basadas en HypothesisTest heredan el constructor
__init__ y PValue da TestStatistic, RunModel, y opcionalmente MakeModel. El constructor
toma los datos en la forma que sea apropiada. Llama a MakeModel, que construye una
representación de la hipótesis nula, entonces pasa los datos a TestSTatistic, que calcula el
tamaño del efecto en la muestra.
© Nicolás Alvarado
8
El método PValue calcula la probabilidad del efecto aparente bajo la hipótesis nula. Toma el
parámetro iters, que es el número de simulaciones que se correrán. La primera línea genera los
datos simulados, calcula los test estadísticos, y los guarda en test_stats. El resultado es la fracción
de elementos en test_stats que excede o iguala los tests estadísticos observados, self.actual.
A modo de ejemplo, supongamos que lanzamos una moneda 250 veces y que vemos 140 caras y
110 sellos. Basados en ese resultado, podemos suponer que la moneda está cargada; es decir, que
tiene más probabilidad de que al lanzarla caiga en cara. Para testear esta hipótesis, calculamos la
probabilidad de ver tal diferencia si la moneda es realmente justa:
class CoinTest(HypothesisTest):
def RunModel(self):
heads, tails = self.data
n = heads + tails
sample = [random.choice('HT') for _ in range(n)]
hist = thinkstats2.Hist(sample)
data = hist['H'], hist['T']
return data
El parámetro data es un par de enteros, el número de caras y sellos. El test estadístico es la diferencia
(en valor absoluto) entre ellos (en este caso self.actual es 30).
ct = CoinTest((140, 110))
pvalue = ct.PValue()
pvalue
El resultado obtenido es alrededor de 0,07, lo que significa que, si la moneda es justa, esperamos
ver una diferencia tan grande como 30 alrededor del 7% del tiempo. ¿Cómo deberíamos interpretar
este resultado? Por convención, 5% es el umbral de significancia estadística. Si el valor p es menor
que 5%, el efecto es considerado significante; de otra forma, no. Pero, la elección de este 5% es
arbitraria, y el valor p depende en la elección del test estadístico y del modelo de la hipótesis nula.
Entonces el valor p no debería ser considerado una medida precisa.
© Nicolás Alvarado
9
Tema 4: Diferencia de medias
Uno de los efectos más comunes para testear es la diferencia de medias entre dos grupos. En los
datos de la NSFG, vimos que la media en la duración del embarazo para los primerizos es un poco
mayor, y que la media del peso al nacer es un poco menor. Ahora veremos si estos efectos son
estadísticamente significantes. Para estos ejemplos, la hipótesis nula es que la distribución de
ambos grupos es la misma. Una manera de modelar la hipótesis nula es por permutación; esto es,
que podemos tomar valores para los nacimientos primerizos y los otros, y luego mezclarlos tratando
a estos dos grupos como uno solo más grande.
class DiffMeansPermute(thinkstats2.HypothesisTest):
def MakeModel(self):
group1, group2 = self.data
self.n, self.m = len(group1), len(group2)
self.pool = np.hstack((group1, group2))
def RunModel(self):
np.random.shuffle(self.pool)
data = self.pool[:self.n], self.pool[self.n:]
return data
El parámetro data es un par de sucesiones, una de cada grupo. Este test estadístico es la diferencia
absoluta en las medias.
El método MakeModel guarda los tamaños de los grupos, n y m, y combina estos grupos en un solo
arreglo NumPy, self.pool. El método RunModel simula la hipótesis nula al mezclar los valores
agrupados y separándolos en dos grupos de tamaños n y m. Como siempre, el valor a retornar de
RunModel tiene el mismo formato que los datos observados. Para testear la diferencia corremos lo
siguiente:
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/nsfg.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/first.py")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/2002FemPreg.dct")
download("https://github.com/AllenDowney/ThinkStats2/raw/master/code/2002FemPreg.dat.gz")
© Nicolás Alvarado
10
live, firsts, others = first.MakeFrames()
data = firsts.prglngth.values, others.prglngth.values
# Calculamos
ht = DiffMeansPermute(data)
pvalue = ht.PValue()
pvalue
El método MakeFrames lee los datos de la NSFG y retorna DataFrames representando todos los
nacimientos exitosos, primerizos y otros. De los datos extraemos la duración de los embarazos como
NumPy arrays, los pasamos como datos a DiffMEansPermute, y calculamos el valor p. Este resultado
es un poco menor que 0,17, lo que significa que esperamos ver una diferencia tan grande como el
efecto observado alrededor del 17% del tiempo. Entonces este efecto no es estadísticamente
significante.
El método HypothesisTest tiene la función PlotCdf, que grafica la distribución del test estadístico
y una línea gris que indica el tamaño del efecto observado:
ht.PlotCdf()
thinkplot.Config(xlabel='Test Estadístico',
ylabel='CDF')
© Nicolás Alvarado
11
Tema 5: Formalización
Formalicemos matemáticamente todo lo que hemos visto hasta el momento acerca de testeo de
hipótesis. Comencemos con una definición:
“Una hipótesis es una afirmación sobre el parámetro poblacional” (Downey A., 2014).
Esta definición de hipótesis es general, pero el punto importante es que se hace una afirmación
sobre la población. El objetivo de un test de hipótesis es decidir, basado en una muestra de la
población, cual de dos hipótesis complementarias es cierta.
Aquí, 𝛩0 es algún subconjunto del espacio de parámetros y 𝛩0𝑐 es su complemento. Por ejemplo, si
𝜃 denota el cambio promedio en la presión de la sangre de un paciente luego de tomar un remedio,
un experimento podría ser el estar interesados en testear 𝐻0 ∶ 𝜃 = 0 versus 𝐻1 ∶ 𝜃 ≠ 0. La
hipótesis nula dice que, en promedio, el remedio no tiene efecto en la presión de la sangre, y una
hipótesis alternativa dice que existe algún efecto. Esta situación común, en la cual 𝐻0 plantea un
tratamiento sin efecto ha llevado a que se llame hipótesis nula.
1. Para cuales valores muestrales la decisión se hace para aceptar 𝐻0 como verdadera.
El subconjunto del espacio muestral para el cual 𝐻0 será rechazada se llama región de rechazo. El
complemento de la región de rechazo se llama región de aceptación. Estudiemos un método general
para encontrar un test.
© Nicolás Alvarado
12
Dada una muestra x definimos a la función de verosimilitud como:
𝑠𝑢𝑝𝛩0 𝑙(𝜃|𝑥)
𝜆(𝑥) =
𝑠𝑢𝑝𝛩 𝑙(𝜃|𝑥)
Un test de máxima verosimilitud es cualquier test que tenga una región de rechazo de la forma
{𝑥: 𝜆(𝑥) ≤ 𝑐} donde c está en el intervalo unitario.
Una forma de usar este test en Python en la siguiente. Primero importamos las funciones
necesarias para definir la razón de verosimilitud:
Luego,
l1 = 43421
l2 = 43424
lR = likelihood_ratio(l1,l2)
p = chi2.sf(lR, 1)
Lo que hicimos al final fue calcular la razón usando el test de chi cuadrado.
Si tenemos alguna razón para pensar que los primerizos son más propensos a atrasarse, entonces
podríamos no tomar el valor absoluto de la diferencia; entonces usaremos el siguiente estadístico
de prueba:
class DiffMeansOneSided(DiffMeansPermute):
© Nicolás Alvarado
13
return test_stat
Donde la clase DiffMeansOneSided hereda los métodos MakeModel y RunModel; la única diferencia
es que TestStatistic no toma el valor absoluto de la diferencia. Este tipo de test se llama one-
sided ya que solo cuenta un lado de la distribución de diferencias. El test de diferencias que vimos
anteriormente, usando ambos lados, es two-sided. Para esta versión del test el valor p es 0,1. En
general, el valor p de un test one-sided es alrededor de la mitad del valor p del two-sided test,
dependiendo de la forma de la distribución.
La hipótesis one-sided, que dice que los primerizos nacen tarde, es más específica que la hipótesis
two-sided, entonces el valor p es más pequeño. Pero incluso para hipótesis más fuertes, la diferencia
no es estadísticamente significante.
ht = DiffMeansOneSided(data)
pvalue = ht.PValue()
pvalue
Tema 6: Ejercicios
• Usando los datos de la NSFG, haga un diagrama de dispersión de los pesos de nacimiento
versus la edad de la madre. Grafique percentiles del peso de nacimiento versus la edad
de la madre. Luego, calcule la correlación de Pearson y Spearman. ¿Cómo podría
caracterizar la relación entre las variables? Repita el ejercicio para:
© Nicolás Alvarado
14
estimates = []
for _ in range(iters):
# defina su variable exponencial xs
lamhat = 1.0 / np.mean(xs)
estimates.append(lamhat)
return stderr
SimulateSample()
• Mientras el tamaño de una muestra crece, la potencia del test de hipótesis también. Esto
significa que es más probable que sea positivo si el efecto es real. Conversamente se
sigue la idea si decrece. Para investigar este comportamiento, corra los test de este
capítulo con diferentes subconjuntos de los datos de la NSFG. Use
thinkstats2.SampleRows para seleccionar un subconjunto aleatorio de las filas en un
DataFrame. ¿Qué pasa con los valores p cuando el tamaño de la muestra decrece? ¿Cuál
es el tamaño de la muestra que deja un test positivo?
Tema 7: Conclusión
Referencias bibliográficas
© Nicolás Alvarado
15