¿Qué productos se compran juntos?
La minería de patrones frecuentes busca grupos de elementos que aparecen juntos en muchos registros, por ejemplo los productos de un ticket de compra. Sirve para colocar mejor las estanterías, preparar ofertas y descubrir hábitos.
Una tienda de barrio guarda cada ticket. Cada ticket es una cesta: los productos que alguien pagó a la vez.
Al final de esta lección
Nota
Puedo encontrar los productos que aparecen juntos en muchas cestas.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Cesta | los productos de una sola compra | pan, leche, huevos |
| Conjunto de elementos | uno o más productos que se miran juntos | pan y leche |
| Soporte | la parte de las cestas que contienen el conjunto | |
| Soporte mínimo | el soporte que hace falta para contar un conjunto | |
| Patrón frecuente | un conjunto cuyo soporte llega al mínimo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
El soporte dice cuántas cestas lo contienen
Para saber si un producto es popular se cuenta en cuántas cestas aparece. Esa cuenta, dividida entre el total de cestas, es el soporte.
Si el pan está en 7 de 10 cestas, su soporte es 7 / 10 = 0,7. Un conjunto de dos productos se cuenta igual: solo vale la cesta que tiene los dos.
Ejemplo resuelto: diez tickets de una tienda
| Ticket | Productos |
|---|---|
| 1 | pan, leche, huevos |
| 2 | pan, leche |
| 3 | leche, yogur, arroz |
| 4 | pan, huevos, queso |
| 5 | pan, leche, queso |
| 6 | arroz, aceite, tomate |
| 7 | pan, leche, huevos, tomate |
| 8 | leche, huevos |
| 9 | pan, queso |
| 10 | pan, leche, aceite |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Cuenta en cuántas cestas sale cada producto
docker exec jupyter python3 -c "import itertools as i, collections as c; B=[x.split() for x in ['pan leche huevos','pan leche','leche yogur arroz','pan huevos queso','pan leche queso','arroz aceite tomate','pan leche huevos tomate','leche huevos','pan queso','pan leche aceite']]; print(sorted(c.Counter(a for b in B for a in b).items()))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Las parejas se cuentan cesta a cesta
Un patrón frecuente puede tener dos o más productos. Para las parejas, recorre cada cesta y suma uno a cada pareja que contiene.
Ordena antes los productos de la cesta. Así «pan, leche» y «leche, pan» cuentan como la misma pareja. Las parejas que llegan al soporte mínimo son los patrones frecuentes.
Cuenta las parejas con un bucle
baskets = [
["pan", "leche", "huevos"],
["pan", "leche"],
["leche", "yogur", "arroz"],
["pan", "huevos", "queso"],
["pan", "leche", "queso"],
["arroz", "aceite", "tomate"],
["pan", "leche", "huevos", "tomate"],
["leche", "huevos"],
["pan", "queso"],
["pan", "leche", "aceite"],
]
pairs = {}
for basket in baskets:
ordered = sorted(basket) # así "leche,pan" y "pan,leche" son la misma pareja
for i in range(len(ordered)):
for j in range(i + 1, len(ordered)):
key = ordered[i] + "," + ordered[j]
if key in pairs:
pairs[key] = pairs[key] + 1
else:
pairs[key] = 1
for key in pairs:
if pairs[key] >= 3:
print(key, pairs[key])
# Cambia el 3 por un 2 y vuelve a ejecutar: ¿cuántas parejas aparecen ahora?
Ejemplo resuelto: las parejas de la tienda
| Pareja | Cestas | Soporte | ¿Con mínimo de 0,3? |
|---|---|---|---|
| leche y pan | 5 | 0,5 | Sí |
| huevos y leche | 3 | 0,3 | Sí |
| huevos y pan | 3 | 0,3 | Sí |
| pan y queso | 3 | 0,3 | Sí |
| aceite y arroz | 1 | 0,1 | No |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error muy común
Advertencia
Mucha gente cree que cuanto más bajo es el soporte mínimo, mejor sale el análisis. Con un mínimo de una sola cesta, cualquier pareja casual cuenta. La lista se llena de patrones sin valor. Elige un mínimo que deje pocos patrones y que se repitan.
Un conjunto no supera a sus partes
Con 8 productos hay 28 parejas. Con 1000 productos hay 499 500. Mirarlas todas es lento.
Hay un atajo. Si un producto es poco frecuente, todo conjunto que lo contenga lo es aún más. Se descarta primero lo raro y solo se juntan los productos que pasaron el mínimo. Este atajo es la base del algoritmo Apriori.
Lista las parejas con tres cestas o más
docker exec jupyter python3 -c "import itertools as i, collections as c; B=[x.split() for x in ['pan leche huevos','pan leche','leche yogur arroz','pan huevos queso','pan leche queso','arroz aceite tomate','pan leche huevos tomate','leche huevos','pan queso','pan leche aceite']]; print(sorted(p for p, n in c.Counter(p for b in B for p in i.combinations(sorted(b), 2)).items() if n >= 3))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un día de bicicletas también es una cesta
Los datos de un laboratorio de alquiler de bicicletas no son tickets, pero sirven. Cada día es una cesta con las etiquetas que cumple: lluvia, finde, calor (15 grados o más) y movido (300 alquileres o más).
Así se pregunta qué etiquetas van juntas en el año.
Cuenta etiquetas y parejas de 365 días
docker exec jupyter python3 -c "import csv, itertools as i, collections as c; d=list(csv.DictReader(open('hires.csv'))); B=[[k for k, t in (('lluvia', float(r['rain_mm'])>0), ('finde', r['weekday'] in ('Sat', 'Sun')), ('calor', float(r['temp_c'])>=15), ('movido', int(r['hires'])>=300)) if t] for r in d]; print(sorted(c.Counter(a for b in B for a in b).items())); print(sorted(c.Counter(p for b in B for p in i.combinations(sorted(b), 2)).items()))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Para ir más lejos: ternas de productos
Una terna es un conjunto de tres productos. Con las cestas de la tienda, ¿hay alguna terna con un soporte de 0,2 o más? Empieza por las parejas que ya pasaron el mínimo, y mira cuáles se pueden ampliar con un tercer producto.