W3docs

Distribuição de Dados em Machine Learning

Aprenda como as distribuições de dados funcionam em Python: normal, assimétrica e uniforme, como detectá-las e por que são importantes.

A distribuição de dados descreve como os valores estão espalhados em um conjunto de dados — quais valores são comuns, quais são raros e o quão longe eles se afastam do centro. Antes de treinar qualquer modelo de machine learning, entender a distribuição dos seus dados ajuda a escolher o algoritmo certo, detectar anomalias, decidir se é necessário dimensionar ou transformar as features, e evitar vieses ocultos nas previsões.

Este capítulo aborda as formas de distribuição mais comuns, como medi-las em Python usando NumPy e SciPy, e o que cada distribuição significa para suas decisões de modelagem.

O Que É Distribuição de Dados?

Uma distribuição de dados é o padrão de frequência com que cada valor (ou intervalo de valores) aparece em um conjunto de dados. Quando você plota uma distribuição, geralmente vê uma curva ou histograma cuja forma revela muito sobre os dados subjacentes.

As três propriedades que definem qualquer distribuição são:

  • Centro — onde a maioria dos valores se concentra (medido pela média, mediana e moda)
  • Dispersão — o quanto os valores se desviam do centro (medido pelo desvio padrão e pelo intervalo interquartil)
  • Forma — se a distribuição é simétrica, assimétrica ou plana

Entender as três propriedades é necessário antes de alimentar um modelo com os dados.

Tipos Comuns de Distribuição

Distribuição Normal

A distribuição normal (também chamada de distribuição gaussiana) é a distribuição mais importante em estatística e machine learning. Seu histograma forma uma curva de sino simétrica: os valores se concentram em torno da média e a frequência diminui igualmente em ambos os lados.

Propriedades principais:

  • Média, mediana e moda são todas iguais.
  • Aproximadamente 68% dos valores estão dentro de um desvio padrão da média, 95% dentro de dois e 99,7% dentro de três (a regra empírica).
  • Definida inteiramente por dois parâmetros: média (μ) e desvio padrão (σ).

Muitos fenômenos do mundo real aproximam uma distribuição normal — alturas humanas, erros de medição e pontuações de QI são exemplos clássicos. Algoritmos como análise discriminante linear, Naive Bayes gaussiano e regressão linear assumem (ou se beneficiam de) features com distribuição normal.

import numpy as np
from scipy import stats

# Simulate 1 000 adult heights (cm) drawn from a normal distribution
rng = np.random.default_rng(seed=42)
heights = rng.normal(loc=170, scale=10, size=1000)

print(f"Mean:   {np.mean(heights):.1f} cm")
print(f"Std:    {np.std(heights):.1f} cm")

# Verify the empirical rule
within_1_std = np.sum(np.abs(heights - 170) < 10) / 1000 * 100
within_2_std = np.sum(np.abs(heights - 170) < 20) / 1000 * 100
within_3_std = np.sum(np.abs(heights - 170) < 30) / 1000 * 100

print(f"Within 1 std: {within_1_std:.1f}%  (expected ~68%)")
print(f"Within 2 std: {within_2_std:.1f}%  (expected ~95%)")
print(f"Within 3 std: {within_3_std:.1f}%  (expected ~99.7%)")

Saída:

Mean:   169.7 cm
Std:    9.9 cm
Within 1 std: 68.8%  (expected ~68%)
Within 2 std: 95.7%  (expected ~95%)
Within 3 std: 99.8%  (expected ~99.7%)

Distribuição Assimétrica

Uma distribuição assimétrica é não simétrica: uma cauda é mais longa do que a outra. A assimetria é medida pela estatística de skewness — valores positivos indicam assimetria à direita (positiva), valores negativos indicam assimetria à esquerda (negativa), e valores próximos de zero indicam aproximada simetria.

Positivamente assimétrica (cauda à direita): a cauda se estende para a direita. A média é puxada acima da mediana por um pequeno número de valores muito grandes. Renda e preços de imóveis são exemplos típicos — um pequeno grupo de pessoas com renda muito alta ou imóveis caros eleva a média bem acima da mediana.

Negativamente assimétrica (cauda à esquerda): a cauda se estende para a esquerda. As notas em uma prova fácil frequentemente mostram esse padrão — a maioria dos alunos tira notas altas, mas alguns tiram notas muito baixas.

