Qué operación realiza una figura

En el capítulo 22 separamos las reglas de un modelo de sus observaciones y de los datos usados para contrastarlas. Falta examinar una operación capaz de modificar la interpretación sin cambiar una sola cifra, que es la representación gráfica. Dos figuras del mismo registro pueden mostrar con claridad aspectos distintos. También pueden sugerir conclusiones incompatibles cuando no declaran sus transformaciones.

Continuaremos con el intercambio entre dos compartimentos y compararemos dos configuraciones con el mismo total y el mismo equilibrio, aunque con distinta velocidad de aproximación. Una gráfica temporal distinguirá sus transitorios y el plano de estados mostrará que ambos recorridos están restringidos a la misma recta. Veremos también una gráfica de desviaciones respecto del equilibrio que hace visible una diferencia casi imperceptible en la escala original de las cantidades.

Ninguna figura conserva por igual toda la información relevante para cualquier pregunta. Elegir las variables y la escala de una figura equivale a definir una operación sobre el registro. Esa operación encadena cuatro pasos, desde la trayectoria calculada hasta la imagen, pasando por un observable y una transformación numérica. Cada paso necesita su propia justificación. Cambiar el observable puede eliminar información y recortar un intervalo excluye estados que ya estaban disponibles, mientras que una conversión de unidades suele ser reversible.

Rougier y colaboradores (2014) recomiendan definir el propósito de cada figura y declarar en su leyenda la información necesaria para interpretarla. Adoptaremos ese criterio sin tratar la presentación gráfica como una prueba independiente del modelo. Todos los datos del capítulo provienen de un ejemplo docente determinista y ninguno procede de pacientes ni de estimaciones empíricas.

Un registro cuya evolución conocemos

El estado es zn=(xn,yn)Tz_n=(x_n,y_n)^{\mathsf T}, con cantidades expresadas en una unidad común QQ. Cada ronda aplica simultáneamente

xn+1=(1−α)xn+βyn,yn+1=αxn+(1−β)yn.x_{n+1}=(1-\alpha)x_n+\beta y_n, \qquad y_{n+1}=\alpha x_n+(1-\beta)y_n.

Las fracciones pertenecen a [0,1][0,1]. El total S0=xn+ynS_0=x_n+y_n permanece constante porque lo que abandona un compartimento ingresa en el otro. Si α+β>0\alpha+\beta>0, el equilibrio correspondiente a ese total es

xeq=βS0α+β,yeq=S0−xeq.x_{\mathrm{eq}} = \frac{\beta S_0}{\alpha+\beta}, \qquad y_{\mathrm{eq}} = S_0-x_{\mathrm{eq}}.

Al sustituir yn=S0−xny_n=S_0-x_n y restar el equilibrio obtenemos la recurrencia escalar

xn+1−xeq=(1−α−β)(xn−xeq).x_{n+1}-x_{\mathrm{eq}}=(1-\alpha-\beta)(x_n-x_{\mathrm{eq}}).

Definamos ρ=1−α−β\rho=1-\alpha-\beta. La aplicación sucesiva de la misma igualdad da

xn=xeq+(x0−xeq)ρn.x_n=x_{\mathrm{eq}}+(x_0-x_{\mathrm{eq}})\rho^n.

El caso A usa (α,β)=(0,20; 0,10)(\alpha,\beta)=(0{,}20;\ 0{,}10) y el caso B, (0,10; 0,05)(0{,}10;\ 0{,}05). Ambos parten de (100,0) Q(100,0)\,Q y tienen el mismo equilibrio, xeq=100/3 Qx_{\mathrm{eq}}=100/3\,Q, sobre la recta x+y=100 Qx+y=100\,Q. Sus multiplicadores son 0,700{,}70 y 0,850{,}85. Las unidades y la duración de una ronda son las mismas en ambos casos, de modo que la segunda configuración realiza un intercambio menor por ronda.

El código siguiente reconstruye ambos registros. Repite en forma compacta la organización del capítulo anterior para que los ejemplos puedan ejecutarse sin abrir otro archivo. También define el formato común de las figuras, con coma decimal en los ejes. El argumento pasos debe ser un entero no negativo y la función no modifica el estado inicial recibido.

from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

plt.rcParams.update({"font.size": 9, "axes.spines.top": False,
                     "axes.spines.right": False})
coma = FuncFormatter(lambda v, _: f"{v:g}".replace(".", ","))


def simular(alpha, beta, inicial=(100.0, 0.0), pasos=30):
    a, b = float(alpha), float(beta)
    if not (np.isfinite(a) and np.isfinite(b)):
        raise ValueError("Las fracciones deben ser finitas.")
    if not (0.0 <= a <= 1.0 and 0.0 <= b <= 1.0):
        raise ValueError("Las fracciones deben estar entre 0 y 1.")
    if (isinstance(pasos, (bool, np.bool_))
            or not isinstance(pasos, (int, np.integer))
            or pasos < 0):
        raise ValueError("pasos debe ser un entero no negativo.")
    z0 = np.array(inicial, dtype=float, copy=True)
    if z0.shape != (2,) or not np.all(np.isfinite(z0)):
        raise ValueError("Se requieren dos cantidades finitas.")
    if np.any(z0 < 0):
        raise ValueError("Las cantidades deben ser no negativas.")
    matriz = np.array([[1.0-a, b], [a, 1.0-b]])
    historia = np.empty((pasos + 1, 2), dtype=float)
    historia[0] = z0
    with np.errstate(over="raise", invalid="raise"):
        for n in range(pasos):
            historia[n+1] = matriz @ historia[n]
    return historia


