Sigmoidal
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
Sem Resultado
Ver Todos Resultados
  • English
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
Sem Resultado
Ver Todos Resultados
Sigmoidal
Sem Resultado
Ver Todos Resultados

Imputação de Dados Ausentes com Scikit-Learn

Carlos Melo por Carlos Melo
julho 9, 2026
em Data Science, Machine Learning, Tutoriais
0
12
VIEWS
Publicar no LinkedInCompartilhar no FacebookCompartilhar no Whatsapp

A técnica mais usada para preencher valores ausentes pode estar distorcendo silenciosamente a distribuição dos seus dados. A imputação pela média é o reflexo padrão de quase todo cientista de dados, e ela de fato resolve o erro imediato: o modelo volta a treinar. O que ela também faz, sem avisar, é concentrar centenas de valores em um único ponto, encolher a variância da coluna e atenuar as correlações que o seu modelo precisaria aprender.

Neste tutorial, você vai medir esse efeito com números, e não com intuição. A imputação de dados ausentes será tratada como um experimento controlado: vamos remover valores de um dataset completo, guardar o gabarito e comparar quatro estratégias do scikit-learn (média, mediana, KNN e imputação iterativa) em duas frentes: o erro de reconstrução contra os valores verdadeiros e o impacto de cada escolha no desempenho do modelo final. No caminho, um resultado inesperado: o KNN, em sua configuração ingênua, perde até para a média, e entender o motivo vale o artigo inteiro.

💻

Código do Artigo

Acesse o código-fonte deste artigo gratuitamente.

Informe seu email para acessar o código:

✓ Seu código está pronto!

Abrir no Google Colab →

Por que valores ausentes exigem mais do que um fillna?

Se você trabalha com dados reais, já conhece a cena: o fit falha, o traceback aponta para um NaN e a solução mais rápida é um fillna com a média ou um dropna sem cerimônia. Para a mecânica dessas operações no pandas, o guia de como tratar dados ausentes com Pandas cobre o essencial. O problema é que a decisão de como preencher raramente recebe a mesma atenção que o restante do pipeline, embora afete todas as etapas seguintes.

A literatura estatística trata o tema com mais rigor do que a prática costuma admitir. Desde o trabalho clássico de Donald Rubin, Inference and Missing Data (Biometrika, 1976), a ausência de dados é classificada em três mecanismos, e a estratégia adequada depende de qual deles está em jogo:

  • MCAR (Missing Completely At Random): a probabilidade de um valor faltar não depende de nada, nem dos valores observados, nem dos ausentes. Formalmente, P(M \mid X_{obs}, X_{mis}) = P(M). É o caso de um sensor que falha aleatoriamente.
  • MAR (Missing At Random): a ausência depende apenas de variáveis observadas, P(M \mid X_{obs}, X_{mis}) = P(M \mid X_{obs}). Pense em imóveis antigos com cadastro incompleto: a falta depende da idade do imóvel, que conhecemos.
  • MNAR (Missing Not At Random): a ausência depende do próprio valor que falta, como pessoas de renda alta que omitem a renda em pesquisas. É o cenário mais difícil, e nenhuma imputação puramente estatística o resolve por completo.

O livro Flexible Imputation of Missing Data, de Stef van Buuren, disponível gratuitamente online, é a referência moderna sobre esses mecanismos e suas consequências. Para o nosso experimento, vamos construir cenários MCAR e MAR de forma deliberada, porque só assim conseguimos medir o que cada imputador acerta.

Um experimento com gabarito

O dataset California Housing, disponível no próprio scikit-learn, descreve 20.640 distritos da Califórnia com oito variáveis numéricas, como renda mediana (MedInc), idade dos imóveis (HouseAge) e média de cômodos (AveRooms). Ele não possui valores ausentes, e é exatamente isso que o torna ideal aqui: nós mesmos removemos os valores, guardando os originais como gabarito. Para manter o experimento leve, trabalhamos com uma amostra de 5.000 distritos.

import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing

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

