Como Migrar do Pandas para o Polars em Python: Guia Prático Completo

Aprenda a migrar do Pandas para o Polars em Python com exemplos de código lado a lado, benchmarks de desempenho reais e uma estratégia de migração gradual que funciona na prática.

Por Que Migrar do Pandas para o Polars em 2026?

Se você trabalha com dados em Python, é bem provável que o Pandas faça parte da sua rotina há um bom tempo. Eu mesmo usei Pandas por anos sem questionar — até começar a lidar com datasets que faziam minha máquina travar. Em 2026, o cenário mudou bastante. O Polars, uma biblioteca DataFrame construída em Rust, entrega ganhos de desempenho de 4x a 14x em operações comuns e até 100x em datasets grandes, consumindo uma fração da memória.

Com metade das equipes de dados já testando ou adotando o Polars, a pergunta deixou de ser "devo considerar o Polars?" e passou a ser "como faço pra migrar?".

Neste guia, vamos ver passo a passo como converter suas operações mais comuns do Pandas para o Polars, com exemplos lado a lado, benchmarks reais e uma estratégia de migração que funciona na prática.

O Que É o Polars e Como Ele Se Diferencia

O Polars é uma biblioteca open-source de processamento de dados escrita em Rust, com bindings para Python. Enquanto o Pandas opera em thread única sobre arrays NumPy, o Polars foi projetado desde o início pra aproveitar todos os núcleos do processador, usando Apache Arrow como base de memória colunar.

As vantagens técnicas principais são:

  • Multi-threading automático — todas as operações são paralelizadas sem configuração extra
  • Lazy execution — o Polars monta um plano de consulta otimizado antes de executar, parecido com um motor SQL
  • Eficiência de memória — armazenamento colunar Apache Arrow consome 30% a 70% menos RAM que o Pandas
  • Streaming — processa datasets que não cabem na memória (algo que o Pandas simplesmente não faz nativamente)

O Polars requer Python 3.10+ e está sob licença MIT. A versão mais recente saiu em março de 2026, com atualizações a cada duas semanas mais ou menos.

Instalação e Configuração Inicial

Instalar o Polars é direto ao ponto:

pip install polars

Se você precisa de funcionalidades extras como leitura de Excel, conexão com bancos de dados ou operações com fuso horário, instale com os extras correspondentes:

# Instalar com todos os extras
pip install "polars[all]"

# Ou selecionar extras específicos
pip install "polars[xlsx2csv,sqlalchemy,timezone]"

Pra verificar se deu tudo certo:

import polars as pl
print(pl.__version__)
pl.show_versions()

Comparação de Sintaxe: Pandas vs Polars

Aqui vai a boa notícia: a sintaxe do Polars é bem intuitiva pra quem já conhece Pandas. Vamos ver as operações mais comuns lado a lado.

Criação de DataFrames

# Pandas
import pandas as pd
df_pd = pd.DataFrame({
    "nome": ["Ana", "Bruno", "Carlos"],
    "idade": [28, 35, 42],
    "salario": [5500.0, 7800.0, 9200.0]
})

# Polars
import polars as pl
df_pl = pl.DataFrame({
    "nome": ["Ana", "Bruno", "Carlos"],
    "idade": [28, 35, 42],
    "salario": [5500.0, 7800.0, 9200.0]
})

Praticamente idêntico, certo? A diferença principal é que o Polars não tem índice — e, honestamente, isso simplifica muita coisa.

Leitura de Arquivos CSV e Parquet

# Pandas
df_pd = pd.read_csv("dados.csv")
df_pd = pd.read_parquet("dados.parquet")

# Polars (eager - execução imediata)
df_pl = pl.read_csv("dados.csv")
df_pl = pl.read_parquet("dados.parquet")

# Polars (lazy - execução otimizada, recomendado)
df_lazy = pl.scan_csv("dados.csv")
df_lazy = pl.scan_parquet("dados.parquet")
# Executa só quando necessário:
resultado = df_lazy.collect()

O scan_* é onde a mágica acontece. Ele cria um LazyFrame que permite ao otimizador reorganizar e eliminar operações desnecessárias antes de executar qualquer coisa. Na prática, isso faz uma diferença enorme em pipelines com vários passos.

