El generador timeseries
Se usa cuando hacen falta valores que se muevan como una señal real en el tiempo:
ventas diarias, lecturas de un sensor, tráfico web. Las series reales no son ruido
plano ni una sola distribución: son capas — una tendencia general (que sube o
baja), una estación que se repite (semanal, anual) y ruido aleatorio encima.
timeseries arma el valor de una fila exactamente así:
value(i) = base + trend·i + amplitude·sin(2π·i / period) + noise·random
donde i es el número de fila (el eje del tiempo), contado desde cero — así que la
primera fila (i = 0) es exactamente base.
Las salidas de ejemplo de abajo son ilustrativas: los dígitos exactos pueden variar
según la versión del núcleo y el seed, pero lo que importa es la forma — la
tendencia, la onda, el temblor.
- Asolo base: una línea plana
- Bse agrega trend: la línea empieza a subir
- Cse agregan period y amplitude: una onda cabalga sobre la tendencia
- Dse agrega noise: la onda deja de ser perfecta
Por qué no simplemente números aleatorios
Un generador number común produce ruido blanco: valores que
brincan alrededor de una media sin ninguna memoria. Aquí está number con una
distribución normal centrada en 1000:
<sequence name="Noise"><gen type="number" distribution="normal" mean="1000" sd="120"/></sequence>
Day 1 841 Day 2 1341 Day 3 1047 Day 4 1010 Day 5 1086 Day 6 1077 Day 7 862 Day 8 1072 Day 9 1114 Day 10 782 Day 11 979 Day 12 1014
Ni subida, ni bajada, ni repetición: cada día simplemente da vueltas alrededor de 1000. Las métricas reales no se ven así: las ventas tienen una tendencia (el negocio
crece), un ritmo semanal (los fines de semana no son como los días hábiles) y solo
encima de eso algo de desviación aleatoria. Esas tres capas son justamente lo que
agrega timeseries.
Atributos
<gen type="timeseries" base="1000" trend="20" period="7" amplitude="150" noise="30"/>
| Atributo | Qué define |
|---|---|
base | Nivel inicial (por omisión 0) |
trend | Pendiente: cuánto sube el valor en cada paso |
period | Largo de la onda estacional, en filas (p. ej. 7 = una semana) — o varias, 7,365 |
amplitude | Altura de la onda estacional — una por cada period |
peak_at | En qué fila alcanza su máximo la onda (por defecto: a un cuarto del período) — una por cada period |
noise | Fuerza del ruido aleatorio (desviación estándar) |
noise_correlation | Cuánto ruido de una fila pasa a la siguiente, -1..1 (por omisión 0) |
decimals | Dígitos después del punto decimal (por omisión 0 — entero) |
Todas las capas son opcionales. Las secciones siguientes las toman una por una: qué hace cada una y cuándo conviene echarle mano.
base — el nivel inicial
base fija el valor de la primerísima fila (i = 0) y el nivel desde el que se mide
todo lo demás. Por sí solo — sin trend, sin onda, sin noise — es apenas una línea
plana.
<gen type="timeseries" base="500"/>
500 500 500 500 500
Sirve para anclar una métrica en un nivel realista — una tienda que promedia 500 pedidos al día, un sensor que reposa en 20 grados — antes de agregarle movimiento.
trend — la dirección
trend es la pendiente: cada fila le suma trend a la anterior. Positiva sube,
negativa baja. Con solo base + trend sale una línea perfectamente recta.
<gen type="timeseries" base="1000" trend="20"/>
1000 1020 1040 1060 1080
Sirve para crecimientos o caídas que se quieren ver a simple vista: una cuenta de suscriptores que gana 20 al día, una batería que se descarga una cantidad fija por ciclo.
period y amplitude — la onda estacional
Estos dos trabajan en pareja, y ninguno hace nada sin el otro. period es cuántas
filas dura un ciclo completo (7 = ritmo semanal, 365 = anual); amplitude es
cuánto se aleja la onda por arriba y por abajo de la línea de tendencia. Juntos
recuestan una onda sin que se repite sobre lo que dé base + trend.
<gen type="timeseries" base="1000" trend="20" period="7" amplitude="150"/>
1000 1137 1186 1125 1015 954 1003
Dentro de cada ventana de 7 filas el valor sube hasta un pico y cae hasta un valle, y luego se repite. Como la tendencia sigue levantando toda la línea, cada ciclo queda más alto que el anterior: la onda cabalga cuesta arriba. Sirve para cualquier cosa con ritmo de calendario: tráfico entre semana contra fin de semana, demanda de verano contra invierno.
peak_at — en qué fila la onda está más alta
period y amplitude dicen qué largo tiene la onda y cuánto oscila. No dicen cuándo
alcanza su máximo, y la respuesta por defecto sorprende: la onda arranca en la mitad de su
oscilación y sube, así que su máximo cae a un cuarto del período.
Sobre doce filas mensuales eso es la fila 3 — abril. El config se escribió para «más calor en verano», y abril no lo es:
<gen type="timeseries" base="15" amplitude="10" period="12" decimals="1"/>
15.0 20.0 23.7 25.0 23.7 20.0 15.0 10.0 6.3 5.0 6.3 10.0
peak_at nombra la fila directamente. Las filas se cuentan desde cero, así que julio es la
fila 6:
<gen type="timeseries" base="15" amplitude="10" period="12" peak_at="6" decimals="1"/>
5.0 6.3 10.0 15.0 20.0 23.7 25.0 23.7 20.0 15.0 10.0 6.3
Nada más se movió: el mismo base, la misma amplitude, el mismo ciclo de doce filas.
Solo cambió el mes en el que cae el máximo.
Es una fila, no un ángulo. period ya se cuenta en filas, así que peak_at también:
182 de 365 es el primero de julio, y ese número sale de un calendario y no de los radianes.
Un valor más allá del período da la vuelta, así que peak_at="18" con period="12" es lo
mismo que 6, y se admite una fracción cuando el máximo cae entre dos filas.
peak_at="0" merece conocerse aparte: hace que la onda empiece en su máximo, una forma
que un seno simple no produce con ninguna amplitud.
phaseEse es el nombre del procesamiento de señales, y TDC no lo tiene. peak_at hace el mismo
trabajo en la unidad que usa el resto del generador. Escribir phase= es un error que lo
dice.
peak_at necesita un period: una onda tiene que tener largo antes de poder tener un punto
más alto. Sin él es TDC253.
noise — la aspereza del mundo real
noise es la desviación estándar de un bamboleo aleatorio que se suma a cada fila. Es
la diferencia entre una curva de libro de texto y una medición real.
<gen type="timeseries" base="1000" trend="20" period="7" amplitude="150" noise="30"/>
1048 1152 1210 1093 1017 978 991
Compare con la onda limpia de arriba: la forma es la misma, pero cada punto tiembla un
poco (1000 → 985). Súbalo para un sensor ruidoso, bájelo para un agregado suave. El
temblor es reproducible — vea Detalles.
decimals — valores fraccionarios
Por defecto la salida se redondea a un número entero. decimals conserva esa cantidad
de dígitos después del punto — para temperaturas, precios o cualquier magnitud medida.
<gen type="timeseries" base="20" trend="0.5" noise="0.3" decimals="1"/>
20.5 20.6 21.2 21.2 22.0
Ármelo capa por capa
La forma más clara de sentir el generador es prender las capas de a una. Abajo, tres
columnas <sequence> corren sobre los mismos
«días»: trend (solo trend), +season (agrega period + amplitude) y
+noise (agrega noise).
<sequence name="A"><gen type="timeseries" base="1000" trend="20"/></sequence>
<sequence name="B"><gen type="timeseries" base="1000" trend="20" period="7" amplitude="150"/></sequence>
<sequence name="C"><gen type="timeseries" base="1000" trend="20" period="7" amplitude="150" noise="30"/></sequence>
...
<data>Day ${{Day}} trend=${{A}} +season=${{B}} +noise=${{C}}</data>
Day trend +season +noise 01 1000 1000 985 02 1020 1137 1087 03 1040 1186 1192 04 1060 1125 1107 05 1080 1015 936 06 1100 954 966 07 1120 1003 1031 08 1140 1140 1087 09 1160 1277 1311 10 1180 1326 1347 11 1200 1265 1261 12 1220 1155 1126
Leyendo las columnas:
- trend — una línea perfectamente recta:
+20cada día,1000, 1020, 1040 …. Hay dirección, pero nada de vida. - +season — una onda semanal (
period="7") recostada sobre la línea. Dentro de cada semana el valor sube a un pico y cae a un valle: los picos caen en los días 3 y 10 (1186 → 1326), el valle en el día 6 (954). Picos y valles se repiten cada 7 filas, y cada uno queda más alto que el anterior por exactamentetrend · period = 20 · 7 = 140— la onda cabalga cuesta arriba sobre la tendencia. - +noise — la misma forma, pero tiembla un poco (
1000 → 985), como lo hacen las mediciones reales.
Cada columna es la anterior más un atributo: dirección, luego ritmo, luego aspereza del mundo real. Así se arma una serie realista.
Varias estaciones a la vez
Una serie real rara vez lleva una sola estación. Una tienda vende más los sábados y
más en diciembre; una red eléctrica tiene un ciclo diario y uno anual. Escriba los
dos: period, amplitude y peak_at aceptan listas separadas por comas, una entrada
por onda, y las ondas se suman.
<gen type="timeseries" base="1000" trend="2"
period="7,365" amplitude="120,400" peak_at="5,182" decimals="0"/>
Eso es una onda semanal de 120 de alto con su máximo el día 5, y una anual de 400 con su máximo el día 182 — en la misma columna.
day 0: 573 day 1: 494 day 2: 496 day 3: 580 day 4: 684 day 5: 732 day 6: 689 day 7: 591 day 8: 512 day 9: 515 day 10: 600 day 11: 705 day 12: 753 day 13: 712 day 14: 614 day 15: 536
Los máximos semanales se ven a simple vista — días 5, 12 y 19 — y cada semana queda un poco más alta que la anterior, porque la onda anual todavía sube hacia el día 182.
Las tres listas describen las mismas ondas, posición por posición, así que tienen
que cuadrar: period="7,365" necesita dos amplitudes. La única abreviatura es una sola
amplitude para ondas de igual altura. Cualquier otra cosa es un error que el motor no
va a adivinar (TDC304).
Ruido con memoria — noise_correlation
El noise normal es independiente: cada fila se sacude por su cuenta, así que una
lectura alta no dice nada de la siguiente. El error de medición real casi nunca se
comporta así. Un sensor que se va hacia arriba se queda arriba un rato; una cola que
empieza a acumularse sigue acumulándose. El código probado solo contra ruido
independiente nunca vio el caso con el que va a fallar de verdad.
noise_correlation dice cuánto ruido de una fila pasa a la siguiente: 0 es el ruido
independiente que este generador siempre produjo, 0.9 es fuertemente correlacionado.
Es el modelo AR(1), si le suena el nombre; si no, léalo como «qué tan pegajoso es el
ruido».
<sequence name="White"> <gen type="timeseries" base="20" noise="2" decimals="1"/></sequence>
<sequence name="Drifty"> <gen type="timeseries" base="20" noise="2" noise_correlation="0.9" decimals="1"/></sequence>
independent 17.8 correlated 22.4 independent 18.5 correlated 21.0 independent 20.8 correlated 21.8 independent 21.1 correlated 20.3 independent 19.3 correlated 22.6 independent 18.4 correlated 23.9 independent 20.4 correlated 23.2 independent 18.7 correlated 21.5 independent 21.6 correlated 20.9 independent 23.1 correlated 20.7 independent 20.0 correlated 20.6 independent 23.2 correlated 20.2 independent 22.4 correlated 18.9 independent 20.0 correlated 18.7 independent 18.5 correlated 18.4 independent 18.5 correlated 18.5
La columna izquierda salta alrededor de 20 al azar. La derecha deambula: sube a 23.9 y en diez filas baja a 18.4. Las dos tienen la misma dispersión — la correlación cambia cómo se mueve el ruido, no cuán grande es.
La letra pequeña
- Necesita
noise=. Si no, ¿correlación de qué? Se rechaza en vez de ignorarse (TDC305). - Entre −1 y 1, y no 1: en 1 la serie se iría y no volvería, lo que es una caminata aleatoria y no ruido.
- Un valor negativo alterna — cada fila se apoya contra la anterior, que es como se ven los lazos de control sobrecorregidos.
- Los dos motores, cualquier tamaño. El valor correlacionado se sigue calculando a partir del número de fila, así que una corrida en streaming de mil millones de filas produce el mismo archivo que una en memoria, y la memoria no crece. Recuerda las últimas 64 filas: lo bastante lejos para que el peso de lo más viejo sea despreciable, y lo bastante cerca para que cueste unos 20 nanosegundos por fila.
Detalles
- Determinista: el mismo
seedda la misma serie. El ruido también es reproducible: se calcula a partir del número de fila, no se tira al vuelo. - Cualquier tamaño, cualquier motor: un valor se calcula a partir de su número de fila, así que la memoria no crece (vea Salidas grandes). Mil millones de puntos no son problema.
- El eje del tiempo es el número de fila. Se lleva de forma natural con un
increment(un contador de días) o una columnadateal lado, para que cada valor cargue una fecha real.
Vea también
- Number — valores aleatorios sueltos, con distribuciones estadísticas.
- Pattern — cuando la forma no se describe con tendencia + estación.
- Contadores / Date — un índice de día o una fecha real para poner junto a la serie.