Polars × pandas: qual é a diferença?
Se você tiver acompanhado os avanços em dataframes para Python no último ano, não pode ter deixado de ouvir falar do Polars, a poderosa biblioteca de dataframes projetada para trabalhar com grandes conjuntos de dados.

Experimente o Polars no DataSpell
Ao contrário de outras bibliotecas para trabalhar com grandes conjuntos de dados, como Spark, Dask e Ray, o Polars foi projetado para ser usado em uma só máquina, o que provoca muitas comparações com o pandas. Porém, o Polars é diferente do pandas de várias maneiras significativas, incluindo a forma como ele trabalha com os dados e quais são suas aplicações ideais. No artigo a seguir, vamos explorar os detalhes técnicos que diferenciam essas duas bibliotecas para dataframes e vamos dar uma olhada nos pontos fortes e nas limitações de cada uma.
Se você quiser saber mais sobre isso do próprio criador do Polars, Ritchie Vink, você também pode ver abaixo nossa entrevista com ele!
Por que usar o Polars e não o pandas?
Em uma palavra: desempenho. O Polars foi criado desde o início para ser incrivelmente rápido e poder fazer operações comuns de 5 a 10 vezes mais rapidamente que o pandas. Além disso, os requisitos de memória das operações com o Polars são significativamente menores que com o pandas: este requer de 5 a 10 vezes mais RAM que o tamanho do conjunto de dados para fazer suas operações, comparado com 2 a 4 vezes no Polars.
Você pode ter aqui uma ideia do desempenho do Polars em comparação com outras bibliotecas para dataframes. Como você pode ver, o Polars é de 10 a 100 vezes mais rápido que o pandas para operações comuns e, de fato, é uma das mais rápidas dentre todas as bibliotecas para dataframes. Além disso, ele consegue trabalhar com conjuntos maiores de dados que o pandas, antes de ocorrerem erros de falta de memória.
Por que o Polars é tão rápido?
Esses resultados são realmente impressionantes. Então, você deve estar se perguntando: como o Polars consegue tanto desempenho sendo executado em uma só máquina? A biblioteca foi projetada desde o início pensando no desempenho e isso é conseguido de algumas maneiras diferentes.
Escrito em Rust
Um dos fatos mais conhecidos sobre o Polars é que ele é escrito em Rust, uma linguagem de baixo nível quase tão rápida quanto C e C++. Já o pandas foi baseado em bibliotecas de Python, uma delas o NumPy. Embora o núcleo do NumPy seja escrito em C, ele ainda é limitado por problemas inerentes à maneira como o Python lida com certos tipos na memória, como strings para dados categóricos. Isso leva a um desempenho ruim ao lidar com esses tipos (veja esta fantástica postagem de blog de Wes McKinney para saber mais detalhes).
Uma das outras vantagens de usar Rust é que esta linguagem permite concorrência segura; ou seja, ela foi projetada para tornar o paralelismo o mais previsível possível. Isso significa que o Polars pode usar com segurança todos os núcleos da sua máquina, até mesmo para consultas complexas envolvendo inúmeras colunas. Isso levou Ritchie Vink a descrever o desempenho do Polars como “tão paralelo que chega a ser constrangedor”. Isso dá ao Polars um desempenho imensamente maior que o do pandas, que usa apenas um núcleo para executar suas operações. Confira esta excelente palestra de Nico Kreiling na PyCon DE deste ano, que entra em mais detalhes sobre como o Polars consegue isso.
Baseado no Arrow
Outro fator que contribui para o desempenho impressionante do Polars é o Apache Arrow, um formato de memória independente da linguagem. Na verdade, o Arrow foi criado em parte por Wes McKinney em resposta a muitos dos problemas que ele via no pandas à medida que o tamanho dos dados explodia. O Arrow é também o back-end do pandas 2.0, uma versão do pandas com melhor desempenho, lançada em 2023. Porém, há ligeiras diferenças entre os back-ends em Arrow das duas bibliotecas: enquanto o pandas 2.0 foi baseado no PyArrow, a equipe do Polars criou sua própria implementação do Arrow.
Uma das principais vantagens de criar uma biblioteca de dados em Arrow é a interoperabilidade. O Arrow foi projetado para padronizar entre bibliotecas o formato de dados usado na memória e esse formato já é usado por diversas bibliotecas e bancos de dados importantes, como você pode ver abaixo.

