codextwo-gaussian-mixture-posterior-responsibilities.py
two-gaussian-mixture-posterior-responsibilities.py
"""Analytic latent-label probabilities; Python 3.14, NumPy 2.3.5, Matplotlib 3.10.7."""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
x = np.linspace(-2, 2, 1601)
r2 = 1 / (1 + 0.5 * np.exp(-4 * x))
r1 = 1 - r2
boundary = -np.log(2) / 4
point = np.log(2) / 4
fig, ax = plt.subplots(figsize=(8.4, 4.8), dpi=100, facecolor="white")
ax.plot(x, r1, color="#007b91", lw=2.6, label="r₁(x): posterior for component 1")
ax.plot(x, r2, color="#c65c22", lw=2.6, label="r₂(x): posterior for component 2")
ax.axhline(1 / 3, color="#007b91", lw=1.3, linestyle=":")
ax.axhline(2 / 3, color="#c65c22", lw=1.3, linestyle=":")
ax.text(-1.94, 1 / 3 + 0.025, "π₁ = ⅓", color="#007b91", fontsize=10)
ax.text(-1.94, 2 / 3 + 0.025, "π₂ = ⅔", color="#c65c22", fontsize=10)
ax.axvline(boundary, color="#777777", lw=1.1, linestyle="--")
ax.plot(boundary, 0.5, "o", color="#333333", ms=5)
ax.annotate("Equal responsibilities\nx* = −log(2)/4 ≈ −0.1733",
xy=(boundary, 0.5), xytext=(0.4, 0.45), fontsize=10,
arrowprops={"arrowstyle": "->", "color": "#555555"})
ax.plot([0, point], [2 / 3, 4 / 5], "o", color="#c65c22", ms=5)
ax.annotate("r₂(0) = ⅔", xy=(0, 2 / 3), xytext=(-1.08, 0.84),
fontsize=10, arrowprops={"arrowstyle": "->", "color": "#555555"})
ax.annotate("r₂(log(2)/4) = ⅘", xy=(point, 4 / 5), xytext=(0.72, 0.72),
fontsize=10, arrowprops={"arrowstyle": "->", "color": "#555555"})
ax.set(xlim=(-2, 2), ylim=(-0.02, 1.02), xlabel="Value x (label unobserved)",
ylabel="Probability of component label", title="Learning x changes the membership probabilities")
ax.set_xticks(np.arange(-2, 2.1, 0.5))
ax.grid(color="#e5e5e5", lw=0.6)
ax.set_axisbelow(True)
ax.spines[["top", "right"]].set_visible(False)
ax.set_facecolor("white")
ax.legend(loc="upper center", bbox_to_anchor=(0.5, -0.19),
ncol=2, fontsize=9.5, frameon=False)
fig.text(0.5, 0.035, "Stipulated Gaussian mixture: weights ⅓ and ⅔, means −2 and +2, variances 1.",
ha="center", fontsize=9.5)
fig.subplots_adjust(left=0.10, right=0.97, bottom=0.27, top=0.90)
fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()