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 umresult_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"]])Tecnologia
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.
defcompute_run_diff(row):# Treat the row as read-only; return a scalarreturn 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)Tecnologia
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
defcompute_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)Tecnologia
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.
defdebug_row(row):# Print the first row onlyif row.name == team_stats.index[0]:print("Example row:", row.to_dict())return0
_ = team_stats.apply(debug_row, axis=1)Tecnologia
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.
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)Tecnologia
calcular o total de corridas marcadas numa temporada
Use aritmética vetorizada nas colunas; não é .apply() necessidade.
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"})Tecnologia
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.
defwins_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)Tecnologia
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.
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.
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.
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!
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.
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)chamafuncem cada coluna por padrão. Comaxis=1, ele chamafuncem cada linha.Series.apply(func)chamafuncem cada elemento (ou em todo oSeries, dependendo das assinaturas nas versões recentes).axis=1significa “por linha”.axis=0(padrão) significa “por coluna”.Series). Se ele retornar umSeriesoudict, o pandas expande essas chaves em umDataFrame. Se ele retornar uma lista/matriz, você vai receber uma série de listas, a menos que defina umresult_type='expand'.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().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.
Quando a função é numérica e só precisa de matrizes brutas, passar
raw=Truepula algumas sobrecargas do pandas, fornecendo uma matriz NumPy para sua função.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.
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.obter somas de colunas de forma eficiente
Use
DataFrame.sum()em vez de.apply(sum). É mais rápido e mais claro.calcular o total de corridas marcadas numa temporada
Use aritmética vetorizada nas colunas; não é
.apply()necessidade.converter um sinalizador 0/1 em texto
Prefira
Series.map()oureplace()para transformações elemento a elemento em uma coluna.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.retornar uma série ou dicionário para nomear colunas automaticamente
Devolvendo um
Seriesoudictde cada linha gera um DataFrame com rótulos de coluna correspondentes.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.sum,mean,clip,where,astypee métodos de string/acessador.raw=Truepara obter uma matriz NumPy e reduzir a sobrecarga do pandas.Series.map()ou métodos vetorizados em vez deDataFrame.apply(axis=1).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.result_type='expand'quando quiser várias colunas.Series` ou ` `dictexpande-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 umobject(por exemplo,s.astype("object").apply(fn)). As assinaturas mais recentes permitem controlar sefnrecebe 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.
axis=1.result_type='expand'para dividir em colunas.raw=True` pra diminuir a sobrecarga.astypese 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 umDataFrame.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 comresult_type, considereraw=Truepara funções numéricas e fique de olho emdtypes. Esses padrões dão resultados previsíveis nos pandas modernos e se adaptam melhor conforme seus dados aumentam.