Pandas práctico (11): La función apply

Ya hemos cubierto la mayoría de los fundamentos de trabajar con datos usando la biblioteca Pandas. Hay un tema más que me gustaría discutir antes de concluir la serie: La función Apply.

En el artículo anterior, aprendimos cómo crear subgrupos de datos usando la función groupby. Esto es bastante útil cuando quieres obtener una mejor comprensión de ciertos subconjuntos de datos o realizar agregaciones de grupo. Hoy añadiremos otro recurso a tu caja de herramientas que te permitirá usar esos grupos para mucho más.

Apply te permite realizar cálculos más complejos en los grupos que creas, funciona así: La función que proporcionas a apply se llama en cada uno de los grupos, y los resultados se concatenan en una sola estructura de datos final.

pandas_apply

De nuevo, esto es mucho más fácil de entender con ejemplos prácticos, ¡así que empecemos!

Aplicaciones básicas de apply

Usaremos la misma tabla con datos de Pokémon que usamos en el último artículo.

Primero, importemos pandas y examinemos el contenido de nuestro DataFrame.

import pandas as pd

pdata = pd.read_csv('./sample_data/poke_colors.csv')
pdata
Name Color Evolves HP Attack Defense SpAtk SpDef Speed
0 Caterpie Green True 45 30 35 20 20 45
1 Metapod Green True 50 20 55 25 25 30
2 Scyther Green False 70 110 80 55 80 105
3 Bulbasaur Green True 45 49 49 65 65 45
4 Dratini Blue True 41 64 45 50 50 50
5 Squirtle Blue True 44 48 65 50 64 43
6 Poliwag Blue True 40 50 40 40 40 90
7 Poliwhirl Blue True 65 65 65 50 50 90
8 Charmander Red True 39 52 43 60 50 65
9 Magmar Red False 65 95 57 100 85 93
10 Paras Red True 35 70 55 45 55 25
11 Parasect Red False 60 95 80 60 80 30
12 Pikachu Yellow True 35 55 40 50 50 90
13 Abra Yellow True 25 20 15 105 55 90
14 Psyduck Yellow True 50 52 48 65 50 55
15 Kadabra Yellow True 40 35 30 120 70 10

El argumento más importante de Apply es una función. Esta función se ejecutará en cada grupo de datos y los resultados se concatenarán en una estructura de datos final. Crearemos una función simple que devuelve los dos Pokémon con el valor de ataque más alto, algo así:

# Dos pokémon con el ataque más alto

def highest_attack(data_frame):
    # Recuerda cómo funciona [], esto selecciona las últimas dos (más altas) entradas de Attack después de ordenar
    return data_frame.sort_values(by='Attack')[-2:]

# Probémoslo en el dataframe completo
highest_attack(pdata)
Name Color Evolves HP Attack Defense SpAtk SpDef Speed
11 Parasect Red False 60 95 80 60 80 30
2 Scyther Green False 70 110 80 55 80 105

Ahora veamos cómo usar apply para hacer algo un poco más interesante. Queremos encontrar los dos pokémon con el valor de ataque más alto por color. Para hacer esto, los agruparemos por Color y luego pasaremos highest_attack a apply, algo así:

# Ahora, encontremos cuáles son los dos pokémon con el ataque más alto en cada grupo de color:
pdata.groupby('Color').apply(highest_attack)
Name Color Evolves HP Attack Defense SpAtk SpDef Speed
Color
Blue 4 Dratini Blue True 41 64 45 50 50 50
7 Poliwhirl Blue True 65 65 65 50 50 90
Green 3 Bulbasaur Green True 45 49 49 65 65 45
2 Scyther Green False 70 110 80 55 80 105
Red 9 Magmar Red False 65 95 57 100 85 93
11 Parasect Red False 60 95 80 60 80 30
Yellow 14 Psyduck Yellow True 50 52 48 65 50 55
12 Pikachu Yellow True 35 55 40 50 50 90

¡Observa cómo la tabla final es el resultado de concatenar juntos los resultados de ejecutar highest_attack en cada grupo!

Funciones con argumentos adicionales