Essa interoperabilidade acelera o desempenho, porque ela evita a necessidade de converter os dados em um formato diferente para transferi-los entre as diferentes etapas do pipeline de dados (em outras palavras, ela evita a necessidade de serializar e desserializar os dados). Ela também resulta em um uso mais eficiente da memória, porque dois processos podem compartilhar os mesmos dados, sem necessidade de fazer uma cópia. Como se estima que fazer e desfazer a serialização representem 80–90% dos custos computacionais em fluxos de trabalho de dados, o formato comum de dados do Arrow dá ao Polars ganhos significativos de desempenho.
O Arrow também incorpora o suporte a uma maior variedade de tipos de dados que no pandas. Como este é baseado no NumPy, é excelente para lidar com colunas de valores inteiros e de ponto flutuante, mas tem dificuldades com outros tipos de dados. Já o Arrow tem um suporte sofisticado a dados de data e hora, booleanos, binários e até tipos complexos de colunas, como as que contêm listas. Além disso, o Arrow tem a capacidade de lidar nativamente com dados faltando, o que precisa ser contornado no NumPy.
Finalmente, o Arrow armazena os dados por colunas, o que significa que todas as colunas são armazenadas em um bloco contínuo de memória, independentemente do tipo de dados. Isso não apenas facilita o paralelismo, como também acelera a recuperação dos dados.
Otimização de consultas
Um dos outros pontos centrais do desempenho do Polars é a forma como ele avalia o código. Como padrão, o pandas usa eager execution, executando as operações na ordem em que você as escreveu. Já o Polars é capaz tanto da eager execution quanto da <0>lazy execution</0>, na qual um otimizador de consultas avalia todas as operações a fazer e mapeia a maneira mais eficiente de executar o código. Dentre outras coisas, isso pode incluir reescrever a ordem de execução das operações ou eliminar cálculos redundantes. Veja, por exemplo, a expressão a seguir, usada para obter a média da coluna Number1
separadamente para as categorias “A” e “B” em Category
:
( df .groupby(by = "Category").agg(pl.col("Number1").mean()) .filter(pl.col("Category").is_in(["A", "B"])) )
Se esta expressão for executada na forma “eager”, a operação groupby
será executada desnecessariamente para o DataFrame inteiro e só depois filtrada por Category
. Na “lazy execution”, o DataFrame pode ser filtrado e groupby
executado apenas nos dados necessários.
API expressiva
Finalmente, o Polars tem uma API extremamente expressiva, querendo dizer que basicamente qualquer operação que você quiser executar pode ser expressa como um método do Polars. Já no pandas, é comum precisar passar operações mais complexas para o método apply
como expressões lambda. O problema do método apply
é que ele executa loops sobre as linhas do DataFrame, executando a operação sequencialmente em cada uma delas. A possibilidade de usar métodos integrados permite que você trabalhe no nível das colunas e possa tirar proveito de outra forma de paralelismo, chamada SIMD.
Em que situações você deve continuar usando o pandas?
Tudo isso soa tão incrível que provavelmente você deve estar se perguntando por que sequer pensar no pandas. Calma, devagar com o andor! Embora o Polars seja excelente para realizar transformações de dados extremamente eficientes, atualmente ele não é a escolha ideal para exploração de dados ou para ser usado como parte de pipelines de aprendizado de máquina. Estas são áreas nas quais o pandas continua a brilhar.
Uma das razões para isso é que embora o Polars tenha excelente interoperabilidade com outros pacotes que usam o Arrow, ele ainda não é compatível com a maioria dos pacotes de visualização de dados em Python e bibliotecas de aprendizado de máquina, como scikit-learn e PyTorch. A única exceção é o Plotly, que permite criar gráficos diretamente a partir de DataFrames do Polars.
Está sendo discutida uma solução, que seria usar o protocolo de intercâmbio de dataframes do Python nesses pacotes, para permitir que eles deem suporte a diversas bibliotecas para dataframes. Isso significaria que fluxos de trabalho de ciência de dados e aprendizado de máquina não teriam mais o gargalo do pandas. Porém, essa é uma ideia relativamente nova e vai demorar até que esses projetos a implementem.
Ferramentas para Polars e pandas
Depois de tudo isso, tenho certeza de que você está ansioso para experimentar o Polars! Tanto o DataSpell quanto o PyCharm Professional 2023.2 oferecem excelentes ferramentas para trabalhar com o pandas e o Polars em notebooks do Jupyter. Em especial, os DataFrames do pandas e do Polars são mostrados com funções interativas, tornando muito mais rápido e cômodo explorar os seus dados.
Dentre os meus recursos favoritos, estão a capacidade de rolar por todas as linhas e colunas do DataFrame sem truncamentos, agregar valores do DataFrame com apenas um clique e exportar o DataFrame para uma variedade enorme de formatos (inclusive o Markdown!).
Se você ainda não estiver usando o DataSpell, poderá experimentá-lo por 30 dias seguindo o link abaixo.
Artigo original em inglês por: