
À medida que o cenário de ciência de dados fica cada vez mais complexo, com novas tecnologias surgindo todos os dias, escolher a caixa de ferramentas certa é crucial para o seu projeto. Quanto mais complexo o projeto, mais cuidado você precisa ter na escolha dos recursos, porque essas decisões impactam diretamente o desenvolvimento e, no fim, o sucesso do seu trabalho.
Se você está tocando um projeto de ciência de dados, as escolhas de design vão muito além do debate Python vs R. Também é sobre quais bibliotecas usar depois que você define as linguagens de programação que vão sustentar o projeto.
No caso do Python para ciência de dados, pandas é a ferramenta padrão para manipulação de dados. Os motivos para usar pandas são muitos e convincentes, mas ele também tem limitações que podem gerar gargalos importantes. Em especial, o pandas é conhecido por ter desempenho limitado com conjuntos de dados muito grandes.
Para lidar com esses pontos, o pandas lançou recentemente a versão 2.0, com revisões relevantes e ganhos de performance (veja este artigo para saber tudo sobre o pandas 2.0).
Enquanto isso, novas alternativas surgiram no ecossistema Python para desafiar a dominância do pandas. Uma das mais populares é o polars, uma biblioteca baseada em Python e Rust para análises de dados mais rápidas.
Neste artigo, vamos analisar as diferenças entre pandas 2.0 e polars para manipulação de dados. Primeiro, veremos estratégias para melhorar a performance computacional e, depois, uma série de testes comparando o desempenho das duas ferramentas. Vamos nessa!
Como escolher entre pandas e polars
Não existe uma tecnologia única, melhor em termos absolutos, para resolver todos os problemas e situações que surgem no seu fluxo de trabalho em ciência de dados. É preciso equilibrar vários fatores antes de decidir. Aqui estão alguns dos mais relevantes:
- Desempenho computacional. Como regra geral, quanto maior e mais complexo o projeto, mais vale considerar ferramentas de alta performance para evitar gargalos de processamento.
- Compatibilidade com o stack. As ferramentas usadas em um projeto de ciência de dados raramente funcionam isoladas. Elas operam em conjunto com outras tecnologias do seu stack. Antes de decidir, avalie sinergias e encaixes entre as soluções.
- Compatibilidade de código. Adotar uma tecnologia nova também envolve pensar na compatibilidade e na eficiência do código. Se a adoção implicar reescrever projetos existentes, isso deve entrar na conta.
- Popularidade. A popularidade de uma ferramenta é um indicador de quantas pessoas a usam, o que pode facilitar na hora de contratar ou tirar dúvidas em plataformas como o Stack Overflow.
Como melhorar a performance na manipulação de dados?
Nesta seção, cobrimos as principais técnicas que ajudam a turbinar a performance na manipulação de dados.
Reduzindo cópias com copy-on-write
Em ferramentas tradicionais de manipulação de dados, cada operação gera uma nova cópia de todo o dataset. Esse comportamento pode ser um problema para a memória quando lidamos com conjuntos de dados grandes.
Copy-on-write é a técnica mais comum para resolver isso. Em essência, copy-on-write é um método de gerenciamento de recursos que permite implementar operações de "duplicar" ou "copiar" de forma eficiente em recursos mutáveis. Isso significa que, se um dataset é duplicado mas não é (totalmente) modificado, não é necessário criar um novo recurso: a memória pode ser compartilhada entre a cópia e o original.
Computação paralela
Uma das principais desvantagens do pandas é ser single-threaded, o que impede o uso de técnicas de computação paralela que já são comuns em ciência de dados. A paralelização pode acontecer via máquinas multi-core ou computação distribuída (um conjunto de computadores trabalhando em cluster).
Veja o exemplo a seguir com a popular operação de group by. Se você quiser calcular a idade média de jogadores de basquete por time, dá para usar computação paralela para atribuir o cálculo da média de cada grupo a um core ou máquina, em vez de calcular um por um — aumentando a performance.

