48

Guía definitiva para dominar Pandas

50019Puntos

hace 17 días

Curso de Manipulación y Análisis de Datos con Pandas y Python
Curso de Manipulación y Análisis de Datos con Pandas y Python

Curso de Manipulación y Análisis de Datos con Pandas y Python

Pandas es la librería de software libre para manipulación de datos con Python más usada en Data Science. Manipula grandes sets de datos numericos, tablas y series de tiempo. Trabaja con múltiples formatos de archivos de datos como csv o xls. Crea DataFrames que podrás manipular y analizar sin preocuparte por el performance de tus aplicaciones, todo esto muy fácil y rápido con Pandas.

Pandas es la librería de Python que te permite cargar datos, modelarlos, analizarlos, manipularlos y prepararlos. En este tutorial desde cero aprenderás todo lo fundamental que necesitas para que ya mismo empieces a sacarle provecho a Pandas en tu día a día como Data Scientist.

¿Qué es Pandas?

Pandas es una librería de Python de código abierto que se encarga de la manipulación de datos de alto nivel y está construida sobre NumPy. Tiene varias estructuras de datos para manipular y tratar la información. Una de las principales estructuras guarda la información tabulada en un objeto llamado DataFrame.

Cómo instalar Pandas

Para instalar Pandas coloca en tu consola:

pip install pandas

Y para importarlo en tu código por convención se usa:

import pandas as pd

Si estás trabajando con un notebook en la nube como Deepnote o Google Colab, Pandas ya estará instalado y solo tendrás que importarlo.

Tus primeros pasos con Pandas

Este tutorial es muy práctico, por lo que la mejor manera de sacarle provecho es ir practicando cada concepto. Preparé un notebook para ti con todo lo que te enseñaré a continuación. Duplícalo (o descárgalo) y ve haciendo los ejercicios ahí. Además, al final te dejé un reto y un regalo.

Descargar notebook del tutorial de Pandas

¡Y eso no es todo! También vamos a necesitar una base de datos con la cual trabajar. En el notebook que te compartí ya estará cargada cuando lo dupliques, pero si quieres trabajar por tu cuenta, estaremos usando la base de datos de las 5 ligas top de fútbol europeo, descargadas de Kaggle:

¡Empecemos! 🥳

¿Qué es un DataFrame y cómo crearlo?

Un DataFrame es la estructura de datos con la que Pandas almacena y manipula datos tabulados (no es la única estructura de datos, pero es la más común y la que usaremos en este tutorial). En palabras más sencillas, es como una hoja de cálculo de Excel. Tiene filas y columnas, acepta distintos tipos de datos y permite interactuar entre ellos. La diferencia con una hoja de cálculo es que es extremadamente más rápida y potente, por lo que podrás trabajar con cantidades muy grandes de datos.

Nota: otra estructura que te encontrarás mucho es Pandas Series, es como un DataFrame de una sola dimensión.

Hay un par de formas de crear un DataFrame con Python:

1) Diccionario de listas (columna por columna)

>>> football_dict = {
		    "player": ["Lionel Messi", "Cristiano Ronaldo"],
		    "year": [2016, 2016],
		    "goals": [37, 25],
		}
>>> football_stats = pd.DataFrame(football_dict)
>>>print(football_stats)
							player  year  goals
0       Lionel Messi  2016     37
1  Cristiano Ronaldo  2016     25

Las listas podrían ser un ndarray de NumPy.

2**) Lista de diccionarios (fila por fila)**

>>> football_list = [
		    {"player": "Lionel Messi", "year": 2016, "goals": 37},
		    {"player": "Cristiano Ronaldo", "year": 2016, "goals": 25},
		]
>>> football_stats = pd.DataFrame(football_list)
>>>print(football_stats)
							player  year  goals
0       Lionel Messi  2016     37
1  Cristiano Ronaldo  2016     25

Importar datos en Pandas

Lo anterior fue una buena base, pero sería muy ineficiente ir llenando todos los datos de esa manera. Comúnmente se importa los datos de archivos CSV, JSON, SQL, etc. Para ello pandas trae varias formas de leer un archivo, el código base suele ser: pd.read_{file_type}('path')

