def graficar_masa(valores, masa, frecuencias, titulo, xlabel, esperanza=None):
fig, ax = plt.subplots(figsize=(8, 3.9))
ax.bar(np.asarray(valores) - 0.2, masa, width=0.4, label="función de masa (teoría)")
ax.bar(np.asarray(valores) + 0.2, frecuencias, width=0.4, color="0.65", label="frecuencia simulada")
if esperanza is not None:
ax.axvline(esperanza, color="C3", linestyle="--", label=f"esperanza = {esperanza:g}")
ax.set_xticks(valores)
ax.set_xlabel(xlabel)
ax.set_ylabel("probabilidad")
ax.set_title(titulo)
ax.legend(fontsize=8)
plt.tight_layout()
plt.show()
def graficar_promedio_dado(tiradas, esperanza, titulo):
n = np.arange(1, len(tiradas) + 1)
fig, ax = plt.subplots(figsize=(8, 3.6))
ax.plot(n, np.cumsum(tiradas) / n, linewidth=1)
ax.axhline(esperanza, color="C3", linestyle="--", label=f"E[X] = {esperanza:g}")
ax.set_xscale("log")
ax.set_xlabel("número de tiradas (escala logarítmica)")
ax.set_ylabel("promedio acumulado")
ax.set_title(titulo)
ax.legend(fontsize=8)
plt.tight_layout()
plt.show()
def graficar_dos_masas(k, masa_a, masa_b, etiqueta_a, etiqueta_b, titulo, xlabel):
fig, ax = plt.subplots(figsize=(8, 3.8))
ax.bar(k - 0.2, masa_a, width=0.4, label=etiqueta_a)
ax.bar(k + 0.2, masa_b, width=0.4, color="C1", label=etiqueta_b)
ax.set_xticks(k)
ax.set_xlabel(xlabel)
ax.set_ylabel("probabilidad")
ax.set_title(titulo)
ax.legend(fontsize=8)
plt.tight_layout()
plt.show()
def graficar_densidad_area(mu, sigma, a, b, datos, titulo):
xs = np.linspace(mu - 4 * sigma, mu + 4 * sigma, 500)
fx = stats.norm.pdf(xs, mu, sigma)
fig, axes = plt.subplots(1, 2, figsize=(11.5, 3.9))
ax = axes[0]
ax.hist(datos, bins=60, density=True, alpha=0.35, label="histograma (área total 1)")
ax.plot(xs, fx, color="C3", label="densidad")
ax.fill_between(xs, fx, where=(xs >= a) & (xs <= b), color="C3", alpha=0.35, label=f"P({a:g} ≤ X ≤ {b:g})")
ax.set_xlabel("latencia (ms)")
ax.set_ylabel("densidad")
ax.set_title("la probabilidad es un área", fontsize=10)
ax.legend(fontsize=8)
ax = axes[1]
ax.plot(xs, stats.norm.cdf(xs, mu, sigma))
for v in (a, b):
ax.plot([v, v], [0, stats.norm.cdf(v, mu, sigma)], color="0.4", linestyle=":")
ax.plot([xs[0], v], [stats.norm.cdf(v, mu, sigma)] * 2, color="0.4", linestyle=":")
ax.set_xlabel("latencia (ms)")
ax.set_ylabel("F(x) = P(X ≤ x)")
ax.set_title("la misma probabilidad como F(b) − F(a)", fontsize=10)
fig.suptitle(titulo, fontsize=11)
plt.tight_layout()
plt.show()
def graficar_normal_bandas(mu, sigma, umbral, percentil, titulo):
xs = np.linspace(mu - 4 * sigma, mu + 4 * sigma, 500)
fx = stats.norm.pdf(xs, mu, sigma)
fig, ax = plt.subplots(figsize=(8.6, 4))
ax.plot(xs, fx, color="0.2")
for k, alfa in ((3, 0.12), (2, 0.2), (1, 0.3)):
ax.fill_between(xs, fx, where=(xs >= mu - k * sigma) & (xs <= mu + k * sigma), color="C0", alpha=alfa,
label=fr"$\mu \pm {k}\sigma$")
ax.fill_between(xs, fx, where=xs >= umbral, color="C3", alpha=0.6, label=f"P(X > {umbral:g})")
ax.axvline(percentil, color="C1", linestyle="--", label=f"percentil 95 = {percentil:.1f}")
ax.set_xlabel("latencia (ms)")
ax.set_ylabel("densidad")
ax.set_title(titulo)
ax.legend(fontsize=8)
plt.tight_layout()
plt.show()
def graficar_trayectorias(promedios, referencia, titulo, etiqueta_ref, ylim=None):
n = np.arange(1, promedios.shape[1] + 1)
fig, ax = plt.subplots(figsize=(8.4, 3.9))
for fila in promedios:
ax.plot(n, fila, linewidth=0.9, alpha=0.8)
if referencia is not None:
ax.axhline(referencia, color="0.1", linestyle="--", label=etiqueta_ref)
ax.legend(fontsize=8)
ax.set_xscale("log")
if ylim is not None:
ax.set_ylim(*ylim)
ax.set_xlabel("número de observaciones (escala logarítmica)")
ax.set_ylabel("promedio acumulado")
ax.set_title(titulo)
plt.tight_layout()
plt.show()
def graficar_tlc(datos, medias_por_n, mu, sigma, titulo):
fig, axes = plt.subplots(1, len(medias_por_n) + 1, figsize=(3.6 * (len(medias_por_n) + 1), 3.5))
axes[0].hist(datos, bins=60, range=(0, np.quantile(datos, 0.995)), density=True, alpha=0.6)
axes[0].set_title("una latencia (n = 1)", fontsize=10)
axes[0].set_ylabel("densidad")
for ax, (n, medias) in zip(axes[1:], medias_por_n.items()):
se = sigma / np.sqrt(n)
xs = np.linspace(mu - 4 * se, mu + 4 * se, 300)
ax.hist(medias, bins=60, density=True, alpha=0.6, label="medias simuladas")
ax.plot(xs, stats.norm.pdf(xs, mu, se), color="C3", label="normal del TLC")
ax.set_title(f"media de n = {n}", fontsize=10)
ax.legend(fontsize=7)
for ax in axes:
ax.set_xlabel("ms")
fig.suptitle(titulo, fontsize=11)
plt.tight_layout()
plt.show()
def graficar_calibracion(tabla, esperado, desviacion, observados, etiquetas, titulo):
fig, axes = plt.subplots(1, 2, figsize=(11.5, 3.9))
ax = axes[0]
ax.plot([0, 0.7], [0, 0.7], color="0.4", linestyle="--", label="calibración perfecta")
ax.errorbar(tabla["probabilidad media"], tabla["frecuencia observada"], yerr=2 * tabla["error estándar"],
fmt="o-", capsize=3, label="modelo (± 2 errores estándar)")
ax.set_xlabel("probabilidad que anunció el modelo")
ax.set_ylabel("frecuencia observada de positivos")
ax.set_title("¿el 0.3 del modelo ocurre el 30% de las veces?", fontsize=10)
ax.legend(fontsize=8)
ax = axes[1]
xs = np.linspace(esperado - 5 * desviacion, max(observados) + 2 * desviacion, 400)
ax.plot(xs, stats.norm.pdf(xs, esperado, desviacion), color="0.2")
ax.fill_between(xs, stats.norm.pdf(xs, esperado, desviacion),
where=(xs >= esperado - 2 * desviacion) & (xs <= esperado + 2 * desviacion),
alpha=0.3, label="esperado ± 2 desviaciones")
for obs, etiqueta, color in zip(observados, etiquetas, ("C2", "C3")):
ax.axvline(obs, color=color, label=f"{etiqueta}: {obs}")
ax.set_xlabel("número de positivos en el día")
ax.set_yticks([])
ax.set_title("conteo observado frente al que el modelo anuncia", fontsize=10)
ax.legend(fontsize=8)
fig.suptitle(titulo, fontsize=11)
plt.tight_layout()
plt.show()