Otimização da importação de dados
O ponto de partida de uma análise normalmente é ler os datasets que você quer estudar. Porém, isso costuma ser um gargalo em projetos com dados volumosos. Aqui vão algumas técnicas para melhorar a performance na leitura:
- Leitura em chunks. Em vez de ler o arquivo inteiro, quebre-o em pedaços menores (chunks). Isso acelera a importação e reduz o uso de memória simultânea.
- Ler apenas as colunas necessárias. Muitas vezes você já sabe quais colunas serão usadas. Em vez de carregar tudo, filtre previamente e leia só o que importa.
- Downcasting de tipos. Ferramentas como pandas atribuem tipos padrão às colunas importadas. Às vezes existem tipos alternativos que consomem menos memória sem perder informação. Downcasting é mudar o tipo para o menor possível que comporte os valores.
Avaliação preguiçosa (lazy) e planejamento de consultas
A ordem das operações pode afetar a performance. Com frequência, dá para reordenar cálculos e chegar ao mesmo resultado de forma mais eficiente.
Há duas estratégias para isso: lazy evaluation e query planning. A primeira adia os cálculos até o momento em que são realmente necessários. Já o planejamento de consultas busca a forma mais eficiente de executar múltiplas manipulações dado um conjunto de queries. Para isso, geralmente se usa um otimizador de consultas.
Processamento out-of-core
Ferramentas como pandas armazenam datasets inteiros na memória, o que complica quando você trabalha com dados que não cabem na memória do computador ou em operações muito intensivas.
É aqui que entra o processamento out-of-core. Em termos simples, ele usa memória externa (por exemplo, um disco) para guardar dados que não caberiam na memória principal. Assim, você processa os dados externamente em chunks e, no final, obtém o mesmo resultado que teria processando tudo em memória.
Quais são alternativas de alta performance ao pandas?
Este artigo foca na comparação pandas 2.0 vs polars, mas vale citar outras ferramentas que podem atender às suas necessidades como alternativa ao pandas. Algumas promissoras:
- Koalas. Uma API de pandas construída sobre o PySpark. Se você já usa Spark, vale considerar.
- Vaex. Uma API de pandas para computação fora da memória, ótima para analisar dados tabulares gigantes a bilhões de linhas por segundo.
- Modin. Uma API de pandas para programação paralela, baseada nos frameworks Dask ou Ray para big data. Se você usa Dask ou Ray, o Modin é um excelente recurso.
- cuDF. Parte do projeto RAPIDS, é uma API no estilo pandas para computação em GPU, que usa GPUs NVIDIA ou outros componentes do RAPIDS para manipular dados em alta velocidade.
Por que escolher polars?
Pandas é a opção padrão para quem usa Python, mas, como já explicamos, traz limitações importantes ao lidar com grandes volumes de dados. A missão central do polars é oferecer um dataframe ultra-rápido que resolva os problemas do pandas.
Escrito em Rust (uma linguagem poderosa que entrega performance de C/C++ e permite controle total das partes críticas do mecanismo de consultas), o polars integra metodologias de ponta para aumentar a performance, projetadas para:
- Expandir a computação paralela para usar todos os cores disponíveis da sua máquina.
- Otimizar consultas e reduzir trabalho/alocações desnecessárias com lazy evaluation e query planning.
- Melhorar o desempenho de armazenamento usando semântica de copy-on-write e Apache Arrow.
- Lidar com datasets muito maiores por meio de recursos out-of-core via sua API de streaming.
Por último, mas não menos importante, o polars tem sintaxe bem parecida com a do pandas e compartilha os mesmos blocos de construção, como Series e DataFrames. Isso facilita a migração caso você decida adotar o polars.
Como o pandas está reagindo com o pandas 2.0?
Para enfrentar questões de performance e a pressão dos concorrentes, o pandas lançou a aguardada versão 2.0. Como uma atualização de grande porte, o pandas 2.0 traz vários recursos novos e também descontinuações impostas, resultando em mudanças na API.
O novo backend PyArrow é a grande aposta para atacar limitações de performance. Agora o usuário pode escolher entre o backend tradicional do NumPy ou o novo PyArrow. PyArrow é uma biblioteca em Python que oferece interface para lidar com grandes volumes de dados usando estruturas de memória Arrow.
pd.read_csv(my_file, engine='pyarrow')
Outro ponto importante é a incorporação de várias melhorias de copy-on-write para economizar memória e ganhar performance.
Como resultado, muitas operações do pandas agora incluem um parâmetro padrão "copy" que retorna uma cópia lazy de objetos básicos do pandas, como series e dataframes, em vez de cópias idênticas em cache.
Ainda é cedo para saber se essas novidades vão resolver de vez os problemas de performance do pandas. Mesmo que outras ferramentas superem seu desempenho, ainda haverá bons motivos para continuar usando pandas: você não precisa reescrever código existente nem aprender uma nova sintaxe, já que provavelmente ele já faz parte do seu stack.
pandas 2.0 vs polars: estrutura de comparação
Agora que você já viu a teoria, é hora de colocar a mão na massa. Nas próximas seções, vamos rodar uma série de testes para comparar o desempenho de pandas 2.0 vs polars. Nosso benchmark será o tempo necessário para executar cada tarefa. Para isso, usaremos o módulo time, que permite medir tempos de execução de forma simples.
Além dos testes de performance, vamos analisar a compatibilidade de código do polars com o pandas (isto é, quanto você precisa mudar caso queira migrar para polars?).
O dataset
Vamos testar o desempenho de pandas 2.0 vs polars com um dataset fictício de vendas por hora de uma empresa com escritórios em vários países, cobrindo o período de 1980 a 2022. Para aumentar a complexidade do benchmark, adicionaremos alguns valores ausentes aleatórios.
No total, o dataset tem mais de 22 milhões de linhas e consome mais de 1,6 GB de memória — o suficiente para colocar o pandas sob pressão. Todo o código dos testes está disponível neste workbook do DataLab.

