Saltar al contenido

Indice / Practicas / EJ-6.4

EJ-6.4 · Tres tablas, validate y huerfanos

Practica de: 6.3 merge avanzadoDificultad: A

Tres tablas: estudiantes, cursos e inscripciones. Hay que juntarlas, apartar las inscripciones que apuntan a alguien que no existe, y encontrar a los que no se anotaron a nada. Con una trampa de clave que rompe el cruce si elegís la columna equivocada.

Qué hay que hacer

Producir tres archivos:

ELI5Explicado facil

Tenés una lista de alumnos, una de materias y una de anotaciones. Cada anotación dice «el alumno 12 se anotó a la materia 3».

Hay una anotación que dice «el alumno 999», y no existe ningún alumno 999. Y hay ocho alumnos que no aparecen en ninguna anotación. Las dos cosas son información, no errores del programa, y hay que informarlas por separado.

Archivos

La trampa: cuál columna es la clave

El padrón tiene id y legajo, y los dos parecen identificar al estudiante. Solo uno lo hace: el legajo E007 está repetido en dos estudiantes distintos (id 7 y id 8).

Si cruzás por legajo, las 9 inscripciones de esos dos estudiantes se multiplican y el archivo sale con filas de más. El total sigue pareciendo razonable - nadie cuenta 108 a mano - y las notas de esos alumnos aparecen dos veces.

validate="m:1" convierte eso en una excepción antes de que llegue al archivo.

Cómo saber si te salió

python comparar.py mi_enriquecidas.csv inscripciones_enriquecidas.csv
python comparar.py mi_sin.csv estudiantes_sin_inscripcion.csv
python comparar.py mi_huerfanas.csv inscripciones_huerfanas.csv

Antes de arrancar, mirá los datos

academico_estudiantes.csv (entrada) · 50 filas, se muestran 5
idlegajonombrecorreo
1E001Javier Herrerajavier.herrera@uni.edu.ar
2E002Pablo Díazpablo.diaz@uni.edu.ar
3E003Ana Peñaana.pena@uni.edu.ar
4E004Lautaro Ruizlautaro.ruiz@uni.edu.ar
5E005Inés Quirogaines.quiroga@uni.edu.ar

El contrato de salida

inscripciones_enriquecidas.csv · 108 filas

ColumnaTipoQue lleva
fila_origenenteroPosicion en academico_inscripciones.csv, empezando en 0
estudiante_identeroLa clave del estudiante
legajotextoDel padron. OJO: no es unico
estudiantetextoEl nombre del estudiante
curso_identeroLa clave del curso
codigotextoEl codigo del curso
cursotextoEl nombre del curso
creditosenteroDel catalogo. Puede quedar vacio: un curso no los tiene cargados
notadecimalTal cual viene, redondeada a 2 decimales. Puede quedar vacia

Orden de las filas: estudiante_id ASC, curso_id ASC, fila_origen ASC. El par (estudiante, curso) se repite una vez, asi que fila_origen es lo que hace total al orden. Indice: no se escribe: to_csv(index=False)

estudiantes_sin_inscripcion.csv · 8 filas

ColumnaTipoQue lleva
estudiante_identeroEl id del estudiante
legajotextoSu legajo
estudiantetextoSu nombre
correotextoSu correo

Orden de las filas: estudiante_id ascendente. Es unico. Indice: no se escribe: to_csv(index=False)

inscripciones_huerfanas.csv · 2 filas

ColumnaTipoQue lleva
fila_origenenteroPosicion en el archivo de inscripciones
estudiante_identeroTal cual viene
curso_identeroTal cual viene
notadecimalTal cual viene
columnatextoCual de las dos referencias no existe
motivotextoSiempre huerfano

Orden de las filas: fila_origen ascendente. Es unico. Indice: no se escribe: to_csv(index=False)

Que hacer con cada defecto