base = simular(0.20, 0.10)
lenta = simular(0.10, 0.05)
rondas = np.arange(base.shape[0])
x_equilibrio = 100.0 / 3.0
salida = Path("figuras")
salida.mkdir(exist_ok=True)

Las treinta transiciones producen treinta y una filas, porque la primera fila guarda el estado inicial. Las figuras usan esas filas y se contrastan con la expresión analítica, porque la impresión visual de que las curvas «parecen correctas» no basta como control.

Puntos, segmentos y significado del tiempo en una serie temporal

Para saber cuándo cambia una cantidad, se dibuja el índice de ronda en el eje horizontal y esa cantidad en el vertical. La figura 23.1 compara xnx_n en ambas configuraciones. Cada marcador corresponde a un estado calculado y los segmentos ayudan a seguir su orden. El bloque siguiente produce exactamente esa figura.

fig, ax = plt.subplots(figsize=(6.4, 3.0))
ax.plot(rondas, base[:, 0], marker="o", markersize=3, color="black",
        label="A (α = 0,20; β = 0,10)")
ax.plot(rondas, lenta[:, 0], marker="s", markersize=3, color="0.45",
        linestyle="--", label="B (α = 0,10; β = 0,05)")
ax.axhline(x_equilibrio, linestyle=":", color="0.4",
           label="Equilibrio")
ax.set(xlabel="Ronda n", ylabel="Cantidad x (Q)",
       xlim=(0, 30), ylim=(0, 105))
ax.yaxis.set_major_formatter(coma)
ax.legend(fontsize=8, frameon=False)
fig.tight_layout()
for ext in ("png", "svg"):
    fig.savefig(salida / f"cap23_fig1.{ext}", dpi=300,
                bbox_inches="tight")
plt.close(fig)

La función plot usa los valores horizontales entregados y, si se omiten, emplea índices consecutivos (Matplotlib Development Team, s. f.-a). Aquí esos índices coinciden con las rondas. En registros con observaciones irregulares, usarlos como si fueran tiempos igualmente espaciados alteraría la información temporal. Cambiar el nombre del eje a «días» no corrige ese problema.

Cantidad x en las rondas 0 a 30 para las configuraciones A y B, sin descartar el transitorio.
Figura 23.1. Cantidad x en las rondas 0 a 30 para las configuraciones A y B, sin descartar el transitorio. Ambos casos parten de 100 Q y comparten el equilibrio de 100/3 Q. Los segmentos guían la vista entre actualizaciones discretas porque el modelo no define valores entre rondas. Ampliar figura ↗

El segmento entre x0=100 Qx_0=100\,Q y x1=80 Qx_1=80\,Q pasa gráficamente por 90 Q90\,Q, aunque la recurrencia no asigna ese valor a media ronda. Una curva suavizada o un trazo escalonado añadirían otras convenciones sobre lo que se dibuja entre registros. Ninguna de ellas convierte el mapa en una ecuación diferencial.

Podemos informar que x1−x0=−20 Qx_1-x_0=-20\,Q en una ronda completa. La pendiente del segmento, en cambio, no puede leerse como una derivada instantánea del proceso, porque para eso haría falta una evolución continua especificada. La diferencia será central cuando introduzcamos el método de Euler en el capítulo 24.

Recorte de ejes y amplificación visual de diferencias

Un eje vertical entre 0 y 105 permite comparar las cantidades con el total inicial, aunque no es la escala más sensible a los cambios tardíos. En el caso A, las rondas quince y treinta dan

x15≈33,649837 Q,x30≈33,334836 Q.x_{15}\approx33{,}649837\,Q, \qquad x_{30}\approx33{,}334836\,Q.

La diferencia es de unos 0,315001 Q0{,}315001\,Q, el 0,315 %0{,}315\,\% del total de 100 Q100\,Q. En la escala de 0 a 105 esa diferencia ocupa el 0,3 % de la altura del eje. En una escala de 33,32 a 33,68 ocupa el 87,5 %, casi toda la figura (figura 23.2). Los datos no cambiaron. Cambió la relación entre la diferencia numérica y la distancia impresa, que aquí se amplifica unas 290 veces.

Ampliación de las rondas finales de una trayectoria con un intervalo vertical reducido.
Figura 23.2. Detalle de las rondas 15 a 30 del caso A ya mostrado en la figura 23.1, con el eje vertical entre 33,32 y 33,68 Q. Los valores son los mismos y solo cambian los límites de los ejes. La caída visible equivale a 0,315001 Q y la ampliación nada dice de su importancia práctica. Ampliar figura ↗