Teste de importação
Vamos começar comparando a performance de pandas 2.0 e polars na importação de dados. O polars divulga explicitamente alto desempenho ao importar CSV. Isso se confirma?
Faremos um teste para medir quanto tempo pandas e polars levam para ler um subconjunto de colunas e linhas. Por exemplo, digamos que você só quer analisar as vendas do escritório da França. Com pandas, é preciso ler todas as linhas e depois filtrar as desnecessárias. Usaremos o método novo .query() para isso. Para avaliar o comportamento do pandas 2.0, vamos importar o CSV tanto com o engine tradicional do numpy quanto com o novo engine do pyarrow.
Já o polars oferece o método filter(), que pode ser usado com condições para ler apenas as linhas de interesse.
# pandas query
df_pd = pd.read_csv("./example.csv", engine="pyarrow")
df_pd = df_pd[['id', 'date', 'office', 'sales']]
df_pd = df_pd.query("office=='France'")
# polars filter
df_pl = pl.read_csv('example.csv').filter(
(pl.col('office') == 'France'))
df_pl.select(pl.col(['id', 'date', 'office', 'sales']))
No teste, o polars tem desempenho consideravelmente melhor que o pandas, como mostra o gráfico. Surpreendentemente, o engine pyarrow não trouxe resultados superiores ao engine padrão do numpy.

Em termos de sintaxe, o polars tem a mesma "cara" do pandas, com funções como pl.read_csv() que espelham bem o pandas. Porém, as bibliotecas funcionam de forma diferente por baixo dos panos, o que leva a diferenças inevitáveis de sintaxe, como vimos em query() vs filter().
Teste de group by
Operações de groupby são ótimas candidatas à paralelização. Vamos ver como pandas e polars se comportam em algumas agregações. Em particular, vamos calcular a média e a mediana de vendas por escritório e mês.
df_pd.groupby([df_pd.office, df_pd.date.dt.month])['sales'].agg('mean') # pandas groupby mean
df_pl.groupby([pl.col('office'), pl.col('date').dt.month()]).agg([pl.mean('sales')]) # polars groupby mean

df_pd.groupby([df_pd.office, df_pd.date.dt.month])['sales'].agg('median') # pandas groupby median
df_pl.groupby([pl.col('office'), pl.col('date').dt.month()]).agg([pl.median('sales')]) pandas groupby median

Os resultados mostram que, em cálculos de group by e agregação, o polars supera o pandas. De novo, a sintaxe do polars lembra a do pandas.
Teste de estatísticas móveis (rolling)
Outra operação interessante para testar desempenho é a de estatísticas móveis. Otimizar esse tipo de cálculo envolve truques algorítmicos. Vamos ver o comportamento ao calcular a média móvel diária de vendas.
# pandas rolling mean
df_pd['sales'].rolling(1440, min_periods=1).mean()
# polars rolling mean
df_pl['sales'].rolling_mean(1440, min_periods=1)
Mais uma vez, o polars leva a melhor. Note a diferença sutil de sintaxe: o polars traz o método rolling_mean(), enquanto o pandas usa rolling() combinado com mean() para chegar ao mesmo resultado.

Teste de amostragem
Estudar toda a população de interesse geralmente é inviável. Por isso, a amostragem é uma das tarefas mais comuns em estatística e ciência de dados. Isso envolve tirar amostras aleatórias com técnicas de Simulação de Monte Carlo, como bootstrap e permutação. Porém, essa operação costuma exigir muitas cópias de variáveis, o que pode ser desafiador se os recursos computacionais forem limitados.
Vamos ver como pandas e polars se saem ao executar um bootstrap (reamostragem com reposição). Vamos estimar a média de vendas em 10.000 amostras com 1.000 pontos cada.
#pandas bootstrap
simu_weights = []
for i in range(10000):
bootstrap_sample = random.choices(df_pd['sales'], k=1000)
simu_weights.append(np.nanmean(bootstrap_sample))
#polars bootstrap
simu_weights = []
for i in range(10000):
bootstrap_sample = df_pl['sales'].sample(n=1000,with_replacement=True)
simu_weights.append(bootstrap_sample.mean())
No bootstrap, o polars é quase 5 vezes mais rápido que o pandas.
Quanto à sintaxe, enquanto o pandas depende do numpy para amostragem, o polars traz um prático método nativo sample().