DefectoDondeAccionAdonde va
inscripcion del estudiante 999, que no esta en el padron1 fila, la 107apartar apartarinscripciones_huerfanas.csv con motivo huerfano y columna estudiante_id
inscripcion al curso 77, que no esta en el catalogo1 fila, la 108apartar apartarinscripciones_huerfanas.csv con motivo huerfano y columna curso_id
el legajo E007 esta repetido en dos estudiantes distintos (id 7 e id 8)2 filas del padronNO NO se toca. Es la trampa del ejercicio: hay que cruzar por id, que si es unico. Cruzar por legajo multiplicaria las 9 inscripciones de esos dos estudiantesinscripciones_enriquecidas.csv, sin filas de mas
el par (estudiante 35, curso 5) aparece dos veces, con notas distintas2 filasNO NO se deduplica: las dos son inscripciones y las dos se enriquecen. Por eso el orden necesita fila_origeninscripciones_enriquecidas.csv
notas ausentes y creditos ausentes2 notas, 1 curso sin creditosNO NO se imputan: este ejercicio cruza, no limpiainscripciones_enriquecidas.csv, con el campo vacio
Orden de comprobacion

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

  1. agregar fila_origen a las inscripciones
  2. marcar como huerfana la que referencia a un estudiante inexistente
  3. marcar como huerfana la que referencia a un curso inexistente
  4. cruzar SOLO las validas contra estudiantes y contra cursos, por id, con validate='m:1'
  5. listar los estudiantes que no aparecen en ninguna inscripcion valida

Los huerfanos se apartan ANTES de cruzar: un how='left' los conservaria con las columnas del padron vacias, y despues serian indistinguibles de un dato que falta. Y validate='m:1' se pone en los dos merges: es lo que falla si alguien cruza por legajo en vez de por id.

Conteos clave

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

inscripciones de entrada110
estudiantes en el padron50
cursos en el catalogo8
inscripciones_enriquecidas.csv108
inscripciones_huerfanas.csv2
estudiantes_sin_inscripcion.csv8
estudiantes con al menos una inscripcion valida42
notas ausentes en las enriquecidas2
por motivohuerfano: 2

Invariantes

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

len(enriquecidas) + len(huerfanas) == 110
enriquecidas['fila_origen'].is_unique
huerfanas['fila_origen'].is_unique
42 + 8 == 50
enriquecidas['estudiante_id'].nunique() == 42
enriquecidas['estudiante_id'].isin(estudiantes['id']).all()
enriquecidas['curso_id'].isin(cursos['id']).all()
set(huerfanas['motivo']) == {'huerfano'}
enriquecidas['legajo'].notna().all()
PISTASSi te trabas, abri esto
  • La clave del padron es id, no legajo. El legajo E007 esta en dos estudiantes distintos: cruzar por ahi multiplica 9 inscripciones.
  • validate='m:1' en los dos merges convierte ese error en una excepcion. Sin el, el archivo sale con filas de mas y la cantidad parece razonable.
  • Apartar los huerfanos ANTES de cruzar. Con how='left' quedarian adentro, con el nombre del estudiante vacio, y no habria forma de distinguirlos de un dato faltante.
  • El par (35, 5) aparece dos veces y las dos son inscripciones legitimas del archivo: no se deduplican. Por eso el orden termina en fila_origen.

Así tiene que quedar

inscripciones_enriquecidas.csv (objetivo) · 108 filas, se muestran 5
fila_origenestudiante_idlegajoestudiantecurso_idcodigocursocreditosnota
281E001Javier Herrera3AL110Álgebra63.7
152E002Pablo Díaz2PR201Programación II8vacio
712E002Pablo Díaz6IA401Inteligencia artificial155.0
882E002Pablo Díaz8ET100Ética profesionalvacio5.3
493E003Ana Peña2PR201Programación II83.4
estudiantes_sin_inscripcion.csv (objetivo) · 8 filas, se muestran 5
estudiante_idlegajoestudiantecorreo
23E023Federico Quirogafederico.quiroga@uni.edu.ar
24E024Gabriela Acostagabriela.acosta@uni.edu.ar
45E045Santiago Bravosantiago.bravo@uni.edu.ar
46E046Lucas Gutiérrezlucas.gutierrez@uni.edu.ar
47E047Carla Duartecarla.duarte@uni.edu.ar
inscripciones_huerfanas.csv (objetivo) · 2 filas, se muestran 2
fila_origenestudiante_idcurso_idnotacolumnamotivo
10799918.0estudiante_idhuerfano
1081777.0curso_idhuerfano
Los huérfanos se apartan antes de cruzar

Con how="left" las dos inscripciones huérfanas se quedarían adentro, con el nombre del estudiante vacío. Y a partir de ahí son indistinguibles de un estudiante cuyo nombre falta en el padrón, que es otro problema y se arregla distinto.

Apartarlas primero deja el archivo enriquecido con la garantía de que todas sus filas tienen nombre, y esa garantía se puede escribir como assert.

Dos cuentas que tienen que cerrar

108 + 2 = 110: ninguna inscripción se perdió en el camino.

42 + 8 = 50: los estudiantes con al menos una inscripción válida más los que no tienen ninguna dan el padrón completo. Esa segunda cuenta es la que atrapa el error de contar sobre las inscripciones sin apartar los huérfanos.