Saltar al contenido

Indice / Practicas / EJ-6.2

EJ-6.2 · Discrepancias entre los pares comunes

Practica de: 6.3 merge avanzadoDificultad: M

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

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

catalogo_sistema_a.csv (entrada) · 62 filas, se muestran 5
skunombrepreciostockactualizado
SKU001Artículo 001205.25222026-07-23
SKU002Artículo 002695.67842026-08-06
SKU003Artículo 00331.891512026-08-09
SKU004Artículo 004vacio1952026-07-15
SKU005Artículo 005174.261262026-08-07

El contrato de salida

catalogo_discrepancias.csv · 18 filas

ColumnaTipoQue lleva
skutextoLa clave del producto
nombre_atextoEl nombre segun A
nombre_btextoEl nombre segun B. Puede quedar vacio
difiere_nombreentero1 si las DOS tienen nombre y son distintos
falta_nombreentero1 si una lo tiene y la otra no. NO es una contradiccion
precio_adecimalEl precio segun A, redondeado a 2 decimales
precio_bdecimalEl precio segun B, redondeado a 2 decimales
diferencia_preciodecimalprecio_b menos precio_a, redondeado a 2 decimales
difiere_precioentero1 si las DOS tienen precio y son distintos

Orden de las filas: sku ascendente. Es unico en la salida, asi que no hace falta desempate. Indice: no se escribe: to_csv(index=False)

Que hacer con cada defecto

DefectoDondeAccionAdonde va
las dos fuentes tienen el nombre y no coinciden9 sku, tipo 'Articulo 018' contra 'Articulo 018 USB'es es una contradiccion: se informa con difiere_nombre = 1catalogo_discrepancias.csv
B no tiene el nombre y A si (SKU033)1 skuNO NO es una contradiccion: es un dato que falta. Va con falta_nombre = 1 y difiere_nombre = 0catalogo_discrepancias.csv
las dos fuentes tienen el precio y no coinciden11 sku, con diferencias de hasta 393.87se se informa con difiere_precio = 1 y la diferencia calculadacatalogo_discrepancias.csv
precios negativos en B (SKU017 pasa de 373.88 a -19.99)1 skuNO NO se valida en este ejercicio: se informa la diferencia y punto. Quien lea el informe decidecatalogo_discrepancias.csv
sku que estan en una sola fuente14 solo en A, 10 solo en BNO NO entran: este informe habla de los que estan en las dos. Los otros son EJ-6.3fuera de catalogo_discrepancias.csv
Orden de comprobacion

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

  1. deduplicar los dos catalogos por recencia
  2. cruzar con inner y validate='1:1'
  3. marcar difiere_* solo donde las DOS tienen el dato
  4. marcar falta_* donde exactamente una lo tiene
  5. 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

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

productos en las dos fuentes46
catalogo_discrepancias.csv18
difiere_nombre9
falta_nombre1
difiere_precio11
con nombre y precio distintos a la vez3
sin ninguna discrepancia28
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

catalogo_discrepancias.csv (objetivo) · 18 filas, se muestran 5
skunombre_anombre_bdifiere_nombrefalta_nombreprecio_aprecio_bdiferencia_preciodifiere_precio
SKU015Artículo 015Artículo 01500146.43164.017.571
SKU017Artículo 017Artículo 01700373.88-19.99-393.871
SKU018Artículo 018Artículo 018 USB10297.22297.220.00
SKU020Artículo 020Artículo 020 Pro10256.96145.0-111.961
SKU024Artículo 024Artículo 024 USB10374.34374.340.00
Una diferencia de precio de −393,87

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.

Un 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().