No exigiremos que todo eje de una serie temporal comience en cero, porque eso puede impedir estudiar variaciones pequeñas. Exigiremos que el intervalo sea explícito y que las magnitudes no se comparen entre figuras con escalas distintas sin advertirlo. En los gráficos de barras, donde la longitud codifica la cantidad desde una base, truncar esa base plantea otro problema de interpretación (Rougier et al., 2014).

Una conversión de unidades conocida conserva las razones entre valores. Si las cantidades se expresan en una unidad cien veces mayor, todos los valores y la tolerancia deben dividirse por cien. Normalizar cada serie por su propio mínimo y su propio máximo, en cambio, fuerza a ambas a ocupar el intervalo de cero a uno aunque sus amplitudes originales sean distintas. Esa operación puede facilitar la comparación de formas, pero impide comparar magnitudes si se omiten los factores usados. En una serie constante ni siquiera está definida, porque el máximo y el mínimo coinciden. Por eso conservaríamos los valores originales y documentaríamos la normalización como una transformación más del registro.

La relación de aspecto también modifica las pendientes aparentes. Al alargar horizontalmente una figura, la misma caída parece más lenta y, al comprimirla, más brusca. La rapidez debe calcularse con los valores y sus intervalos, porque el ángulo de una línea sobre la página depende del formato. Si se cambia de rondas a horas, hay que declarar además la duración atribuida a cada ronda, que las fracciones de intercambio no determinan.

Equilibrio, transitorio y umbral de proximidad

La expresión analítica muestra que ninguna de las dos trayectorias alcanza exactamente xeqx_{\mathrm{eq}} en un número finito de pasos, porque ρn\rho^n es positivo para todo nn finito. El tramo horizontal al final de una gráfica refleja un límite de resolución visual y no demuestra la igualdad.

Para responder cuándo la trayectoria está suficientemente cerca hay que definir una tolerancia. Usaremos, igual que en el capítulo 21, el criterio ∣xn−xeq∣≤1 Q|x_n-x_{\mathrm{eq}}|\leq1\,Q, que no tiene significado clínico ni valor universal. Con la solución anterior,

2003∣ρ∣n≤1⟺n≥ln⁡(3/200)ln⁡∣ρ∣,0<∣ρ∣<1.\frac{200}{3}\left|\rho\right|^n\leq1 \quad\Longleftrightarrow\quad n\geq\frac{\ln(3/200)}{\ln\left|\rho\right|}, \qquad 0<\left|\rho\right|<1.

El sentido de la desigualdad cambia al dividir por un logaritmo negativo. El primer entero que la satisface es 12 en A y 26 en B. Como la magnitud de la desviación disminuye en cada ronda, después del primer cruce ambos casos permanecen dentro de la tolerancia. Esa propiedad depende del modelo, porque en otros sistemas cruzar un umbral una vez no garantiza permanecer dentro.

Cuadro 23.1. Cantidad xx y desviación respecto del equilibrio en las configuraciones A y B, en QQ.

RondaCantidad x en ACantidad x en BDesviación de ADesviación de B
0100,000000100,00000066,66666766,666667
544,53800062,91368811,20466729,580354
1035,21650246,4582941,88316813,124960
2033,38652835,9173020,0531952,583969
3033,33483633,8420510,0015030,508717

Descartar las primeras veinte rondas podría ser pertinente para examinar valores tardíos. Sería inadecuado, en cambio, para comparar tiempos de aproximación o diferencias iniciales. La condición de convergencia proviene de la recurrencia, mientras que la elección del intervalo visible responde a la pregunta que se quiere contestar.

Qué cantidad transformar en una escala logarítmica

Aplicar un eje logarítmico directamente a xnx_n no convierte su evolución en una recta, porque xnx_n contiene el término constante xeqx_{\mathrm{eq}}. La cantidad que decrece geométricamente es la desviación. Para no tomar el logaritmo de una magnitud con unidades definimos

ηn=∣xn−xeq∣S0,ln⁡ηn=ln⁡(2/3)+nln⁡∣ρ∣.\eta_n=\frac{\left| x_n-x_{\mathrm{eq}}\right|}{S_0}, \qquad \ln\eta_n=\ln(2/3)+n\ln\left|\rho\right|.

La cantidad ηn\eta_n es adimensional. Su gráfica semilogarítmica muestra dos rectas porque hemos derivado dos secuencias geométricas, con pendientes de −0,356675-0{,}356675 y −0,162519-0{,}162519 por ronda en logaritmo natural. En base diez las pendientes valen −0,154902-0{,}154902 y −0,070581-0{,}070581, aunque las fracciones de reducción por ronda siguen siendo 0,70{,}7 y 0,850{,}85.

