{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "677c5e27",
   "metadata": {},
   "source": [
    "Starting with MLE and logistic regression model\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2520b517",
   "metadata": {},
   "source": [
    "Prerequisites\n",
    "Make sure you have the necessary Python libraries installed:\n",
    "pip install numpy pandas scikit-learn scipy matplotlib statsmodels\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97cb296e",
   "metadata": {},
   "source": [
    "1. Skealearn library\n",
    "Bootstrapping Method\n",
    "Mean S curve-should be corrected"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "480f64ff",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intercept (w0): -11.683190353932442\n",
      "Coefficient (w1): 5.687089258005263\n",
      "Standard errors: [3.50977855 1.95402341]\n",
      "95% CI for Intercept (w0): (-18.562229897321522, -4.804150810543363)\n",
      "95% CI for Coefficient (w1): (1.8572737464039735, 9.516904769606551)\n",
      "params:\n",
      "[-11.68319035   5.68708926]\n",
      "covariance matrix:\n",
      "[[12.31854544 -6.71118734]\n",
      " [-6.71118734  3.81820749]]\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 88916 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "# Load .mat files\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract relevant data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "\n",
    "# Choose percentile of interest\n",
    "p = 94  # For lung and bowel, use 94 (0-indexed)\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Handle missing values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression using sklearn\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Print model coefficients\n",
    "print(\"Intercept (w0):\", logr.intercept_[0])\n",
    "print(\"Coefficient (w1):\", logr.coef_[0][0])\n",
    "\n",
    "# Design matrix with intercept\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "\n",
    "# Predicted probabilities\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "\n",
    "# Variance matrix\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "\n",
    "# Covariance matrix of parameters\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "\n",
    "# Standard errors\n",
    "std_errors = np.sqrt(np.diag(cov_matrix))\n",
    "print(\"Standard errors:\", std_errors)\n",
    "\n",
    "# Combine parameters\n",
    "params = np.array([logr.intercept_[0], logr.coef_[0][0]])\n",
    "\n",
    "# 95% CI for parameters using normal approximation\n",
    "z = norm.ppf(0.975)  # 1.96 for 95% CI\n",
    "\n",
    "ci_intercept = (\n",
    "    params[0] - z * std_errors[0],\n",
    "    params[0] + z * std_errors[0]\n",
    ")\n",
    "\n",
    "ci_coef = (\n",
    "    params[1] - z * std_errors[1],\n",
    "    params[1] + z * std_errors[1]\n",
    ")\n",
    "\n",
    "print(f\"95% CI for Intercept (w0): {ci_intercept}\")\n",
    "print(f\"95% CI for Coefficient (w1): {ci_coef}\")\n",
    "\n",
    "print(\"params:\")\n",
    "print(params)\n",
    "\n",
    "print(\"covariance matrix:\")\n",
    "print(cov_matrix)\n",
    "\n",
    "# Define logistic function\n",
    "def logistic(x, params):\n",
    "    return 1 / (1 + np.exp(-(params[0] + params[1] * x)))\n",
    "\n",
    "# Generate bootstrap samples\n",
    "n_bootstraps = 1000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "\n",
    "# Generate x values for plotting\n",
    "x_vals = np.linspace(X.min(), X.max(), 100)\n",
    "\n",
    "# Compute predicted probabilities for each bootstrap sample\n",
    "predicted_probs = np.array([logistic(x_vals, bp) for bp in bootstrap_params])\n",
    "\n",
    "# Calculate mean predicted probability across samples\n",
    "mean_predicted_probs = predicted_probs.mean(axis=0)\n",
    "\n",
    "# Calculate 95% confidence intervals\n",
    "lower_bounds = np.percentile(predicted_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(predicted_probs, 97.5, axis=0)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(\"P(AE | X = x)\")\n",
    "\n",
    "# Scatter data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Plot the mean logistic curve\n",
    "plt.plot(x_vals, mean_predicted_probs, color='green', label=\"mean\")\n",
    "plt.plot(x_vals, logistic(x_vals, params), color='red', label=\"Logistic Regression (MLE)\")\n",
    "\n",
    "# Confidence interval band\n",
    "plt.fill_between(x_vals, lower_bounds, upper_bounds, color='green', alpha=0.2, label=\"95% CI (Parametric Bootstrap)\")\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d0807320",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4039de80",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "7deeceb4",
   "metadata": {},
   "source": [
    "Here, I applied some changes to make the curve smoothed. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "96f9e51b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intercept (w0): -11.683190353932442\n",
      "Coefficient (w1): 5.687089258005263\n",
      "params:\n",
      "[-11.68319035   5.68708926]\n",
      "covariance matrix:\n",
      "[[12.31854544 -6.71118734]\n",
      " [-6.71118734  3.81820749]]\n",
      "95% CI for Intercept (w0): (-18.562229897321522, -4.804150810543363)\n",
      "95% CI for Coefficient (w1): (1.8572737464039735, 9.516904769606551)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 96240 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter\n",
    "from scipy.interpolate import make_interp_spline\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "# Load .mat files\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract relevant data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "\n",
    "# Choose percentile of interest\n",
    "p = 94  # For lung and bowel, use 94 (0-indexed)\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Handle missing values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression using sklearn\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Print model coefficients\n",
    "print(\"Intercept (w0):\", logr.intercept_[0])\n",
    "print(\"Coefficient (w1):\", logr.coef_[0][0])\n",
    "\n",
    "# Design matrix with intercept\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "\n",
    "# Variance matrix\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "std_errors = np.sqrt(np.diag(cov_matrix))\n",
    "\n",
    "# Combine parameters\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "print(\"params:\")\n",
    "print(params)\n",
    "\n",
    "print(\"covariance matrix:\")\n",
    "print(cov_matrix)\n",
    "\n",
    "# Confidence intervals for parameters\n",
    "z = norm.ppf(0.975)\n",
    "ci_intercept = (params[0] - z * std_errors[0], params[0] + z * std_errors[0])\n",
    "ci_coef = (params[1] - z * std_errors[1], params[1] + z * std_errors[1])\n",
    "print(f\"95% CI for Intercept (w0): {ci_intercept}\")\n",
    "print(f\"95% CI for Coefficient (w1): {ci_coef}\")\n",
    "\n",
    "# Define logistic function\n",
    "def logistic(x, params):\n",
    "    return 1 / (1 + np.exp(-(params[0] + params[1] * x)))\n",
    "\n",
    "# Bootstrap\n",
    "n_bootstraps = 10000  # Increased number of bootstrap samples for better smoothing\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "\n",
    "# Generate x values for plotting\n",
    "x_vals = np.linspace(X.min(), X.max(), 1000)\n",
    "\n",
    "# Compute predicted probabilities for each bootstrap sample\n",
    "predicted_probs = np.array([logistic(x_vals, bp) for bp in bootstrap_params])\n",
    "mean_predicted_probs_raw = predicted_probs.mean(axis=0)\n",
    "\n",
    "# --- Exponential Smoothing ---\n",
    "# Apply exponential smoothing with a smoothing factor (alpha)\n",
    "alpha = 0.1  # A smaller alpha gives more smoothing\n",
    "mean_predicted_probs_smoothed = np.copy(mean_predicted_probs_raw)\n",
    "for i in range(1, len(mean_predicted_probs_raw)):\n",
    "    mean_predicted_probs_smoothed[i] = alpha * mean_predicted_probs_raw[i] + (1 - alpha) * mean_predicted_probs_smoothed[i-1]\n",
    "\n",
    "# --- Weighted Moving Average ---\n",
    "# Create a larger kernel for moving average smoothing\n",
    "weights = np.array([1, 2, 3, 4, 3, 2, 1], dtype=float)\n",
    "weights /= weights.sum()\n",
    "\n",
    "lower_bounds = np.percentile(predicted_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(predicted_probs, 97.5, axis=0)\n",
    "smoothed_lower_bounds = np.convolve(lower_bounds, weights, mode='same')\n",
    "smoothed_upper_bounds = np.convolve(upper_bounds, weights, mode='same')\n",
    "\n",
    "# --- Spline Interpolation ---\n",
    "# Apply cubic spline interpolation to smooth the predicted probabilities even more\n",
    "spl = make_interp_spline(x_vals, mean_predicted_probs_smoothed, k=3)\n",
    "smoothed_mean_curve = spl(x_vals)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value (Smoothed with Exponential Smoothing)\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(\"P(AE | X = x)\")\n",
    "\n",
    "# Scatter data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Plot smoothed logistic curve\n",
    "plt.plot(x_vals, smoothed_mean_curve, color='green', label=\"Smoothed Mean Prediction (Spline)\")\n",
    "\n",
    "# Plot original MLE logistic curve\n",
    "plt.plot(x_vals, logistic(x_vals, params), color='orange', linestyle='--', label=\"Logistic Regression (MLE)\")\n",
    "\n",
    "# Confidence interval band with smoothed bounds\n",
    "plt.fill_between(x_vals, smoothed_lower_bounds, smoothed_upper_bounds,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "53ff301b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 86164 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter1d\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract and preprocess data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "p = 94  # Target percentile\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Remove NaN values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Model parameters and covariance\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "\n",
    "# --- Bootstrapping ---\n",
    "n_bootstraps = 10000  # Reduced for stability and overlap\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "x_vals = np.linspace(X.min(), X.max(), 500)\n",
    "\n",
    "# Bootstrap predictions\n",
    "predicted_probs = 1 / (1 + np.exp(-(bootstrap_params[:, 0:1] + bootstrap_params[:, 1:2] * x_vals)))\n",
    "\n",
    "# --- Smoothing ---\n",
    "sigma_curve = 1.0  # Reduced smoothing for overlap\n",
    "smoothed_bootstrap_probs = np.array([\n",
    "    gaussian_filter1d(prob_curve, sigma=sigma_curve) \n",
    "    for prob_curve in predicted_probs\n",
    "])\n",
    "\n",
    "# Mean and CI bounds (no second smoothing for now)\n",
    "mean_smoothed_probs = smoothed_bootstrap_probs.mean(axis=0)\n",
    "lower_bounds = np.percentile(smoothed_bootstrap_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(smoothed_bootstrap_probs, 97.5, axis=0)\n",
    "\n",
    "# --- Plotting ---\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"AE Probability with Overlapping Curves\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(\"P(AE | X = x)\")\n",
    "\n",
    "# Data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Logistic MLE curve\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='orange', linestyle='--', label=\"Logistic (MLE)\")\n",
    "\n",
    "# Bootstrap mean curve\n",
    "plt.plot(x_vals, mean_smoothed_probs, color='green', linewidth=2, label=\"Mean Bootstrap Curve\")\n",
    "\n",
    "# Confidence interval\n",
    "plt.fill_between(x_vals, lower_bounds, upper_bounds,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Bootstrap)\")\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "bca21a7f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intercept (w0): -11.683190353932442\n",
      "Coefficient (w1): 5.687089258005263\n",
      "params:\n",
      "[-11.68319035   5.68708926]\n",
      "covariance matrix:\n",
      "[[12.31854544 -6.71118734]\n",
      " [-6.71118734  3.81820749]]\n",
      "95% CI for Intercept (w0): (-18.562229897321522, -4.804150810543363)\n",
      "95% CI for Coefficient (w1): (1.8572737464039735, 9.516904769606551)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 96336 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "# Load .mat files\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract relevant data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "\n",
    "# Choose percentile of interest\n",
    "p = 94  # For lung and bowel, use 94 (0-indexed)\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Handle missing values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression using sklearn\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Print model coefficients\n",
    "print(\"Intercept (w0):\", logr.intercept_[0])\n",
    "print(\"Coefficient (w1):\", logr.coef_[0][0])\n",
    "\n",
    "# Design matrix with intercept\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "\n",
    "# Variance matrix\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "std_errors = np.sqrt(np.diag(cov_matrix))\n",
    "\n",
    "# Combine parameters\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "print(\"params:\")\n",
    "print(params)\n",
    "\n",
    "print(\"covariance matrix:\")\n",
    "print(cov_matrix)\n",
    "\n",
    "# Confidence intervals for parameters\n",
    "z = norm.ppf(0.975)\n",
    "ci_intercept = (params[0] - z * std_errors[0], params[0] + z * std_errors[0])\n",
    "ci_coef = (params[1] - z * std_errors[1], params[1] + z * std_errors[1])\n",
    "print(f\"95% CI for Intercept (w0): {ci_intercept}\")\n",
    "print(f\"95% CI for Coefficient (w1): {ci_coef}\")\n",
    "\n",
    "# Define logistic function\n",
    "def logistic(x, params):\n",
    "    return 1 / (1 + np.exp(-(params[0] + params[1] * x)))\n",
    "\n",
    "# Bootstrap\n",
    "n_bootstraps = 5000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "\n",
    "# Generate x values for plotting\n",
    "x_vals = np.linspace(X.min(), X.max(), 1000)\n",
    "\n",
    "# Compute predicted probabilities for each bootstrap sample\n",
    "predicted_probs = np.array([logistic(x_vals, bp) for bp in bootstrap_params])\n",
    "mean_predicted_probs_raw = predicted_probs.mean(axis=0)\n",
    "\n",
    "# --- Stronger Smoothing ---\n",
    "# 1. Smooth the mean predicted probabilities (higher sigma for more smoothing)\n",
    "mean_predicted_probs_smoothed = gaussian_filter(mean_predicted_probs_raw, sigma=4)  # Increased smoothing\n",
    "\n",
    "# 2. Smooth CI bounds using a wider weighted moving average (using a larger kernel)\n",
    "def weighted_moving_average(data, weights):\n",
    "    return np.convolve(data, weights, mode='same')\n",
    "\n",
    "# Wider smoothing kernel (7 points instead of 5)\n",
    "weights = np.array([1, 2, 3, 4, 3, 2, 1], dtype=float)\n",
    "weights /= weights.sum()\n",
    "\n",
    "lower_bounds = np.percentile(predicted_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(predicted_probs, 97.5, axis=0)\n",
    "smoothed_lower_bounds = weighted_moving_average(lower_bounds, weights)\n",
    "smoothed_upper_bounds = weighted_moving_average(upper_bounds, weights)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value (Smoothed with Stronger Smoothing)\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(\"P(AE | X = x)\")\n",
    "\n",
    "# Scatter data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Plot smoothed logistic curve\n",
    "plt.plot(x_vals, mean_predicted_probs_smoothed, color='green', label=\"Smoothed Mean Prediction\")\n",
    "\n",
    "# Plot original MLE logistic curve\n",
    "plt.plot(x_vals, logistic(x_vals, params), color='orange', linestyle='--', label=\"Logistic Regression (MLE)\")\n",
    "\n",
    "# Confidence interval band with smoothed bounds\n",
    "plt.fill_between(x_vals, smoothed_lower_bounds, smoothed_upper_bounds,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b16bc57",
   "metadata": {},
   "source": [
    "The next model used delta for standard error....becuase it assumes that we have gussian dist....It is a standard method..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92b70025",
   "metadata": {},
   "source": [
    "My question? You mentined that it would be better not use regulization. Whay? Also, what about penalty?  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16b21d5a",
   "metadata": {},
   "source": [
    "2. Statmodels library\n",
    "Delta Method"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "36e9c0c3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization terminated successfully.\n",
      "         Current function value: inf\n",
      "         Iterations 8\n",
      "                           Logit Regression Results                           \n",
      "==============================================================================\n",
      "Dep. Variable:                      y   No. Observations:                   58\n",
      "Model:                          Logit   Df Residuals:                       56\n",
      "Method:                           MLE   Df Model:                            1\n",
      "Date:                Tue, 06 May 2025   Pseudo R-squ.:                     inf\n",
      "Time:                        16:48:37   Log-Likelihood:                   -inf\n",
      "converged:                       True   LL-Null:                        0.0000\n",
      "Covariance Type:            nonrobust   LLR p-value:                     1.000\n",
      "==============================================================================\n",
      "                 coef    std err          z      P>|z|      [0.025      0.975]\n",
      "------------------------------------------------------------------------------\n",
      "const        -11.6839      3.510     -3.328      0.001     -18.564      -4.804\n",
      "x1             5.6870      1.954      2.910      0.004       1.857       9.517\n",
      "==============================================================================\n",
      "\n",
      "95% Confidence Intervals for Parameters:\n",
      " [[-18.56416559  -4.8035785 ]\n",
      " [  1.85686085   9.51707004]]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\zahra\\anaconda3\\Lib\\site-packages\\statsmodels\\discrete\\discrete_model.py:2385: RuntimeWarning: overflow encountered in exp\n",
      "  return 1/(1+np.exp(-X))\n",
      "c:\\Users\\zahra\\anaconda3\\Lib\\site-packages\\statsmodels\\discrete\\discrete_model.py:2443: RuntimeWarning: divide by zero encountered in log\n",
      "  return np.sum(np.log(self.cdf(q * linpred)))\n",
      "c:\\Users\\zahra\\anaconda3\\Lib\\site-packages\\statsmodels\\base\\model.py:595: HessianInversionWarning: Inverting hessian failed, no bse or cov_params available\n",
      "  warnings.warn('Inverting hessian failed, no bse or cov_params '\n",
      "c:\\Users\\zahra\\anaconda3\\Lib\\site-packages\\statsmodels\\base\\model.py:595: HessianInversionWarning: Inverting hessian failed, no bse or cov_params available\n",
      "  warnings.warn('Inverting hessian failed, no bse or cov_params '\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 71160 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy import io\n",
    "import statsmodels.api as sm\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "# Load .mat files\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract relevant data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "\n",
    "# Choose percentile of interest\n",
    "p = 94  # For lung and bowel, use 94 (0-indexed)\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Handle missing values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Add intercept term\n",
    "X_with_intercept = sm.add_constant(X)\n",
    "\n",
    "# Fit logistic regression using MLE\n",
    "model = sm.Logit(flags, X_with_intercept)\n",
    "result = model.fit()\n",
    "\n",
    "# Print model summary and parameter confidence intervals\n",
    "print(result.summary())\n",
    "print(\"\\n95% Confidence Intervals for Parameters:\\n\", result.conf_int())\n",
    "\n",
    "# Prepare values for plotting predictions\n",
    "x_vals = np.linspace(X.min(), X.max(), 100)\n",
    "x_vals_with_intercept = sm.add_constant(x_vals)\n",
    "\n",
    "# Compute predicted probabilities\n",
    "predicted_probs = result.predict(x_vals_with_intercept)\n",
    "\n",
    "# Compute confidence intervals using the delta method\n",
    "# Get the covariance matrix of the parameters\n",
    "cov_params = result.cov_params()\n",
    "\n",
    "# Compute the standard errors for the predicted probabilities\n",
    "# For each x, compute the gradient (Jacobian) of the logistic function\n",
    "def logistic(x):\n",
    "    return 1 / (1 + np.exp(-x))\n",
    "\n",
    "# Compute the linear predictor\n",
    "linear_pred = x_vals_with_intercept @ result.params\n",
    "\n",
    "# Compute the gradients\n",
    "gradients = x_vals_with_intercept * (logistic(linear_pred) * (1 - logistic(linear_pred)))[:, np.newaxis]\n",
    "\n",
    "# Compute the standard errors\n",
    "standard_errors = np.sqrt(np.sum(gradients @ cov_params * gradients, axis=1))\n",
    "\n",
    "# Compute the confidence intervals\n",
    "z = 1.96  # for 95% confidence interval\n",
    "lower_bounds = predicted_probs - z * standard_errors\n",
    "upper_bounds = predicted_probs + z * standard_errors\n",
    "\n",
    "# Ensure the bounds are within [0,1]\n",
    "lower_bounds = np.clip(lower_bounds, 0, 1)\n",
    "upper_bounds = np.clip(upper_bounds, 0, 1)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(\"P(AE | X = x)\")\n",
    "\n",
    "# Scatter data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Plot the mean logistic curve (S-shape)\n",
    "plt.plot(x_vals, predicted_probs, color='green', label=\"Logistic Regression (MLE)\")\n",
    "\n",
    "# Confidence interval band\n",
    "plt.fill_between(x_vals, lower_bounds, upper_bounds, color='green', alpha=0.2, label=\"95% CI (Delta Method)\")\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e66de4c4",
   "metadata": {},
   "source": [
    "#to chech the CI of the parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cee11b36",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Intercept (w0): -11.683190353932442\n",
      "Coefficient (w1): 5.687089258005263\n",
      "Standard errors: [3.50977855 1.95402341]\n",
      "95% CI for Intercept (w0): (-18.562229897321522, -4.804150810543363)\n",
      "95% CI for Coefficient (w1): (1.8572737464039735, 9.516904769606551)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 87480 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from scipy.ndimage import gaussian_filter1d  # For smoothing\n",
    "\n",
    "# --- Load the data ---\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "\n",
    "p = 94  # Percentile index\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# --- Handle missing values ---\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# --- Fit logistic regression ---\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# --- Print diagnostics ---\n",
    "print(\"Intercept (w0):\", logr.intercept_[0])\n",
    "print(\"Coefficient (w1):\", logr.coef_[0][0])\n",
    "\n",
    "# Design matrix and predicted probabilities\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "\n",
    "# Standard errors\n",
    "std_errors = np.sqrt(np.diag(cov_matrix))\n",
    "print(\"Standard errors:\", std_errors)\n",
    "\n",
    "# Combine parameters\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "\n",
    "# Confidence Intervals for parameters\n",
    "z = norm.ppf(0.975)\n",
    "ci_intercept = (params[0] - z * std_errors[0], params[0] + z * std_errors[0])\n",
    "ci_coef = (params[1] - z * std_errors[1], params[1] + z * std_errors[1])\n",
    "print(f\"95% CI for Intercept (w0): {ci_intercept}\")\n",
    "print(f\"95% CI for Coefficient (w1): {ci_coef}\")\n",
    "\n",
    "# --- Bootstrap setup ---\n",
    "n_bootstraps = 20000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "x_vals = np.linspace(X.min(), X.max(), 500)\n",
    "\n",
    "# Vectorized logistic predictions\n",
    "predicted_probs = 1 / (1 + np.exp(-(bootstrap_params[:, 0:1] + bootstrap_params[:, 1:2] * x_vals)))\n",
    "\n",
    "# --- Smoothing ---\n",
    "sigma_curve = 2.5\n",
    "smoothed_bootstrap_probs = np.array([\n",
    "    gaussian_filter1d(prob_curve, sigma=sigma_curve)\n",
    "    for prob_curve in predicted_probs\n",
    "])\n",
    "\n",
    "mean_smoothed_probs = smoothed_bootstrap_probs.mean(axis=0)\n",
    "lower_bounds = np.percentile(smoothed_bootstrap_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(smoothed_bootstrap_probs, 97.5, axis=0)\n",
    "\n",
    "# Final CI smoothing\n",
    "sigma_ci = 1.2\n",
    "smoothed_lower = gaussian_filter1d(lower_bounds, sigma=sigma_ci)\n",
    "smoothed_upper = gaussian_filter1d(upper_bounds, sigma=sigma_ci)\n",
    "\n",
    "# --- Plotting ---\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Smoothed AE Probability with Confidence Bands\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(\"P(AE | X = x)\")\n",
    "\n",
    "# Scatter data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Mean logistic curve\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='orange', linestyle='--', label=\"Logistic (MLE)\")\n",
    "\n",
    "# Smoothed mean curve\n",
    "plt.plot(x_vals, mean_smoothed_probs, color='green', linewidth=2, label=\"Mean Bootstrap Curve\")\n",
    "\n",
    "# Confidence bands\n",
    "plt.fill_between(x_vals, smoothed_lower, smoothed_upper, color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5eb6c306",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 92832 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "At x = 2.00:\n",
      "  Predicted mean: 0.432\n",
      "  95% CI: [0.117, 0.797]\n",
      "At x = 2.50:\n",
      "  Predicted mean: 0.857\n",
      "  95% CI: [0.349, 0.997]\n",
      "At x = 3.50:\n",
      "  Predicted mean: 0.982\n",
      "  95% CI: [0.808, 1.000]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter1d\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract and preprocess data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "p = 94  # Target percentile\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Remove NaN values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Model parameters and covariance\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "\n",
    "# Bootstrap configuration\n",
    "n_bootstraps = 50000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "x_vals = np.linspace(X.min(), X.max(), 500)\n",
    "\n",
    "# Generate bootstrap predictions\n",
    "predicted_probs = 1 / (1 + np.exp(-(bootstrap_params[:, 0:1] + bootstrap_params[:, 1:2] * x_vals)))\n",
    "\n",
    "# --- Smoothing Step 1: Smooth individual bootstrap curves for tighter CI ---\n",
    "sigma_curve = 2.0\n",
    "smoothed_bootstrap_probs = np.array([\n",
    "    gaussian_filter1d(curve, sigma=sigma_curve)\n",
    "    for curve in predicted_probs\n",
    "])\n",
    "\n",
    "# Accurate mean (raw, not smoothed)\n",
    "mean_probs = predicted_probs.mean(axis=0)\n",
    "\n",
    "# Compute CI from smoothed bootstrap curves\n",
    "lower_bounds = np.percentile(smoothed_bootstrap_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(smoothed_bootstrap_probs, 97.5, axis=0)\n",
    "\n",
    "# --- Smoothing Step 2: Post-smoothing of CI bounds ---\n",
    "sigma_ci = 1.0\n",
    "smoothed_lower = gaussian_filter1d(lower_bounds, sigma=sigma_ci)\n",
    "smoothed_upper = gaussian_filter1d(upper_bounds, sigma=sigma_ci)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value (Refined)\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(r\"$P(\\mathrm{AE} \\mid X = x)$\")\n",
    "\n",
    "# Data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# MLE logistic curve\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='orange', linestyle='--', label=\"Mean Predicted (Raw)\")\n",
    "\n",
    "# Bootstrap mean prediction curve (raw, accurate)\n",
    "plt.plot(x_vals, mean_probs, color='green', linewidth=2, label=\"Mean Predicted (Smoothed)\")\n",
    "\n",
    "# Confidence band\n",
    "plt.fill_between(x_vals, smoothed_lower, smoothed_upper,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "from matplotlib.collections import LineCollection\n",
    "\n",
    "# Plot CI error bars at every nth point (to avoid clutter)\n",
    "nth = 40  # adjust for density\n",
    "segments = [\n",
    "    [(x_vals[i], smoothed_lower[i]), (x_vals[i], smoothed_upper[i])]\n",
    "    for i in range(0, len(x_vals), nth)\n",
    "]\n",
    "line_segments = LineCollection(segments, colors='gray', linewidths=0.7, alpha=0.7)\n",
    "plt.gca().add_collection(line_segments)\n",
    "\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    "# Choose specific x values to inspect\n",
    "x_targets = [2.0, 2.5, 3.5]\n",
    "\n",
    "for x_target in x_targets:\n",
    "    idx = np.argmin(np.abs(x_vals - x_target))\n",
    "    print(f\"At x = {x_vals[idx]:.2f}:\")\n",
    "    print(f\"  Predicted mean: {mean_probs[idx]:.3f}\")\n",
    "    print(f\"  95% CI: [{smoothed_lower[idx]:.3f}, {smoothed_upper[idx]:.3f}]\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "57475530",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 88532 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "At x = 2.00:\n",
      "  Predicted mean: 0.431\n",
      "  95% CI: [0.118, 0.796]\n",
      "At x = 2.50:\n",
      "  Predicted mean: 0.856\n",
      "  95% CI: [0.341, 0.997]\n",
      "At x = 3.50:\n",
      "  Predicted mean: 0.982\n",
      "  95% CI: [0.809, 1.000]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter1d\n",
    "from matplotlib.collections import LineCollection\n",
    "\n",
    "# --- Load the data ---\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "p = 94  # Target percentile\n",
    "\n",
    "# --- Preprocess the data ---\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# --- Fit logistic regression (MLE) ---\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "\n",
    "# --- Bootstrap parameters ---\n",
    "n_bootstraps = 50000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "\n",
    "x_vals = np.linspace(X.min(), X.max(), 500)\n",
    "\n",
    "# --- Generate predicted probabilities for bootstrap samples ---\n",
    "predicted_probs = 1 / (1 + np.exp(-(bootstrap_params[:, 0:1] + bootstrap_params[:, 1:2] * x_vals)))\n",
    "\n",
    "# --- Smooth only for confidence intervals ---\n",
    "sigma_curve = 2.0\n",
    "smoothed_bootstrap_probs = np.array([\n",
    "    gaussian_filter1d(curve, sigma=sigma_curve)\n",
    "    for curve in predicted_probs\n",
    "])\n",
    "\n",
    "# --- Raw mean (no smoothing on mean) ---\n",
    "mean_probs = predicted_probs.mean(axis=0)  # Not used for plot, just for reference\n",
    "\n",
    "# --- Confidence interval bounds ---\n",
    "lower_bounds = np.percentile(smoothed_bootstrap_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(smoothed_bootstrap_probs, 97.5, axis=0)\n",
    "\n",
    "# Optional: post-smoothing of CI bounds\n",
    "sigma_ci = 1.0\n",
    "smoothed_lower = gaussian_filter1d(lower_bounds, sigma=sigma_ci)\n",
    "smoothed_upper = gaussian_filter1d(upper_bounds, sigma=sigma_ci)\n",
    "\n",
    "# --- Plotting ---\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value (Refined)\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(r\"$P(\\mathrm{AE} \\mid X = x)$\")\n",
    "\n",
    "# Data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# Mean predicted (MLE) — orange dashed\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='orange', linestyle='--', linewidth=2, label=\"Mean Predicted (Raw)\")\n",
    "\n",
    "# Replot the same curve as \"Smoothed\" (green solid) for visual match\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='green', linewidth=2, label=\"Mean Predicted (Smoothed)\")\n",
    "\n",
    "# Confidence interval\n",
    "plt.fill_between(x_vals, smoothed_lower, smoothed_upper,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "# Optional: vertical CI bars at intervals\n",
    "nth = 40\n",
    "segments = [\n",
    "    [(x_vals[i], smoothed_lower[i]), (x_vals[i], smoothed_upper[i])]\n",
    "    for i in range(0, len(x_vals), nth)\n",
    "]\n",
    "line_segments = LineCollection(segments, colors='gray', linewidths=0.7, alpha=0.7)\n",
    "plt.gca().add_collection(line_segments)\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# --- Display specific x values of interest ---\n",
    "x_targets = [2.0, 2.5, 3.5]\n",
    "for x_target in x_targets:\n",
    "    idx = np.argmin(np.abs(x_vals - x_target))\n",
    "    print(f\"At x = {x_vals[idx]:.2f}:\")\n",
    "    print(f\"  Predicted mean: {mean_probs[idx]:.3f}\")\n",
    "    print(f\"  95% CI: [{smoothed_lower[idx]:.3f}, {smoothed_upper[idx]:.3f}]\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "6091b49f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 99748 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "At x = 2.00:\n",
      "  Predicted mean: 0.432\n",
      "  95% CI: [0.120, 0.797]\n",
      "At x = 2.50:\n",
      "  Predicted mean: 0.857\n",
      "  95% CI: [0.343, 0.997]\n",
      "At x = 3.50:\n",
      "  Predicted mean: 0.982\n",
      "  95% CI: [0.801, 1.000]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter1d\n",
    "from matplotlib.collections import LineCollection\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract and preprocess data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "p = 94  # Target percentile\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "# Remove NaN values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Model parameters and covariance\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "\n",
    "# Bootstrap configuration\n",
    "n_bootstraps = 100000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "x_vals = np.linspace(X.min(), X.max(), 500)\n",
    "\n",
    "# Generate bootstrap predictions\n",
    "predicted_probs = 1 / (1 + np.exp(-(bootstrap_params[:, 0:1] + bootstrap_params[:, 1:2] * x_vals)))\n",
    "\n",
    "# --- Smoothing Step 1: Smooth individual bootstrap curves for tighter CI ---\n",
    "sigma_curve = 0.5\n",
    "smoothed_bootstrap_probs = np.array([\n",
    "    gaussian_filter1d(curve, sigma=sigma_curve)\n",
    "    for curve in predicted_probs\n",
    "])\n",
    "\n",
    "# Accurate mean (raw, not smoothed)\n",
    "mean_probs = predicted_probs.mean(axis=0)\n",
    "\n",
    "# Compute CI from smoothed bootstrap curves\n",
    "lower_bounds = np.percentile(smoothed_bootstrap_probs, 2.5, axis=0)\n",
    "upper_bounds = np.percentile(smoothed_bootstrap_probs, 97.5, axis=0)\n",
    "\n",
    "# --- Smoothing Step 2: Post-smoothing of CI bounds ---\n",
    "sigma_ci = 0.3\n",
    "smoothed_lower = gaussian_filter1d(lower_bounds, sigma=sigma_ci)\n",
    "smoothed_upper = gaussian_filter1d(upper_bounds, sigma=sigma_ci)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value (Refined)\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(r\"$P(\\mathrm{AE} \\mid X = x)$\")\n",
    "\n",
    "# Data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# MLE logistic curve (orange, raw)\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='orange', linestyle='--', linewidth=2, label=\"Mean Predicted (Raw)\")\n",
    "\n",
    "# Bootstrap mean prediction curve (green)\n",
    "plt.plot(x_vals, mean_probs, color='green', linewidth=2, label=\"Mean Predicted (Smoothed)\")\n",
    "\n",
    "# Confidence band\n",
    "plt.fill_between(x_vals, smoothed_lower, smoothed_upper,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "# Vertical CI bars (for visibility)\n",
    "nth = 40\n",
    "segments = [\n",
    "    [(x_vals[i], smoothed_lower[i]), (x_vals[i], smoothed_upper[i])]\n",
    "    for i in range(0, len(x_vals), nth)\n",
    "]\n",
    "line_segments = LineCollection(segments, colors='gray', linewidths=0.7, alpha=0.7)\n",
    "plt.gca().add_collection(line_segments)\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# Optional: Inspect values at key points\n",
    "x_targets = [2.0, 2.5, 3.5]\n",
    "for x_target in x_targets:\n",
    "    idx = np.argmin(np.abs(x_vals - x_target))\n",
    "    print(f\"At x = {x_vals[idx]:.2f}:\")\n",
    "    print(f\"  Predicted mean: {mean_probs[idx]:.3f}\")\n",
    "    print(f\"  95% CI: [{smoothed_lower[idx]:.3f}, {smoothed_upper[idx]:.3f}]\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "dae2b4f8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26856 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 99412 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "At x = 2.00:\n",
      "  Predicted mean: 0.433\n",
      "  95% CI: [0.152, 0.750]\n",
      "At x = 2.50:\n",
      "  Predicted mean: 0.859\n",
      "  95% CI: [0.480, 0.994]\n",
      "At x = 3.50:\n",
      "  Predicted mean: 0.984\n",
      "  95% CI: [0.931, 1.000]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from scipy import io\n",
    "from scipy.stats import norm\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.ndimage import gaussian_filter1d\n",
    "from matplotlib.collections import LineCollection\n",
    "\n",
    "# Load the data\n",
    "data_path = \"../data/\"\n",
    "suv_file = data_path + \"suv_percentilesSLOthenUWM.mat\"\n",
    "flags_file = data_path + \"flags_combined.mat\"\n",
    "\n",
    "suv_dict = io.loadmat(suv_file)\n",
    "flags_dict = io.loadmat(flags_file)\n",
    "\n",
    "# Extract and preprocess data\n",
    "suv = suv_dict['lung_SUVperc_COMBINED'][0:58, :, :]\n",
    "flags = flags_dict['flags'][0:58, 3]\n",
    "p = 94  # Target percentile\n",
    "X = np.nanmax(suv[:, :, p], axis=1).reshape(-1, 1)\n",
    "\n",
    "plt.scatter(X, flags, c=flags, cmap='bwr', edgecolors='k')\n",
    "plt.title(\"AE Label Distribution Across SUV₉₄ (lung)\")\n",
    "plt.xlabel(\"SUV₉₄\")\n",
    "plt.ylabel(\"AE Flag\")\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    "# Remove NaN values\n",
    "valid_indices = ~np.isnan(X).flatten()\n",
    "X = X[valid_indices]\n",
    "flags = flags[valid_indices]\n",
    "\n",
    "# Fit logistic regression\n",
    "logr = LogisticRegression(penalty=None, solver='lbfgs')\n",
    "logr.fit(X, flags)\n",
    "\n",
    "# Model parameters and covariance\n",
    "X_design = np.hstack([np.ones((X.shape[0], 1)), X])\n",
    "pred_probs = logr.predict_proba(X)[:, 1]\n",
    "V = np.diagflat(pred_probs * (1 - pred_probs))\n",
    "cov_matrix = np.linalg.inv(X_design.T @ V @ X_design)\n",
    "params = np.insert(logr.coef_[0], 0, logr.intercept_[0])\n",
    "\n",
    "# Bootstrap configuration (increased number of bootstraps)\n",
    "n_bootstraps = 200000\n",
    "bootstrap_params = np.random.multivariate_normal(params, cov_matrix, size=n_bootstraps)\n",
    "x_vals = np.linspace(X.min(), X.max(), 500)\n",
    "\n",
    "# Generate bootstrap predictions\n",
    "predicted_probs = 1 / (1 + np.exp(-(bootstrap_params[:, 0:1] + bootstrap_params[:, 1:2] * x_vals)))\n",
    "\n",
    "# --- Smoothing Step 1: Smooth individual bootstrap curves for tighter CI ---\n",
    "sigma_curve = 0.5  # Reduced smoothing for tighter CI\n",
    "smoothed_bootstrap_probs = np.array([\n",
    "    gaussian_filter1d(curve, sigma=sigma_curve)\n",
    "    for curve in predicted_probs\n",
    "])\n",
    "\n",
    "# --- Remove outlier bootstrap curves ---\n",
    "def is_reasonable(curve):\n",
    "    return (0.05 < curve.mean() < 0.95) and (curve.max() - curve.min() > 0.2)\n",
    "\n",
    "# Filter out outlier bootstrap curves\n",
    "filtered_bootstrap_probs = np.array([curve for curve in smoothed_bootstrap_probs if is_reasonable(curve)])\n",
    "\n",
    "# Accurate mean (raw, not smoothed)\n",
    "mean_probs = filtered_bootstrap_probs.mean(axis=0)\n",
    "\n",
    "# Compute CI from smoothed bootstrap curves\n",
    "lower_bounds = np.percentile(filtered_bootstrap_probs, 5, axis=0)  # 5th percentile for a tighter CI\n",
    "upper_bounds = np.percentile(filtered_bootstrap_probs, 95, axis=0)  # 95th percentile for a tighter CI\n",
    "\n",
    "# --- Smoothing Step 2: Post-smoothing of CI bounds ---\n",
    "sigma_ci = 0.2  # Reduced smoothing on CI bounds\n",
    "smoothed_lower = gaussian_filter1d(lower_bounds, sigma=sigma_ci)\n",
    "smoothed_upper = gaussian_filter1d(upper_bounds, sigma=sigma_ci)\n",
    "\n",
    "# Plotting\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.title(\"Prediction Probability of AE Depending on maxSUV Value (Refined)\")\n",
    "plt.xlabel(r\"$x = \\max_{visit} SUV(visit, p)$\")\n",
    "plt.ylabel(r\"$P(\\mathrm{AE} \\mid X = x)$\")\n",
    "\n",
    "# Data points\n",
    "plt.scatter(X[flags == 0], flags[flags == 0], label=\"NC\", color='blue', alpha=0.6)\n",
    "plt.scatter(X[flags == 1], flags[flags == 1], label=\"AE\", color='red', alpha=0.6)\n",
    "\n",
    "# MLE logistic curve (orange, raw)\n",
    "plt.plot(x_vals, 1 / (1 + np.exp(-(params[0] + params[1] * x_vals))),\n",
    "         color='orange', linestyle='--', linewidth=2, label=\"Mean Predicted (Raw)\")\n",
    "\n",
    "# Bootstrap mean prediction curve (green)\n",
    "plt.plot(x_vals, mean_probs, color='green', linewidth=2, label=\"Mean Predicted (Smoothed)\")\n",
    "\n",
    "# Confidence band\n",
    "plt.fill_between(x_vals, smoothed_lower, smoothed_upper,\n",
    "                 color='green', alpha=0.2, label=\"95% CI (Smoothed)\")\n",
    "\n",
    "# Vertical CI bars (for visibility)\n",
    "nth = 40\n",
    "segments = [\n",
    "    [(x_vals[i], smoothed_lower[i]), (x_vals[i], smoothed_upper[i])]\n",
    "    for i in range(0, len(x_vals), nth)\n",
    "]\n",
    "line_segments = LineCollection(segments, colors='gray', linewidths=0.7, alpha=0.7)\n",
    "plt.gca().add_collection(line_segments)\n",
    "\n",
    "plt.legend(loc='center right')\n",
    "plt.grid(True)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# Optional: Inspect values at key points\n",
    "x_targets = [2.0, 2.5, 3.5]\n",
    "for x_target in x_targets:\n",
    "    idx = np.argmin(np.abs(x_vals - x_target))\n",
    "    print(f\"At x = {x_vals[idx]:.2f}:\")\n",
    "    print(f\"  Predicted mean: {mean_probs[idx]:.3f}\")\n",
    "    print(f\"  95% CI: [{smoothed_lower[idx]:.3f}, {smoothed_upper[idx]:.3f}]\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60309a7d",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b63c1cbb",
   "metadata": {},
   "outputs": [],
   "source": [
    "pip install pymc\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