Por ejemplo, para cargar un CSV (Comma Separated Values), la función sería: pd.read_csv('path/file.csv'). Esto convertirá el contenido del CSV en un DataFrame, el cual por convención se lo nombra como df.

El DataFrame que creamos anteriormente está guardado ahora como CSV con el nombre de football_mini_stats.csv. La forma de importarlo sería esta:

>>> df = pd.read_csv('football_mini_stats.csv')
>>>print(df)
							player  year  goals
0       Lionel Messi  2016     37
1  Cristiano Ronaldo  2016     25

¿Notaste que siempre se pone como índice una lista de números que parte desde el 0? Bueno, no es 100% necesario que sea así, podrías poner tu propio índice personalizado o usar una de las columnas del DataFrame. Para ello solo debes usar el argumento index_col='col_name'. Pongamos el nombre de los jugadores como índice.

>>> df = pd.read_csv('/work/datasets/football_mini_stats.csv', index_col='player')
>>>print(df)
				   				 year  goals
player                        
Lionel Messi       2016     37
Cristiano Ronaldo  2016     25

¡Genial, ahora puedes acceder a los valores usando el nombre de los jugadores! Más adelante vas a ver cuan útil puede llegar a ser esto. 😉

Inspeccionar un DataFrame

Ya tienes todo lo que necesitas para importar un DataFrame. Pero cuando empiezas a hacer un análisis de datos es muy importante que primero inspecciones todo: una pequeña muestra de los datos, cuántas filas hay, qué columnas existen, qué tipos de datos hay, si faltan datos, una ligera vista de sus estadísticas descriptivas, etc.

Así que te dejaré una serie de funciones de pandas para hacer justo eso:

  • df.head() → retorna las 5 primeras filas. También le puedes pasar un entero como parámetro y te devolverá esa cantidad de primeras filas.
  • df.tail() → retorna las últimas 5 filas del dataset.
  • df.sample() → es parecido a los 2 anteriores, pero este tomará muestras al azar del DataFrame. Aquí es obligatorio especificar la cantidad.
  • df.shape → retorna las filas y columnas que tiene el DataFrame.
  • df.size → multiplica las filas y columnas y te da el total de datos del DataFrame.
  • df.info() → este es genial, te da la cuenta de valores no nulos, el tipo de dato de cada columna (recuerda que solo puede haber un único tipo de dato por columna) y el uso de memoria. Cuando estés preprocesando los datos, será un gran aliado.
  • df.describe() → te ayudará mucho con las primeras impresiones de los datos. Calcula algunas estadísticas descriptivas para cada columna.

Hace un momento te dejé un dataset de Kaggle de las 5 ligas top de Europa. A partir de ahora lo empezaremos a usar. Lo modifiqué un poco para que tenga menos columnas y lo importé con el nombre de df usando el player_id como índice, lo podrás encontrar en el notebook que te compartí en la carpeta de datasets. Dicho eso, ¡pasemos a la acción! 🏃‍♂️

>>># Ejemplo de 3 jugadores al azar
>>>print(df.sample(3))
							 player_name  year  games  goals  npg  shots  assists  \
player_id                                                             
6734       Ambroise Oyongo  2019     21      0    0     10        0   
2071        Diego González  2016      3      0    0      0        0   
1221           Jacopo Sala  2015     18      0    0     11        1   

           yellow_cards  red_cards position    team_name  time  
player_id                                                       
6734                  3          0      D M  Montpellier  1831  
2071                  0          0        S      Sevilla    29  
1221                  6          0  D F M S       Verona  1492

>>># Filas, columnas y total de datos
>>>print(df.shape)
(18633, 12)
>>>print(df.size)
223596

>>># Información de todas las columnas
>>>print(df.info())
'pandas.core.frame.DataFrame'>
Int64Index: 18633 entries, 8865 to 4363
Data columns (total 12 columns):
 #   Column        Non-Null Count  Dtype 
