Indice / Practicas / EJ-4.5
EJ-4.5 · Indice compuesto y clave duplicada
¿Qué identifica una fila de esta tabla? No es el estudiante, y no es el curso. Descubrirlo - y comprobar si los datos lo respetan - es todo el ejercicio.
Qué hay que hacer
A partir de academico_inscripciones.csv, producir dos archivos:
inscripciones_indexadas.csv- las 110 filas ordenadas por la clave, con una bandera que marca las que están en conflicto.clave_duplicada.csv- un informe de tres filas que dice, para tres candidatos a clave, si identifican una fila sin repetir.
ELI5Explicado facil
Una lista de quién se anotó a qué. Ana aparece tres veces porque se anotó a tres materias, y en Álgebra aparecen veinte personas.
Entonces ni el nombre ni la materia alcanzan para señalar una línea de la lista: hace falta el par. Y aun así hay una línea escrita dos veces, con dos notas distintas, que nadie sabe cuál vale.
Archivos
- Entrada ·
academico_inscripciones.csv - Objetivo ·
inscripciones_indexadas.csv - Objetivo ·
clave_duplicada.csv - Herramienta ·
comparar.py
Las tres preguntas del informe
El informe evalúa tres candidatos a clave. Antes de escribir código, respondelas vos:
- ¿
estudiante_ididentifica una fila? - hay 43 estudiantes y 110 filas. - ¿
curso_id? - hay 9 cursos. - ¿El par
(estudiante_id, curso_id)? - esta es la interesante, y la respuesta no es un sí limpio.
Los tres dan es_unica = 0. Pero los tres 0 significan
cosas muy distintas, y esa es la idea que vale más que el archivo.
Cómo saber si te salió
python comparar.py mi_tabla.csv inscripciones_indexadas.csv
python comparar.py mi_informe.csv clave_duplicada.csv
Antes de arrancar, mirá los datos
| estudiante_id | curso_id | nota |
|---|---|---|
| 35 | 5 | 5.8 |
| 28 | 4 | 7.5 |
| 22 | 5 | 7.5 |
| 17 | 6 | 11.5 |
| 21 | 1 | 9.3 |
El contrato de salida
inscripciones_indexadas.csv · 110 filas
| Columna | Tipo | Que lleva |
|---|---|---|
estudiante_id | entero | Primera parte de la clave |
curso_id | entero | Segunda parte de la clave |
fila_origen | entero | Posicion en el archivo de entrada, empezando en 0. Hay que crearla |
nota | decimal | Tal cual viene, redondeada a 2 decimales. Puede quedar vacia |
clave_repetida | entero | 1 si el par (estudiante_id, curso_id) de esa fila aparece mas de una vez en el archivo; 0 si no |
clave_duplicada.csv · 3 filas
| Columna | Tipo | Que lleva |
|---|---|---|
columna | texto | El candidato a clave: 'curso_id', 'estudiante_id' o 'estudiante_id+curso_id' |
es_unica | entero | 1 si ese candidato identifica cada fila sin repetir; 0 si no |
valores_distintos | entero | Cuantas combinaciones distintas de ese candidato hay |
filas | entero | Siempre 110: el total del archivo |
filas_repetidas | entero | Cuantas filas participan de una repeticion, contando TODAS las del grupo (duplicated con keep=False) |
Que hacer con cada defecto
| Defecto | Donde | Accion | Adonde va |
|---|---|---|---|
| el par (35, 5) aparece dos veces, con notas 5.8 y 6.0 | 2 filas: la 0 y la 109 | NO NO se deduplica ni se descarta. Se MARCA con clave_repetida = 1 y se informa en clave_duplicada.csv | las dos salidas |
| nota ausente | 2 filas | NO NO se imputa ni se descarta: la nota no forma parte de la clave | inscripciones_indexadas.csv, con el campo vacio |
| estudiante_id se repite en 99 filas | 43 estudiantes para 110 inscripciones | NO NO es un defecto: una fila es una inscripcion, no un estudiante. El informe lo dice con es_unica = 0 | clave_duplicada.csv |
Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:
- agregar fila_origen antes de tocar nada
- marcar las filas cuyo par de clave se repite, con duplicated(subset=CLAVE, keep=False)
- ordenar por estudiante_id, curso_id y fila_origen
- armar el informe evaluando los tres candidatos sobre el archivo COMPLETO
El informe se calcula sobre el archivo entero y no sobre la tabla ya ordenada: el orden no cambia los conteos, pero calcularlo antes deja claro que es un diagnostico de la entrada. Y keep=False es lo que hace que se marquen LAS DOS filas del par repetido, no solo la segunda.
Conteos clave
| filas de entrada | 110 |
|---|---|
| inscripciones_indexadas.csv | 110 |
| clave_duplicada.csv | 3 |
| estudiantes distintos | 43 |
| cursos distintos | 9 |
| pares (estudiante, curso) distintos | 109 |
| filas con clave_repetida = 1 | 2 |
| notas ausentes | 2 |
| por motivo |
Invariantes
Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:
len(tabla) == 110
tabla['fila_origen'].is_unique
int(tabla['clave_repetida'].sum()) == 2
len(informe) == 3
int(informe['es_unica'].sum()) == 0
informe.loc[informe['columna'] == 'estudiante_id+curso_id', 'valores_distintos'].item() == 109
informe.loc[informe['columna'] == 'estudiante_id+curso_id', 'filas_repetidas'].item() == 2
(informe['filas'] == 110).all()
PISTASSi te trabas, abri esto
- duplicated(keep='first') marca solo la segunda aparicion; duplicated(keep=False) marca las dos. Para una bandera de «esta fila esta en conflicto» hace falta keep=False.
- Ninguno de los tres candidatos es unico, ni siquiera el par. Eso no significa que la clave este mal elegida: significa que los datos la violan una vez.
- El orden termina en fila_origen justamente porque el par se repite: sin ese ultimo criterio, esas dos filas quedan en el orden que decida el algoritmo.
- drop_duplicates(subset=columnas) cuenta combinaciones distintas sin tener que armar una clave de texto a mano.
Así tiene que quedar
| estudiante_id | curso_id | fila_origen | nota | clave_repetida |
|---|---|---|---|---|
| 1 | 3 | 28 | 3.7 | 0 |
| 1 | 77 | 108 | 7.0 | 0 |
| 2 | 2 | 15 | vacio | 0 |
| 2 | 6 | 71 | 5.0 | 0 |
| 2 | 8 | 88 | 5.3 | 0 |
| columna | es_unica | valores_distintos | filas | filas_repetidas |
|---|---|---|---|---|
| curso_id | 0 | 9 | 110 | 109 |
| estudiante_id | 0 | 43 | 110 | 99 |
| estudiante_id+curso_id | 0 | 109 | 110 | 2 |
0 del informe no dicen lo mismo
estudiante_id se repite porque así es la tabla: un
estudiante hace varias materias. Eso no es un defecto, es el grano. La conclusión es
«esta columna no es la clave», no «hay que arreglar algo».
El par (estudiante_id, curso_id) se repite porque un dato está
mal: alguien cargó dos veces la misma inscripción, con dos notas distintas.
Ahí sí hay algo que arreglar, y el enunciado tiene que decidir cuál nota vale.
Confundir los dos casos lleva a deduplicar por estudiante_id y borrar
109 inscripciones legítimas.
keep=False no es un detalle
duplicated() por defecto marca la segunda aparición y deja la
primera sin marcar - sirve para contar «cuántas sobran».
duplicated(keep=False) marca las dos, que es lo que hace
falta para una bandera de «esta fila está en conflicto».
Con el default, la fila 0 saldría con clave_repetida = 0 y quien la
lea pensaría que está bien.