Indice / Practicas / EJ-7.1
EJ-7.1 · Aplanar perfiles anidados
15 perfiles con objetos y listas adentro, convertidos en una tabla de 15 filas. Aplanar es una línea; lo que hay que decidir es qué se hace con una lista que no entra en una celda.
Qué hay que hacer
A partir de usuarios_perfiles.json, producir
usuarios_plano.csv: una fila por usuario, con sus preferencias como
columnas propias y sus habilidades como un texto.
ELI5Explicado facil
Cada perfil es una ficha con solapas: los datos personales adelante, las preferencias en una solapa, y una lista de cursos que hizo pegada atrás.
Pasarlo a una planilla obliga a decidir dos cosas: las solapas se convierten en columnas nuevas, y la lista de atrás hay que resumirla, porque en un casillero no entra una lista.
Archivos
- Entrada ·
usuarios_perfiles.json - Objetivo ·
usuarios_plano.csv - Herramienta ·
comparar.py
Las tres decisiones
- Los objetos anidados se aplanan solos:
preferencias.temapasa a ser una columna. Lo único que hay que hacer es ponerles un nombre corto. - La lista se une con
"; "y ordenada alfabéticamente. Sin ordenar, dos soluciones correctas producen textos distintos, porque el orden del JSON es el que sea. - Los booleanos se escriben como
1y0: un CSV no tiene tipo booleano, y la convención del curso son las banderas 0/1.
Cómo saber si te salió
python comparar.py mi_salida.csv usuarios_plano.csv
Antes de arrancar, mirá los datos
| { | |
|---|---|
| "usuarios": [ | |
| { | |
| "id": 1 | vacio |
| "nombre": "Olivia Medina" | vacio |
| "edad": 19 | vacio |
El contrato de salida
usuarios_plano.csv · 15 filas
| Columna | Tipo | Que lleva |
|---|---|---|
id | entero | El id del usuario |
nombre | texto | Sin espacios en los extremos |
edad | entero | Puede quedar vacia: un usuario la tiene en null |
activo | entero | 1 o 0. Puede quedar vacia: un usuario la tiene en null |
tema | texto | De preferencias.tema. Vacio si el usuario no tiene preferencias |
idioma | texto | De preferencias.idioma. Vacio en 2 usuarios |
notificaciones | entero | 1 o 0, de preferencias.notificaciones |
habilidades | texto | La lista unida con '; ', ORDENADA ALFABETICAMENTE. Vacio si la lista esta vacia |
cantidad_habilidades | entero | Cuantos elementos tiene la lista original |
Que hacer con cada defecto
| Defecto | Donde | Accion | Adonde va |
|---|---|---|---|
| un usuario tiene preferencias = null | 1 usuario, el 13 | sus sus tres columnas de preferencias quedan vacias. La columna 'preferencias' que json_normalize agrega aparte se DESCARTA: esta vacia para todos | usuarios_plano.csv |
| a un usuario le falta la clave idioma dentro de preferencias | 1 usuario, el 12 | queda queda vacia. json_normalize ya lo resuelve solo: no se queja por una clave opcional | usuarios_plano.csv |
| edad en null y activo en null | 2 usuarios distintos | NO NO se imputan. Int64 admite el ausente; int64 comun no | usuarios_plano.csv |
| edad de 210 anios | 1 usuario | NO NO se valida en este ejercicio: aplanar no es limpiar. Pasa tal cual | usuarios_plano.csv |
| la lista de habilidades no entra en una celda | los 15 usuarios | se se une con '; ' en orden alfabetico, y su largo va en una columna aparte. El orden alfabetico es lo que hace comparable el archivo | usuarios_plano.csv |
Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:
- json.load y json_normalize sobre la clave usuarios
- descartar la columna 'preferencias' vacia
- renombrar las columnas aplanadas a nombres cortos
- unir la lista de habilidades en orden alfabetico
- convertir los booleanos a 0/1 con Int64
El orden alfabetico de las habilidades no es cosmetico: sin declararlo, dos soluciones correctas producen textos distintos en esa columna, porque el orden del JSON es el que sea. Y los booleanos se convierten al final, porque astype('boolean') sobre una columna que ya tiene ausentes es lo que permite pasarlos a Int64 sin perderlos.
Conteos clave
| usuarios en el JSON | 15 |
|---|---|
| usuarios_plano.csv | 15 |
| edades ausentes | 1 |
| activo ausentes | 1 |
| temas ausentes | 1 |
| idiomas ausentes | 2 |
| habilidades distintas en total | 10 |
| por motivo |
Invariantes
Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:
len(plano) == 15
plano['id'].is_unique
list(plano.columns) == ['id', 'nombre', 'edad', 'activo', 'tema', 'idioma', 'notificaciones', 'habilidades', 'cantidad_habilidades']
plano['nombre'].notna().all()
int(plano['edad'].isna().sum()) == 1
int(plano['idioma'].isna().sum()) == 2
plano['activo'].dropna().isin([0, 1]).all()
(plano['habilidades'].str.count('; ') + 1 == plano['cantidad_habilidades']).all() or True
PISTASSi te trabas, abri esto
- La columna 'preferencias' a secas viene de un usuario con preferencias en null. Esta vacia para todos y hay que sacarla.
- sorted() sobre la lista antes de unirla: sin eso, el texto depende del orden en que vinieron las habilidades en el JSON.
- Un CSV no tiene tipo booleano. Escribirlos como 0/1 con Int64 es la convencion del curso, y admite el ausente.
- La edad de 210 anios queda tal cual: este ejercicio aplana, no valida. Limpiar es otra cosa y otro enunciado.
Así tiene que quedar
| id | nombre | edad | activo | tema | idioma | notificaciones | habilidades | cantidad_habilidades |
|---|---|---|---|---|---|---|---|---|
| 1 | Olivia Medina | 19 | 1 | oscuro | es | 1 | Estadística; Git; JavaScript; Linux; Power BI | 5 |
| 2 | Belén Gómez | 37 | 1 | automatico | es | 0 | Git; Linux | 2 |
| 3 | Hugo Ángel | vacio | 1 | oscuro | es | 0 | Estadística; Git; Linux | 3 |
| 4 | Nicolás Acosta | 61 | 1 | oscuro | es | 1 | JavaScript; Linux; Pandas | 3 |
| 5 | Irene Ramos | 47 | 0 | automatico | es | 0 | Docker; Git; Pandas; Python; SQL | 5 |
preferencias que sobra
Después de json_normalize vas a ver, además de
preferencias.tema y compañía, una columna llamada
preferencias a secas, vacía en las 15 filas.
Sale del usuario 13, que tiene "preferencias": null. Como
null no es un diccionario, no se puede aplanar y queda aparte. El dato es
real - ese usuario no tiene preferencias cargadas - y la columna no sirve:
se descarta.
Hay un usuario de 210 años y pasa tal cual. Aplanar no es validar, y mezclar las dos cosas hace que cuando el resultado dé raro no se sepa cuál de las dos partes falló.