dados = fetch_california_housing(as_frame=True)
df_completo = dados.frame.sample(n=5000, random_state=RANDOM_STATE).reset_index(drop=True)

X_completo = df_completo.drop(columns="MedHouseVal")
y = df_completo["MedHouseVal"]

Com os dados completos em mãos, injetamos a ausência segundo os dois mecanismos. Em MedInc, removemos 15% dos valores de forma puramente aleatória (MCAR). Em AveRooms, a probabilidade de remoção cresce com a idade do imóvel, de cerca de 5% nos mais novos a 35% nos mais antigos (MAR).

X = X_completo.copy()

# MCAR: 15% dos valores de MedInc removidos ao acaso
mascara_mcar = rng.random(len(X)) < 0.15
X.loc[mascara_mcar, "MedInc"] = np.nan

# MAR: probabilidade de ausência em AveRooms cresce com HouseAge
idade = X["HouseAge"]
prob_mar = 0.05 + 0.30 * (idade - idade.min()) / (idade.max() - idade.min())
mascara_mar = rng.random(len(X)) < prob_mar
X.loc[mascara_mar, "AveRooms"] = np.nan

O resultado são 752 valores ausentes em MedInc (15% da coluna) e 1.068 em AveRooms (21,4%). O diagnóstico visual abaixo confirma que o desenho funcionou: no painel da direita, a fração de AveRooms ausente cresce de forma consistente com a faixa de idade, de menos de 10% nos imóveis com até 10 anos a mais de 30% nos mais antigos. Esse é o retrato de um mecanismo MAR, e detectá-lo em dados reais é parte do trabalho de diagnóstico que antecede qualquer imputação.

Gráficos de barras com a proporção de valores ausentes por coluna e o crescimento da ausência de AveRooms com a idade do imóvel

O que a imputação pela média faz com a distribuição?

Antes de comparar métodos, vale visualizar o problema que motivou o artigo. O gráfico abaixo sobrepõe a distribuição verdadeira de MedInc (que conhecemos, porque guardamos o gabarito) à distribuição da mesma coluna após a imputação pela média e após a imputação por KNN.

Curvas de densidade comparando a distribuição verdadeira de MedInc com as versões imputadas pela média e por KNN

O pico estreito na curva laranja é a assinatura da imputação pela média: os 752 valores imputados caem todos no mesmo ponto, criando uma concentração artificial que não existe nos dados verdadeiros. As consequências práticas são a redução da variância da coluna e a atenuação das correlações com as demais variáveis, já que os valores imputados não carregam nenhuma informação sobre o restante da linha. A curva verde, do KNN, acompanha o formato da distribuição original de perto, porque cada valor imputado é calculado a partir de vizinhos reais no espaço de atributos.

Qual método reconstrói melhor os valores?

Como guardamos o gabarito, podemos medir a raiz do erro quadrático médio (RMSE) entre o valor imputado e o valor verdadeiro, apenas nas posições mascaradas. Comparamos quatro imputadores do scikit-learn, descritos na documentação oficial de imputação: SimpleImputer com média e com mediana, KNNImputer com 5 vizinhos e IterativeImputer, que modela cada coluna com ausentes como função das demais, em rodadas sucessivas de regressão.

from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import SimpleImputer, KNNImputer, IterativeImputer

imputadores = {
    "Média": SimpleImputer(strategy="mean"),
    "Mediana": SimpleImputer(strategy="median"),
    "KNN (k=5)": KNNImputer(n_neighbors=5),
    "Iterativa": IterativeImputer(max_iter=10, random_state=RANDOM_STATE),
}

registros = []
for nome, imputador in imputadores.items():
    X_imputado = pd.DataFrame(imputador.fit_transform(X), columns=X.columns)
    for coluna, mascara in [("MedInc", mascara_mcar), ("AveRooms", mascara_mar)]:
        verdadeiro = X_completo.loc[mascara, coluna]
        imputado = X_imputado.loc[mascara, coluna]
        rmse = np.sqrt(np.mean((verdadeiro - imputado) ** 2))
        registros.append({"Imputador": nome, "Coluna": coluna, "RMSE": rmse})