Las funciones que pasas al método apply pueden recibir argumentos adicionales. Creemos otra versión de nuestra función, esta vez llamada highest_attribute, que te permite especificar el atributo a tomar en consideración y los n pokémon más altos que quieres seleccionar de cada grupo:

# Establecemos el atributo predeterminado como HP y el n predeterminado a 2
def highest_attribute(data_frame, attribute='HP', n=2):
    return data_frame.sort_values(by=attribute)[-n:]

pdata.groupby('Color').apply(highest_attribute, 'Defense', 3)
Name Color Evolves HP Attack Defense SpAtk SpDef Speed
Color
Blue 4 Dratini Blue True 41 64 45 50 50 50
5 Squirtle Blue True 44 48 65 50 64 43
7 Poliwhirl Blue True 65 65 65 50 50 90
Green 3 Bulbasaur Green True 45 49 49 65 65 45
1 Metapod Green True 50 20 55 25 25 30
2 Scyther Green False 70 110 80 55 80 105
Red 10 Paras Red True 35 70 55 45 55 25
9 Magmar Red False 65 95 57 100 85 93
11 Parasect Red False 60 95 80 60 80 30
Yellow 15 Kadabra Yellow True 40 35 30 120 70 10
12 Pikachu Yellow True 35 55 40 50 50 90
14 Psyduck Yellow True 50 52 48 65 50 55

Observa cómo los parámetros adicionales se pasan a la función apply, no a sort_values mismo. Internamente, apply se asegura de que los parámetros correctos se pasen a cualquier función que esté aplicando.

Usando lambdas como argumento para apply

Como nota final, a veces no querrás escribir una definición de función completa si lo que quieres lograr es muy simple. En este caso, puedes pasar una función lambda. En nuestro siguiente ejemplo usaremos este enfoque para seleccionar de cada grupo el pokémon cuyo nombre aparece primero en orden alfabético en cada grupo:

pdata.groupby('Color').apply(lambda df: df.sort_values('Name').head(1) )
Name Color Evolves HP Attack Defense SpAtk SpDef Speed
Color
Blue 4 Dratini Blue True 41 64 45 50 50 50
Green 3 Bulbasaur Green True 45 49 49 65 65 45
Red 8 Charmander Red True 39 52 43 60 50 65
Yellow 13 Abra Yellow True 25 20 15 105 55 90

La práctica hace la perfección

Apply es una función increíblemente flexible que, si se usa de maneras creativas, te permite resolver una gran variedad de problemas en manipulación y transformación de datos. Este artículo te expuso a los conceptos básicos de la función, pero asegúrate de estudiarla más y experimentar con conjuntos de datos reales.

Como comentario de cierre, me gustaría compartir una cita del libro Python For Data Analysis (2da edición), en el que esta serie está ampliamente basada:

Más allá de estas mecánicas de uso básico, obtener el máximo provecho de apply puede requerir algo de creatividad. Lo que ocurre dentro de la función pasada depende de ti; solo necesita devolver un objeto pandas o un valor escalar.

Eso es todo el Pandas que tengo que compartir, por ahora

Con este artículo, concluimos nuestra serie Pandas práctico. Ha sido muy divertido escribir, y realmente espero que hayas aprendido una o dos cosas interesantes en el camino.

Pandas, como cualquier otra herramienta de software o habilidad, requiere una buena cantidad de práctica antes de que se vuelva verdaderamente útil. No te preocupes si no sabes inmediatamente cómo abordar un conjunto de datos o qué función llamar, con experiencia y exposición continua se volverá algo natural.

Si necesitas ayuda, recuerda que Pandas tiene algunas de las mejores documentaciones disponibles y una comunidad enorme y útil que te guiará para encontrar una solución. ¡Te deseo un proceso de aprendizaje feliz y productivo!

¡Gracias por leer!

Qué hacer a continuación

Juan Luis Orozco Villalobos

¡Hola! Soy Juan, ingeniero de software y consultor en Budapest. Me especializo en computación en la nube e IA, y me encanta ayudar a otros a aprender sobre tecnología e ingeniería