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-PT/1-Introduction/04-stats-and-probability/notebook.ipynb

581 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Introdução à Probabilidade e Estatística\n",
"Neste caderno, vamos experimentar alguns dos conceitos que discutimos anteriormente. Muitos conceitos de probabilidade e estatística estão bem representados em bibliotecas importantes 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 por tirar uma amostra de 30 valores de uma distribuição uniforme entre 0 e 9. Também iremos 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 traçar 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",
"A média e a variância são muito importantes ao analisar dados do mundo real. Vamos carregar os dados sobre jogadores de basebol de [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 a usar um pacote chamado [**Pandas**](https://pandas.pydata.org/) aqui para análise de dados. Falaremos mais sobre o Pandas e trabalhar com dados em Python mais à frente 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 olhar para o valor mediano e os quartis. Eles podem ser visualizados usando um **diagrama de caixas**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10,2))\n",
"plt.boxplot(df['Height'].ffill(), vert=False, 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 diagramas 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 jogadores da primeira base são superiores às alturas dos jogadores da segunda base. Mais adiante, iremos aprender como testar esta hipótese de forma mais formal, e como demonstrar que os nossos dados são estatisticamente significativos para o mostrar. \n",
"\n",
"A idade, a altura e o peso são todas variáveis aleatórias contínuas. O que acha que é a distribuição delas? Uma boa forma de descobrir é traçar 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 dos 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 segue uma distribuição normal, 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 basebol. Vamos usar o código [deste debate no 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'].fillna(method='pad'),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 funções no nosso conjunto de dados de jogadores de basebol:\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 Primeiros Basemen são mais altos do que os Segundos Basemen. 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 forma 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 devolvidos pela função `ttest_ind` são:\n",
"* o p-valor pode ser considerado como a probabilidade de duas distribuições terem a mesma média. No nosso caso, é muito baixo, o que significa que existe uma forte evidência a apoiar que os jogadores de primeira base são mais altos.\n",
"* o valor t é o valor intermédio da diferença média normalizada que é usado no teste t, e é comparado com um valor limite para um dado valor de confiança.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulação de uma Distribuição Normal com o Teorema do Limite Central\n",
"\n",
"O gerador pseudo-aleatório em Python é concebido 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, vamos simplesmente calcular a média de uma amostra gerada de forma uniforme.\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 permite-nos encontrar relações entre sequências de dados. No nosso exemplo fictício, vamos fingir que existe uma corporação de basebol malvada que paga os seus jogadores de acordo com a sua altura quanto mais alto for o jogador, mais dinheiro ele/ela recebe. Suponha que há um salário base de $1000, e um bónus adicional de $0 a $100, dependendo da altura. Vamos pegar nos jogadores reais da MLB, e calcular os seus salários imaginários:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"heights = df['Height'].fillna(method='pad')\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 a correlação dessas sequências. `np.cov` fornecerá 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` fornecerá 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 existe uma **relação linear** forte entre duas variáveis. Podemos visualizar a relação linear ao traçar um valor em função do 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 a nossa empresa decidiu esconder a óbvia dependência linear entre alturas e salários, e introduziu alguma 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 continua bastante elevada. Agora, para tornar a relação ainda menos óbvia, podemos querer adicionar alguma aleatoriedade extra adicionando uma 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": [
"> Consegue adivinhar por que é que os pontos se alinham em linhas verticais assim?\n",
"\n",
"Observámos a correlação entre um conceito artificialmente construído como o salário e a variável observada *altura*. Vamos também ver se as duas variáveis observadas, como a altura e o peso, também 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 quaisquer resultados - apenas alguns valores estranhos `nan`. Isto deve-se ao facto de alguns dos valores da nossa série estarem indefinidos, representados como `nan`, o que causa 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 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 em falta e calcular a correlação:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"De facto, existe uma correlação, mas não tão forte como no nosso exemplo artificial. De facto, se olharmos para o gráfico de dispersão de um valor em função do 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 caderno aprendemos como realizar operações básicas em dados para calcular funções estatísticas. Agora sabemos como usar um conjunto sólido 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 utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos empenhemos em garantir a precisão, por favor esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional efetuada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas que decorram da utilização 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"
},
"coopTranslator": {
"original_hash": "0f899e3c5019f948e7c787b22f3b2304",
"translation_date": "2026-01-16T12:48:41+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "pt"
}
},
"nbformat": 4,
"nbformat_minor": 4
}