A imputação iterativa vence com folga nas duas colunas: RMSE de 1,326 em MedInc contra 1,897 da média, e de 0,855 em AveRooms contra 1,584. Até aqui, nenhuma surpresa: um método que usa as relações entre as variáveis reconstrói melhor do que uma constante. A surpresa está no KNN, que registrou 2,021 em MedInc e 1,662 em AveRooms, perdendo para a média e para a mediana nas duas colunas.

A explicação está na métrica de distância. O KNNImputer calcula distâncias euclidianas sobre as colunas em suas escalas originais, e Population, com desvio padrão na casa dos milhares, domina completamente o cálculo. Na prática, os vizinhos escolhidos são os distritos de população parecida, e não os distritos de fato semelhantes no conjunto dos atributos. A correção é padronizar as colunas antes de imputar e desfazer a escala em seguida:

from sklearn.preprocessing import StandardScaler

escala = StandardScaler()
X_escalado = escala.fit_transform(X)
imputado_escalado = KNNImputer(n_neighbors=5).fit_transform(X_escalado)
X_knn_escala = pd.DataFrame(escala.inverse_transform(imputado_escalado), columns=X.columns)

Com a padronização, o RMSE do KNN recua de 2,021 para 1,522 em MedInc e de 1,662 para 1,004 em AveRooms, e o método assume o segundo lugar geral, atrás apenas da imputação iterativa. O gráfico consolida o quadro completo.

Gráfico de barras com o erro de reconstrução de cada método de imputação nas duas colunas

A lição vale para além deste dataset: todo método baseado em distância é sensível à escala das variáveis, e o KNNImputer não padroniza nada por conta própria. Uma configuração ingênua não degrada o método de forma visível: ele continua rodando e produzindo números plausíveis, e é justamente por isso que o erro passa despercebido.

E o impacto no modelo final?

O erro de reconstrução conta apenas metade da história. Em um projeto real, ninguém conhece o gabarito: o que se observa é o desempenho do modelo treinado sobre os dados imputados. Avaliamos cinco estratégias com validação cruzada de 5 folds, usando um Random Forest como regressor. A primeira estratégia é o descarte de linhas (listwise deletion); as demais imputam dentro de um Pipeline, garantindo que as estatísticas de imputação sejam aprendidas apenas no conjunto de treino de cada fold. Esse cuidado evita o vazamento de dados que discutimos em detalhe no tutorial de pipelines no scikit-learn.

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline

modelo = RandomForestRegressor(n_estimators=100, random_state=RANDOM_STATE, n_jobs=-1)

desempenho = {}

# Estratégia 1: descartar linhas com valores ausentes
completos = X.dropna()
scores_drop = cross_val_score(
    modelo, completos, y.loc[completos.index],
    cv=5, scoring="neg_root_mean_squared_error", n_jobs=-1
)
desempenho["Descarte"] = -scores_drop

# Demais estratégias: imputação dentro de um pipeline
pipelines = {
    "Média": Pipeline([("imputacao", SimpleImputer(strategy="mean")), ("modelo", modelo)]),
    "Mediana": Pipeline([("imputacao", SimpleImputer(strategy="median")), ("modelo", modelo)]),
    "KNN + escala": Pipeline([
        ("escala", StandardScaler()),
        ("imputacao", KNNImputer(n_neighbors=5)),
        ("modelo", modelo),
    ]),
    "Iterativa": Pipeline([
        ("imputacao", IterativeImputer(max_iter=10, random_state=RANDOM_STATE)),
        ("modelo", modelo),
    ]),
}

for nome, pipe in pipelines.items():
    scores = cross_val_score(pipe, X, y, cv=5, scoring="neg_root_mean_squared_error", n_jobs=-1)
    desempenho[nome] = -scores

O descarte de linhas elimina todas as observações com pelo menos um valor ausente e reduz o dataset de 5.000 para 3.347 linhas: um terço dos dados é descartado antes do primeiro fit. O resultado da validação cruzada está no gráfico abaixo.