---  ------        --------------  ----- 
 0   player_name   18633 non-null  object
 1   year          18633 non-null  int64 
 2   games         18633 non-null  int64 
 3   goals         18633 non-null  int64 
 4   npg           18633 non-null  int64 
 5   shots         18633 non-null  int64 
 6   assists       18633 non-null  int64 
 7   yellow_cards  18633 non-null  int64 
 8   red_cards     18633 non-null  int64 
 9   position      18633 non-null  object
 10  team_name     18633 non-null  object
 11  time          18633 non-null  int64 
dtypes: int64(9), object(3)
memory usage: 2.4+ MB
None

Nota como la tabla tiene tantas columnas que no las puede mostrar de la sola, así que usa un \ y las divide en 2 manteniendo el índice.

¡Wow, esos son muchos datos! 😯 Parece que tenemos para divertirnos un rato, veamos qué encontramos. 😁

Ordenar los datos

No tenemos muy en claro qué orden está siguiendo la base de datos. Pero te tengo una excelente noticia: puedes darle el orden que tú quieras. ¿Cómo? Te presento a df.sort_values().

Esta función tiene 2 parámetros importantes: by y ascending. El primero recibe el nombre de la columna que quieras ordenar y el segundo un booleano que indica si la quieres ordenar ascendentemente o no.

💡 Toma en cuenta: en la mayoría de funciones de pandas puedes pasar más de un valor si lo pones a manera de lista. Fíjate cómo lo hago a partir de ahora.

Por ejemplo, si quisieras ordenar descendentemente la columna de los nombres de jugadores, usarías: df.sort_values('player_name', ascending=False). Pero si quisieras ordenar varias columnas a la vez, como por equipos ascendentemente y por número de goles descendentemente, usarías:

>>>print(df.sort_values(['team_name', 'goals'], ascending=[True, False]).head(3))
						player_name  year  games  goals  npg  shots  assists  \
player_id                                                          
1125       Carlos Bacca  2015     38     18   16     77        2   
2014       Jérémy Menez  2014     33     16    8     78        4   
1125       Carlos Bacca  2016     32     13    9     56        3   

           yellow_cards  red_cards position team_name  time  
player_id                                                    
1125                  2          0      F S  AC Milan  3179  
2014                  3          1    F M S  AC Milan  2713  
1125                  3          0      F S  AC Milan  2152

Subconjuntos y filtros de datos

No siempre vas a necesitar todo el DataFrame para hacer tus análisis, muchas veces será más cómodo solo tener una parte de él. Para ello podemos hacer subsetting (crear subconjuntos).

En su forma más básica puedes seleccionar las columnas que deseas y filtrar las filas de esta manera:

  • df['col_name'] → selecciona una columna.
  • df[['col1_name', 'col2_name']] → selecciona 2 o más columnas. Nota que puse una lista dentro de los corchetes.
  • df[df.col_name == 'value'] → filtra los datos.
  • df[df['col_name'] == 'value'] → también filtra los datos, pero con distinta notación.
  • df[df.col_name.isin(list)] → puedes añadir una lista con varios datos a filtrar.
  • df.query('player_name == value') → otra forma de filtrar datos.

También puedes usar operadores como & para poner varias condiciones y colocar cada una de ellas entre paréntesis. Vamos a ver todo esto en un par de ejemplos:

>>># Goles de Cristiano Ronaldo en 2014
>>> cr7 = df[(df.player_name == 'Cristiano Ronaldo') & (df.year == 2014)]
>>> cols = ['player_name', 'year', 'goals']
>>>print(cr7[cols])
								 player_name  year  goals
player_id                                
2371       Cristiano Ronaldo  2014     48

>>># Goles de Ronaldo, Messi y Suárez en 2015
>>> players = ['Cristiano Ronaldo', 'Lionel Messi', 'Luis Suárez']
>>> top_players = df[(df.player_name.isin(players)) & (df.year == 2015)]
>>>print(top_players[cols])
								 player_name  year  goals
player_id                                
2098             Luis Suárez  2015     40
2097            Lionel Messi  2015     26
2371       Cristiano Ronaldo  2015     35

Subsetting con .loc

