You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Data-Science-For-Beginners/translations/pt-BR/1-Introduction/04-stats-and-probability/notebook.ipynb

575 lines
18 KiB

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Introdução à Probabilidade e Estatística\n",
"Neste notebook, vamos explorar alguns dos conceitos que discutimos anteriormente. Muitos conceitos de probabilidade e estatística estão bem representados em grandes bibliotecas para processamento de dados em Python, como `numpy` e `pandas`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import random\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Variáveis Aleatórias e Distribuições\n",
"Vamos começar desenhando uma amostra de 30 valores de uma distribuição uniforme de 0 a 9. Também vamos calcular a média e a variância.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"sample = [ random.randint(0,10) for _ in range(30) ]\n",
"print(f\"Sample: {sample}\")\n",
"print(f\"Mean = {np.mean(sample)}\")\n",
"print(f\"Variance = {np.var(sample)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para estimar visualmente quantos valores diferentes existem na amostra, podemos plotar o **histograma**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(sample)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analisando Dados Reais\n",
"\n",
"Média e variância são muito importantes ao analisar dados do mundo real. Vamos carregar os dados sobre jogadores de baseball do [SOCR MLB Height/Weight Data](http://wiki.stat.ucla.edu/socr/index.php/SOCR_Data_MLB_HeightsWeights)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_csv(\"../../data/SOCR_MLB.tsv\",sep='\\t', header=None, names=['Name','Team','Role','Weight','Height','Age'])\n",
"df\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> Estamos usando um pacote chamado [**Pandas**](https://pandas.pydata.org/) aqui para análise de dados. Falaremos mais sobre Pandas e o trabalho com dados em Python mais adiante neste curso.\n",
"\n",
"Vamos calcular os valores médios para idade, altura e peso:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df[['Age','Height','Weight']].mean()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora vamos focar na altura e calcular o desvio padrão e a variância: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(list(df['Height'])[:20])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mean = df['Height'].mean()\n",
"var = df['Height'].var()\n",
"std = df['Height'].std()\n",
"print(f\"Mean = {mean}\\nVariance = {var}\\nStandard Deviation = {std}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Além da média, faz sentido observar o valor mediano e os quartis. Eles podem ser visualizados usando um **box plot**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,2))\n",
"plt.boxplot(df['Height'].ffill(), orientation='horizontal', showmeans=True)\n",
"plt.grid(color='gray', linestyle='dotted')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Também podemos fazer gráficos de caixa de subconjuntos do nosso conjunto de dados, por exemplo, agrupados por função do jogador.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.boxplot(column='Height', by='Role', figsize=(10,8))\n",
"plt.xticks(rotation='vertical')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Nota**: Este diagrama sugere que, em média, as alturas dos primeira base são maiores do que as alturas dos segunda base. Mais adiante aprenderemos como podemos testar essa hipótese de forma mais formal e como demonstrar que nossos dados são estatisticamente significativos para isso. \n",
"\n",
"Idade, altura e peso são todas variáveis aleatórias contínuas. O que você acha que é a distribuição delas? Uma boa maneira de descobrir é plotar o histograma dos valores: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df['Weight'].hist(bins=15, figsize=(10,6))\n",
"plt.suptitle('Weight distribution of MLB Players')\n",
"plt.xlabel('Weight')\n",
"plt.ylabel('Count')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Distribuição Normal\n",
"\n",
"Vamos criar uma amostra artificial de pesos que segue uma distribuição normal com a mesma média e variância que nossos dados reais:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"generated = np.random.normal(mean, std, 1000)\n",
"generated[:20]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.hist(generated, bins=15)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.hist(np.random.normal(0,1,50000), bins=300)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Como a maioria dos valores na vida real é normalmente distribuída, não devemos usar um gerador de números aleatórios uniforme para gerar dados de amostra. Aqui está o que acontece se tentarmos gerar pesos com uma distribuição uniforme (gerada por `np.random.rand`):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"wrong_sample = np.random.rand(1000)*2*std+mean-std\n",
"plt.figure(figsize=(10,6))\n",
"plt.hist(wrong_sample)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Intervalos de Confiança\n",
"\n",
"Vamos agora calcular intervalos de confiança para os pesos e alturas dos jogadores de beisebol. Usaremos o código [desta discussão do stackoverflow](https://stackoverflow.com/questions/15033511/compute-a-confidence-interval-from-sample-data):\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import scipy.stats\n",
"\n",
"def mean_confidence_interval(data, confidence=0.95):\n",
" a = 1.0 * np.array(data)\n",
" n = len(a)\n",
" m, se = np.mean(a), scipy.stats.sem(a)\n",
" h = se * scipy.stats.t.ppf((1 + confidence) / 2., n-1)\n",
" return m, h\n",
"\n",
"for p in [0.85, 0.9, 0.95]:\n",
" m, h = mean_confidence_interval(df['Weight'].ffill(),p)\n",
" print(f\"p={p:.2f}, mean = {m:.2f} ± {h:.2f}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Teste de Hipóteses\n",
"\n",
"Vamos explorar diferentes papéis em nosso conjunto de dados de jogadores de beisebol:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.groupby('Role').agg({ 'Weight' : 'mean', 'Height' : 'mean', 'Age' : 'count'}).rename(columns={ 'Age' : 'Count'})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos testar a hipótese de que os jogadores de primeira base são mais altos do que os jogadores de segunda base. A maneira mais simples de fazer isso é testar os intervalos de confiança:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for p in [0.85,0.9,0.95]:\n",
" m1, h1 = mean_confidence_interval(df.loc[df['Role']=='First_Baseman',['Height']],p)\n",
" m2, h2 = mean_confidence_interval(df.loc[df['Role']=='Second_Baseman',['Height']],p)\n",
" print(f'Conf={p:.2f}, 1st basemen height: {m1-h1[0]:.2f}..{m1+h1[0]:.2f}, 2nd basemen height: {m2-h2[0]:.2f}..{m2+h2[0]:.2f}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Podemos ver que os intervalos não se sobrepõem.\n",
"\n",
"Uma maneira estatisticamente mais correta de provar a hipótese é usar um **teste t de Student**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from scipy.stats import ttest_ind\n",
"\n",
"tval, pval = ttest_ind(df.loc[df['Role']=='First_Baseman',['Height']], df.loc[df['Role']=='Second_Baseman',['Height']],equal_var=False)\n",
"print(f\"T-value = {tval[0]:.2f}\\nP-value: {pval[0]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Os dois valores retornados pela função `ttest_ind` são:\n",
"* valor-p pode ser considerado como a probabilidade de duas distribuições terem a mesma média. No nosso caso, é muito baixo, o que significa que há forte evidência apoiando que os primeiros base são mais altos.\n",
"* valor t é o valor intermediário da diferença de média normalizada que é usado no teste t, e ele é comparado contra um valor limite para um dado nível de confiança.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulando uma Distribuição Normal com o Teorema do Limite Central\n",
"\n",
"O gerador pseudoaleatório no Python é projetado para nos fornecer uma distribuição uniforme. Se quisermos criar um gerador para distribuição normal, podemos usar o teorema do limite central. Para obter um valor distribuído normalmente, basta calcular a média de uma amostra gerada uniformemente.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def normal_random(sample_size=100):\n",
" sample = [random.uniform(0,1) for _ in range(sample_size) ]\n",
" return sum(sample)/sample_size\n",
"\n",
"sample = [normal_random() for _ in range(100)]\n",
"plt.figure(figsize=(10,6))\n",
"plt.hist(sample)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Correlação e Evil Baseball Corp\n",
"\n",
"A correlação nos permite encontrar relações entre sequências de dados. Em nosso exemplo didático, vamos fingir que existe uma corporação malvada de beisebol que paga seus jogadores de acordo com a altura - quanto mais alto o jogador, mais dinheiro ele/ela recebe. Suponha que haja um salário base de $1000, e um bônus adicional de $0 a $100, dependendo da altura. Usaremos os jogadores reais da MLB e calcularemos seus salários imaginários:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"heights = df['Height'].ffill()\n",
"salaries = 1000+(heights-heights.min())/(heights.max()-heights.mean())*100\n",
"print(list(zip(heights, salaries))[:10])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos agora calcular a covariância e correlação dessas sequências. `np.cov` nos dará uma chamada **matriz de covariância**, que é uma extensão da covariância para múltiplas variáveis. O elemento $M_{ij}$ da matriz de covariância $M$ é uma correlação entre as variáveis de entrada $X_i$ e $X_j$, e os valores diagonais $M_{ii}$ são a variância de $X_{i}$. De forma semelhante, `np.corrcoef` nos dará a **matriz de correlação**.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(f\"Covariance matrix:\\n{np.cov(heights, salaries)}\")\n",
"print(f\"Covariance = {np.cov(heights, salaries)[0,1]}\")\n",
"print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Uma correlação igual a 1 significa que há uma forte **relação linear** entre duas variáveis. Podemos visualizar a relação linear ao plotar um valor contra o outro:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.scatter(heights,salaries)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos ver o que acontece se a relação não for linear. Suponha que nossa corporação decidiu esconder a óbvia dependência linear entre alturas e salários, e introduziu algum tipo de não-linearidade na fórmula, como `sin`:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"salaries = 1000+np.sin((heights-heights.min())/(heights.max()-heights.mean()))*100\n",
"print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Neste caso, a correlação é ligeiramente menor, mas ainda assim é bastante alta. Agora, para tornar a relação ainda menos óbvia, podemos querer adicionar um pouco de aleatoriedade extra adicionando alguma variável aleatória ao salário. Vamos ver o que acontece:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"salaries = 1000+np.sin((heights-heights.min())/(heights.max()-heights.mean()))*100+np.random.random(size=len(heights))*20-10\n",
"print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.scatter(heights, salaries)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> Você consegue adivinhar por que os pontos se alinham em linhas verticais assim?\n",
"\n",
"Observamos a correlação entre um conceito artificialmente criado como salário e a variável observada *altura*. Vamos também ver se as duas variáveis observadas, como altura e peso, também se correlacionam:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(),df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Infelizmente, não obtivemos nenhum resultado - apenas alguns valores estranhos `nan`. Isso ocorre porque alguns dos valores em nossa série estão indefinidos, representados como `nan`, o que faz com que o resultado da operação também seja indefinido. Ao observar a matriz, podemos ver que `Weight` é a coluna problemática, porque a autocorrelação entre os valores de `Height` foi calculada.\n",
"\n",
"> Este exemplo mostra a importância da **preparação** e **limpeza** dos dados. Sem dados adequados, não podemos calcular nada.\n",
"\n",
"Vamos usar o método `fillna` para preencher os valores ausentes e calcular a correlação: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"De fato, existe uma correlação, mas não tão forte quanto em nosso exemplo artificial. De fato, se olharmos para o gráfico de dispersão de um valor em relação ao outro, a relação seria muito menos óbvia:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,6))\n",
"plt.scatter(df['Weight'],df['Height'])\n",
"plt.xlabel('Weight')\n",
"plt.ylabel('Height')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusão\n",
"\n",
"Neste notebook aprendemos como realizar operações básicas em dados para calcular funções estatísticas. Agora sabemos como usar um aparato consistente de matemática e estatística para provar algumas hipóteses e como calcular intervalos de confiança para variáveis arbitrárias dado um conjunto de dados.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Aviso Legal**:\nEste documento foi traduzido usando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, por favor, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autorizada. Para informações críticas, recomenda-se tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5"
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}