Pular para o conteúdo principal

Pandas .apply(): O que faz, quando ajuda e alternativas mais rápidas

Aprenda o que é Python pandas .apply e como usá-lo para DataFrame. Aprenda hoje mesmo a iterar sobre DataFrames usando a função .apply()!
Atualizado 7 de out. de 2025  · 5 min lido

Muita gente usa o .apply() pra “evitar loops” e espera que seja rápido e direto. Na prática, o " .apply(axis=1) " por linha ainda é um loop no nível do Python. Pode ser lento com grandes volumes de dados e, às vezes, mostra resultados que você não esperava. A solução é simples: use operações vetorizadas pandas/NumPy para tarefas comuns e reserve .apply() para a lógica que realmente precisa de várias colunas.

Este guia mostra como .apply() funciona hoje, destaca as armadilhas comuns e fornece padrões prontos para uso que são mais rápidos e claros.

O que é DataFrame.apply() e Series.apply()?

DataFrame.apply(func, axis=0) chama func em cada coluna por padrão. Com axis=1, ele chama func em cada linha. Series.apply(func) chama func em cada elemento (ou em todo o Series, dependendo das assinaturas nas versões recentes).

  • Por linha vs. por coluna: axis=1 significa “por linha”. axis=0 (padrão) significa “por coluna”.
  • Regras de retorno de formato (pandas ≥0.23): Se a sua função devolver um escalar por linha/coluna, você vai ter um objeto de matriz ( Series). Se ele retornar um Series ou dict, o pandas expande essas chaves em um DataFrame. Se ele retornar uma lista/matriz, você vai receber uma série de listas, a menos que defina um result_type='expand'.
  • Erros mais rigorosos (pandas ≥2.0): Agora, quando os comprimentos das listas não batem, dá erro, em vez de simplesmente aparecer um resultado meio estranho.

Primeira escolha recomendada: Operações vetorizadas

A maioria das tarefas que envolvem combinar ou transformar colunas são mais rápidas e claras com expressões vetorizadas ou métodos integrados. O exemplo a seguir calcula a diferença de pontos de um time de beisebol sem usar .apply().

import pandas as pd

team_stats = pd.DataFrame({
    "Team": ["ARI", "ATL", "BAL"],
    "League": ["NL", "NL", "AL"],
    "Year": [2012, 2012, 2012],
    "RunsScored": [734, 700, 712],
    "RunsAllowed": [688, 600, 705],
    "Wins": [81, 94, 93],
    "Games": [162, 162, 162],
    "Playoffs": [0, 1, 1],
})

# Vectorized: fast and idiomatic
team_stats["RunDiff"] = team_stats["RunsScored"] - team_stats["RunsAllowed"]
print(team_stats[["Team", "RunsScored", "RunsAllowed", "RunDiff"]])

Row-Wise .apply() quando você realmente precisa

Use isso .apply(axis=1) quando sua lógica realmente abrange várias colunas e não é facilmente vetorizada (por exemplo, regras condicionais que dependem de vários campos).

calcular um valor derivado de várias colunas

Esse padrão calcula um valor por linha usando várias entradas. A abordagem vetorizada acima ainda é a preferida, mas isso mostra o uso correto por linha e as opções que afetam a velocidade e a saída.

def compute_run_diff(row):
    # Treat the row as read-only; return a scalar
    return row["RunsScored"] - row["RunsAllowed"]

# Row-wise apply (Python-level loop; can be slow on large data)
team_stats["RunDiff_apply"] = team_stats.apply(compute_run_diff, axis=1)

Quando a função é numérica e só precisa de matrizes brutas, passar raw=True pula algumas sobrecargas do pandas, fornecendo uma matriz NumPy para sua função.

import numpy as np

def compute_run_diff_raw(values):
    # values is a NumPy array when raw=True
    # Order matches the column order we select
    rs, ra = values
    return rs - ra

team_stats["RunDiff_raw"] = team_stats[["RunsScored", "RunsAllowed"]].apply(
    compute_run_diff_raw, axis=1, raw=True
)

confira a entrada da função uma vez

Quando eu conecto uma nova função de linha, imprimo uma linha uma vez para confirmar o que está sendo passado.

def debug_row(row):
    # Print the first row only
    if row.name == team_stats.index[0]:
        print("Example row:", row.to_dict())
    return 0

