Saltar al contenido

Indice / Practicas / EJ-6.9

EJ-6.9 · Pedidos diarios con resample

Una serie diaria a partir de 120 pedidos sueltos. Las dos decisiones que la definen no son técnicas: los días sin ventas aparecen igual, y el pedido de un cliente que no existe se conserva.

Qué hay que hacer

A partir de tienda_pedidos.csv y tienda_clientes.csv, producir pedidos_diarios.csv: una fila por día del período, con la cantidad de pedidos, el total, los clientes distintos y cuántos pedidos venían de un cliente desconocido.

ELI5Explicado facil

Es el parte diario del negocio. Y tiene dos reglas que parecen obvias y que casi nadie escribe:

  • Un día sin ventas es un día con cero ventas, no un día que no existe. Si lo salteás, el promedio diario sale al doble.
  • Una venta a alguien que no está en la lista de clientes igual se vendió. Sacarla del total porque no encontraste el nombre es perder plata de verdad en un informe.

Archivos

Las dos decisiones

Lo que cambia según qué elijas
DecisiónSi elegís bienSi elegís mal
Días vacíosresample("D") → 205 filasgroupby → 94 filas, y el promedio diario se duplica
Cliente desconocidohow="left" → 120 pedidoshow="inner" → 119, y falta una venta en el total

Los cuatro programas corren. Solo uno produce el archivo del contrato, y los otros tres dan números que parecen razonables.

Cómo saber si te salió

python comparar.py mi_salida.csv pedidos_diarios.csv

Antes de arrancar, mirá los datos

tienda_pedidos.csv (entrada) · 120 filas, se muestran 5
idcliente_idtotalcreadoestado
10132374.942026-07-08 22:39:00preparando
10237223.652026-04-18 02:08:00entregado
10326605.952026-02-22 13:19:00nuevo
104251743.362026-04-04 12:18:00pagado
1058699.822026-05-20 01:42:00pagado

El contrato de salida

pedidos_diarios.csv · 205 filas

ColumnaTipoQue lleva
fechatextoEl dia, en formato AAAA-MM-DD. Estan TODOS los dias del periodo
pedidosenteroCuantos pedidos hubo ese dia. Puede ser 0
totaldecimalSuma de total, redondeada a 2 decimales. 0.00 en los dias sin pedidos
clientes_distintosenteroCuantos cliente_id distintos compraron ese dia
pedidos_sin_clienteenteroPedidos cuyo cliente_id no esta en el padron

Orden de las filas: fecha ascendente. Es unica: hay una fila por dia. Indice: no se escribe: to_csv(index=False). El indice temporal se baja con reset_index()

Que hacer con cada defecto

DefectoDondeAccionAdonde va
111 dias del periodo sin ningun pedidode 205 dias, solo 94 tienen pedidosaparecen aparecen igual, con pedidos = 0 y total = 0.00. Es lo que hace resample y lo que groupby NO puede hacerpedidos_diarios.csv
un pedido cuyo cliente_id no esta en el padron1 filaNO NO se descarta. El cruce es how='left': la venta existio y tiene que contarse. Se informa en pedidos_sin_clientepedidos_diarios.csv
2 pedidos sin total2 filasNO NO se descartan: el pedido existio. sum() ignora el ausente, asi que suman 0 al total de su dia pero cuentan en pedidospedidos_diarios.csv
1 pedido sin estado1 filaNO NO afecta: el estado no participa de este informepedidos_diarios.csv
Orden de comprobacion

Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:

  1. convertir creado a fecha
  2. cruzar con clientes usando how='left' y validate='m:1'
  3. marcar los pedidos sin cliente
  4. poner la fecha en el indice y ordenarlo
  5. resample('D') y agregar

El cruce va ANTES del resample: despues de agrupar por dia ya no se puede saber a que cliente pertenecia cada pedido. Y how='left' es la decision central: con inner, el pedido del cliente desconocido desaparece del total del negocio.

Conteos clave

Si estos numeros no te dan, algo se desvio antes de que llegues a comparar los archivos.

pedidos de entrada120
clientes en el padron40
pedidos_diarios.csv205
dias con al menos un pedido94
dias con 0 pedidos111
pedidos sin cliente en el padron1
total general354824.17
por motivo

Invariantes

Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:

len(diario) == 205
94 + 111 == 205
diario['fecha'].is_unique
int(diario['pedidos'].sum()) == 120
int(diario['pedidos_sin_cliente'].sum()) == 1
abs(diario['total'].sum() - pedidos['total'].sum()) < 0.01
(diario['clientes_distintos'] <= diario['pedidos']).all()
diario.notna().all().all()
PISTASSi te trabas, abri esto
  • resample crea los dias vacios; groupby por fecha solo devuelve los 94 que existen. La diferencia son 111 filas.
  • how='left' conserva el pedido del cliente desconocido. Con inner desaparece del total, y el total del negocio queda mal.
  • La suma de la columna pedidos tiene que dar 120: es el assert que confirma que ningun pedido se perdio al agrupar.
  • sum() ignora los totales ausentes. Los 2 pedidos sin total cuentan en pedidos y suman 0 en total, que es lo declarado.

Así tiene que quedar

pedidos_diarios.csv (objetivo) · 205 filas, se muestran 5
fechapedidostotalclientes_distintospedidos_sin_cliente
2026-01-01133.9710
2026-01-0211344.2410
2026-01-0300.000
2026-01-041903.3610
2026-01-0500.000
El cruce va antes del resample

Después de agrupar por día ya no se puede saber a qué cliente pertenecía cada pedido: la información se perdió al agregar. El orden es cruzar, marcar, y recién ahí agrupar.

Y validate="m:1" en el cruce: muchos pedidos contra una fila por cliente. Si el padrón trajera un cliente duplicado, el merge multiplicaría pedidos y el total del día saldría inflado sin ninguna señal.

El assert que cierra el ejercicio

diario["pedidos"].sum() == 120. Si no da, algún pedido se perdió: en el cruce, al convertir la fecha, o al agrupar. Una línea, y cubre los tres.