Seleção de Colunas e Filtragem

# Pandas
df_pd[["nome", "salario"]]
df_pd[df_pd["idade"] > 30]
df_pd.loc[df_pd["salario"] > 6000, "nome"]

# Polars
df_pl.select(["nome", "salario"])
df_pl.filter(pl.col("idade") > 30)
df_pl.filter(pl.col("salario") > 6000).select("nome")

No Polars, pl.col() é o bloco fundamental de tudo. Toda operação sobre colunas usa expressões baseadas nessa função, o que torna o código mais explícito e — mais importante — otimizável pelo motor interno.

GroupBy e Agregações

# Pandas
df_pd.groupby("departamento").agg(
    media_salario=("salario", "mean"),
    total_funcionarios=("nome", "count")
)

# Polars
df_pl.group_by("departamento").agg(
    pl.col("salario").mean().alias("media_salario"),
    pl.col("nome").count().alias("total_funcionarios")
)

Detalhe importante: no Polars o método é group_by (com underscore), enquanto no Pandas é groupby. Parece bobagem, mas isso pega muita gente no início. As agregações usam expressões encadeadas — mais verboso, sim, mas também mais poderoso e legível quando as coisas ficam complexas.

Joins (Junções)

# Pandas
resultado = pd.merge(df_vendas, df_clientes, on="cliente_id", how="left")

# Polars
resultado = df_vendas.join(df_clientes, on="cliente_id", how="left")

Os joins no Polars são entre 3x e 13x mais rápidos que no Pandas. Sério. Isso graças à implementação paralela de hash join.

Adição e Transformação de Colunas

# Pandas
df_pd["salario_anual"] = df_pd["salario"] * 12
df_pd["faixa_etaria"] = df_pd["idade"].apply(
    lambda x: "jovem" if x < 30 else "senior"
)

# Polars
df_pl = df_pl.with_columns(
    (pl.col("salario") * 12).alias("salario_anual"),
    pl.when(pl.col("idade") < 30)
      .then(pl.lit("jovem"))
      .otherwise(pl.lit("senior"))
      .alias("faixa_etaria")
)

No Polars, with_columns() substitui o assign() ou a atribuição direta do Pandas. E aqui vai um ponto crucial: pl.when().then().otherwise() substitui o temido apply() com lambda. O desempenho é muito superior porque é vetorizado — nada de Python puro rodando linha a linha.

Lazy Execution: O Grande Diferencial do Polars

Se eu tivesse que escolher uma única razão pra adotar o Polars, seria a lazy execution. Esse recurso não tem equivalente direto no Pandas, e ele muda completamente a forma como você pensa sobre pipelines de dados.

A ideia é simples: você descreve toda a sequência de operações que quer fazer, e o Polars otimiza o plano de execução antes de processar qualquer dado.

# Pipeline completo com lazy execution
resultado = (
    pl.scan_parquet("vendas_2026.parquet")
    .filter(pl.col("valor") > 100)
    .filter(pl.col("regiao") == "sudeste")
    .group_by("categoria")
    .agg([
        pl.col("valor").sum().alias("total_vendas"),
        pl.col("valor").mean().alias("ticket_medio"),
        pl.col("id_pedido").n_unique().alias("num_pedidos")
    ])
    .sort("total_vendas", descending=True)
    .collect()  # Executa tudo de uma vez, otimizado
)

O otimizador aplica automaticamente técnicas como:

  • Predicate pushdown — filtros são empurrados pra o mais cedo possível na leitura do arquivo
  • Projection pushdown — só as colunas que você realmente usa são carregadas do disco
  • Eliminação de operações redundantes — passos desnecessários são removidos automaticamente
  • Paralelização automática — operações independentes rodam em paralelo sem você fazer nada

Dá pra visualizar o plano de execução e entender exatamente o que o Polars vai fazer:

# Ver o plano de execução otimizado
lazy_query = (
    pl.scan_parquet("vendas_2026.parquet")
    .filter(pl.col("valor") > 100)
    .select(["categoria", "valor"])
)
print(lazy_query.explain())

