Saltar al contenido

Indice / Practicas / EJ-4.4

EJ-4.4 · Ordenar con desempate y nulos al final

Practica de: 4.8 Ordenar y desempatarDificultad: B

Las mismas 50 filas, en otro orden. No se descarta ni se corrige nada: todo el ejercicio es declarar el orden de forma que dos personas distintas obtengan exactamente el mismo archivo.

Qué hay que hacer

A partir de libros_catalogo.csv, producir libros_ordenados.csv: las 50 filas ordenadas por año descendente, y dentro de cada año por precio descendente, con los ausentes al final.

ELI5Explicado facil

Ordenar los libros de una biblioteca del más nuevo al más viejo, y los del mismo año del más caro al más barato.

¿Y si dos libros son del mismo año y salen lo mismo? Ahí hay que tener una tercera regla. Y una cuarta, por si la tercera tampoco alcanza. Se sigue agregando reglas hasta que sea imposible que dos libros empaten, porque si empatan, mañana la lista sale distinta.

Archivos

Por qué hacen falta cuatro criterios

Cada criterio desempata al anterior
#CriterioPor qué no alcanza
1anio DESC16 años se repiten en el catálogo
2precio DESCpuede empatar, y además hay 2 ausentes
3isbn ASCparece único y no lo es: hay uno repetido
4fila_origen ASCahora sí: es única por construcción

El punto 3 es el que hay que ver venir. Que una columna se llame «clave» o «ISBN» no la hace única: eso se comprueba con is_unique, y en este archivo da False.

Cómo saber si te salió

python comparar.py mi_salida.csv libros_ordenados.csv

Y hay una comprobación que podés hacer solo, sin el objetivo: ordená dos veces, una con kind="stable" y otra con kind="quicksort", y compará las dos listas de fila_origen. Si dan iguales, tu orden es total. Si dan distintas, te falta un criterio.

Antes de arrancar, mirá los datos

libros_catalogo.csv (entrada) · 50 filas, se muestran 5
isbntituloautoranioprecio
978-1000-001Algoritmos vol. 1Ximena Molina200357.24
978-8695-002Bases de datos vol. 1Guadalupe Gutiérrez201673.18
978-7073-003Redes vol. 1Nahuel Vega200747.34
978-7146-004Sistemas operativos vol. 1Olivia Ríos202536.31
978-3259-005Compiladores vol. 1Delfina Molina200681.58

El contrato de salida

libros_ordenados.csv · 50 filas

ColumnaTipoQue lleva
fila_origenenteroPosicion en el archivo de entrada, empezando en 0. Hay que crearla
isbntextoTal cual viene
titulotextoTal cual viene
autortextoTal cual viene. Puede quedar vacio
anioenteroTal cual viene. Puede quedar vacio, y hay un 2199
preciodecimalTal cual viene, redondeado a 2 decimales. Puede quedar vacio, y hay un -5.0

Orden de las filas: anio DESC, precio DESC, isbn ASC, fila_origen ASC. Los ausentes de anio y de precio van al final (na_position='last'), y se usa kind='stable'. Indice: no se escribe: to_csv(index=False)

Que hacer con cada defecto

DefectoDondeAccionAdonde va
anio ausente1 filaNO NO se corrige. Con na_position='last' esa fila queda ULTIMA, porque el primer criterio del orden es el aniolibros_ordenados.csv
precio ausente (vacio y token NaN)2 filasNO NO se corrige. Van al final dentro de su grupo de aniolibros_ordenados.csv
anio 2199 y precio -5.0, que son imposibles2 filasNO NO se validan: son numeros y ordenan como cualquier otro. El 2199 queda primero de todolibros_ordenados.csv
el isbn 978-1000-001 se repite2 filasNO NO se deduplica. Pero obliga a agregar fila_origen: sin ella esas dos filas empatan en los tres criterios y el orden deja de ser totallibros_ordenados.csv
Orden de comprobacion

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

  1. agregar fila_origen antes de ordenar
  2. ordenar por anio DESC
  3. dentro del mismo anio, por precio DESC
  4. si tambien empata el precio, por isbn ASC
  5. y si hasta el isbn empata, por fila_origen ASC

Cada criterio desempata al anterior. El ultimo tiene que ser una columna unica o el orden no es total: aca el isbn no alcanza porque se repite, y por eso hace falta fila_origen. na_position='last' vale para todos los criterios a la vez.

Conteos clave

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

filas de entrada50
libros_ordenados.csv50
anios ausentes1
precios ausentes2
anios que se repiten16
isbn repetidos1
primera fila (anio mas alto)2199
por motivo

Invariantes

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

len(ordenado) == 50
ordenado['fila_origen'].is_unique
sorted(ordenado['fila_origen']) == list(range(50))
ordenado['anio'].dropna().is_monotonic_decreasing
ordenado['anio'].iloc[0] == 2199
ordenado['anio'].isna().iloc[-1]
int(ordenado['precio'].isna().sum()) == 2
set(ordenado['isbn']) == set(pd.read_csv('libros_catalogo.csv')['isbn'])
PISTASSi te trabas, abri esto
  • El orden no descarta nada: la salida tiene las mismas 50 filas que la entrada, en otro orden.
  • na_position='last' es el default, pero escribilo igual: quien lea el codigo dentro de seis meses no tiene por que acordarse del default.
  • El isbn se repite una vez. Si tu orden termina ahi, esas dos filas quedan en el orden que decida el algoritmo, y dos corridas pueden dar archivos distintos.
  • Comprobalo vos mismo: ordena dos veces, una con kind='stable' y otra con kind='quicksort', y compara las listas. Si son iguales, el orden es total.

Así tiene que quedar

libros_ordenados.csv (objetivo) · 50 filas, se muestran 5
fila_origenisbntituloautoranioprecio
19978-3226-020Criptografía vol. 2Gabriela Luna219951.72
46978-6715-047Álgebra lineal vol. 5Hugo Ángel202644.52
10978-5379-011Algoritmos vol. 2Marta Quiroga202642.76
9978-4347-010Criptografía vol. 1Zacarías Castro202583.06
30978-9672-031Algoritmos vol. 4Belén Sol202558.18
El año 2199 queda primero, y está bien

Es un año imposible y encabeza la lista, porque el orden no valida: ordena. Lo mismo con el precio de -5.0, que queda último de su año.

Ver los valores imposibles en los bordes de un orden es, de hecho, una forma barata de encontrarlos - es lo que hace el paso 2 de la animación de la lección 0.2. Corregirlos es EJ-5.6.

Los ausentes van al final incluso cuando el orden es descendente

na_position="last" es el default y no se invierte con ascending=False. La fila sin año queda última de todo el archivo, no primera.

Escribilo explícitamente aunque sea el default: quien lea el código dentro de seis meses no tiene por qué acordarse, y en un sort_values(...).drop_duplicates(keep="last") ese detalle decide qué fila sobrevive.