Indice / Practicas / EJ-5.5
EJ-5.5 · Deduplicar por recencia
62 filas para 60 productos. Sacar las dos que sobran es fácil; lo difícil es quedarse con la copia correcta, porque el conteo de filas da bien de las dos formas.
Qué hay que hacer
A partir de catalogo_sistema_a.csv, producir
catalogo_a_unico.csv: una fila por SKU, conservando de
cada producto repetido la versión más reciente según la columna
actualizado.
ELI5Explicado facil
Tenés dos fichas del mismo producto. Una dice que sale $695 y es de agosto; la otra dice $31 y es de fin de agosto.
Si te quedás con cualquiera te va a quedar una sola ficha, que es lo que pediste. Pero la mitad de las veces vas a tener el precio viejo, y nadie se va a dar cuenta mirando el total: la cantidad de productos va a ser la correcta igual.
Archivos
- Entrada ·
catalogo_sistema_a.csv - Objetivo ·
catalogo_a_unico.csv - Herramienta ·
comparar.py
La trampa, que no da error
drop_duplicates(subset=["sku"]) a secas se queda con la
primera fila de cada SKU, que acá es la vieja. El archivo sale con
60 filas, todos los conteos cierran, ningún assert se rompe… y
dos precios están mal.
Este es el error más caro de la unidad justamente porque es invisible en cualquier
revisión que solo mire cantidades. La única forma de que keep signifique
algo es ordenar antes por la columna que define cuál es la buena.
Cómo saber si te salió
python comparar.py mi_salida.csv catalogo_a_unico.csv
Antes de arrancar, mirá los datos
| sku | nombre | precio | stock | actualizado |
|---|---|---|---|---|
| SKU001 | Artículo 001 | 205.25 | 22 | 2026-07-23 |
| SKU002 | Artículo 002 | 695.67 | 84 | 2026-08-06 |
| SKU003 | Artículo 003 | 31.89 | 151 | 2026-08-09 |
| SKU004 | Artículo 004 | vacio | 195 | 2026-07-15 |
| SKU005 | Artículo 005 | 174.26 | 126 | 2026-08-07 |
Buscá SKU002 y SKU007: son los dos que aparecen dos
veces, y las dos veces con precios muy distintos.
El contrato de salida
catalogo_a_unico.csv · 60 filas
| Columna | Tipo | Que lleva |
|---|---|---|
sku | texto | La clave del producto, unica en la salida |
nombre | texto | Sin espacios en los extremos |
precio | decimal | Redondeado a 2 decimales. Puede quedar vacio: hay 1 producto sin precio |
stock | entero | Puede quedar vacio: hay 1 producto con el token NaN |
actualizado | texto | La fecha AAAA-MM-DD de la version que sobrevivio |
Que hacer con cada defecto
| Defecto | Donde | Accion | Adonde va |
|---|---|---|---|
| SKU002 aparece dos veces, con precio 695.67 (2026-08-06) y 31.5 (2026-08-20) | 2 filas | conservar conservar la version mas reciente: la del 2026-08-20 | catalogo_a_unico.csv, con precio 31.5 |
| SKU007 aparece dos veces, con precio 85.34 (2026-07-15) y 88.0 (2026-08-22) | 2 filas | conservar conservar la version mas reciente: la del 2026-08-22 | catalogo_a_unico.csv, con precio 88.0 |
| empate de fechas entre dos versiones del mismo SKU | no ocurre en este archivo, pero la regla tiene que estar igual | gana gana la que aparece ultima en el archivo: sort_values(kind='stable') y drop_duplicates(keep='last') | catalogo_a_unico.csv |
| precio vacio | 1 fila, SKU004 | NO NO se valida en este ejercicio: la fila se conserva y el precio queda vacio | catalogo_a_unico.csv |
| stock con el token NaN | 1 fila, SKU010 | NO NO se valida en este ejercicio: se convierte a ausente y la fila se conserva | catalogo_a_unico.csv |
Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:
- ordenar por actualizado ascendente, con kind='stable'
- drop_duplicates(subset=['sku'], keep='last')
- ordenar el resultado por sku ascendente
keep='last' significa 'la ultima de la tabla', no 'la mas reciente'. Solo despues de ordenar por fecha las dos cosas coinciden. Y el orden final por sku es del contrato de salida, no del algoritmo: se hace al final, sobre lo que quedo.
Conteos clave
| filas de entrada | 62 |
|---|---|
| catalogo_a_unico.csv | 60 |
| SKU repetidos | 2 |
| filas eliminadas | 2 |
| productos sin precio | 1 |
| productos sin stock | 1 |
| por motivo |
Invariantes
Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:
len(unico) == 60
unico['sku'].is_unique
len(unico) == pd.read_csv('catalogo_sistema_a.csv')['sku'].nunique()
unico.loc[unico['sku'] == 'SKU002', 'actualizado'].item() == '2026-08-20'
unico.loc[unico['sku'] == 'SKU007', 'actualizado'].item() == '2026-08-22'
int(unico['precio'].isna().sum()) == 1
int(unico['stock'].isna().sum()) == 1
PISTASSi te trabas, abri esto
- drop_duplicates sin ordenar antes se queda con la primera del archivo, que aca es la version vieja. La cantidad de filas te va a dar bien igual: por eso el error no se ve en ningun conteo.
- Si ponés actualizado dentro de subset, las dos filas dejan de ser duplicadas y no se elimina ninguna.
- Un assert de unicidad despues de deduplicar cuesta una linea y convierte un error silencioso en uno ruidoso.
- El token NaN de la columna stock es texto en el archivo. Que termine como ausente es una decision, no algo que pase solo si leiste como texto.
Así tiene que quedar
| sku | nombre | precio | stock | actualizado |
|---|---|---|---|---|
| SKU001 | Artículo 001 | 205.25 | 22 | 2026-07-23 |
| SKU002 | Artículo 002 | 31.5 | 12 | 2026-08-20 |
| SKU003 | Artículo 003 | 31.89 | 151 | 2026-08-09 |
| SKU004 | Artículo 004 | vacio | 195 | 2026-07-15 |
| SKU005 | Artículo 005 | 174.26 | 126 | 2026-08-07 |
En este archivo las dos versiones de cada SKU tienen fechas distintas, así que no
hay empate. El contrato lo fija igual: si dos versiones comparten la fecha,
gana la que aparece última en el archivo, que es lo que se obtiene con
sort_values(kind="stable") y keep="last".
Escribir la regla cuando no se necesita es barato. Descubrir que hacía falta cuando el archivo del mes que viene sí tiene un empate, no.
Hay un producto sin precio y otro con el token NaN en el stock. Los
dos se conservan, con el campo vacío. Este ejercicio deduplica y
nada más; validar y decidir qué hacer con los ausentes es EJ-5.6, que
además sí produce un archivo de rechazos.