Quando vi isso pela primeira vez, confesso que fiquei impressionado. É como ter um DBA otimizando suas queries automaticamente.

Benchmarks Reais: Pandas vs Polars em 2026

Números falam mais alto que promessas. Testes independentes com datasets de aproximadamente 1 GB mostram diferenças bem expressivas:

  • Leitura de CSV: Polars é 5x mais rápido e usa 87% menos memória (179 MB vs 1,4 GB no Pandas)
  • Filtragem de linhas: Polars é 4,6x mais rápido graças ao multi-threading
  • GroupBy e agregações: Polars é 2,6x a 10x mais rápido, dependendo da complexidade da operação
  • Joins: Polars é 9x a 13x mais rápido com hash joins paralelos
  • Ordenação (sort): Polars é 11,7x mais rápido — a maior diferença entre todas as operações testadas

Vale ressaltar: pra datasets pequenos (menos de 100 MB), a diferença é bem menos expressiva. E pra operações pesadas de strings e regex, o Pandas ainda pode ganhar em certos cenários. Não é tudo preto e branco.

Guia de Migração Passo a Passo

Migrar um projeto inteiro do Pandas pro Polars de uma tacada só? Péssima ideia. Siga esta estratégia gradual — funciona muito melhor na prática.

Passo 1: Identifique os Gargalos

Antes de sair migrando tudo, meça onde o Pandas é mais lento no seu pipeline. Use profiling simples pra descobrir as operações que mais consomem tempo e memória:

import time

inicio = time.perf_counter()
# Sua operação Pandas aqui
df_resultado = df.groupby("coluna").agg({"valor": "sum"})
tempo = time.perf_counter() - inicio
print(f"Tempo: {tempo:.2f}s")

Não precisa ser sofisticado. Às vezes um time.perf_counter() simples já mostra onde estão os problemas.

Passo 2: Converta as Operações Críticas Primeiro

Comece migrando as operações mais lentas. Leitura de arquivos grandes, joins e agregações costumam ser os candidatos ideais — é onde o Polars brilha mais.

Passo 3: Use Interoperabilidade Pandas ↔ Polars

O Polars facilita bastante a convivência entre as duas bibliotecas:

# Pandas → Polars
df_polars = pl.from_pandas(df_pandas)

# Polars → Pandas
df_pandas = df_polars.to_pandas()

# Conversão eficiente via Arrow (sem cópia de memória)
import pyarrow as pa
arrow_table = df_polars.to_arrow()
df_pandas = arrow_table.to_pandas()

Essa interoperabilidade é o que torna a migração gradual viável. Você não precisa reescrever tudo de uma vez — vai convertendo aos poucos.

Passo 4: Adapte o Código de Machine Learning

A maioria das bibliotecas de ML (scikit-learn, XGBoost, LightGBM) ainda espera Pandas ou NumPy como entrada. A dica aqui é: faça o processamento pesado com Polars e converta só na fronteira com essas bibliotecas.

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

# Processamento pesado com Polars (rápido)
df_processado = (
    pl.scan_parquet("features.parquet")
    .filter(pl.col("valido") == True)
    .select(["feature_1", "feature_2", "feature_3", "target"])
    .collect()
)

# Converte para NumPy apenas para o ML
X = df_processado.select(["feature_1", "feature_2", "feature_3"]).to_numpy()
y = df_processado.select("target").to_numpy().ravel()

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
modelo = RandomForestClassifier()
modelo.fit(X_train, y_train)

Passo 5: Substitua apply() por Expressões

O apply() é uma das maiores fontes de lentidão no Pandas. Ele executa Python puro linha a linha — basicamente anula qualquer vantagem de vetorização. No Polars, substitua por expressões nativas:

# Pandas (lento)
df_pd["desconto"] = df_pd.apply(
    lambda row: row["preco"] * 0.1 if row["vip"] else 0, axis=1
)

# Polars (rápido)
df_pl = df_pl.with_columns(
    pl.when(pl.col("vip"))
      .then(pl.col("preco") * 0.1)
      .otherwise(0)
      .alias("desconto")
)

