Ir al contenido principal

Pandas .apply(): Qué hace, cuándo ayuda y alternativas más rápidas

Aprende qué es Python pandas .apply y cómo utilizarlo para DataFrame. ¡Aprende hoy mismo a iterar sobre DataFrames utilizando la función .apply()!
Actualizado 7 oct 2025  · 5 min de lectura

Muchas personas recurren a .apply() para «evitar bucles» y esperan que sea rápido y sencillo. En la práctica, el « .apply(axis=1) » por filas sigue siendo un bucle a nivel de Python. Puede ser lento con datos de gran tamaño y, en ocasiones, devuelve formas que no esperabas. La solución es sencilla: utiliza operaciones vectorizadas de pandas/NumPy para tareas comunes y reserva .apply() para la lógica que realmente necesite varias columnas.

Esta guía muestra cómo .apply() funciona hoy en día, destaca los errores comunes y proporciona patrones de inserción que son más rápidos y claros.

¿Qué son DataFrame.apply() y Series.apply()?

DataFrame.apply(func, axis=0) Llama a func en cada columna de forma predeterminada. Con axis=1, llama a func en cada fila. Series.apply(func) llama a func en cada elemento (o en todo Series, dependiendo de las firmas en las versiones recientes).

  • Por filas frente a por columnas: axis=1 significa «por fila». axis=0 (por defecto) significa «por columna».
  • Reglas de forma de retorno (pandas ≥0,23): Si tu función devuelve un escalar por fila/columna, obtienes un Series. Si devuelve un Series o un dict, pandas expande esas claves en un DataFrame. Si devuelve una lista/arreglo, obtendrás una serie de listas a menos que establezcas result_type='expand'.
  • Errores más estrictos (pandas ≥2.0): Las longitudes desiguales en las listas ahora generan errores en lugar de producir resultados inconsistentes de forma silenciosa.

Primera opción recomendada: Operaciones vectorizadas

La mayoría de las tareas que implican combinar o transformar columnas son más rápidas y claras con expresiones vectorizadas o métodos integrados. El siguiente ejemplo calcula la diferencia de carreras de un equipo de béisbol sin utilizar .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() cuando realmente lo necesitas

Úsalo .apply(axis=1) cuando tu lógica realmente abarque varias columnas y no sea fácil de vectorizar (por ejemplo, reglas condicionales que dependan de varios campos).

calcular un valor derivado a partir de varias columnas

Este patrón calcula un valor por fila utilizando múltiples entradas. El enfoque vectorizado anterior sigue siendo el preferido, pero esto muestra el uso correcto por filas y las opciones que afectan a la velocidad y al resultado.

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)

Cuando la función es numérica y solo necesita arreglos sin procesar, pasar raw=True omite parte de la sobrecarga de pandas al proporcionar un arreglo NumPy a tu función.

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
)

Verifica la entrada de la función una vez.

Cuando conecto una nueva función de fila, imprimo una fila una vez para confirmar lo que se está pasando.

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)

Caso práctico: Sumas, totales de temporada y marcadores de texto

Dadas las estadísticas de Rays por año, es preferible utilizar métodos integrados y herramientas elementales en lugar de .apply() siempre que sea posible.

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")

obtener sumas de columnas de manera eficiente

Utiliza DataFrame.sum() en lugar de .apply(sum). Es más rápido y más 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 el total de carreras anotadas en una temporada.

Utiliza aritmética vectorizada en todas las columnas; no .apply() necesidad.

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

Convertir un indicador 0/1 en texto

Prefiero Series.map() o replace() para transformaciones elemento por elemento en una columna.

# 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"})

Controla la forma de salida desde .apply()

Cuando tu función devuelva más de un valor por fila, haz que la forma sea explícita. Esto evita sorpresas y problemas con versiones futuras.

Devuelve una lista y la expande en columnas.

Usa result_type='expand' para dividir una lista/arreglo en varias columnas.

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)

Devuelve una serie o un diccionario para nombrar columnas automáticamente.

Devolver un Series o dict de cada fila produce un DataFrame con etiquetas de columna coincidentes.

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)

Consejos importantes para mejorar el rendimiento

Por filas .apply(axis=1) es conveniente, pero lento en marcos grandes, ya que llama a tu función Python una vez por fila. Estos patrones evitan ese cuello de botella.

  • Es preferible utilizar operaciones vectorizadas de pandas/NumPy y métodos integrados como sum, mean, clip, where, astypey métodos de cadena/accesor.
  • Para operaciones numéricas de fila/columna que aceptan arreglos, pasa raw=True para obtener un arreglo NumPy y reducir la sobrecarga de pandas.
  • Para trabajar elemento por elemento en una sola columna, utiliza Series.map() o métodos vectorizados en lugar de DataFrame.apply(axis=1).
  • Evita modificar la fila/columna proporcionada dentro de tu función; en su lugar, devuelve un nuevo valor.