¿Recuerdas que es posible poner una columna como índice? Bueno, es momento de sacarle provecho. Para empezar te dejo un par de funciones con los índices:

  • df.set_index('col_name') → pone una columna como índice.
  • df.reset_index() → remueve el índice.
  • df.sort_index(ascending=True) → ordena el índice.

Ahora sí, veamos cómo funciona loc. Esta funcionalidad te permitirá seleccionar filas y columnas específicas en una sola línea:

  • df.loc[:, ['col_name', 'another_col']] → accede a todas las filas y columnas específicas.
  • df.loc[['row_index', 'another_row']] → accede a todas las columnas y filas específicas.
  • df.loc[['row_index', 'another_row'], ['col_name', 'another_col']]filas y columnas específicas.

Si tienes los índices ordenados, podrías hacer slicing[::].

Ahora que desbloqueaste un nuevo superpoder, vamos a realizar el mismo ejercicio de subconjuntos y filtros de datos. Para ello usaremos los nombres de los jugadores como índice.

>>># Goles de Ronaldo, Messi y Suárez en 2015
>>> df = df.set_index('player_name')
>>> players = ['Cristiano Ronaldo', 'Lionel Messi', 'Luis Suárez']
>>> cols = ['year', 'goals']
>>> top_players = df.loc[players, cols]
>>>print(top_players.query('year==2015'))
									 year  goals
player_name                   
Cristiano Ronaldo  2015     35
Lionel Messi       2015     26
Luis Suárez        2015     40

Aplicar funciones a un DataFrame

Como Pandas está escrito sobre NumPy, podríamos usar muchas de las funciones de NumPy en nuestras columnas (y también otras nativas de Pandas) como por ejemplo:

  • .sum() → suma todos los valores de una columna.
  • .mean() → promedio de los valores de una columna.
  • .max() → valor máximo de una columna.
  • .min() → valor mínimo de una columna.
  • .cumsum() → en cada fila va poniendo la suma acumulada de una columna.
  • .cummax() → en cada fila va poniendo el valor máximo encontrado en orden de una columna.
  • .value_counts(sort=True) → cuenta los distintos valores que existen en una columna (muy útil para contar categorías) y los ordena descendientemente.
  • .drop_duplicates(subset='col_name') → elimina duplicados en una columna.

Pero eso no es todo, también es posible pasar funciones que nosotros mismos hayamos creado u otras funciones importadas de otras librerías. Para ello se usa .agg(function).

>>># Máxima cantidad de goles hechas por un jugador en una temporada
>>> max_goals = df['goals'].max()
>>> cols = ['goals', 'year', 'team_name']
>>>print(df[df.goals == max_goals][cols])
									 goals  year    team_name
player_name                                
Cristiano Ronaldo     48  2014  Real Madrid

>>># Porcentaje de disparos al arco que terminan en gol
>>> total_shots = df['shots'].sum()
>>> total_goals = df['goals'].sum()
>>>print(round(total_goals / total_shots * 100, 2))
10.6

Acabamos de descubrir que Cristiano Ronaldo tiene el récord de más goles en una temporada entre 2014 y 2020, con 48 goles. Y también que la estadística de las 5 grandes ligas de Europa dice que 1 de cada 10 disparos al arco termina en gol.

¡Aplica el resto de funciones y mira qué más puedes encontrar! 🤔🔎

Agrupar datos

Como vimos en este dataset, cada fila representa los datos de un año entero para cada jugador. Pero sería más interesante ver las estadísticas de todos los años al mismo tiempo para todos los jugadores. ¡Vamos a hacerlo!

Para ello usaremos la función groupby, hay varias maneras de sacarle provecho, te dejaré algunas interesantes:

  • df.groupby('col_name_to_group')['col_name_to_aggregate'].mean() → agrupa los datos de la columna que está entre (paréntesis) y obtiene la media de la columna que está entre [corchetes].
  • df.groupby('col_name')['col_name'].agg([min, max, sum]) → obtiene múltiples estadísticas.
  • df.groupby(['col_name', 'another_col'])['col_name'].mean() → agrupa varias columnas.
  • df.groupby(['col_name', 'another_col'])[['col_name', 'another_col']].mean() → obtiene la media de múltiples columnas.

