Pandas & NumPy Academy · Aula

Estatísticas descritivas e teste de normalidade

Calcule assimetria e curtose com scipy.stats, execute um teste de Shapiro-Wilk para normalidade e interprete o valor-p.

Aula 1 de 413 etapas

Estatísticas descritivas e teste de normalidade é uma aula grátis de Pandas & NumPy Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Pandas & NumPy Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Pandas & NumPy Academy inclui 4 aulas no total.

Estatística descritiva versus inferencial

A estatística descritiva resume o que está presente nos seus dados: média, mediana, desvio padrão e assimetria. A estatística inferencial faz afirmações sobre uma população com base em uma amostra: testes de hipóteses, intervalos de confiança e valores de p. O módulo scipy.stats do SciPy conecta esses dois mundos — ele oferece tanto medidas descritivas que vão além de describe() do Pandas quanto o conjunto completo de testes clássicos de hipóteses. Combinar Pandas para manipulação de dados e SciPy para testes estatísticos é o fluxo de trabalho padrão da ciência de dados em Python.

Estatística descritiva ampliada

describe() do Pandas fornece contagem, média, std, mínimo/máximo e quartis. scipy.stats acrescenta a assimetria (falta de simetria da distribuição) e a curtose (peso das caudas). Uma assimetria igual a 0 significa que a distribuição é simétrica; uma assimetria positiva significa uma cauda direita mais longa (muitos valores pequenos e poucos valores muito grandes). Uma curtose igual a 3 (ou 0 na forma de excesso) é normal; valores maiores indicam caudas mais pesadas, com mais valores extremos do que uma distribuição normal produziria.

import pandas as pd
from scipy import stats
import numpy as np

np.random.seed(0)
data = np.concatenate([
    np.random.exponential(scale=2, size=500),  # right-skewed
    np.random.normal(loc=5, scale=1, size=500)
])

print('Mean:', round(data.mean(), 3))
print('Std:', round(data.std(), 3))
print('Skewness:', round(stats.skew(data), 3))
print('Kurtosis (excess):', round(stats.kurtosis(data), 3))

Entendendo a assimetria

A assimetria é importante para escolher testes estatísticos e transformações. Uma distribuição assimétrica à direita (assimetria positiva) tem média maior que a mediana, algo típico de dados de renda, tempos de reação e valores de vendas. Uma distribuição assimétrica à esquerda (assimetria negativa) tem média menor que a mediana. Regra prática: |assimetria| < 0.5 indica uma distribuição aproximadamente simétrica; 0.5–1.0 indica assimetria moderada; > 1.0 indica assimetria elevada e pode justificar uma transformação logarítmica ou de raiz quadrada antes da aplicação de testes que pressuponham normalidade.

import numpy as np
from scipy import stats

# Right-skewed: income-like data
right_skewed = np.random.lognormal(mean=1, sigma=1, size=1000)
print('Right skew:', round(stats.skew(right_skewed), 3))

# After log transform
print('After log transform:', round(stats.skew(np.log(right_skewed)), 3))

# Symmetric normal
normal_data = np.random.normal(0, 1, 1000)
print('Normal skew:', round(stats.skew(normal_data), 3))

Por que os testes de normalidade são importantes

Muitos testes estatísticos — testes t, ANOVA e correlação de Pearson — pressupõem que os dados (ou os resíduos) seguem uma distribuição normal (gaussiana). Se essa suposição for violada em amostras pequenas, os valores de p do teste poderão ser imprecisos. O teste de normalidade verifica se essa suposição é válida. Em amostras grandes (n > 100), os testes de normalidade tornam-se muito sensíveis e quase sempre rejeitam a normalidade por desvios insignificantes; nesse caso, baseie-se no Teorema do Limite Central (as médias amostrais são aproximadamente normais), em vez de testar os dados brutos.

O teste de Shapiro-Wilk

O teste de Shapiro-Wilk (scipy.stats.shapiro(data)) é o teste de normalidade mais potente para tamanhos de amostra de até aproximadamente 5.000. Ele retorna uma estatística W e um valor de p. Se p > 0.05, você não rejeita a normalidade — os dados são compatíveis com uma distribuição normal. Se p ≤ 0.05, você rejeita a normalidade. Lembre-se: não rejeitar a normalidade não prova que os dados sejam normais; significa apenas que não há evidências suficientes para afirmar que não são.

import numpy as np
from scipy import stats

np.random.seed(42)

