Indice / Practicas / EJ-3.5
EJ-3.5 · Resumir una grilla de sensores por eje
Una grilla de 10 sensores × 24 horas, resumida a una fila por
sensor. La práctica del axis=, con dos decisiones que hay que tomar
antes de reducir.
Qué hay que hacer
A partir de numpy_sensores.csv (10 filas, 240 lecturas), producir
sensores_resumen.csv con una fila por sensor y ocho
columnas: identificación, cuántas lecturas quedaron usables, mínima, máxima, media,
amplitud y la hora del pico.
Archivos
- Entrada ·
numpy_sensores.csv - Objetivo ·
sensores_resumen.csv - Herramienta ·
comparar.py
ELI5Explicado facil
Es el parte diario de cada sensor: cuántas veces midió, qué tan frío y qué tan calor, y a qué hora fue el pico.
Lo único que no es obvio: qué contar como «midió». Una celda vacía no midió. Y un sensor que dice 999,9 grados tampoco - aunque haya escrito un número.
Las dos decisiones, antes de reducir
- Con
np.meanen vez denp.nanmean, tres sensores dannan: S03, S06 y S09, que son los que tienen huecos. - Sin marcar el
999.9de S05, su media da 60,65 en vez de 19,81, y su máxima da 999,9. El número sale, se ve raro, y nada falla.
El rango válido - −10 a 50 grados - lo fija el enunciado, no los datos. Ninguna función de NumPy puede saberlo.
La comprobación que cierra el ejercicio
lecturas_validas.sum() tiene que dar 235: 240 celdas,
menos 4 vacías, menos 1 imposible.
| Si te da | Qué falta |
|---|---|
| 235 | Está bien |
| 236 | No marcaste el 999.9 |
| 239 | Marcaste el imposible pero no contaste los ausentes |
| 240 | No hiciste ninguna de las dos cosas |
Cómo saber si te salió
python comparar.py mi_resumen.csv sensores_resumen.csv
Antes de arrancar, mirá los datos
| sensor_id | ubicacion | h00 | h01 | h02 | h03 | h04 | h05 | h06 | h07 | h08 | h09 | h10 | h11 | h12 | h13 | h14 | h15 | h16 | h17 | h18 | h19 | h20 | h21 | h22 | h23 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S01 | deposito | 20.8 | 19.8 | 19.2 | 19.0 | 19.6 | 20.3 | 20.0 | 21.0 | 21.1 | 21.7 | 21.9 | 22.9 | 22.6 | 23.7 | 23.9 | 24.3 | 24.4 | 23.3 | 23.2 | 22.3 | 22.4 | 21.9 | 21.2 | 21.1 |
| S02 | sala_servidores | 18.5 | 17.1 | 16.6 | 16.1 | 16.6 | 17.0 | 18.3 | 18.4 | 18.9 | 19.9 | 19.7 | 21.2 | 21.7 | 21.9 | 22.1 | 23.3 | 22.6 | 22.0 | 21.6 | 20.2 | 20.3 | 19.5 | 19.2 | 18.2 |
| S03 | oficina | 17.8 | 16.6 | 16.6 | 15.5 | 16.1 | 16.5 | 17.4 | vacio | vacio | 18.5 | 19.6 | 19.6 | 20.3 | 20.3 | 21.4 | 20.7 | 20.9 | 20.4 | 20.4 | 19.1 | 19.5 | 19.0 | 18.3 | 17.9 |
| S04 | planta_baja | 21.2 | 20.8 | 20.0 | 19.9 | 19.6 | 20.1 | 20.8 | 21.0 | 21.0 | 21.9 | 21.6 | 22.8 | 22.8 | 22.9 | 23.1 | 23.9 | 23.0 | 23.2 | 22.5 | 21.9 | 21.8 | 21.5 | 21.0 | 20.9 |
| S05 | laboratorio | 19.9 | 18.7 | 18.9 | 18.2 | 18.5 | 18.9 | 18.8 | 19.5 | 19.8 | 19.8 | 20.2 | 999.9 | 20.8 | 20.5 | 20.4 | 20.8 | 21.2 | 21.0 | 20.0 | 20.7 | 20.2 | 20.3 | 19.4 | 19.2 |
El contrato de salida
sensores_resumen.csv · 10 filas
| Columna | Tipo | Que lleva |
|---|---|---|
sensor_id | texto | El identificador tal cual vino: S01 a S10 |
ubicacion | texto | La ubicacion tal cual vino |
lecturas_validas | entero | Cuantas de las 24 lecturas quedan despues de descartar ausentes e imposibles |
minima | decimal | La lectura mas baja valida, 1 decimal |
maxima | decimal | La lectura mas alta valida, 1 decimal |
media | decimal | El promedio de las validas, 2 decimales |
amplitud | decimal | maxima menos minima, 1 decimal |
hora_pico | texto | El nombre de la columna donde ocurre la maxima: h00 a h23 |
Que hacer con cada defecto
| Defecto | Donde | Accion | Adonde va |
|---|---|---|---|
| celdas vacias | 4 celdas: S03 en h07 y h08, S06 en h13, S09 en h21 | no no participan de ninguna reduccion. Bajan lecturas_validas, y por lo tanto el denominador de la media | sensores_resumen.csv: se ven en la columna lecturas_validas |
| lectura fuera del rango fisico | 1 celda: S05 en h11 marca 999.9 | marcarla marcarla como ausente ANTES de reducir. El rango valido es -10 a 50 grados y lo fija el enunciado, no los datos | sensores_resumen.csv: S05 queda con 23 lecturas validas |
| empate en el maximo de una fila | 0 filas en este archivo | gana gana la hora mas temprana, que es lo que devuelve nanargmax | sensores_resumen.csv, columna hora_pico |
Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:
- leer las 24 columnas horarias como una grilla numerica (10, 24)
- marcar como ausente lo que este fuera de -10 a 50
- contar las validas por fila
- recien entonces reducir: minimo, maximo, media y posicion del maximo, todos con axis=1
Si se reduce antes de marcar el imposible, la media de S05 da 60,65 en vez de 19,81 y su maxima da 999,9. Y si se usa mean en vez de nanmean, las tres filas con hueco dan nan. Las dos decisiones se toman ANTES de la reduccion, no despues.
Conteos clave
| filas de entrada | 10 |
|---|---|
| celdas de lectura | 240 |
| sensores_resumen.csv | 10 |
| celdas descartadas | 5 |
| sensores con las 24 lecturas | 6 |
| por motivo | ausente: 4, fuera_de_rango: 1 |
Invariantes
Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:
len(resumen) == 10
resumen['sensor_id'].is_unique
resumen['sensor_id'].is_monotonic_increasing
not resumen.isna().any().any()
resumen['lecturas_validas'].sum() == 235
resumen['lecturas_validas'].between(1, 24).all()
(resumen['minima'] <= resumen['media']).all()
(resumen['media'] <= resumen['maxima']).all()
(resumen['maxima'] <= 50).all()
(resumen['amplitud'] - (resumen['maxima'] - resumen['minima'])).abs().max() < 0.05
resumen['hora_pico'].str.match(r'h\d{2}$').all()
PISTASSi te trabas, abri esto
- axis=1 elimina las 24 horas y deja un valor por sensor. Si tu resultado tiene 24 filas, invertiste el eje.
- np.where(valida, grilla, np.nan) marca sin descartar: la grilla sigue siendo (10, 24) y las reducciones por eje siguen funcionando.
- np.nanargmax(a, axis=1) devuelve la POSICION del maximo dentro de cada fila. El nombre de la hora sale de indexar la lista de columnas con esa posicion.
- La suma de lecturas_validas tiene que dar 235: 240 celdas menos 4 vacias menos 1 imposible. Si te da 236, no marcaste el 999.9; si te da 240, tampoco marcaste los ausentes.
Así tiene que quedar
| sensor_id | ubicacion | lecturas_validas | minima | maxima | media | amplitud | hora_pico |
|---|---|---|---|---|---|---|---|
| S01 | deposito | 24 | 19.0 | 24.4 | 21.73 | 5.4 | h16 |
| S02 | sala_servidores | 24 | 16.1 | 23.3 | 19.62 | 7.2 | h15 |
| S03 | oficina | 22 | 15.5 | 21.4 | 18.75 | 5.9 | h14 |
| S04 | planta_baja | 24 | 19.6 | 23.9 | 21.63 | 4.3 | h15 |
| S05 | laboratorio | 23 | 18.2 | 21.2 | 19.81 | 3.0 | h16 |
axis=1, no axis=0
El eje que se nombra es el que desaparece. Acá hay que eliminar las
24 horas para dejar un valor por sensor, así que va axis=1. Si tu
resultado tiene 24 filas en vez de 10, invertiste el eje.
np.nanargmax(a, axis=1) devuelve la posición del máximo
dentro de cada fila, no el valor. El nombre de la hora sale de indexar la lista de
columnas con esa posición.
Si hubiera empate, gana la hora más temprana - que es lo que
nanargmax devuelve por su cuenta. En este archivo no hay ninguno, pero el
contrato lo declara igual.