Desviación normalizada |x − x_eq|/100 de las configuraciones A y B en escala logarítmica.
Figura 23.3. Desviación normalizada |x − x_eq|/100 de las configuraciones A y B en escala logarítmica. La línea horizontal corresponde a 0,01, que equivale a una desviación de 1 Q. Los primeros puntos que no superan ese nivel son los de las rondas 12 y 26. Cada curva procede de una sola ejecución determinista. Ampliar figura ↗

En Matplotlib, ax.semilogy(rondas, eta, nonpositive="mask") dibuja con un eje vertical logarítmico. El último argumento declara cómo tratar los valores no positivos. La documentación distingue entre enmascararlos y sustituirlos por un valor positivo muy pequeño (Matplotlib Development Team, s. f.-b). Aquí todas las desviaciones son positivas. Añadir una constante arbitraria para poder mostrar un cero cambiaría la forma de la señal transformada.

El valor absoluto elimina el signo. Si ρ<0\rho<0, la desviación alterna alrededor del equilibrio, pero ηn\eta_n puede seguir una recta descendente en escala semilogarítmica. Esa figura conservaría la tasa de disminución de la magnitud y ocultaría la alternancia, así que habría que examinar también la desviación con signo.

Una recta obtenida con datos reales tampoco demuestra una ley geométrica exacta. En este ejemplo la conclusión se apoya en una derivación independiente. Si el cálculo se prolonga mucho, además, la desviación se acerca al nivel del redondeo. Hacia la ronda 90 del caso A, la desviación teórica cae por debajo de 10−12 Q10^{-12}\,Q y la calculada deja de seguir la recta. Interpretar entonces la forma de la gráfica exigiría revisar la precisión numérica antes de atribuir al sistema un régimen nuevo. El capítulo 27 estudia ese límite.

Representación de estados sin eje temporal

En una gráfica temporal, cada componente se dibuja frente a la ronda. En el plano de estados se dibuja yny_n frente a xnx_n. El total conservado obliga a que todos los puntos estén en el segmento no negativo de la recta y=100−xy=100-x, de modo que, una vez fijado el total, queda un solo grado de libertad accesible.

Estados de las configuraciones A (círculos) y B (cuadrados) en el plano x-y durante las rondas 0 a 10.
Figura 23.4. Estados de las configuraciones A (círculos) y B (cuadrados) en el plano x-y durante las rondas 0 a 10. Se señalan los estados de la ronda 5 y el equilibrio límite. Ambos recorridos comparten la recta de conservación y visitan estados distintos. Los ejes tienen la misma escala por unidad. Ampliar figura ↗

En la ronda cinco, A está en (44,538; 55,462) Q(44{,}538;\ 55{,}462)\,Q, mientras que B está en (62,9136875; 37,0863125) Q(62{,}9136875;\ 37{,}0863125)\,Q. Unir los puntos con segmentos y prolongarlos hasta el equilibrio podría hacer que ambos recorridos parecieran idénticos, aunque son órbitas discretas diferentes. Salvo el estado inicial, no comparten ningún punto. Tienen en común una restricción geométrica y un límite, pero cada uno recorre la recta con su propia parametrización temporal.

El código usa ax.plot(x, y, linestyle="None", marker="o") para dibujar puntos sin unirlos (Matplotlib Development Team, s. f.-a). Con ax.set_aspect("equal", adjustable="box"), una unidad de cada eje ocupa la misma longitud en la figura (Matplotlib Development Team, s. f.-c). Esa elección es interpretable porque ambas componentes tienen la misma unidad. Para dibujar, por ejemplo, una cantidad frente a una velocidad, habría que definir escalas de referencia antes de dar significado a distancias o ángulos.

La pendiente negativa de la recta tampoco indica una dirección causal. Aquí surge algebraicamente de yn=S0−xny_n=S_0-x_n. Por la misma razón, la correlación entre las dos columnas de cualquier trayectoria no constante vale −1-1, cualesquiera sean las fracciones. Ese valor no permite estimar cuánto se transfiere por ronda ni distinguir el caso A del B. Para hacerlo hay que recuperar la información temporal que se descartó al mirar solo la relación entre cantidades. Una gráfica de estados no debe leerse, por tanto, como una red de influencias entre variables.

Una trayectoria aislada tampoco es un retrato de fases completo, porque nada dice de lo que ocurre desde otras condiciones iniciales. La ausencia de cruces en una proyección no demuestra determinismo, ya que variables no observadas podrían diferenciar estados que coinciden en ese plano. Aquí la suficiencia del estado se apoya en la especificación del modelo.

Submuestreo y desaparición de una alternancia

Consideremos ahora (α,β)=(0,8; 0,6)(\alpha,\beta)=(0{,}8;\ 0{,}6), fracciones que siguen siendo admisibles. Con el mismo total, xeq=300/7 Qx_{\mathrm{eq}}=300/7\,Q y ρ=−0,4\rho=-0{,}4. Las primeras cantidades de xx son

100; 20; 52; 39,2; 44,32; 42,272; 43,0912.100;\ 20;\ 52;\ 39{,}2;\ 44{,}32;\ 42{,}272;\ 43{,}0912.

