Con una cuenta desbloqueas el cuestionario, el foro de dudas y el tutor con IA de esta lección, además del registro de progreso y el certificado verificable al terminar «Python para Ingeniería Espacial».
Una lista de Python es una colección de objetos genéricos: cada elemento es una caja independiente con su tipo, su contador de referencias y su dirección de memoria propia. Sumar dos listas elemento a elemento obliga al intérprete a recorrerlas, desempaquetar cada caja, hacer la operación y volver a empaquetar. Para diez elementos da igual; para el millón de muestras que produce un pase de un satélite meteorológico, no.
NumPy guarda los números en un bloque contiguo de memoria, todos del mismo tipo, y ejecuta las operaciones en código compilado sobre ese bloque entero. La aceleración típica está entre 10× y 100× según la operación. Pero la razón más importante para usarlo no es la velocidad: es que el código se parece a la fórmula.
# Con listas: el bucle oculta qué se está calculando.
z = []
for x in muestras:
z.append((x - media) / sigma)
# Con NumPy: la línea ES la fórmula.
z = (muestras - media) / sigma
Esa segunda forma se llama vectorización: expresar una operación sobre la colección completa en lugar de sobre sus elementos uno a uno. Menos líneas, menos índices, menos sitios donde equivocarse.
Nota sobre el playground. El sandbox de esta lección ejecuta Python estándar sin paquetes externos, así que el bloque ejecutable de abajo usa el módulo statistics de la biblioteca estándar. Cada operación tiene su equivalente exacto en NumPy, indicado en la tabla de más abajo: en tu máquina, tras pip install numpy, el mismo cálculo cabe en tres líneas.
np.array y las operaciones elemento a elemento
Un ndarray se construye desde una lista y arrastra dos atributos que conviene mirar siempre al depurar: shape (la forma) y dtype (el tipo de los elementos).
Las tres últimas líneas son la clave del estilo NumPy. Comparar un array con un número devuelve un array de booleanos de la misma forma, y ese array sirve de máscara para seleccionar elementos. Con eso, "dame las muestras por encima del umbral" se escribe en una línea y sin ningún bucle.
Estadística en una llamada
Operación
NumPy
Equivalente en la biblioteca estándar
Media
x.mean()
statistics.mean(x)
Desviación típica poblacional
x.std()
statistics.pstdev(x)
Desviación típica muestral
x.std(ddof=1)
statistics.stdev(x)
Máximo
x.max()
max(x)
Índice del máximo
x.argmax()
x.index(max(x))
Suma
x.sum()
sum(x)
La distinción entre max y argmax es la que más se usa en operaciones: max te dice cuánto valió el pico, argmax te dice cuándo ocurrió. En una serie temporal muestreada a intervalo constante, el índice se convierte en tiempo multiplicando por el periodo de muestreo, y con eso ya puedes correlacionar una anomalía térmica con la entrada en eclipse.
El detalle de ddof que cambia el resultado
np.std() calcula por defecto la desviación poblacional, dividiendo entre N; statistics.stdev() calcula la muestral, dividiendo entre N−1. Con N grande la diferencia es despreciable, pero con ventanas pequeñas — que es justo nuestro caso — importa:
σpobl=N1∑(xi−xˉ)2,σmuestral=N−11∑(xi−xˉ)2
Para una ventana de N=8 muestras el factor entre ambas es 8/7=1.069, casi un 7 %. Aplicado a un umbral, eso mueve la frontera de disparo lo bastante como para cambiar el veredicto de una muestra limítrofe. Elige uno, escríbelo en la docstring y no lo mezcles; nosotros usaremos el muestral (ddof=1).
La técnica estrella: z-score con ventana móvil
El z-score mide a cuántas desviaciones típicas está una muestra de la media de su entorno:
z=σventanax−μventana
Y la regla de decisión es un umbral: si ∣z∣>3, la muestra es anómala. El 3 no es arbitrario. Si el ruido fuera gaussiano, la probabilidad de superar tres sigmas por azar es de aproximadamente 0.27%, es decir, unas 27 falsas alarmas por cada 10 000 muestras. Bajarlo a 2 multiplicaría las falsas alarmas por diecisiete; subirlo a 4 dejaría pasar anomalías reales. Tres es el punto de equilibrio habitual en telemetría, y es el que usa PiStation.
Por qué la ventana tiene que ser móvil
La palabra decisiva es ventana. Un z-score calculado contra la media global de toda la serie falla por dos motivos. Primero, porque la telemetría deriva: un radiador se calienta lentamente al entrar en insolación, y esa deriva legítima dispararía alarmas constantes. Segundo, y más grave, porque la propia anomalía entra en el cálculo de la media global y de la desviación global, inflándolas y escondiéndose a sí misma.
La ventana móvil resuelve ambos: para cada muestra xi se calculan μ y σ sobre las N muestras anteriores, no sobre toda la serie ni sobre una ventana que incluya la propia muestra. Así la referencia es siempre "el comportamiento reciente", y la muestra bajo examen se compara contra un pasado que ella no contaminó.
Ejemplo resuelto: el pico de las temperaturas
Una serie de temperaturas de un radiador, muestreada cada minuto. La ventana de referencia son las ocho muestras previas:
La media sale redonda porque las desviaciones se cancelan:
μ=8168.0=21.0°C
Las desviaciones respecto de la media son [0.0,0.2,−0.2,0.1,−0.1,0.0,0.3,−0.3] y la suma de sus cuadrados es 0.28. Con la definición muestral:
σ=8−10.28=0.04=0.20°C
La siguiente muestra que llega vale x=21.8°C. Su z-score:
z=0.2021.8−21.0=0.200.8=4.00
Como ∣4.00∣>3, se dispara la alarma. Y ocho décimas de grado no parecen nada — ese es justo el punto: el z-score no mide la magnitud absoluta, mide lo inesperado. En una serie que oscilaba dos décimas, ocho décimas son un salto de cuatro sigmas.
Con la definición poblacional el resultado sería σ=0.187 y z=4.28: números distintos, mismo veredicto. Así debe ser un umbral bien elegido — robusto frente a esa clase de decisión de implementación.
El contraste que justifica la ventana
Sobre esa misma serie completa de 16 muestras (que incluye además un pico grande de 24.6°C), la media global vale 21.28 y la desviación global 0.921. El z global de nuestra muestra de 21.8 sería:
zglobal=0.92121.8−21.28=0.56
Muy por debajo del umbral: la anomalía habría pasado inadvertida. El pico grande de 24.6 infló la desviación global hasta 0.921 y con ella escondió a su hermana pequeña. La ventana móvil, en cambio, detecta las dos.
Hay una contrapartida que verás en la ejecución y conviene anticipar: después de una anomalía, la propia anomalía entra en la ventana y σ se dispara — de 0.336 a 1.275 en nuestro caso — dejando el detector momentáneamente sordo. Las soluciones habituales son excluir de la ventana las muestras ya marcadas como anómalas, o usar estadísticos robustos como la mediana y la desviación absoluta mediana. Es el siguiente paso natural, y ya no es programación básica.
Ejecuta el detector completo sobre la serie de 16 muestras:
Playground · python
Tres retos. Primero: baja UMBRAL a 2.0 y cuenta cuántas alarmas nuevas aparecen; esa es tu tasa de falsos positivos. Segundo: cambia VENTANA a 4 y a 12, y observa cómo una ventana corta reacciona rápido pero es ruidosa, mientras que una larga es estable pero lenta. Tercero: sustituye statistics.stdev por statistics.pstdev y comprueba que los z suben un 7 % sin que cambien los veredictos.
1 de 7
Comprueba el argumento central de la técnica:
¿Por qué el z-score se calcula contra una ventana móvil y no contra la media de toda la serie?
Ya tienes las cinco piezas: funciones, parseo, robustez, estadística y decisión. En la lección 10 las juntamos en un solo script de misión.