from pathlib import Path
import pandas as pd
import numpy as np
from scipy import stats
from sklearn.utils import resample
import seaborn as sns
import matplotlib.pylab as plt
O diretório DATA contém os arquivos .csv utilizados nos exemplos.
DATA = './'
Se você não mantiver seus dados no mesmo diretório que o código, adapte os nomes dos caminhos.
LOANS_INCOME_CSV = DATA + 'loans_income.csv'
SP500_DATA_CSV = DATA + 'sp500_data.csv.gz'
Um equívoco popular sustenta que a era do big data significa o fim da necessidade de amostragem.
De fato, a proliferação de dados de qualidade e relevância variadas reforça a necessidade de amostragem como uma ferramenta para trabalhar eficientemente com uma variedade de dados e minimizar tendência.
Mesmo em um projeto de big data, os modelos preditivos são normalmente desenvolvidos e pilotado com amostras.
As amostras também são usadas em testes de vários tipos (por exemplo, comparando o efeito de designs de páginas da web em cliques).
A Figura 2-1 mostra um esquema que sustenta os conceitos que discutiremos neste capítulo—dados e distribuições de amostragem.
Figura 2-1:
np.random.seed(seed=1)
x = np.linspace(-3, 3, 300)
xsample = stats.norm.rvs(size=1000)
#
fig, axes = plt.subplots(ncols=2, figsize=(5, 1.5))
#
ax = axes[0]
ax.fill(x, stats.norm.pdf(x))
ax.set_axis_off()
ax.set_xlim(-3, 3)
#
ax = axes[1]
ax.hist(xsample, bins=30)
ax.set_axis_off()
ax.set_xlim(-3, 3)
ax.set_position
# plt.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
#
plt.show()
O lado esquerdo representa uma população que, em estatística, é assumido seguir uma distribuição subjacente, mas desconhecida.
Tudo que está disponível são os dados da amostra e sua distribuição empírica, mostrados à direita lado.
Para ir do lado esquerdo para o lado direito, um procedimento de amostragem é usado (representado por uma seta).
Estatísticas tradicionais focadas muito no lado esquerdo lado, usando a teoria baseada em suposições fortes sobre a população.
Moderno as estatísticas mudaram para o lado direito, onde tais suposições não são necessárias.
Em geral, os cientistas de dados não precisam se preocupar com a natureza teórica do lado esquerdo.
lado e, em vez disso, deve se concentrar nos procedimentos de amostragem e nos dados disponíveis.
Existem algumas exceções notáveis. Às vezes, os dados são gerados a partir de um processo físico que pode ser modelado.
O exemplo mais simples é jogar uma moeda: isso segue um binômio distribuição.
Qualquer situação binomial da vida real (compre ou não compre, fraude ou não fraude, clique ou não clique) pode ser modelado efetivamente por uma moeda (com probabilidade modificada
de cabeças de pouso, é claro).
Nesses casos, podemos obter informações adicionais ao usando nossa compreensão da população.
O termo distribuição amostral de uma estatística refere-se à distribuição de alguma amostra estatística sobre muitas amostras retiradas da mesma população.
Grande parte das estatísticas clássicas está preocupado em fazer inferências de (pequenas) amostras para populações (muito grandes).
loans_income = pd.read_csv(LOANS_INCOME_CSV).squeeze('columns')
sample_data = pd.DataFrame({
'income': loans_income.sample(1000),
'type': 'Data',
})
sample_mean_05 = pd.DataFrame({
'income': [loans_income.sample(5).mean() for _ in range(1000)],
'type': 'Mean of 5',
})
sample_mean_20 = pd.DataFrame({
'income': [loans_income.sample(20).mean() for _ in range(1000)],
'type': 'Mean of 20',
})
results = pd.concat([sample_data, sample_mean_05, sample_mean_20])
print(results.head())
Os três histogramas são plotados com o método FacetGrid do Seaborn:
g = sns.FacetGrid(
results, col='type', col_wrap=1,
height=2, aspect=2)
g.map(
plt.hist, 'income',
range=[0, 200000], bins=40)
g.set_axis_labels('Income', 'Count')
g.set_titles('{col_name}')
plt.tight_layout()
plt.show()
results = []
for nrepeat in range(1000):
sample = resample(loans_income)
results.append(sample.median())
results = pd.Series(results)
#
print('Bootstrap Statistics:')
print(f'original: {loans_income.median()}')
print(f'bias: {results.mean() - loans_income.median()}')
print(f'std. error: {results.std()}')
Tabelas de frequência, histogramas, caixas e erros padrão são formas de entender o erro potencial em uma estimativa amostral.
Os intervalos de confiança são outra.
Exemplo: intervalo de confiança da alça de bota para a renda anual dos solicitantes de empréstimos, com base em uma amostra de 20 itens.
print(loans_income.mean())
np.random.seed(seed=3)
# crie uma amostra de 20 dados de receita de empréstimo
sample20 = resample(loans_income, n_samples=20, replace=False)
print(sample20.mean())
Preparação dos resultados:
results = []
for nrepeat in range(500):
sample = resample(sample20)
results.append(sample.mean())
results = pd.Series(results)
Figura 2-9: intervalo de confiança de 90%:
ci = list(results.quantile([0.05, 0.95]))
#
ax = results.plot.hist(bins=30, figsize=(8, 6))
ax.plot(ci, [55, 55], color='black')
for x in ci:
ax.plot([x, x], [0, 65], color='black')
ax.text(
x, 70, f'{x:.0f}',
horizontalalignment='center',
verticalalignment='center')
ax.text(
sum(ci) / 2,
60,
'90% interval',
horizontalalignment='center',
verticalalignment='center')
#
meanIncome = results.mean()
#
ax.plot(
[meanIncome, meanIncome], [0, 50],
color='black', linestyle='--')
ax.text(
meanIncome, 10,
f'Mean: {meanIncome:.0f}',
bbox=dict(facecolor='white',
edgecolor='white', alpha=0.5),
horizontalalignment='center',
verticalalignment='center')
ax.set_ylim(0, 80)
ax.set_ylabel('Counts')
#
plt.tight_layout()
plt.show()
Intervalos de confiança de 90% e 95%:
ci = list(results.quantile([0.025, 0.975]))
#
ax = results.plot.hist(
bins=30,
figsize=(8, 6),
color='C1')
ax.plot(
ci,
[55, 55],
color='black',
linestyle='--')
for x in ci:
ax.plot(
[x, x],
[0, 60],
color='black')
ax.text(
82000, 50,
f'90% CI\n[{ci[0]:.0f},{ci[1]:.0f}]',
fontsize='medium')
#
ax = results.plot.hist(bins=30, figsize=(8, 6))
ax.plot(
ci,
[65, 65],
color='black',
linestyle='--')
for x in ci:
ax.plot([x, x], [0, 70], color='black')
ax.text(
82000, 65,
f'95% CI\n[{ci[0]:.0f},{ci[1]:.0f}]',
fontsize='medium')
meanIncome = results.mean()
ax.plot(
[meanIncome, meanIncome],
[0, 50],
color='black',
linestyle='--')
ax.text(
meanIncome, 5, f'Mean: {meanIncome:.0f}',
bbox=dict(facecolor='white', edgecolor='white', alpha=0.5),
horizontalalignment='center',
verticalalignment='center')
ax.set_ylim(0, 80)
ax.set_xlim(37000, 102000)
ax.set_xticks([40000, 50000, 60000, 70000, 80000])
ax.set_ylabel('Counts')
#
plt.tight_layout()
plt.show()
O método scipy.stats.probplot do pacote Scipy cria QQ-plots.
O argumento dist especifica a distribuição, que é definida por padrão para a distribuição normal.
fig, ax = plt.subplots(figsize=(4, 4))
#
norm_sample = stats.norm.rvs(size=100)
stats.probplot(norm_sample, plot=ax)
#
plt.tight_layout()
plt.show()
sp500_px = pd.read_csv(SP500_DATA_CSV)
#
nflx = sp500_px.NFLX
nflx = np.diff(np.log(nflx[nflx>0]))
#
fig, ax = plt.subplots(figsize=(4, 4))
stats.probplot(nflx, plot=ax)
#
plt.tight_layout()
plt.show()
print(stats.binom.pmf(2, n=5, p=0.1))
print(stats.binom.cdf(2, n=5, p=0.1))
sample = stats.poisson.rvs(2, size=100)
pd.Series(sample).plot.hist()
plt.show()
sample = stats.expon.rvs(scale=5, size=100)
pd.Series(sample).plot.hist()
plt.show()
sample = stats.weibull_min.rvs(1.5, scale=5000, size=100)
pd.Series(sample).plot.hist()
plt.show()