Se ve algo complicado, pero es más sencillo de lo que crees, vamos a verlo en acción y apliquemos todo lo visto hasta ahora. 🥳

>>># Top 10 jugadores que más goles han marcado entre 2014 y 2020
>>> top_players = df.groupby('player_name')['goals'].sum()
>>>print(top_players.sort_values(ascending=False).head(10))
player_name
Lionel Messi                 205
Cristiano Ronaldo            194
Robert Lewandowski           174
Luis Suárez                  154
Harry Kane                   148
Pierre-Emerick Aubameyang    141
Sergio Agüero                128
Edinson Cavani               125
Ciro Immobile                119
Mohamed Salah                117
Name: goals, dtype: int64

>>># Top 5 equipos con más tarjetas rojas y amarillas
>>> red_cards = df.groupby('team_name')[['red_cards', 'yellow_cards']].sum()
>>>print(red_cards.sort_values('red_cards', ascending=False).head())
					 red_cards  yellow_cards
team_name                         
AC Milan          43           513
Genoa             42           562
Valencia          39           598
Bologna           38           477
Lazio             35           576

Con groupby lograste encontrar estadísticas más generales, como que Lionel Messi es el jugador que más goles ha marcado entre 2014 y 2020 y que el AC Milan es el equipo que más tarjetas rojas se ha llevado.

Crear columnas

Hora del último cálculo. Obtengamos los 5 jugadores más efectivos. Para ello sumemos el total de goles y asistencias de un solo jugador en todo este rango de años y guardémoslo en una nueva columna.

Puedes crear una columna con la notación df['col_name'] = values. Muy parecido a crear un nuevo par key: value en un diccionario. Y operar en columnas es muy parecido a operar entre arrays de NumPy.

>>> df['goals_assists'] = df.goals + df.assists
>>> best_players = df.groupby('player_name')['goals_assists'].sum()
>>>print(best_players.sort_values(ascending=False).head())
player_name
Lionel Messi          293
Cristiano Ronaldo     246
Luis Suárez           224
Robert Lewandowski    203
Harry Kane            178

Al parecer no cambió mucho el orden, solo que Luis Suárez superó a Robert Lewandowski al añadir las asistencias. Pero lo que sí cambió es que ahora sabes crear columnas. 🎉🎊

Exportar datos de Pandas

Listo, terminaste tu análisis, creaste subconjuntos, ordenaste los valores, creaste nuevas columnas y aplicaste funciones, pero resulta que ahora tienes una tabla completamente diferente a la inicial. Así que necesitas exportar tus datos.

Pandas trae una serie de funciones que te permiten exportar tus datos al formato que quieras. Su estructura es df.to_{file_type}('path/file_name'). Además, tiene un argumento interesante que, en caso de tener la lista de índices por defecto, podrías no exportarla usando index=False. Para exportar nuestro DataFrame podríamos usar:

>>> df.to_csv('home/top_football.csv', index=False)

Ejercicios de Pandas

Ahora mismo tienes todo lo fundamental que necesitabas saber, ¡qué emoción! 🥳

Pero te tengo una mala noticia… Todo lo que acabas de aprender en este post se te va a olvidar. 🙁

No te preocupes, te tengo la solución justo aquí. Pon en práctica todo por tu cuenta y ahora sí dominarás Pandas. 😁

Así que te dejaré una serie de retos y comparte el código y sus resultados en los comentarios. Usarás la misma base de datos (aunque si quieres, te dejaré unas cuantas más para que las analices por tu cuenta). Debes completar esto:

  1. Usa df.describe() y cuéntanos todos los insights que te dio y qué podría significar cada uno.
  2. Encuentra la cantidad de goles totales hechos por cada posición.
  3. ¿Cuál es el jugador que más tiempo ha jugado y cuál es la media de tiempo de todos los jugadores? Esta pregunta tiene truco porque hay muchos jugadores suplentes que no juegan casi nunca y van a sesgar los datos, ¿cómo podrías solucionar esto?
  4. ¿Qué posición es la que más tiempo juega? ¿Y la que menos?
  5. ¿Qué porcentaje de goles son hechos por penales? La columnanpgsignifica: goles hechos SIN penales.
  6. ¿Qué porcentaje de goles son hechos con asistencias?
  7. ¿Cuál fue el equipo que más goles hizo cada año? ¿Salió campeón ese año?
  8. ¿Cuántos jugadores jugaron todos los años del dataset? ¿Qué porcentaje del total representan?