La desviación cambia de signo en cada ronda. Si se registran solo las rondas pares, se observan 100100, 5252, 44,3244{,}32 y 43,091243{,}0912. La serie parece una aproximación monótona, porque entre dos observaciones la desviación se multiplica por (−0,4)2=0,16(-0{,}4)^2=0{,}16.

Trayectoria alternante con α = 0,8 y β = 0,6 y observaciones restringidas a las rondas pares.
Figura 23.5. Trayectoria alternante con α = 0,8 y β = 0,6 y observaciones restringidas a las rondas pares. La línea con círculos une las actualizaciones calculadas y los cuadrados marcan el subconjunto de rondas pares. El registro completo alterna alrededor del equilibrio de 300/7 Q, mientras que el subconjunto par no muestra esa alternancia. Ampliar figura ↗

Un caso límite hace la pérdida todavía más clara. Con α=β=1\alpha=\beta=1, el contenido se intercambia por completo y xnx_n alterna entre 100100 y 00. Si solo se registran las rondas pares, la serie vale siempre 100100. El sistema no se estabilizó. Lo que ocurrió es que la frecuencia de observación elegida no distingue sus dos posiciones periódicas.

Se trata de un caso exacto de ambigüedad por muestreo, sin relación con la precisión aritmética. Añadir decimales a los puntos conservados no recupera los estados omitidos. Tampoco una curva suave dibujada entre ellos demuestra cómo ocurrió la transición.

En los sistemas continuos habrá que distinguir los pasos internos del integrador de los instantes en que se guarda o se dibuja la solución. Un integrador puede calcular bien una trayectoria mientras una salida demasiado espaciada oculta rasgos de su evolución. Las condiciones generales de muestreo se estudiarán más adelante.

Diagramas de parámetros con horizonte finito

El eje horizontal también puede recorrer un parámetro. Para construir esa figura se necesitan varias trayectorias de una familia, porque reinterpretar el eje de una sola ejecución no basta. La razón entre las fracciones se mantiene fija mediante

α=2s3,β=s3,0≤s≤1,5.\alpha=\frac{2s}{3},\qquad\beta=\frac{s}{3}, \qquad 0\leq s\leq1{,}5.

El intervalo garantiza que ambas fracciones estén en [0,1][0,1]. Para s>0s>0, el equilibrio del total elegido sigue siendo 100/3 Q100/3\,Q, mientras que ρ=1−s\rho=1-s. El estado después de NN rondas es

xN(s)=1003+2003(1−s)N.x_N(s)=\frac{100}{3}+\frac{200}{3}(1-s)^N.

Dibujaremos esta cantidad para N=5N=5 y N=30N=30 junto con el equilibrio analítico. Cada valor proviene de reiniciar en (100,0) Q(100,0)\,Q con un parámetro fijo. El parámetro ss no cambia dentro de una trayectoria y el estado final de una ejecución no se usa para iniciar la siguiente.

El cálculo conserva las condiciones de cada ejecución. Se usan 151 valores igualmente espaciados de ss. El índice de ese arreglo no es un tiempo.

s = np.linspace(0.0, 1.5, 151)
x_5 = np.empty(s.size)
x_30 = np.empty(s.size)
for j, valor in enumerate(s):
    registro = simular(2.0 * valor / 3.0, valor / 3.0)
    x_5[j] = registro[5, 0]
    x_30[j] = registro[30, 0]
referencia_30 = 100.0 / 3.0 + (200.0 / 3.0) * (1.0-s)**30
if not np.allclose(x_30, referencia_30,
                   rtol=1e-12, atol=1e-10):
    raise RuntimeError("Discrepancia en el barrido paramétrico.")
Estados a corto y largo plazo según el parámetro del modelo.
Figura 23.6. Estados después de cinco y de treinta rondas para distintos valores del parámetro s. Cada punto de una curva resume una ejecución independiente. La línea discontinua marca el equilibrio, válido para s > 0. La diferencia entre las dos curvas se debe al horizonte de cálculo. En s = 0 no hay intercambio y el estado inicial permanece constante. Ampliar figura ↗

Con s=0,01s=0{,}01, treinta rondas dejan x30≈82,646692 Qx_{30}\approx82{,}646692\,Q, todavía lejos de 100/3 Q100/3\,Q. Presentar esa salida como «equilibrio según el parámetro» construiría una rama aparente, que en realidad corresponde al transitorio. Para cada ss fijo con 0<s≤1,50<s\leq1{,}5 hay convergencia sobre la recta de total constante. Ningún número finito de rondas garantiza, sin embargo, la misma proximidad para valores de ss arbitrariamente cercanos a cero.

En s=1s=1 el equilibrio se alcanza en una ronda. Para s>1s>1 aparece una alternancia convergente, que no implica pérdida de estabilidad. En s=0s=0, en cambio, la matriz es la identidad y todos los estados son fijos. El diagnóstico exige examinar esas propiedades, porque no se deduce de un quiebre visual ni de la densidad de puntos. El capítulo 28 formalizará la exploración paramétrica.

Ausencias, promedios y bandas