Notas sobre la versión que debes conocer (pandas 2.x)

Las últimas versiones de pandas han restringido el comportamiento en torno a .apply() para que los resultados sean más predecibles.

  • Resultados en forma de lista: En la versión 2.0+, las longitudes de lista que no coinciden generan un error. Utiliza longitudes uniformes y establece result_type='expand' cuando desees varias columnas.
  • Ampliación de la producción: Al devolver un objeto de tipo Series o dict se expande en un DataFrame con esas claves como columnas (estable desde la versión 0.23).
  • Series.apply() cambios: El argumento convert_dtype está en desuso. Si necesitas tipos mixtos, primero convierte a object (por ejemplo, s.astype("object").apply(fn)). Las firmas más recientes permiten controlar si fn recibe escalares o una serie en más contextos (por ejemplo, by_row).

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

Elige la API que se adapte a la forma de tu transformación.

  • Series.map(func_or_dict): Transformación por elementos en una columna. Ideal para búsquedas o funciones sencillas.
  • DataFrame.apply(func, axis=1): Lógica por filas que requiere varias columnas.
  • DataFrame.apply(func, axis=0): Lógica por columnas (cada entrada es una serie que representa una columna).
  • DataFrame.applymap(func): Por elementos sobre cada celda. Úsalo con moderación; los métodos vectorizados son más rápidos.
  • .agg()/.transform(): Agregaciones y transformaciones por grupos; preferirlos en canalizaciones groupby.

Errores comunes y soluciones rápidas

Estos son los problemas que con mayor frecuencia provocan resultados incorrectos o ralentizaciones, junto con las formas de corregirlos.

  • Olvidando axis=1 para la lógica por fila: Si tu función recibe de repente columnas en lugar de filas, añade axis=1.
  • Serie inesperada de listas: Al devolver una lista/arreglo de cada fila, establece result_type='expand' para dividir en columnas.
  • Código lento por filas: Reemplaza con expresiones vectorizadas o integradas; si no es posible, considera utilizar « raw=True » para reducir la sobrecarga.
  • Mutación de la fila de entrada: Trata las entradas como de solo lectura y devuelve nuevos valores.
  • Desviación del tipo de datos: Si tu función a veces devuelve valores no enteros, las columnas enteras pueden convertirse a flotantes u objetos. A continuación, moldea con astype si es necesario.

Conclusión

.apply() Es una herramienta flexible, pero no es un atajo para mejorar el rendimiento. Utiliza operaciones vectorizadas para realizar operaciones aritméticas, agregaciones y transformaciones elemento por elemento en una sola columna. Utiliza un DataFrame.apply(axis=1) o solo cuando tu lógica realmente necesite varias columnas por fila. Cuando lo utilices, controla la forma de salida con result_type, ten en cuenta raw=True para las funciones numéricas y presta atención a dtypes. Estos patrones producen resultados predecibles en los pandas modernos y se adaptan mejor a medida que tus datos crecen.

Temas

Más información sobre Python y pandas

Curso

Python intermedio

4 h
1.3M
Mejora tus conocimientos de ciencia de datos creando visualizaciones con Matplotlib y manipulando DataFrames con pandas.
Ver detallesRight Arrow
Comienza el curso
Ver másRight Arrow
Relacionado
data-frames-in-python-banner_cgzjxy.jpeg

Tutorial

Tutorial de Pandas: DataFrames en Python

Explora el análisis de datos con Python. Los DataFrames de Pandas facilitan la manipulación de tus datos, desde la selección o sustitución de columnas e índices hasta la remodelación de tus datos.
Karlijn Willems's photo

Karlijn Willems

Tutorial

Tutorial seleccionar columnas con Python

Utiliza Python Pandas y selecciona columnas de los DataFrames. ¡Sigue nuestro tutorial con ejemplos de código y aprende hoy mismo distintas formas de seleccionar tus datos!
DataCamp Team's photo

DataCamp Team

Tutorial

Tutorial pandas read_csv(): importación de datos

La importación de datos es el primer paso importante en cualquier proyecto de ciencia de datos. Aprende por qué los científicos de datos actuales prefieren la función pandas read_csv() para hacerlo.
Kurtis Pykes 's photo

Kurtis Pykes

Tutorial

Tutorial de unión de DataFrames en pandas

En este tutorial, usted aprenderá varias maneras en las que múltiples DataFrames pueden ser fusionados en python usando la librería Pandas.
DataCamp Team's photo

DataCamp Team

Tutorial

Tutorial sobre bucle for en Python

Aprende a implementar bucle «for» en Python para iterar una secuencia o las filas y columnas de un DataFrame.
Aditya Sharma's photo

Aditya Sharma

Tutorial

Tutorial de pandas en Python: La guía definitiva para principiantes

¿Estás preparado para comenzar tu viaje de pandas? Aquí tienes una guía paso a paso sobre cómo empezar.
Vidhi Chugh's photo

Vidhi Chugh

Ver másVer más