2025-12-03 18:16:48 +01:00
|
|
|
|
{
|
|
|
|
|
|
"cells": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
2026-01-06 14:36:08 +01:00
|
|
|
|
"execution_count": 1,
|
2025-12-03 18:16:48 +01:00
|
|
|
|
"id": "dc5d5825",
|
|
|
|
|
|
"metadata": {},
|
2026-01-06 14:36:08 +01:00
|
|
|
|
"outputs": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "stdout",
|
|
|
|
|
|
"output_type": "stream",
|
|
|
|
|
|
"text": [
|
|
|
|
|
|
"OptimizR MCMC Module Loaded!\n"
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
2025-12-03 18:16:48 +01:00
|
|
|
|
"source": [
|
|
|
|
|
|
"import numpy as np\n",
|
|
|
|
|
|
"import matplotlib.pyplot as plt\n",
|
|
|
|
|
|
"from scipy import stats\n",
|
|
|
|
|
|
"from optimizr import mcmc_sample\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"np.random.seed(42)\n",
|
|
|
|
|
|
"print(\"OptimizR MCMC Module Loaded!\")"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "ddfbd617",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"## Example 1: Inferring Parameters of a Normal Distribution\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"Given observed data $\\{x_1, \\ldots, x_n\\}$, infer $\\mu$ and $\\sigma$.\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"### Likelihood\n",
|
|
|
|
|
|
"$$L(\\mu, \\sigma | \\mathbf{x}) = \\prod_{i=1}^n \\frac{1}{\\sqrt{2\\pi\\sigma^2}} \\exp\\left(-\\frac{(x_i - \\mu)^2}{2\\sigma^2}\\right)$$\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"### Log-Likelihood\n",
|
|
|
|
|
|
"$$\\log L(\\mu, \\sigma | \\mathbf{x}) = -\\frac{n}{2}\\log(2\\pi) - n\\log(\\sigma) - \\frac{1}{2\\sigma^2}\\sum_{i=1}^n (x_i - \\mu)^2$$"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "f929c18e",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"# Generate synthetic data\n",
|
|
|
|
|
|
"true_mu = 5.0\n",
|
|
|
|
|
|
"true_sigma = 2.0\n",
|
|
|
|
|
|
"n_obs = 100\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"observed_data = np.random.normal(true_mu, true_sigma, n_obs)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(f\"True parameters: μ={true_mu}, σ={true_sigma}\")\n",
|
|
|
|
|
|
"print(f\"Sample mean: {observed_data.mean():.3f}\")\n",
|
|
|
|
|
|
"print(f\"Sample std: {observed_data.std():.3f}\")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Plot data\n",
|
|
|
|
|
|
"plt.figure(figsize=(10, 5))\n",
|
|
|
|
|
|
"plt.hist(observed_data, bins=20, density=True, alpha=0.6, color='skyblue', edgecolor='black')\n",
|
|
|
|
|
|
"x_range = np.linspace(observed_data.min(), observed_data.max(), 100)\n",
|
|
|
|
|
|
"plt.plot(x_range, stats.norm.pdf(x_range, true_mu, true_sigma), \n",
|
|
|
|
|
|
" 'r-', linewidth=2, label=f'True: N({true_mu}, {true_sigma}²)')\n",
|
|
|
|
|
|
"plt.xlabel('Value', fontsize=12)\n",
|
|
|
|
|
|
"plt.ylabel('Density', fontsize=12)\n",
|
|
|
|
|
|
"plt.title('Observed Data Distribution', fontsize=14, fontweight='bold')\n",
|
|
|
|
|
|
"plt.legend()\n",
|
|
|
|
|
|
"plt.grid(alpha=0.3)\n",
|
|
|
|
|
|
"plt.show()"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "5626ba97",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"### Define Log-Likelihood Function"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "37ac93a1",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"def log_likelihood_normal(params, data):\n",
|
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
|
" Log-likelihood for Normal(μ, σ²) given data.\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" Args:\n",
|
|
|
|
|
|
" params: [μ, σ]\n",
|
|
|
|
|
|
" data: observed data points\n",
|
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
|
" mu, sigma = params\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" # Ensure sigma is positive\n",
|
|
|
|
|
|
" if sigma <= 0:\n",
|
|
|
|
|
|
" return -np.inf\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" n = len(data)\n",
|
|
|
|
|
|
" residuals = (data - mu) / sigma\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" log_lik = -0.5 * n * np.log(2 * np.pi)\n",
|
|
|
|
|
|
" log_lik -= n * np.log(sigma)\n",
|
|
|
|
|
|
" log_lik -= 0.5 * np.sum(residuals**2)\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" return log_lik\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Test the function\n",
|
|
|
|
|
|
"test_params = [5.0, 2.0]\n",
|
|
|
|
|
|
"print(f\"Log-likelihood at true params: {log_likelihood_normal(test_params, observed_data):.2f}\")"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "a36ddef7",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"### Run MCMC Sampling"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "60e64783",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"# MCMC parameters\n",
|
|
|
|
|
|
"initial_params = [0.0, 1.0] # Start far from true values\n",
|
|
|
|
|
|
"param_bounds = [(-10, 10), (0.1, 10)] # μ ∈ [-10, 10], σ ∈ [0.1, 10]\n",
|
|
|
|
|
|
"proposal_std = [0.5, 0.2] # Proposal step sizes\n",
|
|
|
|
|
|
"n_samples = 20000\n",
|
|
|
|
|
|
"burn_in = 2000\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(\"Running MCMC sampling...\")\n",
|
|
|
|
|
|
"samples, acceptance_rate = mcmc_sample(\n",
|
|
|
|
|
|
" log_likelihood_fn=log_likelihood_normal,\n",
|
|
|
|
|
|
" data=observed_data,\n",
|
|
|
|
|
|
" initial_params=initial_params,\n",
|
|
|
|
|
|
" param_bounds=param_bounds,\n",
|
|
|
|
|
|
" proposal_std=proposal_std,\n",
|
|
|
|
|
|
" n_samples=n_samples,\n",
|
|
|
|
|
|
" burn_in=burn_in\n",
|
|
|
|
|
|
")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(f\"\\nAcceptance rate: {acceptance_rate:.2%}\")\n",
|
|
|
|
|
|
"print(f\"Generated {len(samples)} samples after burn-in\")\n",
|
|
|
|
|
|
"print(f\"\\nPosterior estimates:\")\n",
|
|
|
|
|
|
"print(f\"μ: {samples[:, 0].mean():.3f} ± {samples[:, 0].std():.3f}\")\n",
|
|
|
|
|
|
"print(f\"σ: {samples[:, 1].mean():.3f} ± {samples[:, 1].std():.3f}\")\n",
|
|
|
|
|
|
"print(f\"\\nTrue values: μ={true_mu}, σ={true_sigma}\")"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "2306bc9b",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"## Visualize MCMC Results\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"### Trace Plots - Check Convergence"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "856b7ca8",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"fig, axes = plt.subplots(2, 2, figsize=(14, 8))\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Trace plots\n",
|
|
|
|
|
|
"axes[0, 0].plot(samples[:, 0], linewidth=0.5, alpha=0.7)\n",
|
|
|
|
|
|
"axes[0, 0].axhline(true_mu, color='red', linestyle='--', linewidth=2, label='True μ')\n",
|
|
|
|
|
|
"axes[0, 0].set_xlabel('Sample', fontsize=11)\n",
|
|
|
|
|
|
"axes[0, 0].set_ylabel('μ', fontsize=11)\n",
|
|
|
|
|
|
"axes[0, 0].set_title('Trace Plot: μ', fontsize=13, fontweight='bold')\n",
|
|
|
|
|
|
"axes[0, 0].legend()\n",
|
|
|
|
|
|
"axes[0, 0].grid(alpha=0.3)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"axes[0, 1].plot(samples[:, 1], linewidth=0.5, alpha=0.7, color='orange')\n",
|
|
|
|
|
|
"axes[0, 1].axhline(true_sigma, color='red', linestyle='--', linewidth=2, label='True σ')\n",
|
|
|
|
|
|
"axes[0, 1].set_xlabel('Sample', fontsize=11)\n",
|
|
|
|
|
|
"axes[0, 1].set_ylabel('σ', fontsize=11)\n",
|
|
|
|
|
|
"axes[0, 1].set_title('Trace Plot: σ', fontsize=13, fontweight='bold')\n",
|
|
|
|
|
|
"axes[0, 1].legend()\n",
|
|
|
|
|
|
"axes[0, 1].grid(alpha=0.3)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Posterior distributions\n",
|
|
|
|
|
|
"axes[1, 0].hist(samples[:, 0], bins=50, density=True, alpha=0.6, color='skyblue', edgecolor='black')\n",
|
|
|
|
|
|
"axes[1, 0].axvline(true_mu, color='red', linestyle='--', linewidth=2, label='True μ')\n",
|
|
|
|
|
|
"axes[1, 0].axvline(samples[:, 0].mean(), color='green', linestyle='-', linewidth=2, label='Posterior mean')\n",
|
|
|
|
|
|
"axes[1, 0].set_xlabel('μ', fontsize=11)\n",
|
|
|
|
|
|
"axes[1, 0].set_ylabel('Density', fontsize=11)\n",
|
|
|
|
|
|
"axes[1, 0].set_title('Posterior Distribution: μ', fontsize=13, fontweight='bold')\n",
|
|
|
|
|
|
"axes[1, 0].legend()\n",
|
|
|
|
|
|
"axes[1, 0].grid(alpha=0.3)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"axes[1, 1].hist(samples[:, 1], bins=50, density=True, alpha=0.6, color='orange', edgecolor='black')\n",
|
|
|
|
|
|
"axes[1, 1].axvline(true_sigma, color='red', linestyle='--', linewidth=2, label='True σ')\n",
|
|
|
|
|
|
"axes[1, 1].axvline(samples[:, 1].mean(), color='green', linestyle='-', linewidth=2, label='Posterior mean')\n",
|
|
|
|
|
|
"axes[1, 1].set_xlabel('σ', fontsize=11)\n",
|
|
|
|
|
|
"axes[1, 1].set_ylabel('Density', fontsize=11)\n",
|
|
|
|
|
|
"axes[1, 1].set_title('Posterior Distribution: σ', fontsize=13, fontweight='bold')\n",
|
|
|
|
|
|
"axes[1, 1].legend()\n",
|
|
|
|
|
|
"axes[1, 1].grid(alpha=0.3)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"plt.tight_layout()\n",
|
|
|
|
|
|
"plt.show()"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "9b20c718",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"### Joint Posterior Distribution"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "ad2eebc7",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"plt.figure(figsize=(10, 8))\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# 2D histogram\n",
|
|
|
|
|
|
"plt.hist2d(samples[:, 0], samples[:, 1], bins=50, cmap='Blues')\n",
|
|
|
|
|
|
"plt.colorbar(label='Sample Density')\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Mark true values\n",
|
|
|
|
|
|
"plt.scatter([true_mu], [true_sigma], c='red', s=200, marker='*', \n",
|
|
|
|
|
|
" edgecolors='black', linewidths=2, label='True values', zorder=5)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Mark posterior mean\n",
|
|
|
|
|
|
"plt.scatter([samples[:, 0].mean()], [samples[:, 1].mean()], \n",
|
|
|
|
|
|
" c='green', s=200, marker='o', edgecolors='black', \n",
|
|
|
|
|
|
" linewidths=2, label='Posterior mean', zorder=5)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"plt.xlabel('μ', fontsize=12)\n",
|
|
|
|
|
|
"plt.ylabel('σ', fontsize=12)\n",
|
|
|
|
|
|
"plt.title('Joint Posterior Distribution', fontsize=14, fontweight='bold')\n",
|
|
|
|
|
|
"plt.legend(fontsize=11)\n",
|
|
|
|
|
|
"plt.grid(alpha=0.3)\n",
|
|
|
|
|
|
"plt.show()"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "049df073",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"## Example 2: Logistic Regression with MCMC\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"Bayesian inference for binary classification.\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"### Model\n",
|
|
|
|
|
|
"$$P(y=1 | \\mathbf{x}, \\boldsymbol{\\beta}) = \\frac{1}{1 + \\exp(-\\boldsymbol{\\beta}^T \\mathbf{x})}$$\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"### Log-Likelihood\n",
|
|
|
|
|
|
"$$\\log L(\\boldsymbol{\\beta}) = \\sum_{i=1}^n \\left[y_i \\log p_i + (1-y_i) \\log(1-p_i)\\right]$$"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "072639a3",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"# Generate synthetic classification data\n",
|
|
|
|
|
|
"from sklearn.datasets import make_classification\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"X, y = make_classification(n_samples=200, n_features=2, n_redundant=0,\n",
|
|
|
|
|
|
" n_informative=2, random_state=42, n_clusters_per_class=1)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Add intercept\n",
|
|
|
|
|
|
"X_with_intercept = np.column_stack([np.ones(len(X)), X])\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(f\"Features shape: {X_with_intercept.shape}\")\n",
|
|
|
|
|
|
"print(f\"Class distribution: {np.bincount(y)}\")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Visualize data\n",
|
|
|
|
|
|
"plt.figure(figsize=(8, 6))\n",
|
|
|
|
|
|
"plt.scatter(X[y == 0, 0], X[y == 0, 1], c='blue', label='Class 0', alpha=0.6, s=50)\n",
|
|
|
|
|
|
"plt.scatter(X[y == 1, 0], X[y == 1, 1], c='red', label='Class 1', alpha=0.6, s=50)\n",
|
|
|
|
|
|
"plt.xlabel('Feature 1', fontsize=12)\n",
|
|
|
|
|
|
"plt.ylabel('Feature 2', fontsize=12)\n",
|
|
|
|
|
|
"plt.title('Binary Classification Data', fontsize=14, fontweight='bold')\n",
|
|
|
|
|
|
"plt.legend()\n",
|
|
|
|
|
|
"plt.grid(alpha=0.3)\n",
|
|
|
|
|
|
"plt.show()"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "6163cb52",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"def log_likelihood_logistic(beta, X, y):\n",
|
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
|
" Log-likelihood for logistic regression.\n",
|
|
|
|
|
|
" \"\"\"\n",
|
|
|
|
|
|
" z = X @ beta\n",
|
|
|
|
|
|
" # Numerically stable sigmoid\n",
|
|
|
|
|
|
" p = 1 / (1 + np.exp(-np.clip(z, -500, 500)))\n",
|
|
|
|
|
|
" p = np.clip(p, 1e-10, 1 - 1e-10) # Avoid log(0)\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" log_lik = np.sum(y * np.log(p) + (1 - y) * np.log(1 - p))\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" # Add weak prior: beta ~ N(0, 10²)\n",
|
|
|
|
|
|
" log_prior = -0.5 * np.sum(beta**2) / 100\n",
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
" return log_lik + log_prior\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Prepare data tuple\n",
|
|
|
|
|
|
"logistic_data = (X_with_intercept, y)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# MCMC for logistic regression\n",
|
|
|
|
|
|
"initial_beta = np.zeros(3) # [intercept, coef1, coef2]\n",
|
|
|
|
|
|
"beta_bounds = [(-10, 10)] * 3\n",
|
|
|
|
|
|
"beta_proposal_std = [0.1] * 3\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(\"Running MCMC for logistic regression...\")\n",
|
|
|
|
|
|
"beta_samples, beta_acceptance = mcmc_sample(\n",
|
|
|
|
|
|
" log_likelihood_fn=log_likelihood_logistic,\n",
|
|
|
|
|
|
" data=logistic_data,\n",
|
|
|
|
|
|
" initial_params=initial_beta,\n",
|
|
|
|
|
|
" param_bounds=beta_bounds,\n",
|
|
|
|
|
|
" proposal_std=beta_proposal_std,\n",
|
|
|
|
|
|
" n_samples=15000,\n",
|
|
|
|
|
|
" burn_in=1500\n",
|
|
|
|
|
|
")\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(f\"\\nAcceptance rate: {beta_acceptance:.2%}\")\n",
|
|
|
|
|
|
"print(f\"\\nPosterior estimates:\")\n",
|
|
|
|
|
|
"print(f\"β₀ (intercept): {beta_samples[:, 0].mean():.3f} ± {beta_samples[:, 0].std():.3f}\")\n",
|
|
|
|
|
|
"print(f\"β₁: {beta_samples[:, 1].mean():.3f} ± {beta_samples[:, 1].std():.3f}\")\n",
|
|
|
|
|
|
"print(f\"β₂: {beta_samples[:, 2].mean():.3f} ± {beta_samples[:, 2].std():.3f}\")"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "3cc9ff7c",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"### Visualize Decision Boundary with Uncertainty"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "2eb5d0d5",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"# Plot decision boundaries from posterior samples\n",
|
|
|
|
|
|
"plt.figure(figsize=(10, 8))\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Plot data\n",
|
|
|
|
|
|
"plt.scatter(X[y == 0, 0], X[y == 0, 1], c='blue', label='Class 0', alpha=0.6, s=50, zorder=3)\n",
|
|
|
|
|
|
"plt.scatter(X[y == 1, 0], X[y == 1, 1], c='red', label='Class 1', alpha=0.6, s=50, zorder=3)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Create grid\n",
|
|
|
|
|
|
"x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1\n",
|
|
|
|
|
|
"x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Plot decision boundaries from random posterior samples\n",
|
|
|
|
|
|
"n_boundary_samples = 100\n",
|
|
|
|
|
|
"indices = np.random.choice(len(beta_samples), n_boundary_samples, replace=False)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"for idx in indices:\n",
|
|
|
|
|
|
" beta = beta_samples[idx]\n",
|
|
|
|
|
|
" # Decision boundary: β₀ + β₁x₁ + β₂x₂ = 0\n",
|
|
|
|
|
|
" # => x₂ = -(β₀ + β₁x₁) / β₂\n",
|
|
|
|
|
|
" if abs(beta[2]) > 0.01: # Avoid division by zero\n",
|
|
|
|
|
|
" x1_line = np.array([x1_min, x1_max])\n",
|
|
|
|
|
|
" x2_line = -(beta[0] + beta[1] * x1_line) / beta[2]\n",
|
|
|
|
|
|
" plt.plot(x1_line, x2_line, 'gray', alpha=0.02, linewidth=0.5, zorder=1)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"# Plot mean decision boundary\n",
|
|
|
|
|
|
"beta_mean = beta_samples.mean(axis=0)\n",
|
|
|
|
|
|
"if abs(beta_mean[2]) > 0.01:\n",
|
|
|
|
|
|
" x1_line = np.array([x1_min, x1_max])\n",
|
|
|
|
|
|
" x2_line = -(beta_mean[0] + beta_mean[1] * x1_line) / beta_mean[2]\n",
|
|
|
|
|
|
" plt.plot(x1_line, x2_line, 'black', linewidth=3, label='Mean boundary', zorder=2)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"plt.xlim(x1_min, x1_max)\n",
|
|
|
|
|
|
"plt.ylim(x2_min, x2_max)\n",
|
|
|
|
|
|
"plt.xlabel('Feature 1', fontsize=12)\n",
|
|
|
|
|
|
"plt.ylabel('Feature 2', fontsize=12)\n",
|
|
|
|
|
|
"plt.title('Logistic Regression: Decision Boundary with Uncertainty', fontsize=14, fontweight='bold')\n",
|
|
|
|
|
|
"plt.legend()\n",
|
|
|
|
|
|
"plt.grid(alpha=0.3)\n",
|
|
|
|
|
|
"plt.show()"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "8c4facb3",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"## MCMC Diagnostics\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"### Autocorrelation - Check Mixing"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "code",
|
|
|
|
|
|
"execution_count": null,
|
|
|
|
|
|
"id": "0ab8cd82",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"outputs": [],
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"from statsmodels.graphics.tsaplots import plot_acf\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"plot_acf(samples[:, 0], lags=100, ax=axes[0], alpha=0.05)\n",
|
|
|
|
|
|
"axes[0].set_title('Autocorrelation: μ', fontsize=13, fontweight='bold')\n",
|
|
|
|
|
|
"axes[0].set_xlabel('Lag', fontsize=11)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"plot_acf(samples[:, 1], lags=100, ax=axes[1], alpha=0.05)\n",
|
|
|
|
|
|
"axes[1].set_title('Autocorrelation: σ', fontsize=13, fontweight='bold')\n",
|
|
|
|
|
|
"axes[1].set_xlabel('Lag', fontsize=11)\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"plt.tight_layout()\n",
|
|
|
|
|
|
"plt.show()\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"print(\"Low autocorrelation at large lags indicates good mixing!\")"
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
"id": "e2ed2ccd",
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
"## Key Takeaways\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"1. **MCMC samples from complex distributions** using only likelihood evaluations\n",
|
|
|
|
|
|
"2. **Metropolis-Hastings** uses proposal distribution and accept/reject steps\n",
|
|
|
|
|
|
"3. **Burn-in period** allows chain to converge to target distribution\n",
|
|
|
|
|
|
"4. **Diagnostics** (trace plots, autocorrelation) verify convergence and mixing\n",
|
|
|
|
|
|
"5. **OptimizR provides 50-100x speedup** for likelihood evaluations\n",
|
|
|
|
|
|
"6. **Bayesian inference** naturally quantifies uncertainty in parameters\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"## Further Reading\n",
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
"- Gelman, A., et al. (2013). \"Bayesian Data Analysis\" - Chapter 11\n",
|
|
|
|
|
|
"- Brooks, S., et al. (2011). \"Handbook of Markov Chain Monte Carlo\"\n",
|
|
|
|
|
|
"- Betancourt, M. (2017). \"A Conceptual Introduction to Hamiltonian Monte Carlo\""
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"metadata": {
|
2026-01-06 14:36:08 +01:00
|
|
|
|
"kernelspec": {
|
|
|
|
|
|
"display_name": "rhftlab",
|
|
|
|
|
|
"language": "python",
|
|
|
|
|
|
"name": "python3"
|
|
|
|
|
|
},
|
2025-12-03 18:16:48 +01:00
|
|
|
|
"language_info": {
|
2026-01-06 14:36:08 +01:00
|
|
|
|
"codemirror_mode": {
|
|
|
|
|
|
"name": "ipython",
|
|
|
|
|
|
"version": 3
|
|
|
|
|
|
},
|
|
|
|
|
|
"file_extension": ".py",
|
|
|
|
|
|
"mimetype": "text/x-python",
|
|
|
|
|
|
"name": "python",
|
|
|
|
|
|
"nbconvert_exporter": "python",
|
|
|
|
|
|
"pygments_lexer": "ipython3",
|
|
|
|
|
|
"version": "3.11.13"
|
2025-12-03 18:16:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"nbformat": 4,
|
|
|
|
|
|
"nbformat_minor": 5
|
|
|
|
|
|
}
|