import numpy as np
from scipy import stats

# Right-skewed: a small number of very high values pull the mean up
salaries = np.array([30000, 32000, 34000, 35000, 36000, 38000,
                     40000, 42000, 45000, 55000, 70000, 120000, 200000])

print("--- Salary distribution ---")
print(f"Mean:     {np.mean(salaries):.0f}")    # pulled up by outliers
print(f"Median:   {np.median(salaries):.0f}")  # more representative center
print(f"Skewness: {stats.skew(salaries):.2f}") # positive = right skew

# Left-skewed: most values are high, a few are very low
exam_scores = np.array([40, 68, 75, 80, 82, 85, 88, 90, 91, 92, 93, 95, 98])
print("\n--- Exam score distribution ---")
print(f"Mean:     {np.mean(exam_scores):.1f}")
print(f"Median:   {np.median(exam_scores):.1f}")
print(f"Skewness: {stats.skew(exam_scores):.2f}") # negative = left skew

Saída:

--- Salary distribution ---
Mean:     59769
Median:   40000
Skewness: 2.16

--- Exam score distribution ---
Mean:     82.8
Median:   88.0
Skewness: -1.77

Quando há assimetria, a média é uma medida enganosa do centro. A mediana geralmente é uma estatística resumo melhor para dados assimétricos.

Distribuição Uniforme

Em uma distribuição uniforme, todos os valores (ou intervalos de valores) são igualmente prováveis. Um dado justo de seis lados produz uma distribuição discreta uniforme; escolher aleatoriamente um número de ponto flutuante entre 0 e 1 produz uma distribuição uniforme contínua.

import numpy as np

rng = np.random.default_rng(seed=42)
# Continuous uniform distribution between 0 and 1
uniform_data = rng.uniform(low=0, high=1, size=10000)

print(f"Mean:   {np.mean(uniform_data):.3f}  (expected 0.500)")
print(f"Std:    {np.std(uniform_data):.3f}   (expected ~0.289)")
print(f"Min:    {np.min(uniform_data):.3f}")
print(f"Max:    {np.max(uniform_data):.3f}")

Saída:

Mean:   0.497  (expected 0.500)
Std:    0.288   (expected ~0.289)
Min:    0.000
Max:    1.000

Distribuições uniformes aparecem em amostragem aleatória, aumento de dados e como priors em modelos bayesianos.

Resumindo uma Distribuição em Python

Antes de modelar, sempre compute um resumo rápido de cada feature. NumPy e SciPy juntos cobrem as principais estatísticas:

import numpy as np
from scipy import stats

data = np.array([12, 15, 14, 10, 18, 14, 13, 16, 14, 12])

print("--- Distribution Summary ---")
print(f"Mean:     {np.mean(data):.1f}")
print(f"Median:   {np.median(data):.1f}")
print(f"Std:      {np.std(data, ddof=1):.2f}")   # sample std deviation
print(f"Min:      {np.min(data)}")
print(f"Max:      {np.max(data)}")
print(f"Skewness: {stats.skew(data):.3f}")        # near 0 = symmetric

Saída:

--- Distribution Summary ---
Mean:     13.8
Median:   14.0
Std:      2.25
Min:      10
Max:      18
Skewness: 0.200

Um valor de skewness próximo de 0.200 indica que os dados são aproximadamente simétricos — sem forte assimetria em nenhuma direção.

Testando a Normalidade

Alguns algoritmos assumem explicitamente que as features têm distribuição normal. O teste de Shapiro-Wilk é o teste mais confiável para amostras pequenas (n < 5.000). Ele retorna uma estatística de teste W e um valor-p. Um valor-p maior que 0,05 significa que você não pode rejeitar a hipótese de que os dados são normais.

import numpy as np
from scipy import stats

rng = np.random.default_rng(seed=42)

# Sample from a normal distribution
normal_sample = rng.normal(loc=0, scale=1, size=50)
stat, p = stats.shapiro(normal_sample)
print(f"Shapiro-Wilk: W={stat:.3f}, p={p:.3f}")
if p > 0.05:
    print("Data appears to be normally distributed.")
else:
    print("Data does not appear to be normally distributed.")

Saída:

Shapiro-Wilk: W=0.984, p=0.730
Data appears to be normally distributed.