Un registro ausente no equivale a cero. Si una cantidad no se observó entre las rondas ocho y doce, eliminar esas filas y unir las restantes dibuja un segmento que puede ocultar el intervalo sin datos. Matplotlib permite conservar la posición temporal e interrumpir la línea mediante valores NaN o arreglos enmascarados (Matplotlib Development Team, s. f.-f). Sobre una copia de presentación podríamos escribir visible[8:13] = np.nan sin tocar la simulación original. Esa asignación marca la ausencia sin imputar ningún valor.

Los promedios también pueden borrar propiedades dinámicas. En el caso de intercambio completo, una trayectoria que comienza con x0=100x_0=100 y otra con x0=0x_0=0 oscilan en oposición, de modo que su promedio vale siempre 5050. La media describe correctamente la cantidad agregada, aunque no describe la evolución de ninguna de las dos unidades. Una serie promedio plana no demuestra, por tanto, la ausencia de oscilaciones individuales.

Una banda entre las configuraciones A y B mostraría los resultados de dos escenarios elegidos. Esa banda no sería un intervalo de confianza ni tendría una probabilidad de cobertura. La función fill_between dibuja una región entre curvas (Matplotlib Development Team, s. f.-e). La operación gráfica no determina su significado estadístico. Un intervalo inferencial requeriría un procedimiento adicional, con supuestos y un objeto de estimación definidos. Disponer de muchas trayectorias tampoco resolvería la interpretación, porque el rango entre sus extremos significa algo distinto según qué haya variado entre ellas. Antes de dibujar una banda habría que declarar qué varía entre las trayectorias y qué incertidumbre pretende describir. En nuestros dos escenarios no se asignó ninguna distribución de probabilidad a las fracciones de intercambio.

Tampoco las treinta y una filas de una trayectoria son treinta y una réplicas independientes, porque son estados relacionados por una recurrencia. La cantidad de puntos visibles no da un tamaño muestral apropiado para inferencias sobre personas o sobre ejecuciones independientes.

Conservar la relación entre figura y cálculo

Para reconstruir una figura hace falta algo más que la imagen exportada. En este capítulo se conservan las matrices de resultados y los parámetros junto con el programa que dibuja. El archivo complementario cap23_figuras.py reproduce las seis figuras y ejecuta las comprobaciones. Verifica la conservación y compara cada escenario con su solución analítica. También comprueba que dibujar no modifique los arreglos recibidos. Las figuras se generaron con Python 3.12.3, NumPy 2.4.4 y Matplotlib 3.10.8.

La configuración gráfica registra el intervalo de rondas y la escala de cada eje, además de las cantidades derivadas. En la figura 23.3, por ejemplo, guardar solo xnx_n no documentaría que se restó xeqx_{\mathrm{eq}} y se dividió por S0S_0. La procedencia de esos valores forma parte del cálculo. Las recomendaciones de Wilson y colaboradores (2017) sobre conservación de datos y procedimientos reproducibles se aplican también a esta trazabilidad.

La función savefig exporta cada figura con la resolución y el formato que se especifiquen (Matplotlib Development Team, s. f.-d). Para impresión usamos imágenes de 300 puntos por pulgada. El paquete del capítulo incluye además versiones vectoriales en formato SVG. Los marcadores y los tipos de línea distinguen los escenarios sin depender del color. La resolución de una imagen es una propiedad de su representación gráfica y nada dice de la precisión numérica del modelo.

Al final se inspecciona el resultado exportado. Una leyenda puede cubrir un punto o una etiqueta puede quedar recortada al reducir el tamaño de la figura. Esa revisión complementa las verificaciones numéricas, que no detectan problemas de legibilidad.

Elección de la representación y alcance de la conclusión

Cada pregunta del capítulo exigió una representación distinta. Para comparar la rapidez de aproximación usamos las series completas y una tolerancia definida, con la que las configuraciones A y B quedan a no más de 1 Q1\,Q del equilibrio desde las rondas 12 y 26. El plano (x,y)(x,y) mostró que ambos recorridos están restringidos por el mismo balance aunque visitan puntos diferentes. El estudio de la sensibilidad a parámetros necesitó, finalmente, una colección de ejecuciones y la distinción entre resultados finitos y límites asintóticos.

La comparación dejó también controles concretos. Una recta en escala semilogarítmica debe atribuirse a la cantidad que efectivamente se transformó, mientras que una secuencia monótona observada cada dos rondas puede ocultar una alternancia. Del mismo modo, una media constante puede resumir oscilaciones opuestas. En cada caso la limitación se obtuvo siguiendo la operación aplicada a los datos, sin suponer que toda visualización sea arbitraria.

Aplicado a registros clínicos, este procedimiento exigiría identificar el instrumento y los tiempos observados, además de las transformaciones aplicadas. Nada de ello convierte una puntuación en una cantidad conservada ni autoriza a atribuir causalidad por semejanza con nuestras figuras. Lo que se transfiere es el examen del paso que lleva de un registro a una afirmación.