Para terminar, acá te dejo otros datasets interesantes que podrías analizar: estadísticas de la NBA en caso de que te guste más el básquet que el fútbol, seguros médicos y rendimiento de estudiantes en los exámenes.

Despedida

¿Cómo te fue en el reto? ¿Qué cosas geniales descubriste? No te preocupes si no pudiste con alguno, estaré ayudándote en los comentarios. 😉

Por cierto, si estuviste siguiendo el notebook que te compartí, al final te dejé unos regalos, estoy seguro de que te van a encantar. 🎁

¿Recuerdas que se puede importar y exportar varios formatos de archivos? Bueno, te recomiendo seguir tu aprendizaje con el Curso de Manipulación y Análisis de Datos con Pandas y Python en donde aprenderás cuáles son los tipos de archivos más óptimos para ciertos casos de uso. También cómo optimizar memoria cambiando los tipos de datos, lidiar con datos faltantes, visualizar los resultados y, la mejor parte, ver en acción cómo se hace el preprocesamiento de datos en la vida real.

Espero verte también en los comentarios de ese curso. ¡Nunca pares de aprender! 💚

Curso de Manipulación y Análisis de Datos con Pandas y Python
Curso de Manipulación y Análisis de Datos con Pandas y Python

Curso de Manipulación y Análisis de Datos con Pandas y Python

Pandas es la librería de software libre para manipulación de datos con Python más usada en Data Science. Manipula grandes sets de datos numericos, tablas y series de tiempo. Trabaja con múltiples formatos de archivos de datos como csv o xls. Crea DataFrames que podrás manipular y analizar sin preocuparte por el performance de tus aplicaciones, todo esto muy fácil y rápido con Pandas.
Anthony Ismael
Anthony Ismael
anthony_manotoa

50019Puntos

hace 17 días

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
2
14461Puntos

Excelente aporte, me ayudará muchísimo en mi aprendizaje en DS. Gracias Anthony.

2
10012Puntos

No sabía acerca de .cumsum(). Lo peor es que había buscado precisamente como realizar sumas acumuladas con pandas pero no había encontrado info por lo que lo estaba haciendo con ciclos. !Muchas gracias¡

2
17175Puntos

Justo estoy empezando a aprender pandas, esto me sirvió mucho, gracias 😄

1
5865Puntos

Me gustaría aportar la página Kaggle. (https://www.kaggle.com/datasets) Ahí se encuentran conjuntos de datos interesantes además algunos de ellos tienen tareas (Tasks) que puedes intentar y subir tus soluciones.

1
50019Puntos
17 días

Gracias por compartirla por acá 😉
También la dejé junto a un par más de fuentes en la parte final del notebook 😄

1

Me quedé trabado en el punto 7

goals_by_tema_by_year = df.groupby(["year","team_name"])["goals"].sum()
goals_by_tema_by_year.sort_values(ascending=False)

Llego a hacer esto para crear una serie que me muestre el agrupado de goles por equipo y por año pero luego no puedo seleccionar el equipo con mas goles de cada año. Ya que quiero volver a filtrarlo por año pero no me deja por ser un pandas.serie y no un dataframe.

Alguna ayuda? Gracias

1
50019Puntos
7 días

Hola 😃

Podrías hacer que tu Pandas.Series vuelva a ser un DataFrame con .reset_index()

El código final podría quedar añadiendo un par de métodos:

goals_by_team_by_year = df.groupby(["year","team_name"])["goals"].sum()
goals_by_team_by_year.sort_values(ascending=False).reset_index().drop_duplicates('year')
1
33239Puntos

Excelente aporte