Gráfico de barras horizontais com o RMSE do modelo final para cada estratégia de tratamento de valores ausentes

A leitura honesta dos números contraria a expectativa criada pela seção anterior. A mediana e a média produziram os melhores RMSE médios (0,572 e 0,573), seguidas pelo descarte (0,587), pela imputação iterativa (0,592) e pelo KNN com escala (0,599). As diferenças, porém, são pequenas diante do desvio padrão entre folds, na faixa de 0,022 a 0,031: nenhum método se separa dos demais com significância confortável neste dataset.

Dois pontos merecem registro. Primeiro, a qualidade da reconstrução não se traduz automaticamente em ganho no modelo final: o Random Forest particiona o espaço de atributos em regiões e convive bem com os valores constantes da imputação simples, extraindo pouco proveito da reconstrução mais fiel. Com modelos lineares, ou com frações maiores de ausência, o quadro tende a mudar. Segundo, o descarte carrega um custo que a métrica não mostra por inteiro: além de treinar com um terço a menos de dados, um modelo avaliado apenas nas linhas completas aprende com uma amostra enviesada sempre que o mecanismo não é MCAR, como no nosso cenário MAR, em que as linhas descartadas são desproporcionalmente as de imóveis antigos.

A escolha do imputador, portanto, não é uma busca pelo vencedor universal. Se o objetivo é apenas alimentar um modelo de árvores, a mediana dentro de um Pipeline é um padrão difícil de criticar. Se as colunas imputadas alimentam análises estatísticas, relatórios ou modelos sensíveis à distribuição, os métodos multivariados preservam propriedades que a constante destrói, como a variância e as correlações que vimos no gráfico de densidade. E se a suspeita é de MNAR, nenhum imputador substitui uma conversa séria sobre a origem dos dados. Esse tipo de decisão, que combina estatística, contexto e ceticismo, é parte central do ofício descrito no guia de como se tornar um cientista de dados.

O notebook completo do experimento, com todo o código executado e os gráficos deste artigo, está disponível no botão de material no início do texto.

Takeaways

  • A imputação pela média distorce a distribuição: ela concentra os valores imputados em um único ponto, reduz a variância e atenua correlações. O efeito é visível na curva de densidade de MedInc.
  • Conheça o mecanismo antes de escolher o método: MCAR, MAR e MNAR exigem estratégias diferentes, e o diagnóstico do padrão de ausência é a primeira etapa, não a última.
  • Métodos baseados em distância exigem padronização: o KNNImputer sem escala perdeu até para a média (RMSE 2,021 contra 1,897 em MedInc); com padronização, passou ao segundo melhor resultado (1,522).
  • A imputação iterativa venceu a reconstrução: RMSE de 1,326 em MedInc e 0,855 em AveRooms, com folga sobre os demais métodos.
  • Erro de reconstrução e desempenho do modelo são métricas diferentes: com Random Forest, média e mediana empataram na frente, e as diferenças ficaram dentro do desvio padrão entre folds.
  • Impute dentro de um Pipeline: as estatísticas de imputação devem ser aprendidas apenas no conjunto de treino de cada fold, exatamente como qualquer outra transformação.
CompartilharCompartilharEnviar
Post Anterior

Pipelines no Scikit-Learn: Transformações sem Data Leakage

Carlos Melo

Carlos Melo

Engenheiro de Visão Computacional graduado em Ciências Aeronáuticas pela Academia da Força Aérea (AFA) e Mestre em Engenharia Aeroespacial pelo Instituto Tecnológico de Aeronáutica (ITA).

Relacionado Artigos

Machine Learning

Pipelines no Scikit-Learn: Transformações sem Data Leakage

por Carlos Melo
julho 6, 2026
Data Science

Binary Cross-Entropy e Regressão Logística do Zero

por Carlos Melo
junho 1, 2026
Gradient Descent e Loss Function: a Origem do MSE
Data Science

Gradient Descent e Loss Function: a Origem do MSE

por Carlos Melo
maio 27, 2026
Regressão Linear e Aprendizado Supervisionado
Data Science