# Normal data
normal = np.random.normal(0, 1, 100)
stat, p = stats.shapiro(normal)
print(f'Normal data: W={stat:.4f}, p={p:.4f}')
print('Conclusion:', 'Looks normal' if p > 0.05 else 'Not normal')

# Skewed data
skewed = np.random.exponential(1, 100)
stat2, p2 = stats.shapiro(skewed)
print(f'Skewed data: W={stat2:.4f}, p={p2:.4f}')
print('Conclusion:', 'Looks normal' if p2 > 0.05 else 'Not normal')

O teste de Kolmogorov-Smirnov

O teste de Kolmogorov-Smirnov (K-S) (scipy.stats.kstest(data, 'norm', args)) testa se uma amostra segue uma distribuição especificada. Diferentemente do Shapiro-Wilk, ele funciona com qualquer distribuição (não apenas a normal) e com amostras grandes. Ele calcula a diferença máxima entre a CDF empírica dos seus dados e a CDF teórica. Uma variação, o teste K-S de duas amostras (stats.ks_2samp(a, b)), testa se duas amostras vêm da mesma distribuição — útil para comparar distribuições antes e depois.

import numpy as np
from scipy import stats

np.random.seed(0)
data = np.random.normal(loc=5, scale=2, size=200)

# One-sample K-S test against N(5, 2) distribution
stat, p = stats.kstest(data, 'norm', args=(5, 2))
print(f'K-S test: stat={stat:.4f}, p={p:.4f}')
print('Follows N(5,2)?', 'Yes' if p > 0.05 else 'No')

# Two-sample K-S test
data2 = np.random.normal(loc=5.5, scale=2, size=200)
stat2, p2 = stats.ks_2samp(data, data2)
print(f'Two-sample K-S: stat={stat2:.4f}, p={p2:.4f}')

Verificação visual da normalidade: gráfico QQ

O gráfico Q-Q (quantil-quantil) é uma verificação visual da normalidade: ele representa os quantis dos seus dados em relação aos quantis de uma distribuição normal. Se os dados forem normais, os pontos ficarão sobre uma linha diagonal reta. Desvios da linha indicam afastamento da normalidade — curvas em S indicam curtose, e curvas ou mudanças de direção indicam assimetria. Os testes estatísticos informam se os desvios são significativos; os gráficos Q-Q mostram a natureza e a localização desses desvios. Use scipy.stats.probplot() para gerar os dados do gráfico Q-Q.

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(1)
data = np.random.exponential(2, 200)

# Q-Q plot
(osm, osr), (slope, intercept, r) = stats.probplot(data, dist='norm')
print(f'R-squared of Q-Q fit: {r**2:.4f}')  # Close to 1 = normal
# Visual inspection: if plotting, points on the line = normal
# plt.figure()
# stats.probplot(data, dist='norm', plot=plt)
# plt.show()

O Teorema do Limite Central na prática

O Teorema do Limite Central (CLT) afirma que a distribuição das médias amostrais se aproxima da normalidade à medida que o tamanho da amostra aumenta, independentemente da distribuição subjacente. Para n ≥ 30, a média amostral é aproximadamente normal, mesmo que as observações individuais sejam assimétricas. É por isso que os testes t são robustos para amostras grandes: você está testando se a média difere, e a média é aproximadamente normal mesmo quando os dados brutos não são. Para amostras pequenas de populações não normais, use testes não paramétricos.

import numpy as np
from scipy import stats

np.random.seed(0)
# Population: heavily right-skewed (exponential)
population = np.random.exponential(scale=1, size=10000)
print('Population skewness:', round(stats.skew(population), 3))

# Sample means are approximately normal (CLT)
sample_means = [np.random.choice(population, 50).mean()
                for _ in range(1000)]
print('Sample means skewness:', round(stats.skew(sample_means), 3))
_, p = stats.shapiro(sample_means)
print('Shapiro p-value for means:', round(p, 4))

Normalidade por grupo

Em testes de comparação entre grupos (teste t, ANOVA), a normalidade é necessária dentro de cada grupo, não nos dados gerais. Ao testar se as vendas diferem por região, teste a normalidade das vendas separadamente dentro de cada região. Uma distribuição que não é normal no geral ainda pode satisfazer a normalidade dentro dos subgrupos. Aplique stats.shapiro() a cada grupo usando groupby() do Pandas e itere pelos grupos para verificar a suposição de forma sistemática.

import pandas as pd
import numpy as np
from scipy import stats