El capítulo 24 aproximará numéricamente una evolución continua. Las figuras permitirán comparar errores y trayectorias. Seguirá siendo necesario distinguir los estados calculados de los puntos dibujados y de las propiedades que justifica el modelo.

Ejercicios

Ejercicio 23.1. En el caso A, la diferencia entre x15x_{15} y x30x_{30} es 0,315001 Q0{,}315001\,Q. (a) ¿Qué fracción de la altura del eje ocupa si el eje vertical va de 0 a 105? (b) ¿Y si va de 33,32 a 33,68? (c) ¿Cuántas veces amplifica el segundo eje la distancia impresa? (d) ¿Qué habría que añadir a la figura ampliada para que el lector no sobrestime la diferencia?

Ejercicio 23.2. (a) Calcule la pendiente por ronda de ln⁡ηn\ln\eta_n y de log⁡10ηn\log_{10}\eta_n en los casos A y B. (b) Para (α,β)=(0,8; 0,6)(\alpha,\beta)=(0{,}8;\ 0{,}6), calcule la pendiente de ln⁡ηn\ln\eta_n y explique qué oculta la figura semilogarítmica. (c) Prolongue el caso A hasta 120 rondas y dibuje ηn\eta_n. ¿Qué ocurre hacia la ronda 90 y por qué?

Ejercicio 23.3. Con (α,β)=(0,8; 0,6)(\alpha,\beta)=(0{,}8;\ 0{,}6), (a) calcule las desviaciones xn−xeqx_n-x_{\mathrm{eq}} en las rondas 0 a 4. (b) Si se observa una ronda de cada tres, ¿por qué número se multiplica la desviación entre observaciones consecutivas? ¿Se ve la alternancia? (c) Con α=β=1\alpha=\beta=1, compare el registro completo con los que se obtienen observando cada dos y cada tres rondas. (d) Enuncie una regla que indique, cuando ρ<0\rho<0, qué intervalos de observación conservan la alternancia.

Ejercicio 23.4. (a) Demuestre que en cualquier trayectoria con total constante y xnx_n no constante la correlación entre xnx_n e yny_n vale −1-1. (b) ¿Por qué ese valor no distingue la configuración A de la B? (c) Muestre que los recorridos de A y B desde (100,0)(100,0) solo comparten el estado inicial. Como ayuda, escriba 0,7n=0,85m0{,}7^n=0{,}85^m como una igualdad entre enteros y compare sus factores primos.

Ejercicio 23.5. Con α=2s/3\alpha=2s/3 y β=s/3\beta=s/3, (a) calcule x5(s)x_5(s) y x30(s)x_{30}(s) para ss igual a 0,01; 0,5; 1 y 1,5. (b) ¿Para qué valores de ss se cumple ∣x30−100/3∣≤1 Q|x_{30}-100/3|\leq1\,Q? (c) Explique por qué la curva de N=30N=30 parece una rama que se separa del equilibrio cerca de s=0s=0.

Ejercicio 23.6. Dos trayectorias con α=β=1\alpha=\beta=1 parten de (100,0)(100,0) y de (0,100)(0,100). (a) Calcule el promedio de xx en cada ronda. (b) ¿Qué describe una banda dibujada entre las dos trayectorias? (c) ¿Qué información adicional haría falta para que una banda entre trayectorias pudiera leerse como un intervalo de incertidumbre?

Consultar las soluciones de los ejercicios

Soluciones de los ejercicios

Solución 23.1. (a) La diferencia ocupa 0,315/105≈0,0030{,}315/105\approx0{,}003, el 0,3 % de la altura. (b) Ocupa 0,315/0,36≈0,8750{,}315/0{,}36\approx0{,}875, el 87,5 %. (c) El factor de amplificación es 105/0,36≈292105/0{,}36\approx292. (d) Hay que declarar en la leyenda los límites del eje y remitir a la escala completa. Si existe un umbral de relevancia práctica, también puede dibujarse.

Solución 23.2. (a) En logaritmo natural las pendientes son ln⁡0,7≈−0,356675\ln0{,}7\approx-0{,}356675 y ln⁡0,85≈−0,162519\ln0{,}85\approx-0{,}162519. En base diez son log⁡100,7≈−0,154902\log_{10}0{,}7\approx-0{,}154902 y log⁡100,85≈−0,070581\log_{10}0{,}85\approx-0{,}070581. (b) Como ∣ρ∣=0,4|\rho|=0{,}4, la pendiente es ln⁡0,4≈−0,916291\ln0{,}4\approx-0{,}916291 por ronda. La figura muestra una recta y oculta que la desviación cambia de signo en cada ronda. (c) Hacia la ronda 90 la desviación teórica cae por debajo de 10−12 Q10^{-12}\,Q, apenas unas cien veces el espaciado entre números de coma flotante cercanos a 33,3, que es de unos 7×10−15 Q7\times10^{-15}\,Q. La desviación calculada deja de seguir la recta y termina estancada en un valor del orden de 10−13 Q10^{-13}\,Q que depende de los detalles del redondeo. La figura muestra entonces la precisión de la aritmética y ya no la dinámica del modelo.