_ = team_stats.apply(debug_row, axis=1)

Estudo de caso: Somas, totais da temporada e sinalizadores de texto

Dadas as estatísticas Rays por ano, prefira métodos integrados e ferramentas elementares sempre que possível. .apply() onde possível.

rays_by_year = pd.DataFrame(
    {
        "Year": [2012, 2011, 2010, 2009, 2008],
        "RunsScored": [697, 707, 802, 803, 774],
        "RunsAllowed": [577, 614, 649, 754, 671],
        "Wins": [90, 91, 96, 84, 97],
        "Playoffs": [0, 1, 1, 0, 1],
    }
).set_index("Year")

obter somas de colunas de forma eficiente

Use DataFrame.sum() em vez de .apply(sum). É mais rápido e mais claro.

# Preferred
totals = rays_by_year.sum(axis=0)
print(totals)

# If you must use apply (not recommended here)
totals_apply = rays_by_year.apply(sum, axis=0)

calcular o total de corridas marcadas numa temporada

Use aritmética vetorizada nas colunas; não é .apply() necessidade.

rays_by_year["TotalRuns"] = rays_by_year["RunsScored"] + rays_by_year["RunsAllowed"]
print(rays_by_year[["RunsScored", "RunsAllowed", "TotalRuns"]].head())

converter um sinalizador 0/1 em texto

Prefira Series.map() ou replace() para transformações elemento a elemento em uma coluna.

# Using map with a dict
rays_by_year["PlayoffsText"] = rays_by_year["Playoffs"].map({0: "No", 1: "Yes"})

# Equivalent with replace
rays_by_year["PlayoffsText2"] = rays_by_year["Playoffs"].replace({0: "No", 1: "Yes"})

Controle a forma de saída a partir de .apply()

Quando sua função devolver mais de um valor por linha, deixe a forma bem clara. Isso evita surpresas e problemas com versões futuras.

retornar uma lista e expandir para colunas

Use result_type='expand' para dividir uma lista/matriz em várias colunas.

def wins_losses(row):
    # Derive wins and losses as two outputs
    wins = row["Wins"]
    losses = row["Games"] - row["Wins"] if "Games" in row else np.nan
    return [wins, losses]

# Example using team_stats, which has "Wins" and "Games"
expanded = team_stats.apply(wins_losses, axis=1, result_type="expand")
expanded.columns = ["WinsOut", "LossesOut"]
team_stats = pd.concat([team_stats, expanded], axis=1)

retornar uma série ou dicionário para nomear colunas automaticamente

Devolvendo um Series ou dict de cada linha gera um DataFrame com rótulos de coluna correspondentes.

def summary_row(row):
    return pd.Series(
        {
            "IsWinningSeason": row["Wins"] >= 90,
            "RunRatio": (row["RunsScored"] / row["RunsAllowed"]),
        }
    )

summary = team_stats.apply(summary_row, axis=1)
team_stats = pd.concat([team_stats, summary], axis=1)

Dicas de desempenho que fazem a diferença

Por linha .apply(axis=1) é prático, mas lento em quadros grandes, porque chama sua função Python uma vez por linha. Esses padrões evitam esse gargalo.

  • Prefira operações vetorizadas pandas/NumPy e métodos integrados como sum, mean, clip, where, astypee métodos de string/acessador.
  • Para operações numéricas em linhas/colunas que aceitam matrizes, use raw=True para obter uma matriz NumPy e reduzir a sobrecarga do pandas.
  • Para trabalhar elemento a elemento em uma única coluna, use Series.map() ou métodos vetorizados em vez de DataFrame.apply(axis=1).
  • Evite alterar a linha/coluna fornecida dentro da sua função; em vez disso, retorne um novo valor.

Notas sobre a versão que você precisa saber (pandas 2.x)

As versões recentes do pandas tornaram mais rígido o comportamento em torno de .apply() para que os resultados sejam mais previsíveis.

  • Resultados em forma de lista: Na versão 2.0+, se os comprimentos das listas não combinarem, vai aparecer um erro. Use comprimentos consistentes e defina result_type='expand' quando quiser várias colunas.
  • Expansão da produção: Retornar um objeto ` Series ` ou ` ` dict expande-se em um DataFrame com essas chaves como colunas (estável desde 0.23).
  • Series.apply() alterações: O argumento ` convert_dtype ` está obsoleto. Se você precisar de tipos mistos, primeiro converta para um object (por exemplo, s.astype("object").apply(fn)). As assinaturas mais recentes permitem controlar se fn recebe escalares ou uma série em mais contextos (por exemplo, by_row).

