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

581 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 nas principais 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 estão 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 beisebol 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 usando um pacote chamado [**Pandas**](https://pandas.pydata.org/) aqui para análise de dados. Falaremos mais sobre Pandas e trabalhar 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 olhar 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(), 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 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 primeiros base são maiores do que as alturas dos segundos 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 mostrar 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 é 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 amostrais. 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 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 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 Primeiros Bases são mais altos do que os Segundos Bases. 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",
"* 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 há fortes evidências de que os primeiras bases são mais altos.\n",
"* t-valor é o valor intermediário da diferença média normalizada que é usado no teste t, e é comparado contra um valor limite para um dado valor 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 em 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. No nosso exemplo lúdico, vamos fingir que existe uma corporação de beisebol malvada 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. Vamos pegar os jogadores reais da MLB e calcular 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` nos dará a 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}$. Da mesma forma, `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 existe uma **relação linear** forte 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 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 é um pouco menor, mas ainda é bastante alta. Agora, para tornar a relação ainda menos óbvia, podemos querer adicionar um pouco de 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": [
"> 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 olhar para 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'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"De fato, existe uma correlação, mas não tão forte quanto em nosso exemplo artificial. Na verdade, se analisarmos 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 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 dadas uma amostra 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 esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. 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"
},
"coopTranslator": {
"original_hash": "0f899e3c5019f948e7c787b22f3b2304",
"translation_date": "2026-01-16T12:49:37+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "br"
}
},
"nbformat": 4,
"nbformat_minor": 4
}