HOWTO · Pandas
Vectorizar una función en Pandas
Este tutorial demuestra cómo podemos vectorizar una función en pandas.
En esta página
Para vectorizar una función en pandas, primero reescribe su cálculo con operaciones que acepten una Series o un arreglo de NumPy completo. Esto suele evitar llamar a una función de Python una vez por cada valor. Si la lógica no puede expresarse con operaciones de arreglo compatibles, usa Series.map para una transformación clara elemento por elemento; Series.apply es otra opción que opera sobre cada valor, pero no activa la vectorización.
Vectorizar una función en Pandas
Este ejemplo compara una función personalizada con una expresión de arreglo para ajustar pagos. Los datos se crean directamente en el código, así que el ejemplo no depende de un archivo externo. Ejecuta este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import pandas as pd
pay = pd.Series([1000.0, 2000.0, 3000.0], name="pay")
def add_tax(value):
return value * 1.05 + 1
mapped = pay.map(add_tax)
vectorized = pay * 1.05 + 1
applied = pay.apply(add_tax)
reference = pd.Series([1051.0, 2101.0, 3151.0], name="pay")
print(vectorized.tolist())
print(mapped.equals(vectorized))
print(applied.equals(vectorized))
print(vectorized.equals(reference))
La ejecución correcta muestra:
[1051.0, 2101.0, 3151.0]
True
True
True
Qué significa la vectorización para una Series de pandas
Una Series de pandas almacena valores etiquetados. Una expresión como pay * 1.05 + 1 aplica operaciones aritméticas a la Series y conserva su índice. Este código está orientado a arreglos: pandas y sus bibliotecas subyacentes procesan la operación sobre los datos, en vez de que tu código llame explícitamente a add_tax para cada valor.
La vectorización describe cómo se expresa y procesa una operación; no garantiza una implementación concreta. Una operación de pandas aún puede usar bucles internamente, y no debes dar por sentado que utiliza instrucciones SIMD. La diferencia práctica es que una operación compatible de Series o NumPy puede evitar llamadas a funciones de Python para cada elemento. Que sea más rápida depende de la operación, el tamaño de los datos, los tipos de datos y el entorno.
Aplicar una función elemento por elemento con Series.map
Usa Series.map cuando una función escalar personalizada sea la forma más clara de describir una transformación. En el ejemplo, pay.map(add_tax) llama a add_tax para cada valor y devuelve una Series con el índice de entrada. La función debe aceptar un escalar y devolver el escalar transformado. Este patrón resulta útil para reglas personalizadas o búsquedas que no tengan una expresión de arreglo directa.
También puedes pasar un diccionario a Series.map para hacer una asignación fija; los valores sin una clave correspondiente se convierten en valores ausentes. Ten en cuenta este comportamiento si la asignación no cubre todas las entradas posibles. Si el cálculo es una operación aritmética sencilla, prefiere la expresión de la Series: indica directamente la operación y evita envolver código escalar de Python en una llamada elemento por elemento.
Reescribir la función como operaciones de arreglo
La función add_tax calcula value * 1.05 + 1. Como una Series admite la multiplicación y la suma, la misma regla se expresa como pay * 1.05 + 1. Esta es la forma útil de vectorizar una función: expresar su lógica mediante operaciones que actúan sobre todo el arreglo, en lugar de aplicar repetidamente la función original de Python.
Para una columna de DataFrame, selecciónala como Series y aplica la misma expresión; por ejemplo, df["TotalPay"] * 1.05 + 1. Asigna el resultado a una columna nueva si quieres conservarlo junto con los datos de origen. Pandas alinea las Series por índice al asignarlas y al realizar operaciones aritméticas entre ellas, así que comprueba que los índices correspondan cuando combines datos creados por separado.
Elegir entre vectorización, map y apply
Elige una expresión de Series o NumPy cuando la operación esté disponible para el tipo de datos del arreglo. Usa Series.map para una transformación personalizada o una búsqueda que se aplique a cada valor. Usa Series.apply cuando necesites una función escalar y map no describa la tarea con la misma claridad. Tanto map como la ruta habitual de apply sobre una Series ejecutan lógica de Python para cada valor; ninguna convierte automáticamente una función escalar en código vectorizado nativo.
Para calcular una media, no llames a np.mean por separado para cada escalar mediante un bucle o Series.apply. Usa la reducción pay.mean() o numpy.mean(pay) para obtener un único resultado de toda la Series. Una reducción tiene una semántica de salida distinta de una transformación: devuelve un agregado, no un valor por cada fila de entrada.
Comprobar los resultados y medir el rendimiento con cuidado
Antes de usar una expresión reescrita con datos más grandes, compárala con un cálculo de referencia sencillo usando entradas representativas. El ejemplo comprueba que los valores obtenidos con map y apply coincidan con los vectorizados y, después, compara la expresión con una Series de referencia definida manualmente. Las comprobaciones de igualdad incluyen el índice de la Series, lo que ayuda a detectar diferencias de alineación además de diferencias entre valores.
Los valores ausentes y los tipos de datos pueden cambiar el comportamiento. Por ejemplo, la aritmética suele propagar los valores ausentes, mientras que una función personalizada puede tratarlos de otra manera; las columnas enteras, de coma flotante, anulables y de tipo objeto también pueden comportarse de forma distinta. Comprueba el tipo de datos de entrada y define cómo deben tratarse los valores ausentes antes de comparar los métodos.
Mide el rendimiento solo si importa para tu carga de trabajo. Compara cálculos equivalentes con la misma entrada, realiza un calentamiento cuando corresponda, repite las mediciones e indica el método y el entorno. Los tiempos varían según el hardware, las versiones de pandas y NumPy, el tamaño de los datos y el tipo de datos; por eso, un ejemplo pequeño no demuestra una mejora general del rendimiento.