.apply() vs. .map() vs. .applymap() vs. .agg()

Escolha a API que combina com o formato da sua transformação.

  • Series.map(func_or_dict): Transformação elemento a elemento em uma coluna. Ótimo pra pesquisas ou funções simples.
  • DataFrame.apply(func, axis=1): Lógica por linha que precisa de várias colunas.
  • DataFrame.apply(func, axis=0): Lógica por coluna (cada entrada é uma série que representa uma coluna).
  • DataFrame.applymap(func): Elemento por elemento em cada célula. Use com moderação; métodos vetorizados são mais rápidos.
  • .agg()/.transform(): Agregações e transformações por grupo; prefira essas em pipelines groupby.

Erros comuns e soluções rápidas

Esses são os problemas que mais causam resultados errados ou lentidão, com maneiras de corrigi-los.

  • Esquecendo axis=1 para a lógica por linha: Se a sua função de repente receber colunas em vez de linhas, adicione axis=1.
  • Série inesperada de listas: Ao retornar uma lista/matriz de cada linha, defina result_type='expand' para dividir em colunas.
  • Código lento por linha: Troque por expressões vetorizadas ou internas; se não der, pense em usar o ` raw=True ` pra diminuir a sobrecarga.
  • Mudando a linha de entrada: Trate as entradas como somente leitura e retorne novos valores.
  • Desvio do tipo de dados: Se a sua função às vezes retorna valores não inteiros, as colunas inteiras podem ser convertidas para float ou objeto. Depois, manda ver com astype se necessário.

Conclusão

.apply() é uma ferramenta flexível, mas não é um atalho para o desempenho. Use operações vetorizadas para aritmética, agregação e transformações elementares em uma única coluna. Use um DataFrame.apply(axis=1) e apenas quando sua lógica realmente precisar de várias colunas por linha. Quando você usar, controle a forma da saída com result_type, considere raw=True para funções numéricas e fique de olho em dtypes. Esses padrões dão resultados previsíveis nos pandas modernos e se adaptam melhor conforme seus dados aumentam.

Tópicos

Saiba mais sobre Python e pandas

Curso

Python intermediário

4 h
1.3M
Aumente o nível de suas habilidades em ciência de dados criando visualizações usando Matplotlib e manipulando DataFrames com pandas.
Ver detalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado
data-frames-in-python-banner_cgzjxy.jpeg

Tutorial

Pandas Tutorial: DataFrames em Python

Explore a análise de dados com Python. Os DataFrames do Pandas facilitam a manipulação de seus dados, desde a seleção ou substituição de colunas e índices até a remodelagem dos dados.
Karlijn Willems's photo

Karlijn Willems

Tutorial

Tutorial de seleção de colunas em Python

Use o Python Pandas e selecione colunas de DataFrames. Siga nosso tutorial com exemplos de código e aprenda diferentes maneiras de selecionar seus dados hoje mesmo!
DataCamp Team's photo

DataCamp Team

Tutorial

Tutorial de junção de DataFrames no pandas

Neste tutorial, você aprenderá várias maneiras pelas quais vários DataFrames podem ser mesclados em python usando a biblioteca Pandas.
DataCamp Team's photo

DataCamp Team

Tutorial

Tutorial sobre loops for em Python

Aprenda a usar loops “for” em Python pra iterar uma sequência ou as linhas e colunas de um DataFrame pandas.
Aditya Sharma's photo

Aditya Sharma

Tutorial

Tutorial pandas read csv(): Importação de dados

A importação de dados é a primeira etapa de qualquer projeto de ciência de dados. Saiba por que os cientistas de dados atuais preferem a função read_csv() do pandas para fazer isso.
Kurtis Pykes 's photo

Kurtis Pykes

Tutorial

Tutorial do Python pandas: O guia definitivo para iniciantes

Você está pronto para começar sua jornada com os pandas? Aqui está um guia passo a passo sobre como você pode começar.
Vidhi Chugh's photo

Vidhi Chugh

Ver maisVer mais