Quando usar: aplique o teste de Shapiro-Wilk quando as suposições de um modelo exigirem explicitamente normalidade — por exemplo, antes de usar um teste t paramétrico ou análise discriminante linear. Muitos algoritmos modernos (gradient boosting, random forests, redes neurais) não são sensíveis à forma de distribuição das features, portanto nem sempre é necessário esse teste.

Por Que a Forma da Distribuição Importa para a Modelagem

SituaçãoO que significaO que fazer
Features normaisSuposições padrão se aplicamUse modelos paramétricos como estão
Features com assimetria à direitaA média está inflada; outliers dominamAplique transformação logarítmica ou de raiz quadrada
Features com assimetria à esquerdaValores baixos são outliersAplique transformação quadrática ou de reflexão
Features uniformesSem concentração centralGeralmente adequado; normalize para modelos baseados em distância
Features multimodaisMúltiplos clustersConsidere dividir os dados ou usar uma etapa de clustering

Tratando Dados Assimétricos com Transformação Logarítmica

Um remédio comum para dados com assimetria à direita é a transformação logarítmica, que comprime valores grandes e expande valores pequenos, muitas vezes produzindo uma distribuição mais próxima da normal.

import numpy as np
from scipy import stats

rng = np.random.default_rng(seed=7)
# Simulate log-normally distributed incomes (a common real-world pattern)
incomes = rng.lognormal(mean=10.5, sigma=0.5, size=1000)

print(f"Before transform — skewness: {stats.skew(incomes):.2f}")
log_incomes = np.log(incomes)
print(f"After log transform — skewness: {stats.skew(log_incomes):.2f}")

Saída:

Before transform — skewness: 1.44
After log transform — skewness: 0.01

Após a transformação logarítmica, a assimetria cai de 1.44 para quase zero, tornando os dados muito mais adequados para modelos que assumem normalidade.

Nota: a transformação logarítmica requer que todos os valores sejam estritamente positivos. Adicione uma pequena constante (ex.: np.log(x + 1)) se seus dados contiverem zeros.

Visualizando a Distribuição de Dados

A visualização é a maneira mais rápida de inspecionar uma distribuição. Um histograma divide os valores em intervalos e mostra quantas observações caem em cada intervalo. Use histogramas do Matplotlib para criá-los:

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(seed=42)
data = rng.normal(loc=170, scale=10, size=500)

plt.figure(figsize=(8, 4))
plt.hist(data, bins=30, color='steelblue', edgecolor='white')
plt.title("Height Distribution (Normal)")
plt.xlabel("Height (cm)")
plt.ylabel("Frequency")
plt.tight_layout()
plt.show()

Para uma visão geral mais rápida de múltiplas features ao mesmo tempo, use um gráfico de dispersão para identificar relações entre distribuições.

Distribuição e Dimensionamento de Features

Se suas features têm distribuições ou escalas muito diferentes, algoritmos baseados em distância (k-nearest neighbours, SVM, k-means clustering) serão dominados pelas features com maior intervalo. O dimensionamento de features é a solução padrão: StandardScaler normaliza cada feature para média 0 e desvio padrão 1, e MinMaxScaler comprime os valores para [0, 1].

Escolha o scaler com base na distribuição subjacente:

  • Distribuição normal → StandardScaler (remove a média, escala para variância unitária)
  • Distribuição uniforme ou limitada → MinMaxScaler (preserva a forma)
  • Fortemente assimétrica com outliers → RobustScaler (usa mediana e IQR, ignorando valores extremos)

Resumo

  • Distribuição normal: curva de sino simétrica; média ≈ mediana; adequada para modelos paramétricos.
  • Distribuição assimétrica: assimétrica; a média é puxada em direção à cauda; transformações logarítmicas ou de potência podem reduzir a assimetria.
  • Distribuição uniforme: todos os valores igualmente prováveis; aparece em amostragem aleatória e como priors não informativos.
  • Use scipy.stats.skew() para medir a assimetria e scipy.stats.shapiro() para testar formalmente a normalidade.
  • Sempre inspecione as distribuições antes de modelar — a forma influencia qual algoritmo escolher, como transformar as features e qual estratégia de dimensionamento aplicar.

A seguir, explore Distribuição de Dados Normal para uma análise mais aprofundada da distribuição gaussiana e como gerá-la e trabalhá-la com SciPy.

Was this page helpful?