Solución 23.3. (a) Con xeq=300/7≈42,857143x_{\mathrm{eq}}=300/7\approx42{,}857143, las desviaciones son 57,14285757{,}142857; −22,857143-22{,}857143; 9,1428579{,}142857; −3,657143-3{,}657143 y 1,4628571{,}462857. (b) Se multiplica por (−0,4)3=−0,064(-0{,}4)^3=-0{,}064. El signo cambia en cada observación, de modo que la alternancia se ve. (c) El registro completo alterna entre 100 y 0. Cada dos rondas se observa siempre 100. Cada tres rondas se observa 100, 0, 100, 0, de modo que la alternancia reaparece. (d) Si se observa una ronda de cada kk, la desviación se multiplica por ρk\rho^k, que es negativo cuando kk es impar. Los intervalos impares conservan la alternancia y los pares la ocultan.

Solución 23.4. (a) Como yn=S0−xny_n=S_0-x_n, se cumple cov⁡(x,y)=−var⁡(x)\operatorname{cov}(x,y)=-\operatorname{var}(x) y var⁡(y)=var⁡(x)\operatorname{var}(y)=\operatorname{var}(x), así que r=−var⁡(x)/var⁡(x)=−1r=-\operatorname{var}(x)/\operatorname{var}(x)=-1. (b) El valor depende solo de la restricción del total, que ambas configuraciones comparten. Las fracciones determinan el ritmo del recorrido, que el plano de estados no muestra. (c) Dos estados coinciden si 0,7n=0,85m0{,}7^n=0{,}85^m, es decir, si 7n 20m=17m 10n7^n\,20^m=17^m\,10^n. El factor 7 solo aparece a la izquierda y el factor 17 solo a la derecha, de modo que la igualdad exige n=m=0n=m=0.

Solución 23.5. (a) Con s=0,01s=0{,}01 se obtiene x5≈96,733x_5\approx96{,}733 y x30≈82,647x_{30}\approx82{,}647, mientras que con s=0,5s=0{,}5 los valores son 35,41735{,}417 y 33,33333{,}333. En s=1s=1 ambos valen 100/3100/3. En s=1,5s=1{,}5, x5=31,25x_5=31{,}25 y x30≈33,333x_{30}\approx33{,}333. (b) La condición es (200/3)∣1−s∣30≤1(200/3)|1-s|^{30}\leq1, es decir, ∣1−s∣≤(3/200)1/30≈0,8694|1-s|\leq(3/200)^{1/30}\approx0{,}8694. En el intervalo estudiado se cumple para s≥0,1306s\geq0{,}1306. (c) Cerca de s=0s=0 el factor ∣1−s∣30|1-s|^{30} sigue próximo a uno, de modo que treinta rondas no bastan para acercarse al equilibrio. La curva muestra el transitorio en un horizonte fijo, sin que exista una rama de equilibrios.

Solución 23.6. (a) El promedio vale 50 en todas las rondas, aunque cada trayectoria alterna entre 0 y 100. (b) La banda ocupa todo el intervalo de 0 a 100 en cada ronda y describe el rango de dos condiciones iniciales elegidas. No expresa incertidumbre sobre ningún parámetro. (c) Habría que declarar qué varía entre las trayectorias y con qué distribución se eligieron sus valores. También habría que definir el objeto que se quiere estimar.

Referencias

Matplotlib Development Team. (s. f.-a). matplotlib.axes.Axes.plot. Recuperado el 19 de septiembre de 2026, de https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.plot.html

Matplotlib Development Team. (s. f.-b). matplotlib.axes.Axes.semilogy. Recuperado el 19 de septiembre de 2026, de https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.semilogy.html

Matplotlib Development Team. (s. f.-c). matplotlib.axes.Axes.set_aspect. Recuperado el 19 de septiembre de 2026, de https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_aspect.html

Matplotlib Development Team. (s. f.-d). matplotlib.figure.Figure.savefig. Recuperado el 19 de septiembre de 2026, de https://matplotlib.org/stable/api/_as_gen/matplotlib.figure.Figure.savefig.html

Matplotlib Development Team. (s. f.-e). matplotlib.pyplot.fill_between. Recuperado el 19 de septiembre de 2026, de https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.fill_between.html

Matplotlib Development Team. (s. f.-f). Plotting masked and NaN values. Recuperado el 19 de septiembre de 2026, de https://matplotlib.org/stable/gallery/lines_bars_and_markers/masked_demo.html

Rougier, N. P., Droettboom, M. y Bourne, P. E. (2014). Ten simple rules for better figures. PLOS Computational Biology, 10(9), e1003833. https://doi.org/10.1371/journal.pcbi.1003833

Wilson, G., Bryan, J., Cranston, K., Kitzes, J., Nederbragt, L. y Teal, T. K. (2017). Good enough practices in scientific computing. PLOS Computational Biology, 13(6), e1005510. https://doi.org/10.1371/journal.pcbi.1005510