Pandas: 10 funções para turbinar sua análise… além do básico!

Rocketseat

Conheça o Rocketseat Para Empresas
Oferecemos soluções personalizadas para empresas de todos os portes.
Usar pandas sem conhecer os atalhos é tipo montar guarda-roupa sem chave Phillips. Funciona, mas você vai suar mais, demorar o triplo do tempo e provavelmente vai querer desistir no meio.
Muitas pessoas que trabalham com análise de dados já dominam o
read_csv, head, describe e groupby. Mas quando a análise aperta, o código vira uma colcha de retalhos de for loops, .apply() excessivo e variáveis intermediárias que poluem o notebook.Vamos mudar isso.
O objetivo aqui é direto: entregar valor. Vamos explorar 10 funções do pandas que funcionam como atalhos, reduzem linhas de código e deixam seu fluxo de análise mais fluido e legível. Menos
.apply(), mais operações vetorizadas.As 10 funções que vamos detalhar são:
assign, pipe, query, eval, explode, melt, merge_asof, cut, convert_dtypes e astype('category').Bora acelerar essa análise.
1 - Crie colunas sem quebrar o fluxo (assign())
O problema comum: você precisa criar várias colunas novas baseadas nas existentes. A abordagem usual quebra o encadeamento (chaining) e força a criação de dataframes intermediários ou a repetição de
df['nova_coluna'] = ....A solução:
assign() permite criar múltiplas colunas dentro de um fluxo encadeado, mantendo o código limpo e legível. Ele sempre retorna um novo dataframe.Exemplo:
Vamos calcular o imposto e o preço final de alguns produtos.
import pandas as pd import numpy as np df_produtos = pd.DataFrame({ 'produto': ['Teclado', 'Mouse', 'Monitor'], 'preco_base': [300, 150, 1200], 'desconto_perc': [0.05, 0.10, 0.0] }) df_final = ( df_produtos .assign( preco_com_desconto = lambda df: df.preco_base * (1 - df.desconto_perc), imposto = lambda df: df.preco_com_desconto * 0.25, # Podemos referenciar colunas criadas na mesma chamada assign preco_final = lambda df: df.preco_com_desconto + df.imposto ) ) print(df_final)
Note como usamos funções
lambda curtas para referenciar o dataframe no estado atual do encadeamento.Use quando:
- Você quer manter um fluxo de operações limpo (method chaining).
- A lógica para criar a nova coluna é simples e pode ser expressa em uma linha.
Evite quando:
- A lógica é complexa demais para um
lambda. Nesse caso, considere usarpipe()(nossa próxima função).
2 - Organize seu código com funções reutilizáveis (pipe())
O problema comum: seu fluxo de análise tem muitos passos (limpeza, normalização, criação de features). Encadeá-los diretamente pode transformar seu código em um "espaguete" difícil de ler e testar.
A solução:
pipe() permite aplicar funções externas ao seu dataframe dentro do encadeamento. Você organiza a lógica em funções pequenas, puras e testáveis.Exemplo:
Vamos criar funções para limpar e preparar dados de vendas.
def limpar_nulos(df, colunas): # Remove linhas onde as colunas especificadas são nulas return df.dropna(subset=colunas) def normalizar_moeda(df, coluna_origem, coluna_destino, taxa): # Converte valores para outra moeda # Usamos assign aqui também para manter a função pura se preferir df_copia = df.copy() df_copia[coluna_destino] = (df_copia[coluna_origem] * taxa).round(2) return df_copia # Dados de exemplo df_vendas = pd.DataFrame({ 'id_pedido': [1, 2, 3, 4], 'valor_brl': [100.0, np.nan, 300.0, 50.0] }) # Taxa de conversão hipotética BRL para USD taxa_usd = 0.18 df_processado = ( df_vendas .pipe(limpar_nulos, colunas=['valor_brl']) .pipe(normalizar_moeda, coluna_origem='valor_brl', coluna_destino='valor_usd', taxa=taxa_usd) ) print(df_processado)
A beleza do
pipe() é que limpar_nulos e normalizar_moeda podem ser facilmente testadas isoladamente.Use quando:
- Você quer organizar passos complexos de pré-processamento.
- Você precisa reutilizar a mesma lógica em diferentes dataframes.
- Você valoriza código testável.
Evite quando:
- A operação é trivial e pode ser feita diretamente com métodos nativos do pandas (como um simples
.rename()).
3 - Filtros legíveis como SQL (query())
O problema comum: filtrar dataframes usando máscaras booleanas pode ficar verboso e cheio de parênteses e operadores (
&, |, ~).# Verboso e propenso a erros de parênteses # df_filtrado = df[(df['categoria'] == 'A') & (df['preco'] > 100) | (df['desconto'] > 0.2)]
A solução:
query() permite escrever filtros usando strings declarativas, muito parecidas com a cláusula WHERE do SQL.Exemplo:
df_catalogo = pd.DataFrame({ 'item': ['A', 'B', 'C', 'D'], 'preco': [50, 150, 90, 200], 'estoque': [10, 5, 0, 12] }) # Filtro legível df_promocao = df_catalogo.query("preco > 100 and estoque > 0") print(df_promocao) # Usando variáveis locais (prefixo @) limite_minimo = 100 df_caros = df_catalogo.query("preco > @limite_minimo")
Dica: se o nome da sua coluna tiver espaços ou caracteres especiais, use crases (backticks) no
query():# df.query("`preço unitário` > 50")
Use quando:
- Os filtros são complexos e envolvem múltiplas condições.
- Você quer melhorar a legibilidade do código de filtragem.
Evite quando:
- Os nomes das colunas não são válidos como nomes de variáveis em Python (e você não quer usar backticks).
- O filtro envolve tipos de dados complexos que o motor interno do
querynão suporta bem.
4 - Expressões rápidas e vetorizadas (eval())
O problema comum: você precisa calcular novas colunas baseadas em operações aritméticas entre colunas existentes. Usar
.apply() pode ser lento em dataframes grandes, e a sintaxe padrão pode ser um pouco verbosa.A solução:
eval() permite calcular expressões usando strings, similar ao query(), mas focado em computação. Em alguns cenários, eval() pode oferecer melhor performance ao otimizar o uso da memória (evitando a criação de arrays intermediários) e evitar overhead do interpretador Python.Exemplo:
df_pedidos = pd.DataFrame({ 'preco_unitario': np.random.rand(1000) * 100, 'quantidade': np.random.randint(1, 10, 1000), 'frete': np.random.rand(1000) * 20 }) # Calculando o valor total do pedido em uma única expressão df_pedidos.eval("valor_total = (preco_unitario * quantidade) + frete", inplace=True) # Você também pode fazer múltiplas operações df_pedidos.eval(""" custo = preco_unitario * 0.6 lucro = valor_total - custo - frete """, inplace=True) print(df_pedidos.head())
Use quando:
- Você está trabalhando com dataframes grandes e performance é uma prioridade em cálculos numéricos.
- As operações são aritméticas simples entre colunas.
Evite quando:
- As operações envolvem tipos de dados complexos (listas, objetos) ou funções externas que não são suportadas pelo motor do
eval().
5 - Transforme listas em linhas (explode())
O problema comum: você tem dados onde uma célula contém uma lista ou array (ex.: tags de um produto, itens de um pedido) e precisa analisar cada item individualmente.
A solução:
explode() "desembrulha" listas em linhas, duplicando as outras colunas conforme necessário.Exemplo:
df_pedidos_agg = pd.DataFrame({ 'id_pedido': [101, 102], 'cliente': ['Diego', 'Fernanda'], 'itens': [['Teclado', 'Mouse'], ['Monitor', 'Cabo']] }) df_pedidos_detalhado = df_pedidos_agg.explode('itens') print(df_pedidos_detalhado) # id_pedido cliente itens # 0 101 Diego Teclado # 0 101 Diego Mouse # 1 102 Fernanda Monitor # 1 102 Fernanda Cabo
Depois de usar
explode(), você pode facilmente fazer um groupby() para contar a frequência de cada item, por exemplo.Use quando:
- Você precisa analisar elementos individuais dentro de coleções armazenadas em células.
- Ótimo combinado com
groupbyapós a explosão.
Evite quando:
- As células contêm objetos complexos que não são listas/arrays (como dicionários aninhados, onde
json_normalizepode ser mais adequado).
- Seu dataframe é gigantesco e o
explode()gerará um número impraticável de linhas.
6 - De wide para long em uma linha (melt())
O problema comum: seus dados estão no formato "wide" (largo), onde cada variável de observação tem sua própria coluna. Por exemplo, colunas separadas para vendas de janeiro, fevereiro, março. Esse formato é ruim para a maioria das análises e visualizações.
A solução:
melt() transforma o dataframe do formato wide para o formato "long" (longo). Ele "despivota" as colunas selecionadas em linhas.Exemplo:
df_vendas_wide = pd.DataFrame({ 'loja': ['Centro', 'Shopping'], 'vendas_jan': [5000, 7000], 'vendas_fev': [5500, 7200] }) # Formato wide (ruim para agrupar por mês) print(df_vendas_wide) df_vendas_long = df_vendas_wide.melt( id_vars=['loja'], # Colunas que permanecem iguais (identificadores) var_name='mes', # Nome da nova coluna que guarda os nomes das colunas antigas value_name='valor_vendas' # Nome da nova coluna que guarda os valores ) # Formato long (ideal para análise) print(df_vendas_long)
melt() é o oposto de pivot_table(). Enquanto pivot_table() agrega e expande (long para wide), melt() despivota e alonga (wide para long).Use quando:
- Você precisa preparar dados para visualização (seaborn, matplotlib geralmente preferem formato long).
- Seu dataframe tem colunas que representam medidas ao longo do tempo ou categorias diferentes da mesma medida.
Evite quando:
- Seus dados já estão no formato tidy (longo).
7 - Join por tempo mais próximo (merge_asof())
O problema comum: você tem duas séries temporais com timestamps que não se alinham perfeitamente. Por exemplo, dados de transações e dados de cotação de câmbio. Você precisa juntar os dados com base no timestamp mais próximo (ou imediatamente anterior).
A solução:
merge_asof() realiza um "join aproximado". Ele busca a correspondência mais próxima na chave de junção (geralmente data/hora), em vez de uma correspondência exata.Exemplo:
Vamos juntar transações com a cotação do dólar mais recente antes da transação.
# Transações de compra df_transacoes = pd.DataFrame({ 'data_hora': pd.to_datetime(['2025-10-13 10:05:02', '2025-10-13 10:15:30']), 'valor_usd': [100, 250] }) # Cotações do dólar df_cotacoes = pd.DataFrame({ 'data_hora_cotacao': pd.to_datetime(['2025-10-13 10:00:00', '2025-10-13 10:10:00', '2025-10-13 10:20:00']), 'taxa_brl': [5.10, 5.12, 5.09] }) # Os dataframes DEVEM estar ordenados pela chave de junção df_transacoes = df_transacoes.sort_values('data_hora') df_cotacoes = df_cotacoes.sort_values('data_hora_cotacao') df_merged = pd.merge_asof( df_transacoes, df_cotacoes, left_on='data_hora', right_on='data_hora_cotacao', direction='backward' # 'backward' (padrão): cotação mais recente ANTES da transação # 'forward': cotação mais próxima DEPOIS da transação # 'nearest': cotação mais próxima no geral ) print(df_merged)
A transação das 10:05:02 pegou a cotação das 10:00:00 (5.10), e a das 10:15:30 pegou a das 10:10:00 (5.12).
Dica: use o parâmetro tolerance para definir um limite de tempo máximo para a correspondência. Ex: tolerance=pd.Timedelta('2m').
Use quando:
- Juntando dados de séries temporais com frequências diferentes ou timestamps desalinhados.
- Dados de sensores (IoT), logs de eventos ou dados financeiros.
Evite quando:
- Você precisa de correspondências exatas (use
merge()).
- Seus dados não estão ordenados pela chave de junção.
8 - Agrupe dados em faixas (cut())
O problema comum: você tem uma coluna numérica contínua (idade, preço, tempo de resposta) e quer categorizá-la em faixas (bins) para análise de grupo. Fazer isso manualmente com
np.where() ou if/else é trabalhoso.A solução:
cut() divide os dados em bins discretos com base em limites definidos por você.Exemplo:
Categorizando clientes por faixa etária.
df_clientes = pd.DataFrame({ 'nome': ['Mayk', 'Laís', 'Rodrigo', 'Isabela'], 'idade': [38, 22, 45, 16] }) # Definindo os limites das faixas e os rótulos bins = [0, 18, 30, 45, 60, 120] labels = ['0-18', '19-30', '31-45', '46-60', '60+'] df_clientes['faixa_etaria'] = pd.cut( df_clientes.idade, bins=bins, labels=labels, right=True # Inclui o limite direito (ex.: 30 anos entra na faixa 19-30) ) print(df_clientes)
Observação: existe também o
qcut(). A diferença é que cut() usa limites fixos definidos por você, enquanto qcut() tenta dividir os dados em bins com o mesmo número de observações (quantis).Use quando:
Conheça o Rocketseat Para Empresas
Oferecemos soluções personalizadas para empresas de todos os portes.
Artigos_
Explore conteúdos relacionados
Descubra mais artigos que complementam seu aprendizado e expandem seu conhecimento.
NewsletterReceba conteúdos inéditos e novidades gratuitamente