Regressão Linear e Aprendizado Supervisionado

por Carlos Melo
maio 26, 2026
Introdução ao Pandas: capa do guia prático para análise de dados com Python
Data Science

Introdução ao Pandas: Guia Prático para Análise de Dados

por Carlos Melo
abril 27, 2026

Deixe um comentário Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Pós em Visão Computacional Pós em Visão Computacional Pós em Visão Computacional

Mais Populares

  • Cientista de Dados: Salário em 2026 (Júnior, Pleno e Sênior)

    90 compartilhamentos
    Compartilhar 36 Tweet 23
  • Geometria da Formação de Imagens: Matrizes, Transformações e Sistemas de Coordenadas

    438 compartilhamentos
    Compartilhar 175 Tweet 110
  • ORB-SLAM 3: Tutorial Completo para Mapeamento 3D e Localização em Tempo Real

    480 compartilhamentos
    Compartilhar 192 Tweet 120
  • 6 Livros de Visão Computacional e Deep Learning

    25 compartilhamentos
    Compartilhar 10 Tweet 6
  • Introdução ao MediaPipe e Pose Estimation

    570 compartilhamentos
    Compartilhar 228 Tweet 143
  • Em Alta
  • Comentários
  • Mais Recente
Como Tratar Dados Ausentes com Pandas

Como Tratar Dados Ausentes com Pandas

agosto 13, 2019
Introdução ao MediaPipe e Pose Estimation

Introdução ao MediaPipe e Pose Estimation

julho 15, 2023
Como usar o DALL-E 2 para gerar imagens a partir de textos

Como usar o DALL-E 2 para gerar imagens a partir de textos

dezembro 25, 2022

ORB-SLAM 3: Tutorial Completo para Mapeamento 3D e Localização em Tempo Real

abril 10, 2023
Como Analisar Ações da Bolsa com Python

Como Analisar Ações da Bolsa com Python

15
Setembro Amarelo: Análise do Suicídio no Brasil, com Data Science

Setembro Amarelo: Análise do Suicídio no Brasil, com Data Science

13
Como Aprender Data Science?

Como Aprender Data Science?

9
Qual o Cenário de Data Science no Brasil hoje?

Qual o Cenário de Data Science no Brasil hoje?

8

Imputação de Dados Ausentes com Scikit-Learn

julho 9, 2026

Pipelines no Scikit-Learn: Transformações sem Data Leakage

julho 6, 2026

Binary Cross-Entropy e Regressão Logística do Zero

junho 1, 2026
Gradient Descent e Loss Function: a Origem do MSE

Gradient Descent e Loss Function: a Origem do MSE

maio 27, 2026
Instagram Youtube LinkedIn Twitter
Sigmoidal

O melhor conteúdo técnico de Data Science, com projetos práticos e exemplos do mundo real.

Seguir no Instagram

Categorias

  • Aeroespacial
  • Artigos
  • Blog
  • Carreira
  • Cursos
  • Data Science
  • Deep Learning
  • Destaques
  • Entrevistas
  • IA Generativa
  • Livros
  • Machine Learning
  • Notícias
  • Python
  • Teoria
  • Tutoriais
  • Visão Computacional
  • Youtube

Navegar por Tags

algebra-linear camera calibration carreira chatgpt cientista de dados cnn computer vision Cursos dados desbalanceados data science data science na prática decision tree deep learning deploy gpt-3 gradient descent IA generativa inteligência artificial jupyter kaggle keras livros machine learning matplotlib nft openai opencv pandas profissão python pytorch reconstrução 3d redes neurais redes neurais convolucionais regressão linear regressão logística salário scikit-learn sklearn tensorflow tutorial visão computacional vídeo youtube árvore de decisão

© 2024 Sigmoidal - Aprenda Data Science, Visão Computacional e Python na prática.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In

Add New Playlist

Sem Resultado
Ver Todos Resultados
  • Home
  • Pós-Graduação
  • Blog
  • Sobre Mim
  • Contato
  • English

© 2024 Sigmoidal - Aprenda Data Science, Visão Computacional e Python na prática.