Indice / Practicas / EJ-6.2
EJ-6.2 · Discrepancias entre los pares comunes
De los 46 productos que están en los dos catálogos, 18 no dicen lo mismo. La parte difícil no es encontrarlos: es separar dos problemas que parecen uno.
Qué hay que hacer
A partir de los dos catálogos, producir catalogo_discrepancias.csv:
una fila por SKU donde las fuentes no coinciden, con los dos valores, la diferencia
de precio y qué tipo de problema es.
ELI5Explicado facil
Dos personas cuentan el mismo inventario. Cuando comparás sus planillas hay dos situaciones distintas:
- Una anotó $100 y la otra $120. Se contradicen: alguien tiene que decidir quién tiene razón.
- Una anotó el nombre del producto y la otra dejó el casillero vacío. No se contradicen: falta un dato, y se completa copiándolo.
Meter los dos casos en la misma bolsa hace que el informe pida una decisión donde solo hacía falta copiar y pegar.
Archivos
- Entrada ·
catalogo_sistema_a.csv - Entrada ·
catalogo_sistema_b.csv - Objetivo ·
catalogo_discrepancias.csv - Herramienta ·
comparar.py
La trampa, que es de NaN
La forma obvia de comparar es nombre_a != nombre_b. Con esa
comparación salen 10 nombres distintos. Con la comparación correcta
salen 9.
La diferencia es SKU033: A tiene el nombre y B no. Como
NaN != "Artículo 033" da True, la comparación ingenua lo
cuenta como una contradicción - y no lo es.
Las dos versiones producen 18 filas. Lo que cambia es qué dice el informe sobre cada una, y eso es lo que alguien va a usar para decidir qué hacer.
Cómo saber si te salió
python comparar.py mi_salida.csv catalogo_discrepancias.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 |
El contrato de salida
catalogo_discrepancias.csv · 18 filas
| Columna | Tipo | Que lleva |
|---|---|---|
sku | texto | La clave del producto |
nombre_a | texto | El nombre segun A |
nombre_b | texto | El nombre segun B. Puede quedar vacio |
difiere_nombre | entero | 1 si las DOS tienen nombre y son distintos |
falta_nombre | entero | 1 si una lo tiene y la otra no. NO es una contradiccion |
precio_a | decimal | El precio segun A, redondeado a 2 decimales |
precio_b | decimal | El precio segun B, redondeado a 2 decimales |
diferencia_precio | decimal | precio_b menos precio_a, redondeado a 2 decimales |
difiere_precio | entero | 1 si las DOS tienen precio y son distintos |
Que hacer con cada defecto
| Defecto | Donde | Accion | Adonde va |
|---|---|---|---|
| las dos fuentes tienen el nombre y no coinciden | 9 sku, tipo 'Articulo 018' contra 'Articulo 018 USB' | es es una contradiccion: se informa con difiere_nombre = 1 | catalogo_discrepancias.csv |
| B no tiene el nombre y A si (SKU033) | 1 sku | NO NO es una contradiccion: es un dato que falta. Va con falta_nombre = 1 y difiere_nombre = 0 | catalogo_discrepancias.csv |
| las dos fuentes tienen el precio y no coinciden | 11 sku, con diferencias de hasta 393.87 | se se informa con difiere_precio = 1 y la diferencia calculada | catalogo_discrepancias.csv |
| precios negativos en B (SKU017 pasa de 373.88 a -19.99) | 1 sku | NO NO se valida en este ejercicio: se informa la diferencia y punto. Quien lea el informe decide | catalogo_discrepancias.csv |
| sku que estan en una sola fuente | 14 solo en A, 10 solo en B | NO NO entran: este informe habla de los que estan en las dos. Los otros son EJ-6.3 | fuera de catalogo_discrepancias.csv |
Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:
- deduplicar los dos catalogos por recencia
- cruzar con inner y validate='1:1'
- marcar difiere_* solo donde las DOS tienen el dato
- marcar falta_* donde exactamente una lo tiene
- quedarse con las filas donde alguna marca vale 1
Comparar con != a secas cuenta como discrepancia la fila donde B no tiene nombre, porque NaN != valor da True. Eso da 18 filas igual, pero con difiere_nombre = 10 en vez de 9, y mezcla dos problemas que se arreglan distinto: uno es preguntar cual dato vale, el otro es completar el que falta.
Conteos clave
| productos en las dos fuentes | 46 |
|---|---|
| catalogo_discrepancias.csv | 18 |
| difiere_nombre | 9 |
| falta_nombre | 1 |
| difiere_precio | 11 |
| con nombre y precio distintos a la vez | 3 |
| sin ninguna discrepancia | 28 |
| por motivo |
Invariantes
Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:
len(discrepancias) == 18
discrepancias['sku'].is_unique
int(discrepancias['difiere_nombre'].sum()) == 9
int(discrepancias['falta_nombre'].sum()) == 1
int(discrepancias['difiere_precio'].sum()) == 11
(discrepancias[['difiere_nombre', 'falta_nombre', 'difiere_precio']].sum(axis=1) > 0).all()
(discrepancias['difiere_nombre'] & discrepancias['falta_nombre']).eq(0).all()
18 + 28 == 46
PISTASSi te trabas, abri esto
- NaN != NaN da True, y NaN != 'algo' tambien. Sin la guarda de notna, un dato que falta se informa como una contradiccion.
- difiere_nombre y falta_nombre nunca pueden valer 1 en la misma fila: o las dos fuentes tienen el dato, o solo una.
- diferencia_precio se calcula igual en las filas donde el precio no difiere: da 0.00, y eso esta bien.
- Las filas donde ninguna marca vale 1 no van al informe: son los 28 productos donde las dos fuentes coinciden.
Así tiene que quedar
| sku | nombre_a | nombre_b | difiere_nombre | falta_nombre | precio_a | precio_b | diferencia_precio | difiere_precio |
|---|---|---|---|---|---|---|---|---|
| SKU015 | Artículo 015 | Artículo 015 | 0 | 0 | 146.43 | 164.0 | 17.57 | 1 |
| SKU017 | Artículo 017 | Artículo 017 | 0 | 0 | 373.88 | -19.99 | -393.87 | 1 |
| SKU018 | Artículo 018 | Artículo 018 USB | 1 | 0 | 297.22 | 297.22 | 0.0 | 0 |
| SKU020 | Artículo 020 | Artículo 020 Pro | 1 | 0 | 256.96 | 145.0 | -111.96 | 1 |
| SKU024 | Artículo 024 | Artículo 024 USB | 1 | 0 | 374.34 | 374.34 | 0.0 | 0 |
SKU017 pasa de 373.88 en A a -19.99 en B.
Eso no es una actualización de precio: es un dato roto.
Y el informe lo reporta sin juzgarlo, que es lo correcto acá: su
trabajo es decir dónde no coinciden las fuentes, no decidir cuál tiene razón. Esa
decisión la toma EJ-6.1, con una política escrita.
assert que atrapa el error de NaN
difiere_nombre y falta_nombre nunca pueden valer
1 en la misma fila: o las dos fuentes tienen el dato, o solo una. Si tu
archivo tiene una fila con los dos en 1, te faltó la guarda de
notna().