Filtrar y ordenar
En resumen: Filtrar en pandas se queda solo con las filas donde una máscara es True (o isin, between, query), y sort_values las ordena por una columna.
Problema
La lista para el proveedor
Mañana viene el proveedor de alimentos. El gerente quiere una lista: los alimentos de los que tenemos menos de 20, lo más urgente primero. Luego pregunta también por los pedidos del año: cuántos se cancelaron y cuántos clientes nos compran con regularidad.
25 productos se pueden revisar a ojo. Los pedidos del año son 11 116, y ahí los ojos no bastan. Necesitas una manera de decirle a la tabla «dame solo estas filas» y «ordénalas así».
La idea
Una máscara sobre una tabla
La máscara de NumPy funciona también en pandas. products['stock'] < 20 compara cada fila y da una columna (una Serie) de True y False, con el índice de la tabla. Puesta entre corchetes, la máscara se queda con las filas con True:
low.sum() cuenta los Trues: 9 productos tienen menos de 20 en stock. Esto se llama un filtro: una tabla con solo las filas para las que la condición es verdadera.
Mira el índice a la izquierda: 3, 6, 7, 12… Las filas conservan sus etiquetas de products, así que siempre sabes de dónde vino cada una. Dentro de [], un nombre de columna elige una columna, y una máscara elige filas.
La idea
Dos condiciones: &, | y ~
Menos de 20 en stock y menos de 5 € son dos condiciones juntas. Con and obtienes lo mismo que en NumPy:
and quiere un solo True o False, y la columna tiene 25. Así que aquí también escribes & para «y», | para «o» y ~ para «no», con cada condición entre paréntesis:
Con menos de 20 en stock y menos de 5 € están la banitsa y los pepinos, los dos agotados. Con menos de 1 € o más de 20 € están el bollo de mantequilla (0,80 €), el agua (0,90 €), la sartén (24,90 €) y el juego de cuchillos (39 €). La tarjeta de regalo cuesta exactamente 20 € y no es «más de 20».
Pruébalo
Los lácteos más caros
¿Qué lácteos (categoría 4) cuestan más de 3 €? Pon la tabla con ellos en pricey_dairy.
Solución
import pandas as pd
products = pd.read_csv('products.csv')
pricey_dairy = products[(products['category_id'] == 4) & (products['price'] > 3)]
pricey_dairy[['name', 'price']]products[(products['category_id'] == 4) & (products['price'] > 3)] da 3 productos: el queso blanco (7,90 €), el queso kashkaval (9,50 €) y la mantequilla (3,20 €). Con | entran todos los lácteos y todo lo que cuesta más de 3 €, y sin los paréntesis el código falla con un error. La máscara sola, sin products[...], es solo una columna de True y False.
La idea
De una lista y entre dos números: isin y between
Los alimentos están en cuatro categorías: 3, 4, 5 y 6. En lugar de cuatro condiciones con | escribes isin, que pregunta «¿está en esta lista?»:
Hay 18 alimentos. Con ~ obtienes los otros 7: los seis productos del hogar y la tarjeta de regalo. La tarjeta no tiene categoría (NaN), y NaN no está en ninguna lista, así que ~ la atrapa.
Para un rango hay between. between(2, 5) es «de 2 a 5 inclusive»: los dos extremos entran:
Da 9 productos, tantos como (prices >= 2) & (prices <= 5) en la lección de NumPy.
Más precisamente, para curiosos
between(2, 5, inclusive='neither') deja fuera los dos extremos, y 'left' y 'right' se quedan solo con uno. Por defecto es 'both'.
La idea
Texto que contiene: str.contains
«Muéstrame todos los panes.» Entre los nombres están «Pan blanco» y «Pan integral», pero no puedes escribir == 'Pan': ningún nombre es exactamente «Pan». str.contains pregunta si el texto aparece en cualquier parte del nombre:
.str abre los métodos de texto para toda la columna. Lo verás con más detalle en la lección sobre tipos.
La búsqueda distingue mayúsculas de minúsculas. «queso» en minúscula solo encuentra «Banitsa de queso», así que el primer número es 1. «Queso blanco» y «Queso kashkaval» empiezan con mayúscula y quedan fuera. Con case=False no se distinguen las letras y obtienes 3.
La idea
La condición como texto: query
Las máscaras largas con products['...'] por todas partes cuestan de leer. query toma la condición como texto, donde los nombres de las columnas van solos:
En query escribes and, or y not. El texto no lo calcula Python sino pandas, y pandas sabe que son columnas. Menos de 20 en stock y más de 5 € son 7 productos.
Una variable de Python entra con @: category_id in @food es lo mismo que isin(food). Eso da los cinco alimentos con menos de 20 en stock, con los que harás la lista para el proveedor.
La idea
Ordenar: sort_values y nlargest
sort_values('price') ordena las filas por precio, de menor a mayor. Con ascending=False es al revés. Para «los N primeros» hay nlargest(N, columna) y nsmallest:
Los más caros son el juego de cuchillos (39 €), la sartén (24,90 €) y la tarjeta de regalo (20 €). nlargest(3, 'price') da los mismos tres en una línea.
También puedes ordenar por varias columnas: primero por categoría, y dentro de ella por precio. ascending es entonces una lista, una para cada columna. Las categorías suben y los precios dentro de ellas bajan: la banitsa (2,50 €) va primera en pan, el queso kashkaval (9,50 €) en lácteos.
Más precisamente, para curiosos
Ordenar mueve las filas pero no cambia sus etiquetas: el índice de la salida es 22, 21, 24… Si necesitas los números 0, 1, 2 en el orden nuevo, añade .reset_index(drop=True).
La idea
Cuántos de cada uno: value_counts
«¿Cuántos pedidos se cancelaron?» es una pregunta de conteo. value_counts cuenta cuántas veces aparece cada valor en una columna, el más frecuente arriba:
De los 11 116 pedidos del año, 10 254 se entregaron y 657 se cancelaron. Con normalize=True obtienes una proporción en lugar de una cantidad: 0.059, es decir, el 5,9 % de los pedidos se canceló.
Lo mismo con el número de cliente te dice quién pidió cuántas veces:
1390 clientes han pedido. El más fiel, el cliente 1, pidió 121 veces, y 224 clientes pidieron una sola vez. El índice del resultado son los números de cliente, y los valores son cuántos pedidos hizo cada uno.
Pruébalo
Los pedidos abiertos
Los pedidos con el estado new, paid o shipped todavía no han llegado al cliente. Pon la tabla con ellos en open_orders.
Solución
import pandas as pd
year = pd.read_csv('year_orders.csv')
open_orders = year[year['status'].isin(['new', 'paid', 'shipped'])]
print(len(open_orders))year[year['status'].isin(['new', 'paid', 'shipped'])] da 205 pedidos: 90 nuevos, 63 pagados y 52 enviados, exactamente como dice value_counts. != 'delivered' dejaría entrar también los 657 cancelados, y esos no se enviarán.
Ejercicio
La lista y los clientes habituales
Haz la lista para el proveedor: los alimentos (categorías 3, 4, 5 y 6) con stock menor que 20, ordenados por stock de menor a mayor. Con el mismo stock, va primero el producto más caro. Pon la tabla en restock.
Solución
import pandas as pd
products = pd.read_csv('products.csv')
food = [3, 4, 5, 6]
restock = products[products['category_id'].isin(food) & (products['stock'] < 20)]
restock = restock.sort_values(['stock', 'price'], ascending=[True, False])
restock[['name', 'price', 'stock']]El filtro isin(food) & (stock < 20) da 5 alimentos. sort_values(['stock', 'price'], ascending=[True, False]) los ordena: los pepinos (2,80 €, stock 0), la banitsa (2,50 €, stock 0), el queso kashkaval (12), el café (15) y el queso blanco (18). Sin isin entran también la sartén, el juego de cuchillos, la tabla de cortar y el detergente en polvo, y con ascending=False para las dos columnas los más urgentes se van al final.
¿Cuántos clientes pidieron al menos 20 veces en el año? Pon su número en regulars.
Solución
import pandas as pd
year = pd.read_csv('year_orders.csv')
per_customer = year['customer_id'].value_counts()
regulars = (per_customer >= 20).sum()
print(regulars)per_customer = year['customer_id'].value_counts() da el número de pedidos de cada cliente, y (per_customer >= 20).sum() cuenta los clientes con al menos 20: son 119. (year['customer_id'] >= 20).sum() da 9471, porque compara números de cliente, no sus pedidos. Con > 20 obtienes 110: te pierdes a los que tienen exactamente 20.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Vectorización · Resúmenes y valores faltantes · Series y DataFrame · Seleccionar: [], loc e iloc
- Continúa en: Columnas nuevas · Tipos y valores faltantes · Grupos: groupby · Unir tablas: merge
- Ejercicios sobre el tema: Tablas con pandas