Manipulações encadeadas
No último teste, vamos executar uma série de manipulações conectadas. Isso faz parte do dia a dia de quem trabalha com dados. Ainda assim, operações com muitos passos são fáceis de escrever de forma subótima.
Imagine que o escritório italiano da empresa fictícia está considerando contratar alguns estagiários de 2022 após o fim do período de trainee. Nosso objetivo é analisar quais estagiários fizeram as dez maiores vendas em 2022 para ajudar na escolha dos candidatos mais promissores.
Para isso, precisamos juntar nosso dataset a um segundo dataset, chamado "italy_2022", que contém informações sobre quem realizou cada transação em 2022. A coluna "id" é comum aos dois conjuntos.

# pandas compound operations
df_pd.merge(italy_2022, on='id').query("responsibility =='Sales Intern'").sort_values('sales', ascending=False).head(10)[['name','surname','sales','sex']]
#polars compound manipulations
df_pl.join(italy_2022_pl, on="id").filter(pl.col('responsability') == 'Sales Intern').sort('sales',descending=True).head(10).select(pl.col(['name','surname','sales','sex']))

Como nos testes anteriores, o polars superou o pandas em performance. Aqui, a operação de join parece ser o maior desafio do pandas. Já o polars é bem mais eficiente, levando menos de dois segundos para concluir todas as etapas encadeadas.
Tabela comparativa: pandas 2.0 vs polars
Resumimos os testes acima em uma tabela para uma visão rápida:
|
Teste |
Pandas 2.0 |
Polars |
Vencedor |
Similaridade de sintaxe |
|
Teste de importação |
Lê todas as linhas e depois filtra as indesejadas usando o método .query() |
Lê diretamente apenas as linhas de interesse com o método filter() |
Polars (melhor desempenho) |
Parecido, mas com diferenças pela implementação interna (.query() vs filter()) |
|
Teste de group by |
Usa .groupby() para agregações como média e mediana de vendas por escritório e mês |
Igual ao pandas, mas com melhor performance |
Polars (melhor desempenho) |
Similar |
|
Teste de estatísticas móveis |
Usa o método rolling() combinado com outros, como mean(), para médias móveis |
Usa o método rolling_mean() para médias móveis |
Polars (melhor desempenho) |
Parecido, com pequenas diferenças (.rolling().mean() vs rolling_mean()) |
|
Teste de amostragem |
Usa numpy para operações de bootstrap |
Usa o método nativo sample() para bootstrap |
Polars (quase 5x mais rápido) |
Diferente: pandas depende do numpy, polars tem métodos nativos |
|
Teste de manipulações encadeadas |
Faz join com outro dataset e depois ordena e seleciona dados |
Executa as mesmas tarefas com mais eficiência |
Polars (significativamente mais rápido) |
Parecido, com diferenças sutis (merge().query().sort_values().head() vs join().filter().sort().head().select()) |
Leve isso para o próximo nível
Parabéns por chegar até o fim deste tutorial. Pelos testes, o polars tem desempenho bem superior ao pandas 2.0 em quase todos os cenários. Embora isso ameace sua dominância, o pandas ainda tem a vantagem de ser a opção padrão para manipulação de dados em Python, com todos os benefícios de uma comunidade de usuários enorme.
Se você trabalha com grandes volumes de dados, ganhar performance é obrigação. A DataCamp te ajuda nessa. Aqui vão alguns cursos para levar seu desempenho computacional para o próximo nível:
Sou analista de dados freelancer, colaborando com empresas e organizações em todo o mundo em projetos de ciência de dados. Também sou instrutor de ciência de dados com mais de 2 anos de experiência. Escrevo regularmente artigos relacionados à ciência de dados em inglês e espanhol, alguns dos quais foram publicados em sites consagrados, como DataCamp, Towards Data Science e Analytics Vidhya Como cientista de dados com formação em ciência política e direito, meu objetivo é trabalhar na interação de políticas públicas, direito e tecnologia, aproveitando o poder das ideias para promover soluções e narrativas inovadoras que possam nos ajudar a enfrentar desafios urgentes, como a crise climática. Eu me considero uma pessoa autodidata, um aprendiz constante e um firme defensor da multidisciplinaridade. Nunca é tarde demais para aprender coisas novas.