Essa mudança sozinha já pode acelerar partes do seu pipeline em 10x ou mais.

Quando NÃO Migrar para o Polars

Nem tudo é sobre velocidade. Existem cenários onde manter o Pandas faz total sentido:

  • Datasets pequenos (menos de 100 MB) — o ganho é mínimo e não justifica reescrever código que já funciona
  • Manipulação intensiva de strings — regex complexo, parsing de texto e codificação categórica ainda são mais rápidos no Pandas em vários casos
  • Integração forte com ecossistema ML — se seu pipeline depende pesadamente de scikit-learn, a conversão constante entre formatos pode anular os ganhos
  • Equipe sem familiaridade — se todo mundo só conhece Pandas e o prazo tá apertado, migrar agora pode não ser a melhor escolha
  • Análise exploratória rápida — pra EDA em Jupyter Notebooks com datasets moderados, o Pandas continua excelente

O importante é usar a ferramenta certa pro problema certo. Não é porque o Polars é mais rápido que você precisa migrar tudo cegamente.

Pipeline Híbrido: O Melhor dos Dois Mundos

Na minha experiência, a abordagem mais prática em 2026 é o pipeline híbrido. Use Polars pros gargalos de ETL e processamento pesado, e converta pra Pandas nas fronteiras com bibliotecas de visualização e ML.

import polars as pl
import pandas as pd
import matplotlib.pyplot as plt

# ETL pesado com Polars (rápido)
df_resultado = (
    pl.scan_parquet("vendas_grande.parquet")
    .filter(pl.col("ano") == 2026)
    .group_by("mes")
    .agg(pl.col("receita").sum().alias("receita_total"))
    .sort("mes")
    .collect()
)

# Visualização com Matplotlib via Pandas
df_plot = df_resultado.to_pandas()
plt.figure(figsize=(10, 6))
plt.bar(df_plot["mes"], df_plot["receita_total"])
plt.title("Receita Mensal 2026")
plt.xlabel("Mês")
plt.ylabel("Receita (R$)")
plt.show()

Esse padrão permite que você aproveite a velocidade do Polars onde realmente importa, sem abrir mão do ecossistema gigante do Pandas. É pragmático, funciona, e evita aquela dor de cabeça de reescrever tudo de uma vez.

Perguntas Frequentes

O Polars vai substituir o Pandas completamente?

Não no curto prazo — e talvez nunca completamente. O Pandas tem mais de uma década de desenvolvimento, um ecossistema massivo e milhões de usuários. O Polars é uma alternativa poderosa pra cenários onde desempenho e escala são críticos, mas o Pandas continua sendo a escolha padrão pra análise exploratória e projetos menores. A tendência em 2026 é dominar ambos e usar cada um no contexto certo.

Preciso reescrever todo o meu código Pandas para usar Polars?

De jeito nenhum. A melhor estratégia é a migração gradual. Identifique os gargalos de desempenho no seu pipeline e converta apenas essas partes. O Polars oferece pl.from_pandas() e .to_pandas() justamente pra facilitar a convivência entre as duas bibliotecas no mesmo projeto.

O Polars funciona com Jupyter Notebooks?

Sim, funciona perfeitamente. O Polars exibe DataFrames de forma organizada no Jupyter, e a experiência é bem parecida com a do Pandas. A diferença é que operações sobre datasets grandes vão ser significativamente mais rápidas.

Qual a diferença entre Polars e PySpark?

O PySpark é feito pra computação distribuída em clusters — ideal pra datasets de dezenas ou centenas de gigabytes que não cabem numa máquina só. O Polars é otimizado pra processamento local, aproveitando ao máximo os recursos de uma única máquina. Pra datasets de até 10-50 GB, o Polars geralmente é mais rápido e muito mais simples de configurar.

Como o Polars lida com valores nulos?

O Polars usa null nativo do Apache Arrow pra representar valores ausentes, que é mais eficiente que o NaN do NumPy usado pelo Pandas. Pra tratar nulos, use fill_null(), drop_nulls() ou interpolate() — os nomes são parecidos com os do Pandas, então a adaptação é rápida.

Sobre o Autor Editorial Team

Our team of expert writers and editors.