Amostragem

Amostrando sub-conjuntos de dados de forma inteligente.

Resultados Esperados

  1. Rever pequenos códigos de diferentes tipos de amostragem
  2. Entender amostragem uniforme e estratificada.

Sumário

  1. Introdução
  2. Problema de Poucas Amostras em uma Estatística
  3. Qual o motivo de simular?

#In: 
# -*- coding: utf8

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#In: 
plt.style.use('seaborn-colorblind')

plt.rcParams['figure.figsize']  = (16, 10)
plt.rcParams['axes.labelsize']  = 20
plt.rcParams['axes.titlesize']  = 20
plt.rcParams['legend.fontsize'] = 20
plt.rcParams['xtick.labelsize'] = 20
plt.rcParams['ytick.labelsize'] = 20
plt.rcParams['lines.linewidth'] = 4
#In: 
plt.ion()
#In: 
def despine(ax=None):
    if ax is None:
        ax = plt.gca()
    # Hide the right and top spines
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)

    # Only show ticks on the left and bottom spines
    ax.yaxis.set_ticks_position('left')
    ax.xaxis.set_ticks_position('bottom')

Introdução

Durante a segunda parte do curso o uso de amostras vai ser aplicado para resolver problemas complexos. Embora se fala muito de big data, na prática, são boas amostras que são utilizadas para responder boas perguntas. Inclusive, existem falácias em big data quando a forma da amostra é muito viésada.

Vamos considerar uma base de dados de voos com atrasos nos estados unidos. Cada linha da tabela é composta de uma data, o número do vôo, destino e atraso do vôo em minutos.

#In: 
df = pd.read_csv('https://media.githubusercontent.com/media/icd-ufmg/material/master/aulas/08extra-Amostras/united_summer2015.csv')
df.head()
DateFlight NumberDestinationDelay
06/1/1573HNL257
16/1/15217EWR28
26/1/15237STL-3
36/1/15250SAN0
46/1/15267PHL64

Vamos assumir que esta é nossa população. Ou seja, eu estou apenas interessado em estudar dados de voos united do verão de 2015. Além do mais, a tabela representa um censo completo dos atrasos no ano.

A população consiste de quase 14 mil atrasos no ano de 2015.

#In: 
df.shape
(13825, 4)

Vamos entender a distribuição dos atrasos:

#In: 
delay_bins = np.append(np.arange(-20, 301, 10), 600)
plt.hist(df['Delay'], bins=delay_bins, edgecolor='k')
plt.xlabel('Atraso')
plt.ylabel('Número de Voos')
despine()

png

Agora vamos olhar para a mesmo distribuição quanto temos amostras menores dos nossos dados. Em particular, vamos iniciar com o caso de $n=1$. Note como a nova distribuição não parece com os dados da população.

#In: 
def amostre_n(df, n):
    index = df.index
    novo = np.random.choice(index, size=n)
    return df.loc[novo]
#In: 
novo = amostre_n(df, 10)
plt.hist(novo['Delay'], bins=delay_bins, edgecolor='k')
plt.xlabel('Atraso')
plt.ylabel('Número de Voos')
despine()

png

Na animação abaixo conseguimos ver o processo de chegar cada vez mais próximo da distribuição real. Portanto, cada frame da figura mostra o histograma com um valor de $n$ diferente. Quando $n$ se apróxima do valor da população, obviamente, vamos ter uma distribuição similar. Note que isto é uma forma de pensar na lei dos grandes números, ao aumentar $n$, aumentamos a chance de acertar cada bin do meu histograma. Lembre-se da simulação do dado.

#In: 
from IPython.display import HTML
import matplotlib.animation

def animate(n):
    novo = amostre_n(df, n)
    plt.clf()
    plt.title('N={}'.format(n))
    plt.hist(novo['Delay'], bins=delay_bins, edgecolor='k')
    plt.xlabel('Atraso')
    plt.ylabel('Número de Voos')
    despine()

fig = plt.figure()
n = np.arange(1, len(df), 200)
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=n)

html = HTML(ani.to_html5_video())
html

png

Problema de Poucas Amostras em uma Estatística

Note que com poucas amostras teremos problemas em computar a mediana. Por exemplo, abaixo eu escolho 100 voos e a mediana muda batante em cada rodada.

#In: 
df['Delay'].median()
2.0
#In: 
for _ in range(10):
    novo = amostre_n(df, 1000)
    print(novo['Delay'].median())
3.0
2.0
2.0
2.0
2.0
2.0
2.0
2.5
2.0
2.0

Além do mais, não podemos fazer nada se geramos amostras com algum viés. Por exemplo, se mensuramos atrasos em um único aeroporto!

#In: 
for _ in range(10):
    novo = amostre_n(df[df['Destination'] == 'ORD'], 100)
    print(novo['Delay'].median())
6.5
3.0
2.5
5.0
2.5
5.0
4.0
0.5
3.0
3.0

Por fim, com uma amostragem estratificada, podemos garantir que temos uma proporção representativa de cada aeroporto.

#In: 
novo = amostre_n(df, 100)
duas_colunas = novo[['Destination', 'Delay']]
print(duas_colunas.groupby('Destination').median())
             Delay
Destination       
ANC           11.5
AUS           -7.0
BOS            2.5
CLE          104.0
DEN           13.0
EWR            3.0
HNL            3.0
IAD            2.0
IAH           18.5
JFK           -1.0
KOA            4.0
LAS           14.0
LAX           25.5
LIH            1.0
MCO           16.0
OGG            0.0
ORD            8.0
PDX            6.0
PHL            5.0
PHX           -2.0
PIT           47.0
RDU           12.0
SAN           15.5
SEA            9.0
SNA           -2.0
#In: 
from sklearn.model_selection import StratifiedShuffleSplit
for train, test in StratifiedShuffleSplit(test_size=200).split(df, df['Destination']):
    duas_colunas = df[['Destination', 'Delay']]
    amostra = duas_colunas.iloc[test]
    print(amostra.groupby('Destination').median())
    break
             Delay
Destination       
ANC           -1.0
ATL           -2.0
AUS           -6.0
BOS            1.5
BWI           81.0
CLE           -2.0
DCA            4.0
DEN            1.5
DFW           -6.5
EWR            1.0
FLL           15.0
HNL           30.0
IAD           -1.0
IAH            4.0
IND            9.0
JFK            0.0
KOA            7.0
LAS           -0.5
LAX            7.0
LIH           -1.0
MCO            7.5
MSP           57.0
OGG            4.0
ORD            4.0
PDX           -2.0
PHL            2.0
PHX           -2.5
PIT            6.0
RDU           -3.0
RNO            2.0
SAN            2.5
SEA            0.0
SLC           -5.0
SNA           -3.0
STL           -1.0

Qual o motivo de simular?

Para muitos casos, tipo a distribuição de médias, o teorema central do limite vai nos ajudar teoricamente pois sabemos que os dados da ditribuição de amostragem converge para uma normal. Note que isto não vai ser o caso para a mediana, porém podemos simular e ter uma ideia da mesma. Vamos iniciar olhando para a mediana.

Então muitos resultados teóricos podem ser feitos quando pensamos em distribuições amostrais da média, porém para a mediana simular é uma boa solução.

Abaixo brincamos um pouco com a distribuição amostral da mediana, note que a no fim não temos nada muito perto da normal.

#In: 
amostral = []
for _ in range(10000):
    novo = amostre_n(df, 100)
    amostral.append(novo['Delay'].median())
#In: 
plt.hist(amostral, bins=20, edgecolor='k');
plt.xlabel('Mediana de 100 amostras')
plt.ylabel('P(X = x)')
despine()

png