Publicado el: 17 de Diciembre del 2020 - Jhonatan Montilla
Como ya sabemos la librería de Python más popular utilizada por quienes trabajan con datos es Pandas, una librería de análisis y manipulación de datos fácil y flexible. existe una gran cantidad de métodos y funciones increíbles, algunas de las cuales, probablemente sean menos conocidas que otras. En este artículo se utilizarán varios ejemplos en el uso de estos métodos y funciones que pueden ser bastente útiles.
Para seguir el desarrollo del código será necesario tener disponible:
Asegúrese de tener las librerías, pandas y seaborn instaladas si aún no lo estáno. Si usted es un nuevo usuario en Python, este es un buen momento para comenzar, y Si tampoco ha utilizado Pandas con anterioridad, este será un buen recurso para tener en consideración.
Se hará uso del conjunto de datos de la librería Seaborn "Tips" para ejemplificar.
import pandas as pd
import seaborn as sns
df = sns.load_dataset('tips')
print(f"{df.shape[0]} rows and {df.shape[1]} columns")
df.head()
244 rows and 7 columns
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
El conjunto de datos se refiere a los datos registrados por un camarero sobre cada propina que recibió durante un período de tiempo trabajando en un restaurante".
Se requiere filtrar los datos para aquellos clientes que dieron una propina de más de 6USD.
df.loc[(df['tip']>6) & (df['total_bill']>=30)]
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
23 | 39.42 | 7.58 | Male | No | Sat | Dinner | 4 |
59 | 48.27 | 6.73 | Male | No | Sat | Dinner | 4 |
141 | 34.30 | 6.70 | Male | No | Thur | Lunch | 6 |
170 | 50.81 | 10.00 | Male | Yes | Sat | Dinner | 3 |
212 | 48.33 | 9.00 | Male | No | Sat | Dinner | 4 |
En el código anterior, cada condición requiere de una referencia al conjunto de datos y un ajuste entre paréntesis si existen varias condiciones.
Sin embargo, a continuación se mostrará cómo se obtiene el mismo resultado con código más elegante con haciendo uso de la función query()
df.query("tip>6 & total_bill>=30")
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
23 | 39.42 | 7.58 | Male | No | Sat | Dinner | 4 |
59 | 48.27 | 6.73 | Male | No | Sat | Dinner | 4 |
141 | 34.30 | 6.70 | Male | No | Thur | Lunch | 6 |
170 | 50.81 | 10.00 | Male | Yes | Sat | Dinner | 3 |
212 | 48.33 | 9.00 | Male | No | Sat | Dinner | 4 |
# hace referencia al nombre de la variable global con @
median_tip = df['tip'].median()
display(df.query("tip>@median_tip").head())
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
5 | 25.29 | 4.71 | Male | No | Sun | Dinner | 4 |
7 | 26.88 | 3.12 | Male | No | Sun | Dinner | 4 |
# Se renombrar la columna para demostración
df.rename(columns={"total_bill":"total.bill"}, inplace=True)
display(df.query("`total.bill`<20").head())
# Se renombra nuevamente la columna
df.rename(columns={"total.bill":"total_bill"}, inplace=True)
total.bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
6 | 8.77 | 2.00 | Male | No | Sun | Dinner | 2 |
8 | 15.04 | 1.96 | Male | No | Sun | Dinner | 2 |
9 | 14.78 | 3.23 | Male | No | Sun | Dinner | 2 |
# Filtrar por día, "Sábado"
display(df.query("day=='Sat'").head())
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
19 | 20.65 | 3.35 | Male | No | Sat | Dinner | 3 |
20 | 17.92 | 4.08 | Male | No | Sat | Dinner | 2 |
21 | 20.29 | 2.75 | Female | No | Sat | Dinner | 2 |
22 | 15.77 | 2.23 | Female | No | Sat | Dinner | 2 |
23 | 39.42 | 7.58 | Male | No | Sat | Dinner | 4 |
df.tail()
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
239 | 29.03 | 5.92 | Male | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Female | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Male | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | Male | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | Female | No | Thur | Dinner | 2 |
display(df.head())
df.tail()
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
239 | 29.03 | 5.92 | Male | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Female | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Male | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | Male | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | Female | No | Thur | Dinner | 2 |
Ordenar varias columnas.
Si alguna vez ha tenido que ordenar sus datos con varias columnas en diferentes direcciones, este ejemplo le podrá ser familiar, se ordenarán los datos por factura total en orden ascendente y rompiendo el vínculo con la cantidad de propina en orden descendente.
Antes de continuar será necesario crear una columna provisional para invertir la escala de la cuenta total o de la propina para hacer que todas las columnas relevantes tuvieran la misma dirección y ordenar posteriormente.
df['rev_tip'] = -df['tip']
df.sort_values(by=['total_bill', 'rev_tip'], ascending=True).head()
total_bill | tip | sex | smoker | day | time | size | rev_tip | |
---|---|---|---|---|---|---|---|---|
67 | 3.07 | 1.00 | Female | Yes | Sat | Dinner | 1 | -1.00 |
92 | 5.75 | 1.00 | Female | Yes | Fri | Dinner | 2 | -1.00 |
172 | 7.25 | 5.15 | Male | Yes | Sun | Dinner | 2 | -5.15 |
111 | 7.25 | 1.00 | Female | No | Sat | Dinner | 1 | -1.00 |
149 | 7.51 | 2.00 | Male | No | Thur | Lunch | 2 | -2.00 |
df.sort_values(by=['total_bill', 'tip'], ascending=[True, False]).head()
total_bill | tip | sex | smoker | day | time | size | rev_tip | |
---|---|---|---|---|---|---|---|---|
67 | 3.07 | 1.00 | Female | Yes | Sat | Dinner | 1 | -1.00 |
92 | 5.75 | 1.00 | Female | Yes | Fri | Dinner | 2 | -1.00 |
172 | 7.25 | 5.15 | Male | Yes | Sun | Dinner | 2 | -5.15 |
111 | 7.25 | 1.00 | Female | No | Sat | Dinner | 1 | -1.00 |
149 | 7.51 | 2.00 | Male | No | Thur | Lunch | 2 | -2.00 |
No solamente se requiere de crear una columna adicional, ahora código también se ve más limpio y más legible.
También es posible utilizar la representación numérica de valores booleanos. Es decir, si cambiando a ascendente = [1,0], también se obtendrá la misma salida.
Si alguna vez tuvo que verificar rápidamente la extracción de datos para los registros que tienen los valores más pequeños o más grandes en una columna en particular. Usando nsmallest (), se pueden verificar 5 registros con la factura total más pequeña de la siguiente manera.
df.nsmallest(5, 'total_bill')
total_bill | tip | sex | smoker | day | time | size | rev_tip | |
---|---|---|---|---|---|---|---|---|
67 | 3.07 | 1.00 | Female | Yes | Sat | Dinner | 1 | -1.00 |
92 | 5.75 | 1.00 | Female | Yes | Fri | Dinner | 2 | -1.00 |
111 | 7.25 | 1.00 | Female | No | Sat | Dinner | 1 | -1.00 |
172 | 7.25 | 5.15 | Male | Yes | Sun | Dinner | 2 | -5.15 |
149 | 7.51 | 2.00 | Male | No | Thur | Lunch | 2 | -2.00 |
df.sort_values(by='total_bill').head()
total_bill | tip | sex | smoker | day | time | size | rev_tip | |
---|---|---|---|---|---|---|---|---|
67 | 3.07 | 1.00 | Female | Yes | Sat | Dinner | 1 | -1.00 |
92 | 5.75 | 1.00 | Female | Yes | Fri | Dinner | 2 | -1.00 |
111 | 7.25 | 1.00 | Female | No | Sat | Dinner | 1 | -1.00 |
172 | 7.25 | 5.15 | Male | Yes | Sun | Dinner | 2 | -5.15 |
149 | 7.51 | 2.00 | Male | No | Thur | Lunch | 2 | -2.00 |
Las salidas de las dos líneas anteriores son idénticas.
Cualquier usuario de pandas probablemente esté familiarizado con df.describe (). Esto muestra estadísticas resumidas para columnas numéricas. Pero se podría obtener más que eso especificando sus argumentos.
En primer lugar, se verificarán los tipos de columnas
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 244 entries, 0 to 243 Data columns (total 8 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 total_bill 244 non-null float64 1 tip 244 non-null float64 2 sex 244 non-null category 3 smoker 244 non-null category 4 day 244 non-null category 5 time 244 non-null category 6 size 244 non-null int64 7 rev_tip 244 non-null float64 dtypes: category(4), float64(3), int64(1) memory usage: 9.3 KB
El conjunto de datos contiene columnas numéricas y categóricas. Se procederá a revisar las estadísticas resumidas de todas las columnas agregando include = 'all':
df.describe(include='all')
total_bill | tip | sex | smoker | day | time | size | rev_tip | |
---|---|---|---|---|---|---|---|---|
count | 244.000000 | 244.000000 | 244 | 244 | 244 | 244 | 244.000000 | 244.000000 |
unique | NaN | NaN | 2 | 2 | 4 | 2 | NaN | NaN |
top | NaN | NaN | Male | No | Sat | Dinner | NaN | NaN |
freq | NaN | NaN | 157 | 151 | 87 | 176 | NaN | NaN |
mean | 19.785943 | 2.998279 | NaN | NaN | NaN | NaN | 2.569672 | -2.998279 |
std | 8.902412 | 1.383638 | NaN | NaN | NaN | NaN | 0.951100 | 1.383638 |
min | 3.070000 | 1.000000 | NaN | NaN | NaN | NaN | 1.000000 | -10.000000 |
25% | 13.347500 | 2.000000 | NaN | NaN | NaN | NaN | 2.000000 | -3.562500 |
50% | 17.795000 | 2.900000 | NaN | NaN | NaN | NaN | 2.000000 | -2.900000 |
75% | 24.127500 | 3.562500 | NaN | NaN | NaN | NaN | 3.000000 | -2.000000 |
max | 50.810000 | 10.000000 | NaN | NaN | NaN | NaN | 6.000000 | -1.000000 |
display(df.describe(include=['category'])) # tipos categóricos
display(df.describe(include=['number'])) # tipos numéricos
sex | smoker | day | time | |
---|---|---|---|---|
count | 244 | 244 | 244 | 244 |
unique | 2 | 2 | 4 | 2 |
top | Male | No | Sat | Dinner |
freq | 157 | 151 | 87 | 176 |
total_bill | tip | size | rev_tip | |
---|---|---|---|---|
count | 244.000000 | 244.000000 | 244.000000 | 244.000000 |
mean | 19.785943 | 2.998279 | 2.569672 | -2.998279 |
std | 8.902412 | 1.383638 | 0.951100 | 1.383638 |
min | 3.070000 | 1.000000 | 1.000000 | -10.000000 |
25% | 13.347500 | 2.000000 | 2.000000 | -3.562500 |
50% | 17.795000 | 2.900000 | 2.000000 | -2.900000 |
75% | 24.127500 | 3.562500 | 3.000000 | -2.000000 |
max | 50.810000 | 10.000000 | 6.000000 | -1.000000 |
Actualizar la configuración de pantalla predeterminada
print(f"{pd.options.display.max_columns} columns")
print(f"{pd.options.display.max_rows} rows")
20 columns 60 rows
Esto significa que si se intenta mostrar un conjunto de datos con más de 20 columnas, solo se podrán ver las primeras 10 y las últimas 10 (se muestran un total de 20 columnas) mientras que el resto se truncará con tres puntos.
La misma lógica se aplica a las filas. A menudo, es posible requerir ver más que estos máximos. Es posible cambiar este comportamiento de la siguiente manera.
pd.options.display.max_columns = None
pd.options.display.max_rows = None
pd.options.display.max_columns = 50
pd.options.display.max_rows = 100
Dependiendo de la escala de las variables numéricas en las que esté trabajando, a veces es posible encontrar notaciones científicas para números muy grandes o muy pequeños cuando trabaja con pandas.
Si le resulta más fácil leer números como 1200 y 0.012 en comparación con 1.2e3 y 1.2e-2 respectivamente, es probable que encuentre esta línea de código útil:
# 2 lugares decimales
pd.options.display.float_format = '{:.2f}'.format
df.head(5)
total_bill | tip | sex | smoker | day | time | size | rev_tip | |
---|---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 | -1.01 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 | -1.66 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 | -3.50 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 | -3.31 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 | -3.61 |
Hemos concluido esta publicación con cinco ejemplos que le ayudará a sacar más provecho de una de las librerías más importantes de Python, si tiene curiosidad por obtener más información sobre otras opciones para personalizar, consulte la documentación.