np.random.seed(0)
df = pd.DataFrame({
    'region': ['N']*50 + ['S']*50 + ['E']*50,
    'sales': np.concatenate([
        np.random.normal(100, 20, 50),
        np.random.normal(110, 25, 50),
        np.random.normal(95, 15, 50)
    ])
})

for region, group in df.groupby('region'):
    stat, p = stats.shapiro(group['sales'])
    print(f'Region {region}: W={stat:.4f}, p={p:.4f} -> '
          f'{"Normal" if p>0.05 else "Not normal"}')

Alternativas não paramétricas

Quando a normalidade é violada, use testes não paramétricos, que não fazem suposições sobre a distribuição. O teste U de Mann-Whitney (stats.mannwhitneyu) substitui o teste t independente; o teste de postos sinalizados de Wilcoxon (stats.wilcoxon) substitui o teste t pareado; o teste de Kruskal-Wallis (stats.kruskal) substitui a ANOVA de uma via. Esses testes usam postos em vez dos valores brutos e são robustos a valores atípicos, mas têm menor poder estatístico que seus equivalentes paramétricos quando a normalidade de fato é válida.

import numpy as np
from scipy import stats

np.random.seed(0)
# Non-normal data
group_a = np.random.exponential(2, 40)
group_b = np.random.exponential(2.5, 40)

# Parametric would be wrong here; use non-parametric
stat, p = stats.mannwhitneyu(group_a, group_b, alternative='two-sided')
print(f'Mann-Whitney U test: U={stat:.1f}, p={p:.4f}')
print('Groups differ?' , 'Yes' if p < 0.05 else 'No')

Resumindo estatísticas para várias colunas

Na EDA, muitas vezes é necessário verificar a normalidade e a assimetria de todas as colunas numéricas de uma só vez. Combine select_dtypes do Pandas com um laço pelas colunas, chamando stats.shapiro() e stats.skew(). Crie um DataFrame de resumo com colunas para assimetria, curtose e valor de p de Shapiro, para obter uma visão geral das colunas que não são normais e precisam de transformação antes da modelagem. Isso faz parte de uma lista de verificação sistemática da qualidade dos dados.

import pandas as pd
import numpy as np
from scipy import stats

np.random.seed(0)
df = pd.DataFrame({
    'age': np.random.normal(35, 10, 200),
    'income': np.random.lognormal(10, 1, 200),
    'score': np.random.uniform(0, 100, 200)
})

rows = []
for col in df.select_dtypes(include='number').columns:
    s = stats.skew(df[col])
    _, p = stats.shapiro(df[col][:200])
    rows.append({'column': col, 'skewness': round(s, 3),
                 'shapiro_p': round(p, 4), 'normal': p > 0.05})

print(pd.DataFrame(rows).to_string(index=False))

Verificação rápida

Teste sua compreensão dos conceitos de Análise de Dados desta lição.

Recapitulação da lição

Nesta lição, você aprendeu que scipy.stats.skew() e kurtosis() descrevem o formato de uma distribuição além do que describe() fornece, que scipy.stats.shapiro() testa a normalidade, com p > 0.05 significando ausência de evidências contra a normalidade, e que o Teorema do Limite Central torna os testes t robustos para amostras grandes, mesmo com dados não normais. A seguir, aplicaremos testes de hipóteses com testes t para comparar médias de grupos.

Grátis para começar

Aprenda Python com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
30
Aulas
120

Perguntas Frequentes

A aula “Estatísticas descritivas e teste de normalidade” é grátis?

Sim — o texto completo de “Estatísticas descritivas e teste de normalidade” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Pandas & NumPy Academy, atualize para CoddyKit PRO. O curso de Pandas & NumPy Academy inclui 4 aulas no total.

O que vou aprender em “Estatísticas descritivas e teste de normalidade”?

Calcule assimetria e curtose com scipy.stats, execute um teste de Shapiro-Wilk para normalidade e interprete o valor-p. Você pratica Pandas & NumPy Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Pandas & NumPy Academy?

Nenhuma experiência prévia é necessária. Pandas & NumPy Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Estatísticas descritivas e teste de normalidade”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Pandas & NumPy Academy?

Sim. Cada aula de Pandas & NumPy Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Estatísticas descritivas e teste de normalidade
  2. Testes t para comparar médias
  3. Teste qui-quadrado de independência
  4. ANOVA e testes pós-hoc
← Voltar para Pandas & NumPy Academy