Saltar al contenido

Indice / Practicas / EJ-7.1

EJ-7.1 · Aplanar perfiles anidados

Practica de: 7.2 JSON con pandasDificultad: M

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

Las tres decisiones

  1. Los objetos anidados se aplanan solos: preferencias.tema pasa a ser una columna. Lo único que hay que hacer es ponerles un nombre corto.
  2. 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.
  3. Los booleanos se escriben como 1 y 0: 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_perfiles.json (entrada) · 242 filas, se muestran 5
{
"usuarios": [
{
"id": 1vacio
"nombre": "Olivia Medina"vacio
"edad": 19vacio

El contrato de salida

usuarios_plano.csv · 15 filas

ColumnaTipoQue lleva
identeroEl id del usuario
nombretextoSin espacios en los extremos
edadenteroPuede quedar vacia: un usuario la tiene en null
activoentero1 o 0. Puede quedar vacia: un usuario la tiene en null
tematextoDe preferencias.tema. Vacio si el usuario no tiene preferencias
idiomatextoDe preferencias.idioma. Vacio en 2 usuarios
notificacionesentero1 o 0, de preferencias.notificaciones
habilidadestextoLa lista unida con '; ', ORDENADA ALFABETICAMENTE. Vacio si la lista esta vacia
cantidad_habilidadesenteroCuantos elementos tiene la lista original

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

Que hacer con cada defecto

DefectoDondeAccionAdonde va
un usuario tiene preferencias = null1 usuario, el 13sus sus tres columnas de preferencias quedan vacias. La columna 'preferencias' que json_normalize agrega aparte se DESCARTA: esta vacia para todosusuarios_plano.csv
a un usuario le falta la clave idioma dentro de preferencias1 usuario, el 12queda queda vacia. json_normalize ya lo resuelve solo: no se queja por una clave opcionalusuarios_plano.csv
edad en null y activo en null2 usuarios distintosNO NO se imputan. Int64 admite el ausente; int64 comun nousuarios_plano.csv
edad de 210 anios1 usuarioNO NO se valida en este ejercicio: aplanar no es limpiar. Pasa tal cualusuarios_plano.csv
la lista de habilidades no entra en una celdalos 15 usuariosse se une con '; ' en orden alfabetico, y su largo va en una columna aparte. El orden alfabetico es lo que hace comparable el archivousuarios_plano.csv
Orden de comprobacion

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

  1. json.load y json_normalize sobre la clave usuarios
  2. descartar la columna 'preferencias' vacia
  3. renombrar las columnas aplanadas a nombres cortos
  4. unir la lista de habilidades en orden alfabetico
  5. 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

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

usuarios en el JSON15
usuarios_plano.csv15
edades ausentes1
activo ausentes1
temas ausentes1
idiomas ausentes2
habilidades distintas en total10
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

usuarios_plano.csv (objetivo) · 15 filas, se muestran 5
idnombreedadactivotemaidiomanotificacioneshabilidadescantidad_habilidades
1Olivia Medina191oscuroes1Estadística; Git; JavaScript; Linux; Power BI5
2Belén Gómez371automaticoes0Git; Linux2
3Hugo Ángelvacio1oscuroes0Estadística; Git; Linux3
4Nicolás Acosta611oscuroes1JavaScript; Linux; Pandas3
5Irene Ramos470automaticoes0Docker; Git; Pandas; Python; SQL5
La columna 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.

Lo que este ejercicio no hace

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ó.