From ef0df0e9dfc086839c67ddf842a773faaa30baf3 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Fri, 6 Mar 2026 23:25:23 +0530 Subject: [PATCH 01/13] Set final segplus notebook, persona outputs schema, and project scaffolding --- .gitignore | 27 + Clustering1.ipynb | 347 ++++ Data_generator.ipynb | 272 ++++ README.md | 37 + architecture.md.resolved | 238 +++ architecture_detailed.html | 952 +++++++++++ architecture_presentation.html | 988 ++++++++++++ cluster_evaluation.py | 381 +++++ clustering.py | 311 ++++ config.py | 181 +++ dashboard.py | 317 ++++ data/.gitkeep | 0 data_import.py | 275 ++++ domains/_template.yaml | 51 + domains/financial_services.yaml | 113 ++ domains/retail.yaml | 104 ++ eda_preprocessing.py | 412 +++++ implementation_plan.md.resolved | 131 ++ main.py | 275 ++++ notebook.ipynb | 1295 +++++++++++++++ persona_generation.py | 318 ++++ persona_identification_pipeline.ipynb | 2120 +++++++++++++++++++++++++ requirements.txt | 13 + segplus/clustering.py | 131 ++ segplus/config.py | 146 ++ segplus/data_input.py | 140 ++ segplus/evaluation.py | 212 +++ segplus/experiment_log.py | 135 ++ segplus/explainability.py | 300 ++++ segplus/feature_engineering.py | 141 ++ segplus/final_segplus_pipeline.ipynb | 1295 +++++++++++++++ segplus/final_segplus_pipeline2.ipynb | 1295 +++++++++++++++ segplus/modeling_loop.py | 273 ++++ segplus/ollama_client.py | 162 ++ segplus/persona_generation.py | 675 ++++++++ segplus/persona_generator.py | 5 + segplus/pipeline.py | 16 + segplus/types.py | 210 +++ segplus/visualization.py | 439 +++++ 39 files changed, 14733 insertions(+) create mode 100644 .gitignore create mode 100644 Clustering1.ipynb create mode 100644 Data_generator.ipynb create mode 100644 README.md create mode 100644 architecture.md.resolved create mode 100644 architecture_detailed.html create mode 100644 architecture_presentation.html create mode 100644 cluster_evaluation.py create mode 100644 clustering.py create mode 100644 config.py create mode 100644 dashboard.py create mode 100644 data/.gitkeep create mode 100644 data_import.py create mode 100644 domains/_template.yaml create mode 100644 domains/financial_services.yaml create mode 100644 domains/retail.yaml create mode 100644 eda_preprocessing.py create mode 100644 implementation_plan.md.resolved create mode 100644 main.py create mode 100644 notebook.ipynb create mode 100644 persona_generation.py create mode 100644 persona_identification_pipeline.ipynb create mode 100644 requirements.txt create mode 100644 segplus/clustering.py create mode 100644 segplus/config.py create mode 100644 segplus/data_input.py create mode 100644 segplus/evaluation.py create mode 100644 segplus/experiment_log.py create mode 100644 segplus/explainability.py create mode 100644 segplus/feature_engineering.py create mode 100644 segplus/final_segplus_pipeline.ipynb create mode 100644 segplus/final_segplus_pipeline2.ipynb create mode 100644 segplus/modeling_loop.py create mode 100644 segplus/ollama_client.py create mode 100644 segplus/persona_generation.py create mode 100644 segplus/persona_generator.py create mode 100644 segplus/pipeline.py create mode 100644 segplus/types.py create mode 100644 segplus/visualization.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc15621 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Data and binaries +*.xlsx +*.xls +*.parquet +*.csv +*.exe + +# Outputs +output/ +persona_output/ +segplus_output/ + +# Python cache +__pycache__/ +*.pyc + +# Env +.venv/ +venv/ + +# OS +.DS_Store +Thumbs.db + +Claude code/ +data/* +!data/.gitkeep diff --git a/Clustering1.ipynb b/Clustering1.ipynb new file mode 100644 index 0000000..2ca7357 --- /dev/null +++ b/Clustering1.ipynb @@ -0,0 +1,347 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "81ef225d", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from dataclasses import dataclass\n", + "from typing import Dict, List, Tuple\n", + "\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.decomposition import PCA\n", + "\n", + "from sklearn.cluster import KMeans, DBSCAN\n", + "from sklearn.mixture import GaussianMixture\n", + "\n", + "from sklearn.metrics import (\n", + " silhouette_score,\n", + " calinski_harabasz_score,\n", + " davies_bouldin_score\n", + ")\n", + "\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "af3ca3d7", + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass\n", + "class ClusterResult:\n", + " \n", + " algorithm: str\n", + " labels: np.ndarray\n", + " metadata: Dict\n", + "\n", + "\n", + "@dataclass\n", + "class EvaluationResult:\n", + "\n", + " algorithm: str\n", + " silhouette: float\n", + " calinski: float\n", + " davies: float\n", + "\n", + "\n", + "@dataclass\n", + "class PipelineState:\n", + "\n", + " raw_df: pd.DataFrame\n", + " feature_df: pd.DataFrame\n", + " X_scaled: np.ndarray\n", + " X_embedding: np.ndarray\n", + "\n", + " cluster_results: Dict[str, ClusterResult] = None\n", + " evaluation_results: Dict[str, EvaluationResult] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "13982a78", + "metadata": {}, + "outputs": [], + "source": [ + "class DataInputService:\n", + "\n", + " def __init__(self, file_path: str):\n", + " self.file_path = file_path\n", + "\n", + " def load(self) -> pd.DataFrame:\n", + "\n", + " df = pd.read_csv(self.file_path)\n", + "\n", + " if df.empty:\n", + " raise ValueError(\"Dataset is empty\")\n", + "\n", + " return df\n", + "\n", + "\n", + " def validate(self, df: pd.DataFrame) -> Dict:\n", + "\n", + " report = {\n", + " \"rows\": len(df),\n", + " \"columns\": len(df.columns),\n", + " \"missing_values\": df.isna().sum().to_dict(),\n", + " \"duplicates\": int(df.duplicated().sum())\n", + " }\n", + "\n", + " return report" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "1a83d30c", + "metadata": {}, + "outputs": [], + "source": [ + "class FeatureEngineeringPipeline:\n", + "\n", + " def __init__(self, pca_variance: float = 0.85):\n", + "\n", + " self.scaler = StandardScaler()\n", + " self.pca = PCA(n_components=pca_variance)\n", + "\n", + "\n", + " def run(self, df: pd.DataFrame):\n", + "\n", + " numeric_df = df.select_dtypes(include=[\"int64\",\"float64\"]).copy()\n", + "\n", + " X_scaled = self.scaler.fit_transform(numeric_df)\n", + "\n", + " X_emb = self.pca.fit_transform(X_scaled)\n", + "\n", + " return numeric_df, X_scaled, X_emb" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "385f0fcf", + "metadata": {}, + "outputs": [], + "source": [ + "class BaseClustering:\n", + "\n", + " def fit(self, X: np.ndarray):\n", + " raise NotImplementedError" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "77c31356", + "metadata": {}, + "outputs": [], + "source": [ + "class KMeansRunner(BaseClustering):\n", + "\n", + " def __init__(self, k_min=2, k_max=10):\n", + "\n", + " self.k_min = k_min\n", + " self.k_max = k_max\n", + "\n", + "\n", + " def fit(self, X):\n", + "\n", + " best_k = None\n", + " best_score = -1\n", + " best_labels = None\n", + "\n", + " for k in range(self.k_min, self.k_max):\n", + "\n", + " model = KMeans(n_clusters=k, random_state=42)\n", + "\n", + " labels = model.fit_predict(X)\n", + "\n", + " score = silhouette_score(X, labels)\n", + "\n", + " if score > best_score:\n", + "\n", + " best_score = score\n", + " best_k = k\n", + " best_labels = labels\n", + "\n", + " metadata = {\n", + " \"best_k\": best_k,\n", + " \"silhouette\": best_score\n", + " }\n", + "\n", + " return ClusterResult(\"kmeans\", best_labels, metadata)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1be0e821", + "metadata": {}, + "outputs": [], + "source": [ + "class DBSCANRunner(BaseClustering):\n", + "\n", + " def __init__(self, eps=0.5, min_samples=5):\n", + "\n", + " self.eps = eps\n", + " self.min_samples = min_samples\n", + "\n", + "\n", + " def fit(self, X):\n", + "\n", + " model = DBSCAN(eps=self.eps, min_samples=self.min_samples)\n", + "\n", + " labels = model.fit_predict(X)\n", + "\n", + " metadata = {\n", + " \"clusters\": len(set(labels)) - (1 if -1 in labels else 0)\n", + " }\n", + "\n", + " return ClusterResult(\"dbscan\", labels, metadata)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "fee767e0", + "metadata": {}, + "outputs": [], + "source": [ + "class GMMRunner(BaseClustering):\n", + "\n", + " def __init__(self, k_min=2, k_max=10):\n", + "\n", + " self.k_min = k_min\n", + " self.k_max = k_max\n", + "\n", + "\n", + " def fit(self, X):\n", + "\n", + " best_k = None\n", + " best_bic = np.inf\n", + " best_labels = None\n", + "\n", + " for k in range(self.k_min, self.k_max):\n", + "\n", + " model = GaussianMixture(n_components=k)\n", + "\n", + " model.fit(X)\n", + "\n", + " bic = model.bic(X)\n", + "\n", + " if bic < best_bic:\n", + "\n", + " best_bic = bic\n", + " best_k = k\n", + " best_labels = model.predict(X)\n", + "\n", + " metadata = {\n", + " \"best_k\": best_k,\n", + " \"bic\": best_bic\n", + " }\n", + "\n", + " return ClusterResult(\"gmm\", best_labels, metadata)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d9f6db6e", + "metadata": {}, + "outputs": [], + "source": [ + "class ClusteringEngine:\n", + "\n", + " def __init__(self):\n", + "\n", + " self.runners = {\n", + " \"kmeans\": KMeansRunner(),\n", + " \"dbscan\": DBSCANRunner(),\n", + " \"gmm\": GMMRunner()\n", + " }\n", + "\n", + "\n", + " def run(self, X):\n", + "\n", + " results = {}\n", + "\n", + " for name, runner in self.runners.items():\n", + "\n", + " result = runner.fit(X)\n", + "\n", + " results[name] = result\n", + "\n", + " return results" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "5a042e6a", + "metadata": {}, + "outputs": [], + "source": [ + "class ClusterEvaluationEngine:\n", + "\n", + " def evaluate(self, X, cluster_results):\n", + "\n", + " evaluations = {}\n", + "\n", + " for name, result in cluster_results.items():\n", + "\n", + " labels = result.labels\n", + "\n", + " if len(set(labels)) <= 1:\n", + " continue\n", + "\n", + " metrics = EvaluationResult(\n", + " algorithm=name,\n", + " silhouette=silhouette_score(X, labels),\n", + " calinski=calinski_harabasz_score(X, labels),\n", + " davies=davies_bouldin_score(X, labels)\n", + " )\n", + "\n", + " evaluations[name] = metrics\n", + "\n", + " return evaluations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8570bf88", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/Data_generator.ipynb b/Data_generator.ipynb new file mode 100644 index 0000000..f5dd20f --- /dev/null +++ b/Data_generator.ipynb @@ -0,0 +1,272 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "cf9ddabf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Customer Master: (150000, 8)\n", + "Transactions: (3001170, 5)\n", + "Digital: (150000, 4)\n", + "Churn: (150000, 2)\n", + "MMM Weekly: (120, 8)\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "from scipy.special import expit\n", + "from scipy.stats import multivariate_normal\n", + "from datetime import timedelta\n", + "\n", + "np.random.seed(42)\n", + "\n", + "# ============================================================\n", + "# CONFIG\n", + "# ============================================================\n", + "\n", + "N_CUSTOMERS = 150_000\n", + "WEEKS = 120\n", + "START_DATE = pd.to_datetime(\"2023-01-01\")\n", + "\n", + "# ============================================================\n", + "# 1️⃣ CUSTOMER MASTER (Correlated Structure)\n", + "# ============================================================\n", + "\n", + "def generate_customer_master(n):\n", + "\n", + " # Correlated latent variables: income, age, risk_factor\n", + " mean = [12, 40, 0] # log-income, age, latent risk\n", + " cov = [\n", + " [1.2, -0.3, -0.5],\n", + " [-0.3, 25, 0.2],\n", + " [-0.5, 0.2, 1]\n", + " ]\n", + "\n", + " latent = multivariate_normal(mean, cov).rvs(n)\n", + "\n", + " log_income = latent[:,0]\n", + " age = np.clip(latent[:,1], 21, 75)\n", + " latent_risk = latent[:,2]\n", + "\n", + " income = np.exp(log_income) * 1000\n", + " credit_score = np.clip(750 + 40*(log_income - log_income.mean()) - 60*latent_risk, 300, 900)\n", + " risk_score = expit(latent_risk)\n", + "\n", + " digital_affinity = np.clip(1 - (age - 21)/60 + np.random.normal(0,0.1,n), 0,1)\n", + " tenure = np.random.randint(6, 180, n)\n", + "\n", + " credit_limit = income * np.random.uniform(0.2, 0.5, n)\n", + "\n", + " df = pd.DataFrame({\n", + " \"customer_id\": [f\"CUST_{i}\" for i in range(n)],\n", + " \"age\": age,\n", + " \"annual_income\": income,\n", + " \"credit_score\": credit_score,\n", + " \"risk_score\": risk_score,\n", + " \"digital_affinity\": digital_affinity,\n", + " \"tenure_months\": tenure,\n", + " \"credit_limit\": credit_limit\n", + " })\n", + "\n", + " return df\n", + "\n", + "# ============================================================\n", + "# 2️⃣ TRANSACTION ENGINE (Heavy-Tailed + Utilization)\n", + "# ============================================================\n", + "\n", + "def generate_transactions(customers):\n", + "\n", + " txn_rows = []\n", + "\n", + " for _, row in customers.iterrows():\n", + "\n", + " base_spend = np.random.lognormal(mean=10, sigma=1.0)\n", + " utilization = base_spend / row.credit_limit\n", + "\n", + " delinquency_prob = expit(4*utilization + 3*row.risk_score - 3)\n", + " delinquency_flag = np.random.binomial(1, delinquency_prob)\n", + "\n", + " n_txn = np.random.poisson(20)\n", + "\n", + " for _ in range(n_txn):\n", + " txn_rows.append([\n", + " row.customer_id,\n", + " START_DATE + timedelta(days=int(np.random.uniform(0,365))),\n", + " np.random.lognormal(mean=8, sigma=1.2),\n", + " utilization,\n", + " delinquency_flag\n", + " ])\n", + "\n", + " txn_df = pd.DataFrame(txn_rows, columns=[\n", + " \"customer_id\",\n", + " \"txn_date\",\n", + " \"txn_amount\",\n", + " \"utilization_ratio\",\n", + " \"delinquency_flag\"\n", + " ])\n", + "\n", + " return txn_df\n", + "\n", + "# ============================================================\n", + "# 3️⃣ DIGITAL ENGAGEMENT\n", + "# ============================================================\n", + "\n", + "def generate_digital(customers):\n", + "\n", + " df = customers.copy()\n", + "\n", + " df[\"app_sessions_30d\"] = (\n", + " df.digital_affinity * 35 + np.random.normal(0,5,len(df))\n", + " ).astype(int)\n", + "\n", + " df[\"email_open_rate\"] = np.clip(\n", + " df.digital_affinity + np.random.normal(0,0.1,len(df)),0,1\n", + " )\n", + "\n", + " df[\"complaints\"] = np.random.poisson(df.risk_score * 3)\n", + "\n", + " return df[[\n", + " \"customer_id\",\n", + " \"app_sessions_30d\",\n", + " \"email_open_rate\",\n", + " \"complaints\"\n", + " ]]\n", + "\n", + "# ============================================================\n", + "# 4️⃣ CHURN SIMULATION\n", + "# ============================================================\n", + "\n", + "def generate_churn(customers, digital):\n", + "\n", + " merged = customers.merge(digital, on=\"customer_id\")\n", + "\n", + " logit = (\n", + " -2.5\n", + " + 3*merged.risk_score\n", + " + 2*(merged.complaints > 2)\n", + " - 0.02*merged.tenure_months\n", + " - 1.5*merged.digital_affinity\n", + " )\n", + "\n", + " churn_prob = expit(logit)\n", + " merged[\"churn_flag\"] = np.random.binomial(1, churn_prob)\n", + "\n", + " return merged[[\"customer_id\", \"churn_flag\"]]\n", + "\n", + "# ============================================================\n", + "# 5️⃣ MMM ENGINE (Correlated + Adstock + Saturation + Shock)\n", + "# ============================================================\n", + "\n", + "def adstock(x, decay=0.6):\n", + " result = np.zeros_like(x)\n", + " for t in range(len(x)):\n", + " result[t] = x[t] + (decay * result[t-1] if t > 0 else 0)\n", + " return result\n", + "\n", + "def hill(x, alpha=1.5):\n", + " return x**alpha / (x**alpha + 1)\n", + "\n", + "def generate_mmm(weeks):\n", + "\n", + " mean = [10, 8, 7]\n", + " cov = [\n", + " [1, 0.6, 0.4],\n", + " [0.6, 1, 0.5],\n", + " [0.4, 0.5, 1]\n", + " ]\n", + "\n", + " latent_spend = multivariate_normal(mean, cov).rvs(weeks)\n", + " tv = np.exp(latent_spend[:,0]) * 1e5\n", + " meta = np.exp(latent_spend[:,1]) * 8e4\n", + " search = np.exp(latent_spend[:,2]) * 5e4\n", + "\n", + " seasonality = 1 + 0.2*np.sin(np.linspace(0, 4*np.pi, weeks))\n", + "\n", + " macro = np.ones(weeks)\n", + " macro[50:60] *= 0.85 # recession shock\n", + "\n", + " competitor = np.ones(weeks)\n", + " competitor[70:80] *= 1.2\n", + "\n", + " tv_ad = adstock(tv)\n", + " meta_ad = hill(adstock(meta))\n", + " search_ad = search\n", + "\n", + " sales = (\n", + " 0.00002 * tv_ad\n", + " + 0.00004 * meta_ad\n", + " + 0.00005 * search_ad\n", + " + 2000 * seasonality\n", + " + 1500 * macro\n", + " - 1000 * (competitor - 1)\n", + " + np.random.normal(0, 800, weeks)\n", + " )\n", + "\n", + " df = pd.DataFrame({\n", + " \"week\": np.arange(weeks),\n", + " \"tv_spend\": tv,\n", + " \"meta_spend\": meta,\n", + " \"search_spend\": search,\n", + " \"seasonality\": seasonality,\n", + " \"macro_index\": macro,\n", + " \"competitor_index\": competitor,\n", + " \"sales\": sales\n", + " })\n", + "\n", + " return df\n", + "\n", + "# ============================================================\n", + "# RUN FULL PIPELINE\n", + "# ============================================================\n", + "\n", + "customers = generate_customer_master(N_CUSTOMERS)\n", + "transactions = generate_transactions(customers)\n", + "digital = generate_digital(customers)\n", + "churn = generate_churn(customers, digital)\n", + "mmm_weekly = generate_mmm(WEEKS)\n", + "\n", + "print(\"Customer Master:\", customers.shape)\n", + "print(\"Transactions:\", transactions.shape)\n", + "print(\"Digital:\", digital.shape)\n", + "print(\"Churn:\", churn.shape)\n", + "print(\"MMM Weekly:\", mmm_weekly.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56531166", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..64616c2 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Segmentation_Plus + +End-to-end customer segmentation and GenAI persona workflow. + +## Project Structure + +```text +Segmentation_Plus +│ +├── data +│ └── dataset.xlsx +│ +├── segplus +│ ├── clustering.py +│ ├── persona_generator.py +│ ├── pipeline.py +│ +├── notebook.ipynb +└── requirements.txt +``` + +## Main Notebook + +Use `notebook.ipynb` as the final runnable notebook. +It is synced from `segplus/final_segplus_pipeline.ipynb`. + +## Setup + +```bash +pip install -r requirements.txt +``` + +## Run + +1. Open `notebook.ipynb`. +2. Run cells top-to-bottom. +3. Outputs are written under `segplus_output/`. diff --git a/architecture.md.resolved b/architecture.md.resolved new file mode 100644 index 0000000..5e94516 --- /dev/null +++ b/architecture.md.resolved @@ -0,0 +1,238 @@ +# Architecture: Financial Services Client Segmentation & GenAI Persona Generation + +## High-Level System Architecture + +```mermaid +graph TB + subgraph "1. DATA LAYER" + A["🏗️ Synthetic Data Generator
generate_data.py"] --> B[("📊 Raw Client Data
data/synthetic_clients.csv
2,000 records × 25 features")] + end + + subgraph "2. PROCESSING LAYER" + B --> C["🔍 EDA & Preprocessing
eda_preprocessing.py"] + C --> D[("🧹 Processed Data
data/processed_clients.csv
Scaled + PCA")] + C --> E["📈 EDA Charts
output/eda/"] + end + + subgraph "3. ANALYTICS LAYER" + D --> F["🎯 Clustering Engine
clustering.py"] + F --> G["K-Means"] + F --> H["DBSCAN"] + F --> I["Hierarchical"] + G --> J[("📋 Clustered Data
data/clustered_clients.csv")] + H --> J + I --> J + end + + subgraph "4. GenAI LAYER" + J --> K["🤖 Persona Generator
persona_generation.py"] + K <--> L["☁️ Google Gemini API"] + K --> M["📝 Persona Profiles
output/personas.md
output/personas.json"] + end + + subgraph "5. PRESENTATION LAYER" + J --> N["📊 Dashboard Builder
dashboard.py"] + M --> N + N --> O["🌐 Interactive Dashboard
output/dashboard.html"] + end + + subgraph "6. ORCHESTRATION" + P["🚀 main.py"] -.-> A + P -.-> C + P -.-> F + P -.-> K + P -.-> N + end + + style A fill:#4CAF50,color:#fff + style C fill:#2196F3,color:#fff + style F fill:#FF9800,color:#fff + style K fill:#9C27B0,color:#fff + style N fill:#E91E63,color:#fff + style P fill:#607D8B,color:#fff +``` + +--- + +## Data Flow Pipeline + +```mermaid +flowchart LR + A["Generate
2,000 Clients"] -->|raw CSV| B["Clean &
Scale"] -->|processed CSV| C["Cluster
Clients"] -->|labeled CSV| D["GenAI
Personas"] -->|JSON + MD| E["Dashboard"] + + style A fill:#4CAF50,color:#fff + style B fill:#2196F3,color:#fff + style C fill:#FF9800,color:#fff + style D fill:#9C27B0,color:#fff + style E fill:#E91E63,color:#fff +``` + +--- + +## Synthetic Data Schema + +```mermaid +erDiagram + CLIENT { + string client_id PK + int age + string gender + float income + string education + string marital_status + int dependents + string occupation + } + + FINANCIAL_PROFILE { + string client_id FK + float account_balance + int credit_score + float monthly_spending + float savings_rate + float debt_to_income_ratio + float investment_portfolio_value + } + + PRODUCT_HOLDINGS { + string client_id FK + bool has_credit_card + bool has_mortgage + bool has_personal_loan + bool has_investment_account + bool has_insurance + int num_products + } + + BEHAVIORAL { + string client_id FK + float digital_engagement_score + int branch_visits_monthly + float customer_tenure_years + int transaction_frequency_monthly + float avg_transaction_amount + } + + SATISFACTION { + string client_id FK + int nps_score + int complaint_count_yearly + float churn_risk_score + } + + CLIENT ||--|| FINANCIAL_PROFILE : has + CLIENT ||--|| PRODUCT_HOLDINGS : holds + CLIENT ||--|| BEHAVIORAL : exhibits + CLIENT ||--|| SATISFACTION : rates +``` + +> All entities are stored as columns in a **single flat CSV** for ML simplicity. + +--- + +## Clustering Strategy + +```mermaid +graph TD + A["Preprocessed Features
(StandardScaler + PCA)"] --> B{"Method Selection"} + + B --> C["K-Means"] + B --> D["DBSCAN"] + B --> E["Agglomerative"] + + C --> C1["Elbow Method
↳ Optimal K"] + C --> C2["Silhouette Score
↳ Cluster Quality"] + C1 --> F["Final Segments"] + C2 --> F + + D --> D1["Epsilon Tuning
↳ k-distance plot"] + D1 --> F + + E --> E1["Dendrogram
↳ Cut Height"] + E1 --> F + + F --> G["Cluster Profiling
Mean/Median per feature"] + G --> H["Radar Charts +
Box Plots"] + + style C fill:#FF9800,color:#fff + style D fill:#FF5722,color:#fff + style E fill:#795548,color:#fff + style F fill:#4CAF50,color:#fff +``` + +--- + +## GenAI Persona Generation Flow + +```mermaid +sequenceDiagram + participant P as persona_generation.py + participant D as Clustered Data + participant G as Google Gemini API + + P->>D: Load cluster profiles + loop For each cluster + P->>P: Aggregate cluster stats
(mean age, income, products, etc.) + P->>P: Build structured prompt + P->>G: Send prompt with cluster profile + G-->>P: Return persona (name, goals,
pain points, strategy) + P->>P: Parse & format response + end + P->>P: Save personas.json + personas.md +``` + +### Example Prompt Structure +``` +You are a financial services marketing strategist. + +Cluster 3 Profile: +- Avg Age: 42, Income: $125K, Credit Score: 780 +- Products: Mortgage (80%), Investment Account (90%) +- Digital Engagement: High, Tenure: 12 years +- NPS: 8.5, Churn Risk: Low + +Generate a detailed customer persona including: +1. Persona name and one-line description +2. Demographics and lifestyle +3. Financial goals and pain points +4. Product recommendations +5. Preferred communication channels +6. Marketing strategy (tone, offers, timing) +``` + +--- + +## Directory Structure + +``` +Segmentation_Plus/ +├── main.py # 🚀 Pipeline orchestrator +├── generate_data.py # 🏗️ Synthetic data generator +├── eda_preprocessing.py # 🔍 EDA + feature engineering +├── clustering.py # 🎯 Segmentation algorithms +├── persona_generation.py # 🤖 GenAI persona builder +├── dashboard.py # 📊 Interactive visualizations +├── requirements.txt # 📦 Dependencies +├── data/ +│ ├── synthetic_clients.csv # Raw generated data +│ ├── processed_clients.csv # Scaled/transformed data +│ └── clustered_clients.csv # Data with cluster labels +└── output/ + ├── eda/ # EDA charts (PNG) + ├── clusters/ # Clustering charts (PNG) + ├── personas.md # AI-generated personas (readable) + ├── personas.json # AI-generated personas (structured) + └── dashboard.html # Interactive Plotly dashboard +``` + +--- + +## Technology Stack + +| Layer | Technology | Purpose | +|---|---|---| +| **Data Generation** | `numpy`, `pandas` | Correlated synthetic data | +| **Visualization** | `matplotlib`, `seaborn`, `plotly` | Static + interactive charts | +| **ML / Clustering** | `scikit-learn` | K-Means, DBSCAN, Hierarchical, PCA | +| **GenAI** | `google-generativeai` (Gemini) | Persona narrative generation | +| **Orchestration** | `main.py` | End-to-end pipeline runner | diff --git a/architecture_detailed.html b/architecture_detailed.html new file mode 100644 index 0000000..f2e52c9 --- /dev/null +++ b/architecture_detailed.html @@ -0,0 +1,952 @@ + + + + + + + Segmentation Plus — Detailed Technical Guide + + + + + + + +
+
Detailed Technical Guide
+

Segmentation Plus — Step-by-Step

+

Deep-dive into each pipeline step: the conceptual "why" and the technical "how" behind domain configuration, + EDA, clustering, evaluation, and GenAI persona generation.

+
+ +
+ + +
+
+
1
+

Domain Configuration Foundation Layer

+
+ +
+
+

💡 Conceptual — Why?

+

Different industries have fundamentally different customer attributes and business questions. A + bank cares about credit risk and product cross-sell; a retailer about purchase frequency and + basket size. Rather than building separate systems, we use a configuration-driven + architecture — one engine, many domains.

+
    +
  • Eliminates code duplication across client engagements
  • +
  • New domains added by creating a YAML file, not writing new code
  • +
  • Ensures consistency in methodology across all domains
  • +
+
+
+

⚙️ Technical — How?

+

Each domain is defined in a domains/*.yaml file containing:

+
    +
  • Feature schema — required columns, data types, valid ranges
  • +
  • EDA rules — which domain-specific analyses to run
  • +
  • Feature engineering recipes — computed columns, ratios, derived scores
  • +
  • Persona prompt template — domain-specific GenAI instructions
  • +
  • Synthetic data distributions — realistic parameter ranges for demo + generation
  • +
+

config.py loads the YAML at pipeline start and injects the domain context into every + downstream module via a DomainConfig dataclass.

+
+
+ +
+
# domains/financial_services.yaml (simplified)
+domain: financial_services
+display_name: "Financial Services"
+
+features:
+  demographics: [age, gender, annual_income, education, occupation]
+  financial: [credit_score, account_balance, portfolio_value, debt_to_income]
+  products: [has_mortgage, has_credit_card, has_investment_account]
+  behavioral: [digital_engagement, branch_visits, transaction_frequency]
+  satisfaction: [nps_score, churn_risk_score]
+
+feature_engineering:
+  - name: wealth_tier
+    formula: "annual_income * portfolio_value"
+    bins: [low, medium, high, ultra_high]
+  - name: digital_ratio
+    formula: "digital_engagement / (digital_engagement + branch_visits)"
+
+eda:
+  domain_analyses:
+    - income_vs_credit_risk
+    - product_cross_holdings_matrix
+    - high_value_customer_identification
+
+persona_prompt_template: |
+  You are advising a {institution_type} on their customer segments...
+
+
+ +
+ + +
+
+
2
+

Data Input Layer Synthetic Generation + Real Data Import

+
+ +
+
+

💡 Conceptual — Why?

+
    +
  • Synthetic data enables POC/demo without waiting for real client data — + critical for fast sales cycles and internal showcases
  • +
  • Real data import is the production path — when a client provides their + actual customer data, the same pipeline processes it without code changes
  • +
  • Synthetic data is generated with realistic correlations (e.g., higher + income → higher portfolio value → higher credit score) so the downstream clustering produces + meaningful segments even in demo mode
  • +
+
+
+

⚙️ Technical — How?

+

Synthetic generation (generate_data.py):

+
    +
  • Uses numpy.random with multivariate normal distributions to create correlated + features
  • +
  • Categorical features sampled via weighted np.random.choice
  • +
  • Domain config defines realistic ranges (e.g., credit_score: 300–850, age: 18–80)
  • +
+

Real data import (data_import.py):

+
    +
  • Schema validation against domain YAML — checks required columns, types, ranges
  • +
  • Automatic column mapping (fuzzy matching for similar column names)
  • +
  • Outputs standardized DataFrame regardless of input source (CSV, SQL, API)
  • +
+
+
+ +
Synthetic correlation: X ~ 𝒩(μ, Σ) where Σ encodes realistic inter-feature correlations +
+ +
Key design principle: The pipeline is data-source agnostic + — once data passes the schema validator, every downstream step works identically whether the data is + synthetic or real.
+
+ +
+ + +
+
+
3
+

Domain-Aware EDA & Feature Engineering Understanding + Transforming the Data

+
+ +
+
+

💡 Conceptual — Why?

+

EDA tells us what patterns exist in the data before we cluster. Without EDA, + we're clustering blindly — and bad features produce bad segments.

+
    +
  • Generic EDA — distributions, correlations, outliers, missing values. + Applied to every domain uniformly.
  • +
  • Domain-specific EDA — analyses that only make sense in context. Example: + RFM analysis is meaningless for healthcare but critical for retail.
  • +
  • Feature engineering creates new variables that capture business logic + (e.g., wealth_tier = income × portfolio) and improve clustering quality.
  • +
+
+
+

⚙️ Technical — How?

+

Generic EDA (always runs):

+
    +
  • Distribution histograms + KDE plots (seaborn.histplot)
  • +
  • Pearson correlation matrix heatmap
  • +
  • Box plots for outlier detection (IQR method)
  • +
  • Missing value matrix (missingno pattern)
  • +
+

Domain-specific EDA (from YAML config):

+
    +
  • FS: Income decile analysis, credit score vs. product count scatter
  • +
  • Retail: Recency-Frequency-Monetary (RFM) scoring matrix
  • +
  • Healthcare: Risk stratification pyramid, utilization heatmap
  • +
+
+
+ +
+

Feature Engineering Pipeline

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StageWhat It DoesMethod
1. Domain featuresCreate business-meaningful derived columnsFormulas from YAML config (ratios, tiers, scores)
2. EncodingConvert categorical to numericalOne-hot encoding (pd.get_dummies) or Label encoding
3. Outlier handlingCap extreme valuesWinsorization at 1st/99th percentile
4. ScalingNormalize all features to same scaleStandardScaler → mean=0, std=1 (critical for distance-based algorithms) +
5. Dimensionality reductionReduce feature space for visualizationPCA — retain components explaining ≥85% variance
+
+ +
Why StandardScaler matters: K-Means and DBSCAN use Euclidean + distance. Without scaling, a feature like income (range: $20K–$500K) would dominate over credit_score + (range: 300–850) simply due to magnitude, not importance.
+
+ +
+ + +
+
+
4
+

Clustering Algorithms Segmenting the Customer Base

+
+ +
+
+

💡 Conceptual — Why 3 algorithms?

+

No single clustering algorithm works best for all data shapes. We run three complementary + approaches and compare:

+
    +
  • K-Means — fast, interpretable, assumes spherical clusters. Good baseline. +
  • +
  • DBSCAN — finds arbitrarily-shaped clusters and detects noise/outliers. + Great when some customers don't fit any group.
  • +
  • GMM — probabilistic (soft) assignment. Each customer gets a probability of + belonging to each cluster. Handles elliptical shapes and correlated features.
  • +
+
+
+

⚙️ Technical — How?

+

All algorithms operate on the scaled, engineered feature matrix from Step 3.

+
    +
  • Algorithms from scikit-learn: KMeans, DBSCAN, + GaussianMixture
  • +
  • We vary hyperparameters and pick the best model via evaluation metrics (Step 5)
  • +
  • GMM additionally outputs predict_proba() — a probability matrix showing each + customer's likelihood per segment
  • +
+
+
+ +
+

Algorithm Deep-Dive

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AlgorithmHow It WorksKey HyperparameterBest For
K-Means1. Place K random centroids
2. Assign each point to nearest centroid
3. Recompute + centroids as cluster means
4. Repeat until convergence
n_clusters (K) — found via Elbow/SilhouetteWell-separated, roughly equal-size, spherical clusters
DBSCAN1. For each point, count neighbors within radius ε
2. Points with ≥ min_samples + neighbors are "core points"
3. Expand clusters from core points
4. Unlabeled + points become noise (-1)
eps (radius) + min_samples — found via k-distance plotIrregular shapes, noisy data, unknown number of clusters
GMM1. Assume data comes from K Gaussian distributions
2. EM algorithm: E-step assigns + soft probabilities, M-step updates Gaussian parameters
3. Iterate until + log-likelihood converges
4. Each point gets probability per cluster
n_components — found via BIC/AICCorrelated features, overlapping clusters, soft assignment needed
+
+ +
K-Means objective: minimize J = Σᵢ Σₓ∈Cᵢ ||x - μᵢ||² (within-cluster sum of squares = + Inertia)
+
GMM: P(x) = Σₖ πₖ · 𝒩(x | μₖ, Σₖ) — mixture of K Gaussians with weights πₖ
+ +
Why GMM over Hierarchical? GMM gives soft assignments + (e.g., "Customer X is 70% Segment A, 30% Segment B") — ideal for marketing where customers often sit + between segments. GMM also handles correlated features via full covariance matrices, and BIC/AIC provide + principled model selection vs. subjective dendrogram cutting.
+
+ +
+ + +
+
+
5
+

Cluster Evaluation Framework Validating Segment Quality

+
+ +
+
+

💡 Conceptual — Why?

+

Clustering is unsupervised — there's no ground truth to check against. + Evaluation ensures our segments are:

+
    +
  • Optimal K — not too few (overgeneralized) or too many (noise)
  • +
  • Well-separated — customers within a cluster are similar; customers across + clusters are different
  • +
  • Interpretable — we can explain what drives each segment
  • +
  • Stable — segments persist if we resample the data
  • +
+
+
+

⚙️ Technical — How?

+

Four-step evaluation pipeline, each step uses different techniques:

+
    +
  • Step 5a: Inertia elbow + BIC/AIC + Silhouette sweeps
  • +
  • Step 5b: Quality scores (Silhouette, Davies-Bouldin, Calinski-Harabasz) +
  • +
  • Step 5c: PCA loadings + SHAP + cluster profiles
  • +
  • Step 5d: Bootstrap resampling + GMM probability confidence
  • +
+

All implemented in cluster_evaluation.py using scikit-learn metrics and + shap library.

+
+
+ +
+

5a · Finding Optimal K

+ + + + + + + + + + + + + + + + + + + + + + + + + +
MethodWhat It DoesHow to Read
Inertia / ElbowPlots within-cluster sum of squares (WCSS) vs. K. As K increases, inertia decreases — + but at diminishing returns.Look for the "elbow" — the K where the curve bends sharply. Beyond that, adding clusters + gives little improvement.
BIC / AICBayesian/Akaike Information Criterion — penalizes model complexity. Used for GMM + specifically.Pick the K where BIC/AIC is minimized. BIC penalizes complexity more than AIC, + so it tends to prefer fewer clusters.
Silhouette vs KComputes silhouette score for each K. Measures how similar each point is to its own + cluster vs. nearest neighbor cluster.Pick K with the highest average silhouette. Range: -1 (wrong cluster) to +1 + (perfect fit).
+
+ +
Silhouette(i) = (b(i) - a(i)) / max(a(i), b(i))
where a(i) = avg distance to + same-cluster points, b(i) = avg distance to nearest-other-cluster points
+ +
+

5b · Cluster Quality Metrics

+ + + + + + + + + + + + + + + + + + + + + + + + + +
MetricFormula IntuitionIdeal Value
Silhouette ScoreHow well each point fits its cluster vs. the next-best clusterCloser to +1 (≥0.5 is good, ≥0.7 is strong)
Davies-Bouldin IndexRatio of within-cluster scatter to between-cluster separation. Lower = tighter, more + separated clusters.Closer to 0
Calinski-HarabaszRatio of between-cluster variance to within-cluster variance (like an F-statistic for + clusters)Higher = better defined clusters
+
+ +
+

5c · Interpretability: PCA Loadings + SHAP

+ + + + + + + + + + + + + + + + + + + + + + + + + +
MethodWhat It AnswersTechnical Detail
PCA LoadingsWhich original features drive each principal component?The loading matrix shows how much each original feature contributes to each PC. A + heatmap of loadings reveals feature groupings. E.g., if PC1 has high loadings for + income, portfolio_value, and credit_score — PC1 represents "wealth". Clusters separated + along PC1 are primarily differentiated by wealth.
SHAP SummaryWhich features are most important for distinguishing clusters? Why is a specific + customer in a specific cluster?Train a RandomForestClassifier on cluster_label as target. Use + shap.TreeExplainer to compute SHAP values. Summary beeswarm plot shows + global feature importance. Per-cluster bar plots show what defines each segment. Force + plots explain individual customer assignments.
Cluster ProfilesWhat does each cluster "look like" statistically?Compute mean/median of every feature per cluster. Visualize as radar charts (comparing + clusters on key dimensions) and violin/box plots (distribution of each feature per + cluster).
+
+ +
PCA Loadings vs. SHAP — when to use which?
+ • PCA Loadings answer: "What features vary together in the data?" — useful for + understanding data structure before clustering.
+ • SHAP answers: "What features distinguish the clusters we found?" — useful for + explaining cluster assignments after clustering.
+ Both are needed: PCA loadings validate that clustering operates on meaningful dimensions; SHAP validates + that the resulting segments are interpretable.
+ +
+

5d · Stability Testing

+ + + + + + + + + + + + + + + + + + + + +
MethodHow It WorksWhat It Proves
Bootstrap ResamplingResample the dataset with replacement N times (e.g., 100), re-cluster each time, and + measure agreement using the Adjusted Rand Index (ARI) between the original and resampled + clusters.If ARI is consistently high (≥0.8), the segments are robust — they aren't just artifacts + of the specific data sample.
GMM Probability DistributionPlot a histogram of each customer's max assignment probability from GMM.If most customers have max-prob ≥0.8, the segments are clearly defined. A flat + distribution means ambiguous assignments — clusters may be overlapping or poorly + separated.
+
+
+ +
+ + +
+
+
6
+

GenAI Persona Generation Turning Segments into Narratives

+
+ +
+
+

💡 Conceptual — Why?

+

Cluster labels ("Segment 1, 2, 3…") are meaningless to business stakeholders. Marketing teams + need personas — named, narrative profiles that bring segments to life.

+
    +
  • A persona bridges the gap between statistical output and actionable + strategy
  • +
  • GenAI (Gemini) transforms cluster statistics + SHAP drivers into natural-language personas + with goals, pain points, and recommendations
  • +
  • Domain-aware prompts ensure personas are contextually relevant (banking language for FS, + shopping language for retail)
  • +
+
+
+

⚙️ Technical — How?

+
    +
  1. Aggregate cluster statistics: mean of every feature per cluster
  2. +
  3. Extract top 5 SHAP drivers per cluster (features that most define the segment)
  4. +
  5. Load domain-specific prompt template from YAML config
  6. +
  7. Inject cluster stats + SHAP drivers into the template
  8. +
  9. Call google.generativeai.GenerativeModel('gemini-pro')
  10. +
  11. Parse the structured response (name, goals, pain points, strategy)
  12. +
  13. Save to personas.json (machine-readable) and personas.md + (human-readable)
  14. +
+

Uses google-generativeai SDK. API key read from + GOOGLE_API_KEY env var.

+
+
+ +
Why SHAP drivers in the prompt? Without SHAP, the GenAI model only + sees averages (e.g., "Avg Income: $125K"). With SHAP, it also knows what makes this segment + unique — e.g., "income is the #1 differentiator with SHAP value +0.8". This produces much more + targeted and insightful personas.
+
+ +
+ + +
+
+
7
+

Interactive Dashboard Unified Visualization Layer

+
+ +
+
+

💡 Conceptual — Why?

+
    +
  • Stakeholders need a single place to explore segments, not scattered PNG files
  • +
  • Interactivity (hover, filter, zoom) enables self-service exploration without data science + involvement
  • +
  • Combining cluster visualizations + persona cards in one view tells the complete story: "Who + are these customers, and what should we do about them?"
  • +
+
+
+

⚙️ Technical — How?

+
    +
  • Built with plotly for interactive charts, output as self-contained HTML
  • +
  • PCA scatter — 2D/3D projection colored by cluster
  • +
  • Cluster size bar chart — segment distribution
  • +
  • Violin plots — feature distributions per cluster
  • +
  • Radar charts — comparative cluster profiles
  • +
  • Persona cards — rendered as styled HTML cards with GenAI output
  • +
  • Single dashboard.html file — no server needed, opens in any browser
  • +
+
+
+
+ +
+ + + + + + + \ No newline at end of file diff --git a/architecture_presentation.html b/architecture_presentation.html new file mode 100644 index 0000000..b6b1a60 --- /dev/null +++ b/architecture_presentation.html @@ -0,0 +1,988 @@ + + + + + + + Segmentation Plus — Architecture + + + + + + + + +
+
Architecture Document
+

Segmentation Plus

+

Multi-domain customer segmentation & GenAI persona generation platform. Works across Financial Services, + Retail, Healthcare, Telecom — or any custom domain. Supports synthetic demo data and real client data + import.

+
+
📅 March 2026
+
🏦🛒🏥📡 Multi-Domain
+
📊 Synthetic + Real Data
+
🤖 GenAI Personas
+
+
+ +
+ + +
+
+
⚙️
+

Supported Domains

+
+

Configurable via YAML files — all downstream modules (data generation, EDA, feature + engineering, persona prompts) adapt automatically per domain.

+
+
+
🏦
+
Financial Services
+
Banks · Insurers · Wealth Mgmt
+
+
+
🛒
+
Retail
+
E-commerce · Brick & Mortar · D2C
+
+
+
🏥
+
Healthcare
+
Payers · Providers · Pharma
+
+
+
📡
+
Telecom
+
Mobile · Broadband · OTT
+
+
+
+ +
+ + +
+
+
🔄
+

Data Flow Pipeline

+
+
+
⚙️ Domain Config
+
+
📥 Data Input
+
+
🔍 Domain EDA
+
+
🎯 Cluster
+
+
🔬 Evaluate
+
+
🤖 GenAI Personas
+
+
📊 Dashboard
+
+
+ +
+ + +
+
+
🏛️
+

High-Level System Architecture

+
+
+
+graph TB
+    subgraph "CONFIGURATION"
+        CFG["⚙️ Domain Config\ndomains/*.yaml"]
+    end
+
+    subgraph "1 · DATA INPUT"
+        A1["🏗️ Synthetic Generator\n(Demo Mode)"] --> DATA
+        A2["📥 Real Data Import\n(CSV / DB / API)"] --> DATA
+        DATA[("📊 Customer Data")]
+    end
+
+    subgraph "2 · DOMAIN-AWARE PROCESSING"
+        DATA --> EDA["🔍 EDA Engine\nDomain-specific analysis\n+ Feature engineering"]
+        EDA --> PROC[("🧹 Processed Data")]
+    end
+
+    subgraph "3 · CLUSTERING & EVALUATION"
+        PROC --> CL["🎯 Clustering\nK-Means · DBSCAN · GMM"]
+        CL --> EVAL["🔬 Evaluation\nInertia · BIC/AIC · Silhouette\nPCA Loadings · SHAP"]
+        EVAL --> SEG[("📋 Segmented\nCustomers")]
+    end
+
+    subgraph "4 · GenAI"
+        SEG --> PERS["🤖 Persona Generator\nDomain-aware prompts"]
+        EVAL --> PERS
+        PERS <--> LLM["☁️ Gemini API"]
+        PERS --> OUT["📝 Personas"]
+    end
+
+    subgraph "5 · OUTPUT"
+        SEG --> DASH["📊 Dashboard"]
+        OUT --> DASH
+        DASH --> HTML["🌐 dashboard.html"]
+    end
+
+    CFG -.-> A1
+    CFG -.-> EDA
+    CFG -.-> PERS
+
+    style CFG fill:#607D8B,color:#fff
+    style A1 fill:#4CAF50,color:#fff
+    style A2 fill:#8BC34A,color:#fff
+    style EDA fill:#2196F3,color:#fff
+    style CL fill:#FF9800,color:#fff
+    style EVAL fill:#F44336,color:#fff
+    style PERS fill:#9C27B0,color:#fff
+    style DASH fill:#E91E63,color:#fff
+            
+
+
+ +
+ + +
+
+
📥
+

Data Input: Synthetic vs. Real

+
+

Start with synthetic data for POC/demos. When a client provides their real data, the + system validates it against the domain schema and runs the same pipeline — no code changes needed.

+
+
+flowchart TB
+    subgraph "Demo / POC Mode"
+        S1["Synthetic Generator"] --> S2["Domain-specific\nrealistic records"]
+        S2 --> PIPE
+    end
+
+    subgraph "Production Mode"
+        R1["CSV Upload"] --> VAL
+        R2["Database"] --> VAL
+        R3["API"] --> VAL
+        VAL["🔍 Schema Validator\n• Column mapping\n• Type checks\n• Domain validation"] --> PIPE
+    end
+
+    PIPE["→ Same Pipeline"]
+
+    style S1 fill:#4CAF50,color:#fff
+    style R1 fill:#2196F3,color:#fff
+    style R2 fill:#1976D2,color:#fff
+    style R3 fill:#1565C0,color:#fff
+    style VAL fill:#FF9800,color:#fff
+            
+
+
+ +
+ + +
+
+
📋
+

Domain Configuration

+
+

Each domain defines its own features, EDA focus, and persona angles. A single YAML + file controls the entire pipeline behavior.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Config Key🏦 Financial Services🛒 Retail🏥 Healthcare
Key Featurescredit_score, portfolio_value, debt_to_incomepurchase_frequency, avg_basket_size, return_ratevisit_frequency, chronic_conditions, insurance_type
ProductsMortgage, credit card, investment accountLoyalty card, subscription, premium tierHealth plan, dental, vision, wellness
BehavioralDigital engagement, branch visitsOnline vs. in-store, coupon usagePortal usage, appointment adherence
EDA FocusIncome vs. credit risk, cross-holdingsRFM analysis, seasonal patternsRisk stratification, cost drivers
Feature Eng.wealth_tier, risk_category, digital_ratiorfm_score, discount_sensitivityacuity_score, care_gap_count
Persona AngleFinancial goals, product upsellShopping behavior, brand loyaltyCare journey, health goals
+
+
+ +
+ + +
+
+
🔍
+

Domain-Aware EDA & Feature Engineering

+
+
+
+graph TD
+    INPUT["Raw Customer Data"] --> DETECT["Domain Detection\n(from config)"]
+
+    DETECT --> GEN["📊 Generic EDA\nDistributions · Correlations · Outliers"]
+
+    DETECT --> DOM["🎯 Domain-Specific EDA"]
+
+    DOM --> FS["🏦 Financial Services\nIncome distributions\nCredit vs. products\nDebt-to-income analysis"]
+
+    DOM --> RT["🛒 Retail\nRFM scoring\nBasket analysis\nSeasonal patterns"]
+
+    DOM --> HC["🏥 Healthcare\nRisk stratification\nCare utilization\nChronic clustering"]
+
+    GEN --> FE["🛠️ Feature Engineering"]
+    FS --> FE
+    RT --> FE
+    HC --> FE
+
+    FE --> OUT[("Processed Data")]
+
+    style GEN fill:#2196F3,color:#fff
+    style DOM fill:#FF9800,color:#fff
+    style FS fill:#1565C0,color:#fff
+    style RT fill:#E65100,color:#fff
+    style HC fill:#2E7D32,color:#fff
+    style FE fill:#9C27B0,color:#fff
+            
+
+
+ +
+ + +
+
+
🎯
+

Clustering & Evaluation

+
+
+
+graph TD
+    A["Engineered Features"] --> B{"Algorithm Suite"}
+
+    B --> C["K-Means\nHard, spherical"]
+    B --> D["DBSCAN\nDensity, noise"]
+    B --> E["GMM\nSoft, elliptical"]
+
+    C --> C1["Inertia / Elbow\nSilhouette"]
+    D --> D1["k-distance plot\nNoise ratio"]
+    E --> E1["BIC / AIC\nLog-Likelihood"]
+
+    C1 --> F["🏆 Best Model"]
+    D1 --> F
+    E1 --> F
+
+    F --> G["🔬 Deep Evaluation"]
+
+    style C fill:#FF9800,color:#fff
+    style D fill:#FF5722,color:#fff
+    style E fill:#3F51B5,color:#fff
+    style F fill:#4CAF50,color:#fff
+            
+
+ +
+

4-Step Evaluation Pipeline

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StepMethodsPurpose
1 · Optimal KInertia Elbow, BIC/AIC, Silhouette vs KFind the right number of segments
2 · QualitySilhouette, Davies-Bouldin, Calinski-HarabaszValidate compactness & separation
3 · InterpretabilityPCA Loadings Heatmap, SHAP Summary, Cluster Radar ChartsUnderstand what defines each segment
4 · StabilityBootstrap Resampling, GMM Probability DistributionConfirm robustness across resamples
+
+
+ +
+ + +
+
+
🎯
+

SHAP for Cluster Interpretability

+
+

Train a Random Forest on cluster labels, then use SHAP to explain why each + customer belongs to its segment — making results explainable to business stakeholders across any domain. +

+
+
+sequenceDiagram
+    participant D as Segmented Data
+    participant RF as Random Forest (cluster target)
+    participant S as SHAP Explainer
+    participant V as Visualizations
+
+    D->>RF: Train features → cluster_label
+    RF->>S: Generate SHAP values
+    S->>V: Summary Plot (global importance)
+    S->>V: Per-Cluster Bar Plot (segment drivers)
+    S->>V: Dependence Plots (interactions)
+    S->>V: Force Plots (individual explanations)
+            
+
+
+ 💡 Example Insight:
+ "Customer X is in Segment 2 because of high income (+0.8), low digital + engagement (−0.5), and high portfolio value (+0.7)" — actionable for the + client's marketing team. +
+
+ +
+ + +
+
+
🤖
+

GenAI Persona Generation

+
+

Personas adapt to the domain context automatically — prompts pull domain-specific + language, product catalogs, and strategy angles from the config.

+
+
+sequenceDiagram
+    participant P as Persona Generator
+    participant C as Domain Config
+    participant D as Cluster Profiles + SHAP
+    participant G as Gemini API
+
+    P->>C: Load domain context
+    P->>D: Load cluster stats + SHAP drivers
+    loop For each segment
+        P->>P: Build domain-aware prompt
+        P->>G: Send prompt
+        G-->>P: Persona response
+        P->>P: Parse & format
+    end
+    P->>P: Save personas.json + personas.md
+            
+
+ +

Example Prompts by Domain

+
+

🏦 Financial Services

+
+
You are a marketing strategist advising a bank on their customers.
+
+Segment 3: Avg Age 42, Income $125K, Credit Score 780
+Products: Mortgage (80%), Investment Account (90%)
+SHAP Drivers: income (+0.8), portfolio_value (+0.7)
+
+Generate persona: name, financial goals, pain points,
+cross-sell recommendations, channel preferences, campaign strategy.
+
+
+
+

🛒 Retail

+
+
You are a retail marketing strategist advising a brand.
+
+Segment 2: Avg Age 28, AOV $75, Purchase Freq 3x/month
+Categories: Apparel (90%), Accessories (60%), Footwear (40%)
+SHAP Drivers: purchase_frequency (+0.9), discount_sensitivity (+0.6)
+
+Generate persona: name, shopping habits, brand affinities,
+product recommendations, channel mix, retention strategy.
+
+
+
+ +
+ + +
+
+
📁
+

Directory Structure

+
+
+
Segmentation_Plus/
+├── main.py                         # Pipeline orchestrator
+├── config.py                       # Domain config loader
+├── generate_data.py                # Synthetic data generator (per domain)
+├── data_import.py                  # Real data ingestion + validation
+├── eda_preprocessing.py            # Domain-aware EDA + feature engineering
+├── clustering.py                   # K-Means, DBSCAN, GMM
+├── cluster_evaluation.py           # Metrics + SHAP + PCA loadings
+├── persona_generation.py           # GenAI persona builder
+├── dashboard.py                    # Interactive Plotly dashboard
+├── requirements.txt
+├── domains/
+│   ├── financial_services.yaml     # Financial Services config
+│   ├── retail.yaml                 # Retail config
+│   ├── healthcare.yaml             # Healthcare config
+│   └── _template.yaml              # Template for new domains
+├── data/
+│   ├── synthetic_customers.csv     # Demo data
+│   ├── imported_data.csv           # Real client data
+│   ├── processed_customers.csv     # Scaled + engineered
+│   └── clustered_customers.csv     # With labels + probabilities
+└── output/
+    ├── eda/                        # EDA charts
+    ├── evaluation/                 # PCA, SHAP, metrics
+    ├── personas.md / .json         # GenAI personas
+    └── dashboard.html              # Interactive dashboard
+
+
+ +
+ + +
+
+
⚙️
+

Technology Stack

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LayerTechnologyPurpose
ConfigurationpyyamlDomain configs
Datanumpy, pandasGeneration + processing
Visualizationmatplotlib, seaborn, plotlyCharts + dashboard
Clusteringscikit-learnK-Means, DBSCAN, GMM, PCA
Evaluationscikit-learn, shapMetrics + SHAP interpretability
GenAIgoogle-generativeaiPersona generation via Gemini
+
+
+ +
+ + + + + + + + \ No newline at end of file diff --git a/cluster_evaluation.py b/cluster_evaluation.py new file mode 100644 index 0000000..a50bc77 --- /dev/null +++ b/cluster_evaluation.py @@ -0,0 +1,381 @@ +""" +Segmentation Plus — Cluster Evaluation Framework +================================================= +4-step evaluation: Optimal K, Quality Metrics, Interpretability +(PCA loadings + SHAP), and Stability testing. +""" + +from __future__ import annotations + +import json +import logging +from pathlib import Path +from typing import Dict, List, Optional, Tuple + +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns +from sklearn.decomposition import PCA +from sklearn.ensemble import RandomForestClassifier +from sklearn.cluster import KMeans +from sklearn.metrics import silhouette_score, adjusted_rand_score +from sklearn.mixture import GaussianMixture + +from clustering import ClusteringResult + +logger = logging.getLogger(__name__) + + +class ClusterEvaluator: + """ + Comprehensive cluster evaluation framework. + + Parameters + ---------- + X : np.ndarray + Feature matrix used for clustering. + labels : np.ndarray + Cluster assignments. + feature_names : list[str] + Names of the features (columns). + output_dir : Path + Directory to save evaluation plots and reports. + """ + + def __init__( + self, + X: np.ndarray, + labels: np.ndarray, + feature_names: List[str], + output_dir: Path, + ) -> None: + self.X = X + self.labels = labels + self.feature_names = feature_names + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + self.report: Dict = {} + + def run_full_evaluation( + self, + pca: Optional[PCA] = None, + k_range: Tuple[int, int] = (2, 10), + random_state: int = 42, + ) -> Dict: + """ + Run the complete 4-step evaluation pipeline. + + Returns + ------- + dict + Full evaluation report. + """ + logger.info("Starting cluster evaluation (4 steps)...") + + # Step 1: Optimal K analysis + self.report["optimal_k"] = self._step1_optimal_k(k_range, random_state) + + # Step 2: Quality metrics + self.report["quality_metrics"] = self._step2_quality_metrics() + + # Step 3: Interpretability + self.report["pca_loadings"] = self._step3a_pca_loadings(pca) + self.report["shap_importance"] = self._step3b_shap_analysis(random_state) + self._step3c_cluster_profiles() + + # Step 4: Stability + self.report["stability"] = self._step4_stability(random_state) + + # Save report + report_path = self.output_dir / "evaluation_report.json" + with open(report_path, "w") as f: + json.dump(self._serialize_report(self.report), f, indent=2) + logger.info("Evaluation report saved to %s", report_path) + + return self.report + + # ── Step 1: Optimal K ── + + def _step1_optimal_k(self, k_range: Tuple[int, int], random_state: int) -> Dict: + """Elbow plot (inertia), Silhouette vs K, BIC/AIC curves.""" + k_min, k_max = k_range + ks = list(range(k_min, k_max + 1)) + inertias, silhouettes, bics, aics = [], [], [], [] + + for k in ks: + # K-Means + km = KMeans(n_clusters=k, n_init=10, random_state=random_state) + labs = km.fit_predict(self.X) + inertias.append(float(km.inertia_)) + silhouettes.append(float(silhouette_score(self.X, labs))) + + # GMM + gm = GaussianMixture(n_components=k, n_init=3, random_state=random_state) + gm.fit(self.X) + bics.append(float(gm.bic(self.X))) + aics.append(float(gm.aic(self.X))) + + # Plot + fig, axes = plt.subplots(1, 3, figsize=(18, 5)) + + axes[0].plot(ks, inertias, "bo-", linewidth=2) + axes[0].set_title("Elbow Method (Inertia)", fontweight="bold") + axes[0].set_xlabel("K"); axes[0].set_ylabel("Inertia") + + axes[1].plot(ks, silhouettes, "go-", linewidth=2) + axes[1].set_title("Silhouette Score vs K", fontweight="bold") + axes[1].set_xlabel("K"); axes[1].set_ylabel("Silhouette") + + axes[2].plot(ks, bics, "ro-", linewidth=2, label="BIC") + axes[2].plot(ks, aics, "mo-", linewidth=2, label="AIC") + axes[2].set_title("GMM: BIC / AIC", fontweight="bold") + axes[2].set_xlabel("K"); axes[2].legend() + + plt.tight_layout() + fig.savefig(self.output_dir / "optimal_k_analysis.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + return {"k_range": ks, "inertias": inertias, "silhouettes": silhouettes, "bics": bics, "aics": aics} + + # ── Step 2: Quality Metrics ── + + def _step2_quality_metrics(self) -> Dict[str, float]: + """Compute silhouette, Davies-Bouldin, Calinski-Harabasz.""" + from sklearn.metrics import davies_bouldin_score, calinski_harabasz_score + + mask = self.labels != -1 + X, labels = self.X[mask], self.labels[mask] + + if len(set(labels)) < 2: + logger.warning("Cannot compute quality metrics: < 2 clusters") + return {} + + metrics = { + "silhouette": float(silhouette_score(X, labels)), + "davies_bouldin": float(davies_bouldin_score(X, labels)), + "calinski_harabasz": float(calinski_harabasz_score(X, labels)), + "n_clusters": int(len(set(labels))), + } + + logger.info( + "Quality: Silhouette=%.3f, DB=%.3f, CH=%.1f", + metrics["silhouette"], metrics["davies_bouldin"], metrics["calinski_harabasz"], + ) + return metrics + + # ── Step 3a: PCA Loadings ── + + def _step3a_pca_loadings(self, pca: Optional[PCA]) -> Optional[Dict]: + """Generate PCA loadings heatmap.""" + if pca is None: + logger.info("No PCA object provided — fitting new PCA for loadings analysis") + pca = PCA(n_components=min(5, self.X.shape[1])).fit(self.X) + + n_components = pca.n_components_ + feature_names = self.feature_names[:pca.components_.shape[1]] + + loadings = pd.DataFrame( + pca.components_.T, + columns=[f"PC{i+1}" for i in range(n_components)], + index=feature_names, + ) + + # Heatmap + fig, ax = plt.subplots(figsize=(max(8, n_components * 1.5), max(6, len(feature_names) * 0.4))) + sns.heatmap( + loadings, annot=True, fmt=".2f", cmap="RdBu_r", + center=0, ax=ax, linewidths=0.5 + ) + ax.set_title("PCA Loadings Heatmap", fontsize=14, fontweight="bold") + plt.tight_layout() + fig.savefig(self.output_dir / "pca_loadings_heatmap.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + logger.info("PCA loadings heatmap saved (%d components × %d features)", n_components, len(feature_names)) + + return { + "explained_variance": pca.explained_variance_ratio_.tolist(), + "top_features_per_pc": { + f"PC{i+1}": loadings.iloc[:, i].abs().nlargest(5).index.tolist() + for i in range(n_components) + } + } + + # ── Step 3b: SHAP Analysis ── + + def _step3b_shap_analysis(self, random_state: int) -> Optional[Dict]: + """Train RF on cluster labels → SHAP feature importance.""" + mask = self.labels != -1 + X, labels = self.X[mask], self.labels[mask] + + if len(set(labels)) < 2: + return None + + # Train Random Forest + rf = RandomForestClassifier( + n_estimators=100, max_depth=10, random_state=random_state, n_jobs=-1, + ) + rf.fit(X, labels) + accuracy = rf.score(X, labels) + logger.info("RF classifier accuracy on cluster labels: %.3f", accuracy) + + try: + import shap + explainer = shap.TreeExplainer(rf) + shap_values = explainer.shap_values(X) + + # Summary plot + fig, ax = plt.subplots(figsize=(10, max(6, len(self.feature_names) * 0.35))) + plt.sca(ax) + shap.summary_plot( + shap_values, X, + feature_names=self.feature_names[:X.shape[1]], + show=False, max_display=15, + ) + plt.tight_layout() + fig.savefig(self.output_dir / "shap_summary.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + # Feature importance bar plot + fig, ax = plt.subplots(figsize=(10, max(6, len(self.feature_names) * 0.35))) + plt.sca(ax) + shap.summary_plot( + shap_values, X, + feature_names=self.feature_names[:X.shape[1]], + plot_type="bar", show=False, max_display=15, + ) + plt.tight_layout() + fig.savefig(self.output_dir / "shap_feature_importance.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + logger.info("SHAP plots saved") + + # Extract top features + if isinstance(shap_values, list): + mean_abs = np.mean([np.abs(sv).mean(axis=0) for sv in shap_values], axis=0) + else: + mean_abs = np.abs(shap_values).mean(axis=0) + + feature_importance = dict(zip( + self.feature_names[:X.shape[1]], + mean_abs.tolist() if hasattr(mean_abs, 'tolist') else mean_abs, + )) + + return { + "rf_accuracy": accuracy, + "feature_importance": feature_importance, + } + + except ImportError: + logger.warning("shap not installed — using RF feature_importances_ as fallback") + importance = dict(zip( + self.feature_names[:X.shape[1]], + rf.feature_importances_.tolist(), + )) + # Fallback bar plot + sorted_imp = sorted(importance.items(), key=lambda x: x[1], reverse=True)[:15] + fig, ax = plt.subplots(figsize=(10, 6)) + ax.barh([x[0] for x in sorted_imp], [x[1] for x in sorted_imp], color="#5b8def") + ax.set_title("Feature Importance (RF)", fontweight="bold") + ax.invert_yaxis() + plt.tight_layout() + fig.savefig(self.output_dir / "rf_feature_importance.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + return {"rf_accuracy": accuracy, "feature_importance": importance} + + # ── Step 3c: Cluster Profiles ── + + def _step3c_cluster_profiles(self) -> None: + """Generate radar charts and box plots per cluster.""" + mask = self.labels != -1 + n_features = min(len(self.feature_names), self.X.shape[1]) + df = pd.DataFrame(self.X[mask, :n_features], columns=self.feature_names[:n_features]) + df["cluster"] = self.labels[mask] + + n_clusters = df["cluster"].nunique() + + # Box plots for top features + top_features = self.feature_names[:min(8, n_features)] + if top_features: + fig, axes = plt.subplots(2, 4, figsize=(20, 10)) + axes = axes.flatten() + for idx, feat in enumerate(top_features): + if idx >= len(axes): + break + df.boxplot(column=feat, by="cluster", ax=axes[idx]) + axes[idx].set_title(feat, fontweight="bold") + for idx in range(len(top_features), len(axes)): + axes[idx].set_visible(False) + plt.suptitle("Feature Distributions by Cluster", fontsize=14, fontweight="bold", y=1.02) + plt.tight_layout() + fig.savefig(self.output_dir / "cluster_boxplots.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + # Cluster size distribution + fig, ax = plt.subplots(figsize=(8, 5)) + cluster_sizes = df["cluster"].value_counts().sort_index() + cluster_sizes.plot(kind="bar", ax=ax, color="#5b8def", edgecolor="white") + ax.set_title("Cluster Size Distribution", fontweight="bold") + ax.set_xlabel("Cluster"); ax.set_ylabel("Count") + for i, v in enumerate(cluster_sizes): + ax.text(i, v + 5, str(v), ha="center", fontweight="bold") + plt.tight_layout() + fig.savefig(self.output_dir / "cluster_sizes.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + logger.info("Cluster profile plots saved") + + # ── Step 4: Stability ── + + def _step4_stability(self, random_state: int, n_bootstraps: int = 30) -> Dict: + """Bootstrap stability test using Adjusted Rand Index.""" + ari_scores = [] + n_samples = len(self.X) + n_clusters = len(set(self.labels) - {-1}) + + if n_clusters < 2: + return {"ari_mean": 0, "ari_std": 0, "n_bootstraps": 0} + + for i in range(n_bootstraps): + rng = np.random.RandomState(random_state + i) + idx = rng.choice(n_samples, size=n_samples, replace=True) + + km = KMeans(n_clusters=n_clusters, n_init=5, random_state=random_state + i) + boot_labels = km.fit_predict(self.X[idx]) + + # Compare with original labels (reindexed) + ari = adjusted_rand_score(self.labels[idx], boot_labels) + ari_scores.append(float(ari)) + + result = { + "ari_mean": float(np.mean(ari_scores)), + "ari_std": float(np.std(ari_scores)), + "n_bootstraps": n_bootstraps, + "stable": float(np.mean(ari_scores)) >= 0.7, + } + + logger.info("Bootstrap stability: ARI=%.3f ± %.3f (stable=%s)", result["ari_mean"], result["ari_std"], result["stable"]) + return result + + # ── Utility ── + + @staticmethod + def _serialize_report(report: Dict) -> Dict: + """Make report JSON-serializable.""" + def _convert(obj): + if isinstance(obj, (np.integer,)): + return int(obj) + if isinstance(obj, (np.floating,)): + return float(obj) + if isinstance(obj, np.ndarray): + return obj.tolist() + if isinstance(obj, dict): + return {k: _convert(v) for k, v in obj.items()} + if isinstance(obj, list): + return [_convert(v) for v in obj] + return obj + return _convert(report) diff --git a/clustering.py b/clustering.py new file mode 100644 index 0000000..4ea046b --- /dev/null +++ b/clustering.py @@ -0,0 +1,311 @@ +""" +Segmentation Plus — Clustering Engine +====================================== +K-Means, DBSCAN, and GMM clustering with hyperparameter search +and model comparison. +""" + +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Tuple + +import numpy as np +import pandas as pd +from sklearn.cluster import DBSCAN, KMeans +from sklearn.metrics import ( + calinski_harabasz_score, + davies_bouldin_score, + silhouette_score, +) +from sklearn.mixture import GaussianMixture + +logger = logging.getLogger(__name__) + + +# ────────────────────────────────────────────── +# Clustering Result +# ────────────────────────────────────────────── + +@dataclass +class ClusteringResult: + """Container for a single clustering run's outputs.""" + + algorithm: str + labels: np.ndarray + n_clusters: int + metrics: Dict[str, float] = field(default_factory=dict) + model: object = None # The fitted model object + probabilities: Optional[np.ndarray] = None # GMM soft assignments + extra: Dict = field(default_factory=dict) + + @property + def is_valid(self) -> bool: + """Check if clustering produced at least 2 distinct clusters.""" + unique = len(set(self.labels) - {-1}) # Exclude DBSCAN noise + return unique >= 2 + + +# ────────────────────────────────────────────── +# Clustering Engine +# ────────────────────────────────────────────── + +class ClusteringEngine: + """ + Runs multiple clustering algorithms, evaluates them, + and selects the best model. + + Parameters + ---------- + X : np.ndarray + Scaled/PCA-transformed feature matrix (n_samples, n_features). + k_range : tuple + Min and max K to evaluate (default: 2 to 10). + random_state : int + Random seed for reproducibility. + """ + + def __init__( + self, + X: np.ndarray, + k_range: Tuple[int, int] = (2, 10), + random_state: int = 42, + ) -> None: + self.X = X + self.k_min, self.k_max = k_range + self.random_state = random_state + self.results: Dict[str, ClusteringResult] = {} + + # ── K-Means ── + + def run_kmeans(self, n_clusters: Optional[int] = None) -> ClusteringResult: + """ + Run K-Means clustering. + + If n_clusters is None, runs elbow analysis and picks the optimal K. + """ + logger.info("Running K-Means clustering...") + + if n_clusters is None: + n_clusters = self._find_optimal_k_kmeans() + + model = KMeans( + n_clusters=n_clusters, + n_init=10, + max_iter=300, + random_state=self.random_state, + ) + labels = model.fit_predict(self.X) + + result = ClusteringResult( + algorithm="kmeans", + labels=labels, + n_clusters=n_clusters, + model=model, + extra={"inertia": model.inertia_}, + ) + result.metrics = self._compute_metrics(labels) + + self.results["kmeans"] = result + logger.info( + "K-Means: K=%d, Silhouette=%.3f, Inertia=%.1f", + n_clusters, result.metrics.get("silhouette", 0), model.inertia_, + ) + return result + + def _find_optimal_k_kmeans(self) -> int: + """Find optimal K using silhouette score sweep.""" + best_k, best_score = 2, -1 + scores = {} + + for k in range(self.k_min, self.k_max + 1): + km = KMeans(n_clusters=k, n_init=10, random_state=self.random_state) + labs = km.fit_predict(self.X) + score = silhouette_score(self.X, labs) + scores[k] = score + if score > best_score: + best_k, best_score = k, score + + logger.info("K-Means silhouette sweep: %s → optimal K=%d (%.3f)", scores, best_k, best_score) + return best_k + + # ── DBSCAN ── + + def run_dbscan( + self, + eps: Optional[float] = None, + min_samples: int = 5, + ) -> ClusteringResult: + """ + Run DBSCAN clustering. + + If eps is None, auto-selects using k-distance heuristic. + """ + logger.info("Running DBSCAN clustering...") + + if eps is None: + eps = self._estimate_eps(min_samples) + + model = DBSCAN(eps=eps, min_samples=min_samples) + labels = model.fit_predict(self.X) + + n_clusters = len(set(labels) - {-1}) + n_noise = int((labels == -1).sum()) + + result = ClusteringResult( + algorithm="dbscan", + labels=labels, + n_clusters=n_clusters, + model=model, + extra={"eps": eps, "min_samples": min_samples, "n_noise": n_noise}, + ) + + if result.is_valid: + result.metrics = self._compute_metrics(labels[labels != -1], exclude_noise=True) + else: + logger.warning("DBSCAN found < 2 clusters (n_clusters=%d, noise=%d)", n_clusters, n_noise) + + self.results["dbscan"] = result + logger.info("DBSCAN: clusters=%d, noise=%d, eps=%.3f", n_clusters, n_noise, eps) + return result + + def _estimate_eps(self, min_samples: int) -> float: + """Estimate eps using k-distance plot knee detection.""" + from sklearn.neighbors import NearestNeighbors + + nn = NearestNeighbors(n_neighbors=min_samples) + nn.fit(self.X) + distances, _ = nn.kneighbors(self.X) + k_distances = np.sort(distances[:, -1]) + + # Simple knee detection: point of max curvature + diffs = np.diff(k_distances) + knee_idx = np.argmax(diffs) + 1 + eps = float(k_distances[knee_idx]) + + logger.info("Auto-estimated DBSCAN eps=%.3f (knee at index %d)", eps, knee_idx) + return eps + + # ── GMM ── + + def run_gmm(self, n_components: Optional[int] = None) -> ClusteringResult: + """ + Run Gaussian Mixture Model clustering. + + If n_components is None, selects using BIC minimization. + """ + logger.info("Running GMM clustering...") + + if n_components is None: + n_components = self._find_optimal_k_gmm() + + model = GaussianMixture( + n_components=n_components, + covariance_type="full", + n_init=3, + random_state=self.random_state, + ) + labels = model.fit_predict(self.X) + probabilities = model.predict_proba(self.X) + + result = ClusteringResult( + algorithm="gmm", + labels=labels, + n_clusters=n_components, + model=model, + probabilities=probabilities, + extra={ + "bic": model.bic(self.X), + "aic": model.aic(self.X), + "converged": model.converged_, + }, + ) + result.metrics = self._compute_metrics(labels) + + self.results["gmm"] = result + logger.info( + "GMM: K=%d, Silhouette=%.3f, BIC=%.1f, AIC=%.1f", + n_components, result.metrics.get("silhouette", 0), + result.extra["bic"], result.extra["aic"], + ) + return result + + def _find_optimal_k_gmm(self) -> int: + """Find optimal K for GMM using BIC minimization.""" + best_k, best_bic = 2, np.inf + + for k in range(self.k_min, self.k_max + 1): + gm = GaussianMixture( + n_components=k, covariance_type="full", + n_init=3, random_state=self.random_state, + ) + gm.fit(self.X) + bic = gm.bic(self.X) + if bic < best_bic: + best_k, best_bic = k, bic + + logger.info("GMM BIC sweep → optimal K=%d (BIC=%.1f)", best_k, best_bic) + return best_k + + # ── Metrics ── + + def _compute_metrics( + self, labels: np.ndarray, exclude_noise: bool = False, + ) -> Dict[str, float]: + """Compute clustering quality metrics.""" + X = self.X + if exclude_noise: + mask = labels != -1 + X = self.X[mask] + labels = labels[mask] + + if len(set(labels)) < 2: + return {} + + return { + "silhouette": float(silhouette_score(X, labels)), + "davies_bouldin": float(davies_bouldin_score(X, labels)), + "calinski_harabasz": float(calinski_harabasz_score(X, labels)), + } + + # ── Run All & Compare ── + + def run_all(self) -> Dict[str, ClusteringResult]: + """Run all three algorithms and return results.""" + self.run_kmeans() + self.run_dbscan() + self.run_gmm() + return self.results + + def get_best_model(self, metric: str = "silhouette") -> ClusteringResult: + """ + Select best model by a given metric. + + Parameters + ---------- + metric : str + Metric to compare (default: 'silhouette', higher is better). + + Returns + ------- + ClusteringResult + Best performing clustering result. + """ + valid = { + name: r for name, r in self.results.items() + if r.is_valid and metric in r.metrics + } + + if not valid: + raise ValueError("No valid clustering results found.") + + # Higher is better for silhouette & calinski_harabasz; lower for davies_bouldin + reverse = metric != "davies_bouldin" + best_name = max(valid, key=lambda n: valid[n].metrics[metric] * (1 if reverse else -1)) + + logger.info( + "Best model by %s: %s (%.4f)", + metric, best_name, valid[best_name].metrics[metric], + ) + return valid[best_name] diff --git a/config.py b/config.py new file mode 100644 index 0000000..3a8450c --- /dev/null +++ b/config.py @@ -0,0 +1,181 @@ +""" +Segmentation Plus — Domain Configuration System +================================================= +Loads domain-specific YAML configs that drive the entire pipeline: +EDA, feature engineering, clustering, and persona generation. +""" + +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Dict, List, Optional + +import yaml + +logger = logging.getLogger(__name__) + +# ────────────────────────────────────────────── +# Domain Config Dataclass +# ────────────────────────────────────────────── + +@dataclass +class FeatureEngineeringRule: + """Single feature engineering rule from the domain config.""" + name: str + formula: str + bins: Optional[List[str]] = None + description: str = "" + + +@dataclass +class DomainConfig: + """ + Complete configuration for a single domain. + + Attributes + ---------- + domain_key : str + Machine-readable domain identifier (e.g., 'financial_services'). + display_name : str + Human-readable name (e.g., 'Financial Services'). + features : dict + Feature groups → list of column names. + required_columns : list + Columns that MUST exist in any input dataset for this domain. + feature_engineering : list + Derived feature rules (formulas, bins, etc.). + eda_analyses : list + Domain-specific EDA analyses to run. + persona_prompt_template : str + Jinja-style prompt template for GenAI persona generation. + scaling_exclude : list + Columns to exclude from StandardScaler (e.g., IDs, booleans). + categorical_columns : list + Columns to one-hot encode. + target_column : str | None + Optional target column (not used in unsupervised, but kept for flexibility). + metadata : dict + Any extra domain-specific metadata. + """ + + domain_key: str + display_name: str + features: Dict[str, List[str]] = field(default_factory=dict) + required_columns: List[str] = field(default_factory=list) + feature_engineering: List[FeatureEngineeringRule] = field(default_factory=list) + eda_analyses: List[str] = field(default_factory=list) + persona_prompt_template: str = "" + scaling_exclude: List[str] = field(default_factory=list) + categorical_columns: List[str] = field(default_factory=list) + target_column: Optional[str] = None + metadata: Dict[str, Any] = field(default_factory=dict) + + # ── Computed properties ── + + @property + def all_feature_columns(self) -> List[str]: + """Flatten all feature groups into a single list.""" + cols = [] + for group_cols in self.features.values(): + cols.extend(group_cols) + return cols + + @property + def numerical_columns(self) -> List[str]: + """All feature columns minus categorical ones.""" + return [c for c in self.all_feature_columns if c not in self.categorical_columns] + + +# ────────────────────────────────────────────── +# Config Loader +# ────────────────────────────────────────────── + +_DOMAINS_DIR = Path(__file__).parent / "domains" + + +def list_available_domains() -> List[str]: + """Return names of all available domain configs (without .yaml extension).""" + if not _DOMAINS_DIR.exists(): + return [] + return [ + p.stem for p in _DOMAINS_DIR.glob("*.yaml") + if not p.stem.startswith("_") + ] + + +def load_domain_config(domain_key: str, config_path: Optional[Path] = None) -> DomainConfig: + """ + Load and parse a domain YAML config into a DomainConfig dataclass. + + Parameters + ---------- + domain_key : str + Name of the domain (matches the YAML filename without extension). + config_path : Path, optional + Override path. If None, looks in the default `domains/` directory. + + Returns + ------- + DomainConfig + Fully parsed domain configuration. + + Raises + ------ + FileNotFoundError + If the YAML file does not exist. + ValueError + If the YAML is malformed or missing required fields. + """ + if config_path is None: + config_path = _DOMAINS_DIR / f"{domain_key}.yaml" + + if not config_path.exists(): + available = list_available_domains() + raise FileNotFoundError( + f"Domain config '{domain_key}' not found at {config_path}. " + f"Available domains: {available}" + ) + + logger.info("Loading domain config: %s from %s", domain_key, config_path) + + with open(config_path, "r", encoding="utf-8") as f: + raw: Dict[str, Any] = yaml.safe_load(f) + + if not raw or not isinstance(raw, dict): + raise ValueError(f"Domain config '{config_path}' is empty or malformed.") + + # Parse feature engineering rules + fe_rules = [] + for rule_dict in raw.get("feature_engineering", []): + fe_rules.append(FeatureEngineeringRule( + name=rule_dict["name"], + formula=rule_dict.get("formula", ""), + bins=rule_dict.get("bins"), + description=rule_dict.get("description", ""), + )) + + config = DomainConfig( + domain_key=raw.get("domain", domain_key), + display_name=raw.get("display_name", domain_key.replace("_", " ").title()), + features=raw.get("features", {}), + required_columns=raw.get("required_columns", []), + feature_engineering=fe_rules, + eda_analyses=raw.get("eda", {}).get("domain_analyses", []), + persona_prompt_template=raw.get("persona_prompt_template", ""), + scaling_exclude=raw.get("scaling_exclude", []), + categorical_columns=raw.get("categorical_columns", []), + target_column=raw.get("target_column"), + metadata=raw.get("metadata", {}), + ) + + logger.info( + "Loaded domain '%s': %d feature groups, %d FE rules, %d EDA analyses", + config.display_name, + len(config.features), + len(config.feature_engineering), + len(config.eda_analyses), + ) + + return config diff --git a/dashboard.py b/dashboard.py new file mode 100644 index 0000000..77f8158 --- /dev/null +++ b/dashboard.py @@ -0,0 +1,317 @@ +""" +Segmentation Plus — Interactive Dashboard +========================================== +Plotly-based interactive dashboard combining cluster visualizations, +evaluation metrics, and persona cards into a single HTML file. +""" + +from __future__ import annotations + +import json +import logging +from pathlib import Path +from typing import Any, Dict, List, Optional + +import numpy as np +import pandas as pd +import plotly.express as px +import plotly.graph_objects as go +from plotly.subplots import make_subplots + +logger = logging.getLogger(__name__) + + +class DashboardBuilder: + """ + Builds an interactive HTML dashboard. + + Parameters + ---------- + output_dir : Path + Directory to save the dashboard HTML. + """ + + def __init__(self, output_dir: Path) -> None: + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + self.sections: List[str] = [] + + def build( + self, + df: pd.DataFrame, + labels: np.ndarray, + X_for_viz: np.ndarray, + feature_names: List[str], + personas: Optional[List[Dict]] = None, + evaluation_report: Optional[Dict] = None, + ) -> Path: + """ + Build and save the full dashboard. + + Parameters + ---------- + df : pd.DataFrame + Original DataFrame. + labels : np.ndarray + Cluster assignments. + X_for_viz : np.ndarray + 2D or 3D array for scatter plots (PCA-reduced). + feature_names : list[str] + Feature column names. + personas : list[dict], optional + Generated personas. + evaluation_report : dict, optional + Evaluation metrics. + + Returns + ------- + Path + Path to the saved dashboard HTML file. + """ + logger.info("Building interactive dashboard...") + + self.sections = [] + + # Cluster scatter plot + self._add_cluster_scatter(X_for_viz, labels) + + # Cluster size distribution + self._add_cluster_sizes(labels) + + # Feature distributions by cluster + self._add_feature_distributions(df, labels, feature_names) + + # Cluster radar chart + self._add_radar_chart(df, labels, feature_names) + + # Evaluation metrics summary + if evaluation_report: + self._add_metrics_summary(evaluation_report) + + # Persona cards + if personas: + self._add_persona_cards(personas) + + # Combine into HTML + html = self._render_html() + output_path = self.output_dir / "dashboard.html" + with open(output_path, "w", encoding="utf-8") as f: + f.write(html) + + logger.info("Dashboard saved to %s", output_path) + return output_path + + def _add_cluster_scatter(self, X: np.ndarray, labels: np.ndarray) -> None: + """PCA scatter plot colored by cluster.""" + df_plot = pd.DataFrame({ + "PC1": X[:, 0], + "PC2": X[:, 1] if X.shape[1] > 1 else np.zeros(len(X)), + "Cluster": labels.astype(str), + }) + + fig = px.scatter( + df_plot, x="PC1", y="PC2", color="Cluster", + title="Customer Segments (PCA Projection)", + opacity=0.6, width=900, height=500, + color_discrete_sequence=px.colors.qualitative.Set2, + ) + fig.update_layout( + template="plotly_dark", + plot_bgcolor="#1e2233", + paper_bgcolor="#0f1117", + font=dict(family="Inter"), + ) + self.sections.append(("Cluster Scatter Plot", fig.to_html(include_plotlyjs=False, full_html=False))) + + def _add_cluster_sizes(self, labels: np.ndarray) -> None: + """Cluster size bar chart.""" + unique, counts = np.unique(labels[labels != -1], return_counts=True) + + fig = go.Figure(data=[go.Bar( + x=[f"Segment {c}" for c in unique], + y=counts, + marker_color=px.colors.qualitative.Set2[:len(unique)], + text=counts, textposition="auto", + )]) + fig.update_layout( + title="Segment Size Distribution", + template="plotly_dark", + plot_bgcolor="#1e2233", + paper_bgcolor="#0f1117", + width=900, height=400, + font=dict(family="Inter"), + ) + self.sections.append(("Segment Sizes", fig.to_html(include_plotlyjs=False, full_html=False))) + + def _add_feature_distributions( + self, df: pd.DataFrame, labels: np.ndarray, feature_names: List[str], + ) -> None: + """Violin plots for key features per cluster.""" + plot_df = df.copy() + plot_df["Cluster"] = labels.astype(str) + + numeric_features = [ + c for c in feature_names + if c in plot_df.columns and plot_df[c].dtype in [np.float64, np.int64] + ][:6] # Top 6 features + + if not numeric_features: + return + + fig = make_subplots(rows=2, cols=3, subplot_titles=numeric_features) + for idx, feat in enumerate(numeric_features): + row, col = idx // 3 + 1, idx % 3 + 1 + for cluster_val in sorted(plot_df["Cluster"].unique()): + subset = plot_df[plot_df["Cluster"] == cluster_val] + fig.add_trace( + go.Violin(y=subset[feat], name=f"Seg {cluster_val}", legendgroup=cluster_val, + scalemode="count", showlegend=(idx == 0)), + row=row, col=col, + ) + + fig.update_layout( + title="Feature Distributions by Segment", + template="plotly_dark", plot_bgcolor="#1e2233", paper_bgcolor="#0f1117", + width=1000, height=600, font=dict(family="Inter"), + ) + self.sections.append(("Feature Distributions", fig.to_html(include_plotlyjs=False, full_html=False))) + + def _add_radar_chart( + self, df: pd.DataFrame, labels: np.ndarray, feature_names: List[str], + ) -> None: + """Radar chart comparing cluster profiles.""" + plot_df = df.copy() + plot_df["cluster"] = labels + + numeric_features = [ + c for c in feature_names + if c in plot_df.columns and plot_df[c].dtype in [np.float64, np.int64] + ][:8] + + if len(numeric_features) < 3: + return + + # Normalize to 0-1 for radar + means = plot_df.groupby("cluster")[numeric_features].mean() + for col in numeric_features: + col_range = means[col].max() - means[col].min() + if col_range > 0: + means[col] = (means[col] - means[col].min()) / col_range + + fig = go.Figure() + colors = px.colors.qualitative.Set2 + for idx, (cluster_id, row) in enumerate(means.iterrows()): + if cluster_id == -1: + continue + fig.add_trace(go.Scatterpolar( + r=row.values.tolist() + [row.values[0]], + theta=numeric_features + [numeric_features[0]], + fill="toself", name=f"Segment {cluster_id}", + opacity=0.6, line=dict(color=colors[idx % len(colors)]), + )) + + fig.update_layout( + title="Segment Profile Comparison", + template="plotly_dark", paper_bgcolor="#0f1117", + width=800, height=500, font=dict(family="Inter"), + polar=dict(bgcolor="#1e2233"), + ) + self.sections.append(("Radar Comparison", fig.to_html(include_plotlyjs=False, full_html=False))) + + def _add_metrics_summary(self, report: Dict) -> None: + """Render evaluation metrics as an HTML card.""" + quality = report.get("quality_metrics", {}) + stability = report.get("stability", {}) + + html = '
' + metrics = [ + ("Silhouette", f"{quality.get('silhouette', 0):.3f}", "#5b8def"), + ("Davies-Bouldin", f"{quality.get('davies_bouldin', 0):.3f}", "#fb923c"), + ("Calinski-Harabasz", f"{quality.get('calinski_harabasz', 0):.0f}", "#34d399"), + ("Stability (ARI)", f"{stability.get('ari_mean', 0):.3f}", "#a78bfa"), + ] + for name, val, color in metrics: + html += f''' +
+
{name}
+
{val}
+
''' + html += '
' + self.sections.append(("Evaluation Metrics", html)) + + def _add_persona_cards(self, personas: List[Dict]) -> None: + """Render persona cards as styled HTML.""" + cards_html = '
' + + for p in personas: + name = p.get("name", f"Segment {p.get('segment_id', '?')}") + tagline = p.get("tagline", "") + size = p.get("segment_size", "?") + pct = p.get("segment_pct", "?") + + goals = p.get("goals", []) + if isinstance(goals, str): + goals = [goals] + goals_html = "".join(f"
  • {g}
  • " for g in goals[:4]) + + pain_points = p.get("pain_points", []) + if isinstance(pain_points, str): + pain_points = [pain_points] + pp_html = "".join(f"
  • {pp}
  • " for pp in pain_points[:4]) + + cards_html += f''' +
    +
    + 🧑 {name} +
    +
    + {tagline} +
    +
    + {size} customers ({pct}% of total) +
    +
    + Goals: +
      {goals_html}
    + Pain Points: +
      {pp_html}
    +
    +
    ''' + cards_html += '
    ' + self.sections.append(("Customer Personas", cards_html)) + + def _render_html(self) -> str: + """Combine all sections into a final HTML page.""" + sections_html = "" + for title, content in self.sections: + sections_html += f''' +
    +

    {title}

    + {content} +
    ''' + + return f''' + + +Segmentation Plus — Dashboard + + + +
    +

    Segmentation Plus — Dashboard

    +

    Interactive customer segmentation results and AI-generated personas

    +
    +
    {sections_html}
    +''' diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data_import.py b/data_import.py new file mode 100644 index 0000000..800e51b --- /dev/null +++ b/data_import.py @@ -0,0 +1,275 @@ +""" +Segmentation Plus — Data Import & Validation +============================================= +Production-grade data ingestion with schema validation, +column mapping, and data quality checks. +""" + +from __future__ import annotations + +import logging +from pathlib import Path +from typing import Optional, Tuple + +import numpy as np +import pandas as pd + +from config import DomainConfig + +logger = logging.getLogger(__name__) + + +# ────────────────────────────────────────────── +# Data Quality Report +# ────────────────────────────────────────────── + +class DataQualityReport: + """Stores data quality check results.""" + + def __init__(self) -> None: + self.total_rows: int = 0 + self.total_columns: int = 0 + self.missing_values: dict[str, int] = {} + self.missing_pct: dict[str, float] = {} + self.duplicate_rows: int = 0 + self.column_types: dict[str, str] = {} + self.warnings: list[str] = [] + self.errors: list[str] = [] + self.passed: bool = True + + def summary(self) -> str: + status = "✅ PASSED" if self.passed else "❌ FAILED" + lines = [ + f"Data Quality Report — {status}", + f" Rows: {self.total_rows:,} | Columns: {self.total_columns}", + f" Duplicates: {self.duplicate_rows}", + ] + if self.warnings: + lines.append(f" Warnings ({len(self.warnings)}):") + for w in self.warnings: + lines.append(f" ⚠ {w}") + if self.errors: + lines.append(f" Errors ({len(self.errors)}):") + for e in self.errors: + lines.append(f" ✗ {e}") + return "\n".join(lines) + + +# ────────────────────────────────────────────── +# Data Loader +# ────────────────────────────────────────────── + +def load_data( + file_path: str | Path, + sheet_name: Optional[str] = None, +) -> pd.DataFrame: + """ + Load data from CSV or Excel file. + + Parameters + ---------- + file_path : str or Path + Path to the data file (.csv, .xlsx, .xls). + sheet_name : str, optional + Sheet name for Excel files. + + Returns + ------- + pd.DataFrame + Raw loaded DataFrame. + + Raises + ------ + FileNotFoundError + If the file does not exist. + ValueError + If the file format is not supported. + """ + path = Path(file_path) + + if not path.exists(): + raise FileNotFoundError(f"Data file not found: {path}") + + suffix = path.suffix.lower() + logger.info("Loading data from %s (%s)", path.name, suffix) + + if suffix == ".csv": + df = pd.read_csv(path) + elif suffix in (".xlsx", ".xls"): + df = pd.read_excel(path, sheet_name=sheet_name) + elif suffix == ".parquet": + df = pd.read_parquet(path) + else: + raise ValueError( + f"Unsupported file format: '{suffix}'. " + f"Supported: .csv, .xlsx, .xls, .parquet" + ) + + logger.info("Loaded %d rows × %d columns", len(df), len(df.columns)) + return df + + +# ────────────────────────────────────────────── +# Schema Validation +# ────────────────────────────────────────────── + +def validate_schema( + df: pd.DataFrame, + domain_config: DomainConfig, + strict: bool = False, +) -> DataQualityReport: + """ + Validate a DataFrame against the domain schema. + + Parameters + ---------- + df : pd.DataFrame + Input data to validate. + domain_config : DomainConfig + Domain configuration with required columns and feature schema. + strict : bool + If True, fail on warnings (missing optional columns). Default False. + + Returns + ------- + DataQualityReport + Detailed quality report with pass/fail status. + """ + report = DataQualityReport() + report.total_rows = len(df) + report.total_columns = len(df.columns) + report.column_types = {col: str(df[col].dtype) for col in df.columns} + + # 1. Check required columns + df_cols_lower = {c.lower(): c for c in df.columns} + for req_col in domain_config.required_columns: + if req_col.lower() not in df_cols_lower: + report.errors.append(f"Required column missing: '{req_col}'") + report.passed = False + + # 2. Check optional domain feature columns + all_domain_cols = domain_config.all_feature_columns + for col in all_domain_cols: + if col.lower() not in df_cols_lower and col not in df.columns: + report.warnings.append(f"Domain feature column missing: '{col}'") + if strict: + report.passed = False + + # 3. Missing values + missing = df.isnull().sum() + for col in df.columns: + if missing[col] > 0: + report.missing_values[col] = int(missing[col]) + report.missing_pct[col] = round(missing[col] / len(df) * 100, 2) + if report.missing_pct[col] > 50: + report.warnings.append( + f"Column '{col}' has {report.missing_pct[col]:.1f}% missing values" + ) + + # 4. Duplicate rows + report.duplicate_rows = int(df.duplicated().sum()) + if report.duplicate_rows > 0: + report.warnings.append( + f"{report.duplicate_rows} duplicate rows found ({report.duplicate_rows/len(df)*100:.1f}%)" + ) + + # 5. Row count check + if len(df) < 50: + report.warnings.append( + f"Very small dataset ({len(df)} rows) — clustering may not be reliable" + ) + + logger.info("Schema validation: %s", "PASSED" if report.passed else "FAILED") + return report + + +# ────────────────────────────────────────────── +# Column Mapping (fuzzy matching) +# ────────────────────────────────────────────── + +def auto_map_columns( + df: pd.DataFrame, + domain_config: DomainConfig, +) -> Tuple[pd.DataFrame, dict[str, str]]: + """ + Attempt to auto-map DataFrame columns to domain schema columns + using case-insensitive and partial matching. + + Parameters + ---------- + df : pd.DataFrame + Input DataFrame with potentially different column names. + domain_config : DomainConfig + Domain config with expected column names. + + Returns + ------- + tuple[pd.DataFrame, dict] + Renamed DataFrame and the mapping used (original → domain). + """ + mapping: dict[str, str] = {} + domain_cols = ( + domain_config.required_columns + domain_config.all_feature_columns + ) + + df_cols_lower = {c.lower().replace(" ", "_").replace("-", "_"): c for c in df.columns} + + for domain_col in domain_cols: + normalized = domain_col.lower().replace(" ", "_").replace("-", "_") + + # Exact match (case-insensitive) + if normalized in df_cols_lower: + original = df_cols_lower[normalized] + if original != domain_col: + mapping[original] = domain_col + + if mapping: + logger.info("Auto-mapped %d columns: %s", len(mapping), mapping) + df = df.rename(columns=mapping) + + return df, mapping + + +# ────────────────────────────────────────────── +# Public API +# ────────────────────────────────────────────── + +def import_and_validate( + file_path: str | Path, + domain_config: DomainConfig, + auto_map: bool = True, + sheet_name: Optional[str] = None, +) -> Tuple[pd.DataFrame, DataQualityReport]: + """ + Full import pipeline: load → auto-map → validate → report. + + Parameters + ---------- + file_path : str or Path + Path to data file. + domain_config : DomainConfig + Domain configuration to validate against. + auto_map : bool + Whether to attempt automatic column name mapping. + sheet_name : str, optional + Sheet name for Excel files. + + Returns + ------- + tuple[pd.DataFrame, DataQualityReport] + Processed DataFrame and its quality report. + """ + # Load + df = load_data(file_path, sheet_name=sheet_name) + + # Auto-map columns + if auto_map: + df, col_mapping = auto_map_columns(df, domain_config) + + # Validate + report = validate_schema(df, domain_config) + + # Log summary + logger.info("\n%s", report.summary()) + + return df, report diff --git a/domains/_template.yaml b/domains/_template.yaml new file mode 100644 index 0000000..a18d032 --- /dev/null +++ b/domains/_template.yaml @@ -0,0 +1,51 @@ +# Domain Configuration Template +# Copy this file and customize for your domain. + +domain: my_domain +display_name: "My Domain" + +required_columns: + - customer_id + +features: + demographics: [] + # Add your feature groups here: + # financial: [col1, col2] + # behavioral: [col3, col4] + +categorical_columns: [] + +scaling_exclude: + - customer_id + +feature_engineering: [] + # - name: derived_feature + # formula: "col1 * col2" + # description: "Description of what this feature captures" + +eda: + domain_analyses: [] + # - my_custom_analysis + +persona_prompt_template: | + You are a marketing strategist advising a company on their customer segments. + + Segment {segment_id} Profile: + {segment_stats} + + Top SHAP Feature Drivers: + {shap_drivers} + + Generate a detailed customer persona with: + 1. Persona Name + 2. One-Line Description + 3. Demographics & Lifestyle + 4. Goals + 5. Pain Points + 6. Product Recommendations + 7. Preferred Channels + 8. Marketing Strategy + + Output as structured JSON. + +metadata: {} diff --git a/domains/financial_services.yaml b/domains/financial_services.yaml new file mode 100644 index 0000000..beeed7c --- /dev/null +++ b/domains/financial_services.yaml @@ -0,0 +1,113 @@ +domain: financial_services +display_name: "Financial Services" + +required_columns: + - customer_id + - age + - annual_income + +features: + demographics: + - age + - gender + - annual_income + - education + - marital_status + - dependents + - occupation + financial: + - account_balance + - credit_score + - monthly_spending + - savings_rate + - debt_to_income_ratio + - investment_portfolio_value + products: + - has_credit_card + - has_mortgage + - has_personal_loan + - has_investment_account + - has_insurance + - num_products + behavioral: + - digital_engagement_score + - branch_visits_monthly + - customer_tenure_years + - transaction_frequency_monthly + - avg_transaction_amount + satisfaction: + - nps_score + - complaint_count_yearly + - churn_risk_score + +categorical_columns: + - gender + - education + - marital_status + - occupation + +scaling_exclude: + - customer_id + - has_credit_card + - has_mortgage + - has_personal_loan + - has_investment_account + - has_insurance + +feature_engineering: + - name: wealth_tier + formula: "annual_income * investment_portfolio_value" + bins: [low, medium, high, ultra_high] + description: "Combined wealth indicator from income and portfolio" + + - name: digital_vs_branch_ratio + formula: "digital_engagement_score / (digital_engagement_score + branch_visits_monthly + 1)" + description: "Channel preference ratio: higher = more digital" + + - name: product_depth + formula: "has_credit_card + has_mortgage + has_personal_loan + has_investment_account + has_insurance" + description: "Total number of product types held" + + - name: spending_to_income_ratio + formula: "monthly_spending / (annual_income / 12 + 1)" + description: "Monthly spending as fraction of monthly income" + + - name: risk_category + formula: "credit_score * (1 - debt_to_income_ratio)" + description: "Combined credit-risk indicator" + +eda: + domain_analyses: + - income_distribution_by_segment + - credit_score_vs_product_holdings + - debt_to_income_analysis + - high_value_customer_identification + - product_cross_holding_matrix + - digital_vs_branch_preference + +persona_prompt_template: | + You are a marketing strategist advising a financial services institution + (bank, insurer, or wealth management firm) on their customer segments. + + Segment {segment_id} Profile: + {segment_stats} + + Top SHAP Feature Drivers: + {shap_drivers} + + Based on this data, generate a detailed customer persona including: + 1. Persona Name — a memorable, representative name + 2. One-Line Description — a concise tagline + 3. Demographics & Lifestyle — age range, income bracket, life stage + 4. Financial Goals — what they want to achieve + 5. Pain Points — frustrations, unmet needs + 6. Product Recommendations — cross-sell / upsell opportunities + 7. Preferred Communication Channels — email, app, branch, phone + 8. Marketing Strategy — tone, timing, offer types, campaign ideas + + Output as structured JSON with keys: name, tagline, demographics, + goals, pain_points, product_recommendations, channels, strategy. + +metadata: + institution_types: [bank, insurer, wealth_manager, credit_union] + typical_customer_count: "10K - 5M" diff --git a/domains/retail.yaml b/domains/retail.yaml new file mode 100644 index 0000000..01685cc --- /dev/null +++ b/domains/retail.yaml @@ -0,0 +1,104 @@ +domain: retail +display_name: "Retail" + +required_columns: + - customer_id + - total_spend + +features: + demographics: + - age + - gender + - annual_income + - location_tier + - marital_status + transactional: + - total_spend + - avg_order_value + - purchase_frequency_monthly + - days_since_last_purchase + - total_orders + - return_rate + product: + - has_loyalty_card + - has_subscription + - is_premium_tier + - top_category + - num_categories_purchased + behavioral: + - online_vs_instore_ratio + - browse_to_buy_ratio + - coupon_usage_rate + - avg_session_duration_min + - app_visits_monthly + satisfaction: + - csat_score + - review_rating + - support_tickets_yearly + +categorical_columns: + - gender + - location_tier + - marital_status + - top_category + +scaling_exclude: + - customer_id + - has_loyalty_card + - has_subscription + - is_premium_tier + +feature_engineering: + - name: rfm_recency + formula: "1 / (days_since_last_purchase + 1)" + description: "Inverse recency — higher = more recent purchase" + + - name: rfm_frequency + formula: "purchase_frequency_monthly" + description: "Direct frequency measure" + + - name: rfm_monetary + formula: "avg_order_value * purchase_frequency_monthly" + description: "Estimated monthly revenue from customer" + + - name: discount_sensitivity + formula: "coupon_usage_rate * (1 - avg_order_value / (total_spend / (total_orders + 1) + 1))" + description: "How responsive customer is to discounts" + + - name: cross_category_shopper + formula: "num_categories_purchased >= 3" + description: "Boolean: shops across 3+ categories" + +eda: + domain_analyses: + - rfm_scoring_matrix + - basket_composition_analysis + - seasonal_purchase_patterns + - channel_preference_mapping + - category_affinity_heatmap + - customer_lifetime_value_distribution + +persona_prompt_template: | + You are a retail marketing strategist advising a brand on their customer segments. + + Segment {segment_id} Profile: + {segment_stats} + + Top SHAP Feature Drivers: + {shap_drivers} + + Based on this data, generate a detailed customer persona including: + 1. Persona Name — a memorable, representative shopper name + 2. One-Line Description — a concise tagline + 3. Demographics & Lifestyle — age range, income, shopping style + 4. Shopping Habits — frequency, channels, categories, timing + 5. Brand Affinities — what they value in a brand + 6. Pain Points — frustrations, barriers to purchase + 7. Product Recommendations — categories, items, bundles + 8. Retention Strategy — loyalty, re-engagement, upsell ideas + + Output as structured JSON with keys: name, tagline, demographics, + shopping_habits, brand_affinities, pain_points, product_recommendations, strategy. + +metadata: + business_types: [ecommerce, brick_and_mortar, d2c, marketplace] diff --git a/eda_preprocessing.py b/eda_preprocessing.py new file mode 100644 index 0000000..0839626 --- /dev/null +++ b/eda_preprocessing.py @@ -0,0 +1,412 @@ +""" +Segmentation Plus — Domain-Aware EDA & Feature Engineering +========================================================== +Generic + domain-specific exploratory analysis, data cleaning, +feature engineering, and preprocessing for clustering. +""" + +from __future__ import annotations + +import logging +from pathlib import Path +from typing import Optional, Tuple + +import matplotlib +matplotlib.use("Agg") # Non-interactive backend +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns +from sklearn.decomposition import PCA +from sklearn.preprocessing import StandardScaler, LabelEncoder + +from config import DomainConfig + +logger = logging.getLogger(__name__) + + +# ────────────────────────────────────────────── +# EDA Engine +# ────────────────────────────────────────────── + +class EDAEngine: + """ + Runs generic and domain-specific exploratory data analysis. + + Parameters + ---------- + df : pd.DataFrame + Input data (raw or lightly cleaned). + domain_config : DomainConfig + Domain configuration driving domain-specific analyses. + output_dir : Path + Directory to save EDA charts. + """ + + def __init__( + self, + df: pd.DataFrame, + domain_config: DomainConfig, + output_dir: Path, + ) -> None: + self.df = df.copy() + self.config = domain_config + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + + def run_all(self) -> dict: + """Run all EDA analyses and return summary statistics.""" + logger.info("Running EDA for domain: %s", self.config.display_name) + results = {} + + results["summary_stats"] = self._summary_statistics() + results["missing_analysis"] = self._missing_value_analysis() + self._distribution_plots() + self._correlation_heatmap() + self._outlier_detection() + self._run_domain_analyses() + + logger.info("EDA complete. Charts saved to %s", self.output_dir) + return results + + def _summary_statistics(self) -> dict: + """Compute and log summary statistics.""" + numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() + stats = self.df[numeric_cols].describe().to_dict() + logger.info("Summary stats computed for %d numeric columns", len(numeric_cols)) + return stats + + def _missing_value_analysis(self) -> dict: + """Analyze missing values.""" + missing = self.df.isnull().sum() + missing_pct = (missing / len(self.df) * 100).round(2) + missing_report = { + col: {"count": int(missing[col]), "pct": float(missing_pct[col])} + for col in self.df.columns if missing[col] > 0 + } + if missing_report: + logger.warning("Missing values found in %d columns", len(missing_report)) + else: + logger.info("No missing values detected") + return missing_report + + def _distribution_plots(self) -> None: + """Plot distributions for all numeric features.""" + numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() + # Exclude ID-like columns + plot_cols = [c for c in numeric_cols if "id" not in c.lower()] + + if not plot_cols: + return + + n_cols = min(4, len(plot_cols)) + n_rows = (len(plot_cols) + n_cols - 1) // n_cols + + fig, axes = plt.subplots(n_rows, n_cols, figsize=(5 * n_cols, 4 * n_rows)) + axes = np.atleast_2d(axes) + + for idx, col in enumerate(plot_cols): + ax = axes[idx // n_cols, idx % n_cols] + self.df[col].hist(bins=30, ax=ax, color="#5b8def", edgecolor="white", alpha=0.8) + ax.set_title(col, fontsize=10, fontweight="bold") + ax.tick_params(labelsize=8) + + # Hide unused axes + for idx in range(len(plot_cols), n_rows * n_cols): + axes[idx // n_cols, idx % n_cols].set_visible(False) + + plt.tight_layout() + fig.savefig(self.output_dir / "distributions.png", dpi=150, bbox_inches="tight") + plt.close(fig) + logger.info("Distribution plots saved") + + def _correlation_heatmap(self) -> None: + """Plot correlation heatmap for numeric features.""" + numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() + numeric_cols = [c for c in numeric_cols if "id" not in c.lower()] + + if len(numeric_cols) < 2: + return + + corr = self.df[numeric_cols].corr() + fig, ax = plt.subplots(figsize=(max(10, len(numeric_cols) * 0.6), max(8, len(numeric_cols) * 0.5))) + mask = np.triu(np.ones_like(corr, dtype=bool)) + sns.heatmap( + corr, mask=mask, annot=len(numeric_cols) <= 15, fmt=".2f", + cmap="RdBu_r", center=0, vmin=-1, vmax=1, + square=True, linewidths=0.5, ax=ax, + cbar_kws={"shrink": 0.8} + ) + ax.set_title("Feature Correlation Matrix", fontsize=14, fontweight="bold", pad=15) + plt.tight_layout() + fig.savefig(self.output_dir / "correlation_heatmap.png", dpi=150, bbox_inches="tight") + plt.close(fig) + logger.info("Correlation heatmap saved") + + def _outlier_detection(self) -> None: + """Box plots for outlier detection.""" + numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() + plot_cols = [c for c in numeric_cols if "id" not in c.lower()] + + if not plot_cols: + return + + n_cols = min(4, len(plot_cols)) + n_rows = (len(plot_cols) + n_cols - 1) // n_cols + + fig, axes = plt.subplots(n_rows, n_cols, figsize=(5 * n_cols, 3 * n_rows)) + axes = np.atleast_2d(axes) + + for idx, col in enumerate(plot_cols): + ax = axes[idx // n_cols, idx % n_cols] + self.df.boxplot(column=col, ax=ax) + ax.set_title(col, fontsize=10, fontweight="bold") + ax.tick_params(labelsize=8) + + for idx in range(len(plot_cols), n_rows * n_cols): + axes[idx // n_cols, idx % n_cols].set_visible(False) + + plt.tight_layout() + fig.savefig(self.output_dir / "outlier_boxplots.png", dpi=150, bbox_inches="tight") + plt.close(fig) + logger.info("Outlier box plots saved") + + def _run_domain_analyses(self) -> None: + """Run domain-specific EDA analyses defined in config.""" + for analysis_name in self.config.eda_analyses: + method_name = f"_eda_{analysis_name}" + if hasattr(self, method_name): + logger.info("Running domain analysis: %s", analysis_name) + getattr(self, method_name)() + else: + logger.debug( + "Domain analysis '%s' not implemented — skipping. " + "Implement as method '%s' in EDAEngine.", + analysis_name, method_name, + ) + + # ── Domain-specific EDA methods (add more as needed) ── + + def _eda_product_cross_holding_matrix(self) -> None: + """Cross-holding heatmap for product columns.""" + product_cols = self.config.features.get("products", []) + bool_cols = [c for c in product_cols if c in self.df.columns and self.df[c].dtype in ["bool", "int64", "float64"]] + if len(bool_cols) < 2: + return + + cross = self.df[bool_cols].corr() + fig, ax = plt.subplots(figsize=(8, 6)) + sns.heatmap(cross, annot=True, fmt=".2f", cmap="YlOrRd", ax=ax, square=True) + ax.set_title("Product Cross-Holding Matrix", fontsize=13, fontweight="bold") + plt.tight_layout() + fig.savefig(self.output_dir / "product_cross_holdings.png", dpi=150, bbox_inches="tight") + plt.close(fig) + + +# ────────────────────────────────────────────── +# Feature Engineering +# ────────────────────────────────────────────── + +class FeatureEngineer: + """ + Applies domain-specific and generic feature engineering. + + Parameters + ---------- + domain_config : DomainConfig + Domain configuration with FE rules. + """ + + def __init__(self, domain_config: DomainConfig) -> None: + self.config = domain_config + + def engineer_features(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Apply all feature engineering rules from domain config. + + Parameters + ---------- + df : pd.DataFrame + Cleaned DataFrame. + + Returns + ------- + pd.DataFrame + DataFrame with new engineered columns added. + """ + df = df.copy() + + for rule in self.config.feature_engineering: + try: + # Evaluate the formula safely using DataFrame columns + df[rule.name] = df.eval(rule.formula) + logger.info("Engineered feature: '%s'", rule.name) + + # Apply binning if specified + if rule.bins: + df[f"{rule.name}_bin"] = pd.qcut( + df[rule.name], q=len(rule.bins), labels=rule.bins, duplicates="drop" + ) + logger.info(" → Binned into %d categories", len(rule.bins)) + + except Exception as e: + logger.warning( + "Failed to engineer feature '%s': %s. " + "Check that all columns in formula '%s' exist.", + rule.name, e, rule.formula, + ) + + return df + + +# ────────────────────────────────────────────── +# Preprocessor +# ────────────────────────────────────────────── + +class Preprocessor: + """ + Data cleaning, encoding, scaling, and PCA. + + Parameters + ---------- + domain_config : DomainConfig + Domain configuration. + """ + + def __init__(self, domain_config: DomainConfig) -> None: + self.config = domain_config + self.scaler: Optional[StandardScaler] = None + self.pca: Optional[PCA] = None + self.label_encoders: dict[str, LabelEncoder] = {} + self.feature_columns: list[str] = [] + + def fit_transform( + self, + df: pd.DataFrame, + n_pca_components: Optional[int] = None, + pca_variance_threshold: float = 0.85, + ) -> Tuple[pd.DataFrame, np.ndarray, Optional[PCA]]: + """ + Full preprocessing pipeline: clean → encode → scale → PCA. + + Parameters + ---------- + df : pd.DataFrame + Input DataFrame (after feature engineering). + n_pca_components : int, optional + Fixed number of PCA components. If None, auto-selects based on + variance threshold. + pca_variance_threshold : float + Minimum cumulative variance to retain (default 85%). + + Returns + ------- + tuple[pd.DataFrame, np.ndarray, PCA | None] + - Processed DataFrame (with encodings, scaled features) + - Feature matrix for clustering (scaled, optionally PCA-reduced) + - Fitted PCA object (or None if not applied) + """ + df = df.copy() + + # 1. Handle missing values + df = self._handle_missing(df) + + # 2. Encode categoricals + df = self._encode_categoricals(df) + + # 3. Select numeric features for clustering + exclude = set(self.config.scaling_exclude) + numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist() + self.feature_columns = [c for c in numeric_cols if c not in exclude] + + if not self.feature_columns: + raise ValueError("No numeric feature columns found for clustering after exclusions.") + + logger.info("Features for clustering: %d columns", len(self.feature_columns)) + + # 4. Handle outliers (winsorize) + df = self._winsorize(df) + + # 5. Scale + self.scaler = StandardScaler() + X_scaled = self.scaler.fit_transform(df[self.feature_columns]) + + logger.info("Scaling applied: StandardScaler (mean=0, std=1)") + + # 6. PCA (optional) + if n_pca_components is not None or pca_variance_threshold < 1.0: + X_scaled, self.pca = self._apply_pca( + X_scaled, n_pca_components, pca_variance_threshold + ) + + return df, X_scaled, self.pca + + def _handle_missing(self, df: pd.DataFrame) -> pd.DataFrame: + """Impute missing values: median for numeric, mode for categorical.""" + for col in df.columns: + if df[col].isnull().sum() == 0: + continue + if df[col].dtype in [np.float64, np.int64, float, int]: + median_val = df[col].median() + df[col] = df[col].fillna(median_val) + logger.info("Imputed '%s' with median: %.2f", col, median_val) + else: + mode_val = df[col].mode() + if len(mode_val) > 0: + df[col] = df[col].fillna(mode_val.iloc[0]) + logger.info("Imputed '%s' with mode: %s", col, mode_val.iloc[0]) + return df + + def _encode_categoricals(self, df: pd.DataFrame) -> pd.DataFrame: + """Label-encode categorical columns.""" + cat_cols = [ + c for c in self.config.categorical_columns + if c in df.columns and df[c].dtype == "object" + ] + for col in cat_cols: + le = LabelEncoder() + df[col] = le.fit_transform(df[col].astype(str)) + self.label_encoders[col] = le + logger.info("Label-encoded '%s' (%d classes)", col, len(le.classes_)) + return df + + def _winsorize(self, df: pd.DataFrame, lower: float = 0.01, upper: float = 0.99) -> pd.DataFrame: + """Winsorize numeric features at given percentiles.""" + for col in self.feature_columns: + lo = df[col].quantile(lower) + hi = df[col].quantile(upper) + clipped = df[col].clip(lo, hi) + n_clipped = (df[col] != clipped).sum() + if n_clipped > 0: + df[col] = clipped + logger.debug("Winsorized '%s': %d values clipped", col, n_clipped) + return df + + def _apply_pca( + self, + X: np.ndarray, + n_components: Optional[int], + variance_threshold: float, + ) -> Tuple[np.ndarray, PCA]: + """Apply PCA for dimensionality reduction.""" + if n_components is None: + # Auto-select: find n_components that explain ≥ threshold variance + pca_full = PCA().fit(X) + cumvar = np.cumsum(pca_full.explained_variance_ratio_) + n_components = int(np.searchsorted(cumvar, variance_threshold) + 1) + n_components = max(2, min(n_components, X.shape[1])) + logger.info( + "Auto-selected %d PCA components (%.1f%% variance)", + n_components, cumvar[n_components - 1] * 100, + ) + + pca = PCA(n_components=n_components) + X_pca = pca.fit_transform(X) + + logger.info( + "PCA: %d → %d components (%.1f%% variance explained)", + X.shape[1], n_components, + sum(pca.explained_variance_ratio_) * 100, + ) + + return X_pca, pca diff --git a/implementation_plan.md.resolved b/implementation_plan.md.resolved new file mode 100644 index 0000000..b1bad1b --- /dev/null +++ b/implementation_plan.md.resolved @@ -0,0 +1,131 @@ +# Financial Services Client Segmentation & GenAI Persona Generation + +Build a complete pipeline that generates synthetic financial client data, segments clients using clustering algorithms, and generates rich customer personas using Generative AI (Google Gemini). + +## Proposed Changes + +### 1. Synthetic Data Generation + +#### [NEW] [generate_data.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/generate_data.py) + +Generate **2,000 synthetic client records** with realistic financial services attributes: + +| Category | Fields | +|---|---| +| **Demographics** | `client_id`, `age`, `gender`, `income`, `education`, `marital_status`, `dependents`, `occupation` | +| **Financial Profile** | `account_balance`, `credit_score`, `monthly_spending`, `savings_rate`, `debt_to_income_ratio`, `investment_portfolio_value` | +| **Product Holdings** | `has_credit_card`, `has_mortgage`, `has_personal_loan`, `has_investment_account`, `has_insurance`, `num_products` | +| **Behavioral** | `digital_engagement_score`, `branch_visits_monthly`, `customer_tenure_years`, `transaction_frequency_monthly`, `avg_transaction_amount` | +| **Satisfaction** | `nps_score`, `complaint_count_yearly`, `churn_risk_score` | + +Data will be generated using `numpy` and `pandas` with correlated distributions (e.g., higher income → higher portfolio value, younger age → higher digital engagement). + +--- + +### 2. EDA & Preprocessing + +#### [NEW] [eda_preprocessing.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/eda_preprocessing.py) + +- Summary statistics and distribution plots for each feature +- Correlation heatmap across all numerical features +- Missing value analysis (none expected, but included for robustness) +- Feature scaling using `StandardScaler` +- Dimensionality reduction with PCA for visualization +- Export preprocessed data to `data/processed_clients.csv` + +--- + +### 3. Clustering & Segmentation + +#### [NEW] [clustering.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/clustering.py) + +- **K-Means Clustering** with Elbow Method and Silhouette Score to find optimal K +- **DBSCAN** as alternative density-based method +- **Hierarchical Clustering** with dendrogram visualization +- Cluster profiling: aggregate statistics per cluster (mean income, avg products, etc.) +- Radar charts and box plots per cluster +- Export cluster assignments back to the dataset + +--- + +### 4. GenAI Persona Generation + +#### [NEW] [persona_generation.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/persona_generation.py) + +Uses **Google Gemini API** to generate rich marketing personas for each cluster: + +- Summarize each cluster's statistical profile into a prompt +- Send structured prompts to Gemini asking for: + - Persona name and demographic snapshot + - Financial goals and pain points + - Preferred products and services + - Communication channel preferences + - Marketing strategy recommendations +- Parse and format the AI-generated personas +- Save output as `output/personas.md` and `output/personas.json` + +> [!IMPORTANT] +> **API Key required**: You'll need a Google Gemini API key. The script will read it from the environment variable `GOOGLE_API_KEY`. Please have your key ready, or let me know if you'd prefer a different GenAI provider (OpenAI, Azure, etc.). + +--- + +### 5. Visualization Dashboard + +#### [NEW] [dashboard.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/dashboard.py) + +An interactive **Plotly** dashboard (HTML output) combining: + +- PCA scatter plot colored by cluster +- Cluster size distribution (bar chart) +- Feature distributions per cluster (violin plots) +- Radar chart of cluster profiles +- Persona cards rendered as styled HTML + +--- + +### 6. Project Configuration + +#### [NEW] [requirements.txt](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/requirements.txt) + +``` +pandas +numpy +scikit-learn +matplotlib +seaborn +plotly +google-generativeai +``` + +#### [NEW] [main.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/main.py) + +Orchestrator script that runs the full pipeline end-to-end: +1. Generate data → 2. EDA & preprocess → 3. Cluster → 4. Generate personas → 5. Build dashboard + +--- + +## Verification Plan + +### Automated Tests + +1. **Data generation validity**: + ``` + python -c "import pandas as pd; df=pd.read_csv('data/synthetic_clients.csv'); assert len(df)==2000; assert df.isnull().sum().sum()==0; print('✓ Data OK')" + ``` + +2. **Clustering output check**: + ``` + python -c "import pandas as pd; df=pd.read_csv('data/clustered_clients.csv'); assert 'cluster' in df.columns; print(f'✓ {df.cluster.nunique()} clusters found')" + ``` + +3. **Full pipeline run**: + ``` + python main.py + ``` + Expected: All output files generated in `data/` and `output/` directories without errors. + +### Manual Verification + +- Review generated charts in `output/` folder for visual correctness +- Read persona output in `output/personas.md` for quality and relevance +- Open `output/dashboard.html` in a browser to verify interactivity diff --git a/main.py b/main.py new file mode 100644 index 0000000..d5c10e7 --- /dev/null +++ b/main.py @@ -0,0 +1,275 @@ +""" +Segmentation Plus — Pipeline Orchestrator +========================================== +End-to-end pipeline: Data Import → EDA → Cluster → Evaluate → Personas → Dashboard. + +Usage: + python main.py --data path/to/data.csv --domain financial_services + python main.py --data path/to/data.csv --domain retail --skip-personas +""" + +from __future__ import annotations + +import argparse +import logging +import sys +from pathlib import Path +from typing import Optional + +import numpy as np +import pandas as pd + +# ────────────────────────────────────────────── +# Logging Setup +# ────────────────────────────────────────────── + +def setup_logging(verbose: bool = False) -> None: + """Configure logging for the pipeline.""" + level = logging.DEBUG if verbose else logging.INFO + fmt = "%(asctime)s | %(levelname)-8s | %(name)-25s | %(message)s" + logging.basicConfig(level=level, format=fmt, datefmt="%H:%M:%S") + # Suppress noisy libraries + logging.getLogger("matplotlib").setLevel(logging.WARNING) + logging.getLogger("PIL").setLevel(logging.WARNING) + +logger = logging.getLogger("segmentation_plus") + + +# ────────────────────────────────────────────── +# Pipeline +# ────────────────────────────────────────────── + +def run_pipeline( + data_path: str, + domain_key: str, + output_base: str = "output", + skip_personas: bool = False, + k_range: tuple = (2, 10), + pca_variance: float = 0.85, + verbose: bool = False, +) -> dict: + """ + Run the full segmentation pipeline. + + Parameters + ---------- + data_path : str + Path to the input data file (CSV/Excel/Parquet). + domain_key : str + Domain config to use (e.g., 'financial_services', 'retail'). + output_base : str + Base output directory (default: 'output'). + skip_personas : bool + If True, skip GenAI persona generation (useful if no API key). + k_range : tuple + Min and max K for clustering (default: 2 to 10). + pca_variance : float + Cumulative variance threshold for PCA (default: 0.85). + verbose : bool + Enable debug logging. + + Returns + ------- + dict + Pipeline results including cluster labels, evaluation, and personas. + """ + setup_logging(verbose) + results = {} + + # ── Setup directories ── + output_dir = Path(output_base) + eda_dir = output_dir / "eda" + eval_dir = output_dir / "evaluation" + data_dir = Path("data") + data_dir.mkdir(exist_ok=True) + + logger.info("=" * 60) + logger.info("SEGMENTATION PLUS — Pipeline Start") + logger.info(" Data: %s", data_path) + logger.info(" Domain: %s", domain_key) + logger.info(" Output: %s", output_dir) + logger.info("=" * 60) + + # ──────────────────────────────────────── + # STEP 1: Load Domain Config + # ──────────────────────────────────────── + logger.info("\n📋 Step 1: Loading domain configuration...") + from config import load_domain_config + domain_config = load_domain_config(domain_key) + logger.info(" Domain: %s", domain_config.display_name) + + # ──────────────────────────────────────── + # STEP 2: Import & Validate Data + # ──────────────────────────────────────── + logger.info("\n📥 Step 2: Importing and validating data...") + from data_import import import_and_validate + df, quality_report = import_and_validate(data_path, domain_config) + logger.info("\n%s", quality_report.summary()) + + if not quality_report.passed: + logger.error("Data validation FAILED. Fix the errors above and retry.") + sys.exit(1) + + results["data_shape"] = df.shape + results["quality_report"] = quality_report + + # ──────────────────────────────────────── + # STEP 3: EDA & Feature Engineering + # ──────────────────────────────────────── + logger.info("\n🔍 Step 3: Running EDA & feature engineering...") + from eda_preprocessing import EDAEngine, FeatureEngineer, Preprocessor + + # EDA + eda = EDAEngine(df, domain_config, eda_dir) + eda_results = eda.run_all() + + # Feature Engineering + fe = FeatureEngineer(domain_config) + df_engineered = fe.engineer_features(df) + + # Preprocessing + preprocessor = Preprocessor(domain_config) + df_processed, X_scaled, pca = preprocessor.fit_transform( + df_engineered, + pca_variance_threshold=pca_variance, + ) + + feature_names = preprocessor.feature_columns + results["n_features"] = len(feature_names) + results["pca_components"] = pca.n_components_ if pca else None + + # Save processed data + df_processed.to_csv(data_dir / "processed_customers.csv", index=False) + logger.info(" Processed data saved: %d rows × %d features", len(df_processed), len(feature_names)) + + # ──────────────────────────────────────── + # STEP 4: Clustering + # ──────────────────────────────────────── + logger.info("\n🎯 Step 4: Running clustering algorithms...") + from clustering import ClusteringEngine + + engine = ClusteringEngine(X_scaled, k_range=k_range) + all_results = engine.run_all() + + # Select best model + best = engine.get_best_model(metric="silhouette") + labels = best.labels + logger.info(" Best model: %s (K=%d, Silhouette=%.3f)", + best.algorithm, best.n_clusters, best.metrics.get("silhouette", 0)) + + results["best_algorithm"] = best.algorithm + results["n_clusters"] = best.n_clusters + results["cluster_metrics"] = best.metrics + + # Save clustered data + df_processed["cluster"] = labels + df_processed.to_csv(data_dir / "clustered_customers.csv", index=False) + logger.info(" Clustered data saved") + + # ──────────────────────────────────────── + # STEP 5: Cluster Evaluation + # ──────────────────────────────────────── + logger.info("\n🔬 Step 5: Evaluating clusters...") + from cluster_evaluation import ClusterEvaluator + + evaluator = ClusterEvaluator(X_scaled, labels, feature_names, eval_dir) + eval_report = evaluator.run_full_evaluation(pca=pca, k_range=k_range) + results["evaluation"] = eval_report + + # ──────────────────────────────────────── + # STEP 6: GenAI Persona Generation + # ──────────────────────────────────────── + personas = [] + if not skip_personas: + logger.info("\n🤖 Step 6: Generating personas with GenAI...") + from persona_generation import PersonaGenerator, build_cluster_profiles + + profiles = build_cluster_profiles( + df_processed, labels, feature_names, + shap_importance=eval_report.get("shap_importance", {}).get("feature_importance"), + ) + + try: + generator = PersonaGenerator(domain_config, output_dir) + personas = generator.generate_personas(profiles) + results["personas"] = personas + logger.info(" Generated %d personas", len(personas)) + except Exception as e: + logger.warning("Persona generation failed: %s (continuing without personas)", e) + else: + logger.info("\n⏭️ Step 6: Skipping persona generation (--skip-personas)") + + # ──────────────────────────────────────── + # STEP 7: Dashboard + # ──────────────────────────────────────── + logger.info("\n📊 Step 7: Building dashboard...") + from dashboard import DashboardBuilder + + # Prepare 2D projection for scatter plot + X_viz = X_scaled[:, :2] if X_scaled.shape[1] >= 2 else X_scaled + + builder = DashboardBuilder(output_dir) + dashboard_path = builder.build( + df=df_processed, + labels=labels, + X_for_viz=X_viz, + feature_names=feature_names, + personas=personas, + evaluation_report=eval_report, + ) + results["dashboard_path"] = str(dashboard_path) + + # ──────────────────────────────────────── + # Done + # ──────────────────────────────────────── + logger.info("\n" + "=" * 60) + logger.info("✅ PIPELINE COMPLETE") + logger.info(" Clusters: %d (%s)", best.n_clusters, best.algorithm) + logger.info(" Silhouette: %.3f", best.metrics.get("silhouette", 0)) + logger.info(" Dashboard: %s", dashboard_path) + logger.info("=" * 60) + + return results + + +# ────────────────────────────────────────────── +# CLI +# ────────────────────────────────────────────── + +def main() -> None: + """CLI entry point.""" + parser = argparse.ArgumentParser( + description="Segmentation Plus — Customer Segmentation & Persona Generation", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python main.py --data data/customers.csv --domain financial_services + python main.py --data data/sales.xlsx --domain retail --skip-personas + python main.py --data data/patients.csv --domain healthcare --k-min 3 --k-max 8 + """, + ) + + parser.add_argument("--data", required=True, help="Path to input data file (CSV/Excel/Parquet)") + parser.add_argument("--domain", required=True, help="Domain config name (e.g., financial_services, retail)") + parser.add_argument("--output", default="output", help="Output directory (default: output)") + parser.add_argument("--skip-personas", action="store_true", help="Skip GenAI persona generation") + parser.add_argument("--k-min", type=int, default=2, help="Minimum K for clustering (default: 2)") + parser.add_argument("--k-max", type=int, default=10, help="Maximum K for clustering (default: 10)") + parser.add_argument("--pca-variance", type=float, default=0.85, help="PCA variance threshold (default: 0.85)") + parser.add_argument("--verbose", "-v", action="store_true", help="Enable debug logging") + + args = parser.parse_args() + + run_pipeline( + data_path=args.data, + domain_key=args.domain, + output_base=args.output, + skip_personas=args.skip_personas, + k_range=(args.k_min, args.k_max), + pca_variance=args.pca_variance, + verbose=args.verbose, + ) + + +if __name__ == "__main__": + main() diff --git a/notebook.ipynb b/notebook.ipynb new file mode 100644 index 0000000..d2b827e --- /dev/null +++ b/notebook.ipynb @@ -0,0 +1,1295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SegPlus Final End-to-End Pipeline\n", + "\n", + "This notebook runs the full architecture:\n", + "- Data input and validation\n", + "- Feature engineering\n", + "- KMeans + DBSCAN + GMM modeling loop\n", + "- Cluster evaluation + stability\n", + "- Explainability (feature drivers, PCA loadings, profiles)\n", + "- Persona generation and business grounding (Ollama with fallback)\n", + "- Visualization and export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "64579db4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Missing required: ['scikit-learn', 'pyyaml']\n", + "Missing optional: []\n" + ] + } + ], + "source": [ + "# Optional dependency installer/check\n", + "import importlib\n", + "import subprocess\n", + "import sys\n", + "\n", + "REQUIRED_PACKAGES = [\n", + " \"numpy\", \"pandas\", \"scikit-learn\", \"matplotlib\", \"seaborn\",\n", + " \"pyyaml\", \"openpyxl\", \"requests\", \"scipy\"\n", + "]\n", + "OPTIONAL_PACKAGES = [\"shap\"]\n", + "AUTO_INSTALL_MISSING = False # set True if you want notebook to install missing packages\n", + "\n", + "missing_required = []\n", + "missing_optional = []\n", + "\n", + "for pkg in REQUIRED_PACKAGES:\n", + " mod = pkg.replace(\"-\", \"_\")\n", + " try:\n", + " importlib.import_module(mod)\n", + " except Exception:\n", + " missing_required.append(pkg)\n", + "\n", + "for pkg in OPTIONAL_PACKAGES:\n", + " try:\n", + " importlib.import_module(pkg)\n", + " except Exception:\n", + " missing_optional.append(pkg)\n", + "\n", + "print(\"Missing required:\", missing_required)\n", + "print(\"Missing optional:\", missing_optional)\n", + "\n", + "if missing_required and AUTO_INSTALL_MISSING:\n", + " cmd = [sys.executable, \"-m\", \"pip\", \"install\", *missing_required]\n", + " print(\"Installing:\", \" \".join(missing_required))\n", + " subprocess.check_call(cmd)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "32c77bb2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Project root: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\n" + ] + } + ], + "source": [ + "import logging\n", + "import json\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# Ensure project root is importable when notebook is inside segplus/\n", + "cwd = Path.cwd()\n", + "project_root = cwd.parent if cwd.name.lower() == \"segplus\" else cwd\n", + "if str(project_root) not in sys.path:\n", + " sys.path.insert(0, str(project_root))\n", + "\n", + "from segplus.config import PipelineConfig, load_domain_config\n", + "from segplus.data_input import import_and_validate\n", + "from segplus.feature_engineering import FeatureEngineer\n", + "from segplus.modeling_loop import modeling_loop\n", + "from segplus.evaluation import run_stability_test\n", + "from segplus.experiment_log import ExperimentLog\n", + "from segplus.explainability import build_explainability_report\n", + "from segplus.ollama_client import OllamaClient\n", + "from segplus.persona_generation import PersonaGenerator\n", + "from segplus.visualization import (\n", + " plot_cluster_scatter_2d,\n", + " plot_shap_importance,\n", + " plot_shap_summary,\n", + " plot_pca_loadings_heatmap,\n", + " plot_cluster_profiles_heatmap,\n", + " plot_cluster_sizes,\n", + " plot_radar_charts,\n", + " plot_experiment_history,\n", + " plot_elbow_curve,\n", + ")\n", + "\n", + "logging.basicConfig(\n", + " level=logging.INFO,\n", + " format=\"%(asctime)s | %(levelname)-8s | %(name)-30s | %(message)s\",\n", + ")\n", + "\n", + "print(\"Project root:\", project_root)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e0196175", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Domain: Financial Services\n", + "Data: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\final_enterprise_clustering_dataset_single_sheet.xlsx\n", + "Output: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n", + "Ollama host: http://localhost:11434\n", + "Primary LLM: qwen2.5:7b\n" + ] + } + ], + "source": [ + "# Configuration (edit these as needed)\n", + "default_data_path = project_root / \"final_enterprise_clustering_dataset_single_sheet.xlsx\"\n", + "default_output_dir = project_root / \"segplus_output\"\n", + "\n", + "config = PipelineConfig(\n", + " data_path=str(default_data_path),\n", + " domain_key=\"financial_services\", # or \"retail\"\n", + " sheet_name=None,\n", + " k_range=(2, 8),\n", + " max_iterations=5,\n", + " pca_variance_threshold=0.85,\n", + " output_dir=str(default_output_dir),\n", + " ollama_host=\"http://localhost:11434\", # local Ollama endpoint\n", + " ollama_model=\"qwen2.5:7b\", # primary local model`n ollama_timeout=240,\n", + " business_objective=(\n", + " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", + " \"improve retention for high-value customers, and convert mid-tier customers \"\n", + " \"to premium products.\"\n", + " ),\n", + ")\n", + "\n", + "# Preferred model order for local Ollama auto-selection\n", + "PREFERRED_OLLAMA_MODELS = [\n", + " \"qwen2.5\",\n", + " \"qwen2\",\n", + " \"llama3.2\",\n", + " \"llama3.1\",\n", + " \"llama3\",\n", + " \"mistral\",\n", + "]\n", + "\n", + "output_dir = Path(config.output_dir)\n", + "output_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + "domain_config = load_domain_config(config.domain_key, domains_dir=project_root / \"domains\")\n", + "print(\"Domain:\", domain_config.display_name)\n", + "print(\"Data:\", config.data_path)\n", + "print(\"Output:\", output_dir)\n", + "print(\"Ollama host:\", config.ollama_host)\n", + "print(\"Primary LLM:\", config.ollama_model)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "85b24976", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:49:51,635 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n", + "2026-03-06 22:49:51,833 | INFO | segplus.data_input | Data quality: PASSED\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Data Quality Report\n", + " Rows: 120,000 | Columns: 27\n", + " Duplicates: 0\n", + " Status: PASSED\n", + "Raw shape: (120000, 27)\n" + ] + } + ], + "source": [ + "# 1) Data Input + Validation\n", + "df_raw, quality_report, schema = import_and_validate(\n", + " file_path=config.data_path,\n", + " domain_config=domain_config,\n", + " auto_map=True,\n", + " sheet_name=config.sheet_name,\n", + ")\n", + "\n", + "print(quality_report.summary())\n", + "if not quality_report.passed:\n", + " raise ValueError(\"Data quality checks failed. Fix input data and rerun.\")\n", + "\n", + "print(\"Raw shape:\", df_raw.shape)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7e4bf552", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:49:51,888 | WARNING | segplus.feature_engineering | FE rule 'wealth_tier' failed: name 'investment_portfolio_value' is not defined\n", + "2026-03-06 22:49:51,902 | WARNING | segplus.feature_engineering | FE rule 'digital_vs_branch_ratio' failed: name 'digital_engagement_score' is not defined\n", + "2026-03-06 22:49:51,918 | WARNING | segplus.feature_engineering | FE rule 'product_depth' failed: name 'has_credit_card' is not defined\n", + "2026-03-06 22:49:51,926 | WARNING | segplus.feature_engineering | FE rule 'spending_to_income_ratio' failed: name 'monthly_spending' is not defined\n", + "2026-03-06 22:49:51,942 | WARNING | segplus.feature_engineering | FE rule 'risk_category' failed: name 'debt_to_income_ratio' is not defined\n", + "2026-03-06 22:49:52,618 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", + "2026-03-06 22:49:52,619 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Engineered dataframe shape: (120000, 26)\n", + "Model matrix shape used for clustering: (120000, 7)\n", + "Feature count used for clustering: 7\n", + "SHAP source feature count (original vars): 26\n", + "First SHAP source vars: ['month', 'monthly_spend_x', 'utilization_ratio_x', 'delinquency_flag_x', 'age', 'annual_income', 'risk_score', 'credit_score', 'digital_affinity', 'tenure_months']\n" + ] + } + ], + "source": [ + "# 2) Feature Engineering\n", + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "feature_engineer = FeatureEngineer(domain_config, config)\n", + "fe_result = feature_engineer.run(df_raw)\n", + "\n", + "# Original-variable matrix for SHAP (never PCA names)\n", + "original_feature_names_for_shap = fe_result.df_engineered.columns.tolist()\n", + "X_original_for_shap = StandardScaler().fit_transform(fe_result.df_engineered.values)\n", + "\n", + "# Optional latent representation via local autoencoder (if tensorflow is installed)\n", + "USE_AUTOENCODER_REPRESENTATION = False\n", + "AE_LATENT_DIM = 8\n", + "AE_EPOCHS = 40\n", + "AE_BATCH_SIZE = 256\n", + "\n", + "X = fe_result.X_scaled\n", + "feature_names = fe_result.feature_names\n", + "pca_for_explainability = fe_result.pca\n", + "\n", + "if USE_AUTOENCODER_REPRESENTATION:\n", + " try:\n", + " import tensorflow as tf\n", + " from tensorflow.keras import Model\n", + " from tensorflow.keras.layers import Dense, Input\n", + " from tensorflow.keras.callbacks import EarlyStopping\n", + "\n", + " tf.random.set_seed(config.random_state)\n", + " input_dim = X.shape[1]\n", + " latent_dim = max(2, min(AE_LATENT_DIM, input_dim - 1))\n", + "\n", + " inp = Input(shape=(input_dim,))\n", + " x = Dense(max(16, input_dim // 2), activation=\"relu\")(inp)\n", + " latent = Dense(latent_dim, activation=\"linear\", name=\"latent\")(x)\n", + " x = Dense(max(16, input_dim // 2), activation=\"relu\")(latent)\n", + " out = Dense(input_dim, activation=\"linear\")(x)\n", + "\n", + " autoencoder = Model(inp, out)\n", + " encoder = Model(inp, latent)\n", + " autoencoder.compile(optimizer=\"adam\", loss=\"mse\")\n", + " autoencoder.fit(\n", + " X,\n", + " X,\n", + " epochs=AE_EPOCHS,\n", + " batch_size=min(AE_BATCH_SIZE, len(X)),\n", + " verbose=0,\n", + " callbacks=[EarlyStopping(monitor=\"loss\", patience=5, restore_best_weights=True)],\n", + " )\n", + "\n", + " X = encoder.predict(X, verbose=0)\n", + " feature_names = [f\"AE{i+1}\" for i in range(X.shape[1])]\n", + " pca_for_explainability = None # PCA loadings no longer match AE latent space\n", + " print(f\"Autoencoder latent representation enabled: {X.shape}\")\n", + " except Exception as e:\n", + " print(f\"Autoencoder path unavailable ({e}); continuing with FE output.\")\n", + "\n", + "print(\"Engineered dataframe shape:\", fe_result.df_engineered.shape)\n", + "print(\"Model matrix shape used for clustering:\", X.shape)\n", + "print(\"Feature count used for clustering:\", len(feature_names))\n", + "print(\"SHAP source feature count (original vars):\", len(original_feature_names_for_shap))\n", + "print(\"First SHAP source vars:\", original_feature_names_for_shap[:10])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ca7f19aa", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:\n", + "[WinError 2] The system cannot find the file specified\n", + "Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.\n", + " warnings.warn(\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", + " cpu_info = subprocess.run(\n", + " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", + " capture_output=True,\n", + " text=True,\n", + " )\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", + " with Popen(*popenargs, **kwargs) as process:\n", + " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", + " self._execute_child(args, executable, preexec_fn, close_fds,\n", + " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " pass_fds, cwd, env,\n", + " ^^^^^^^^^^^^^^^^^^^\n", + " ...<5 lines>...\n", + " gid, gids, uid, umask,\n", + " ^^^^^^^^^^^^^^^^^^^^^^\n", + " start_new_session, process_group)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", + " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", + " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", + " # no special security\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " ...<4 lines>...\n", + " cwd,\n", + " ^^^^\n", + " startupinfo)\n", + " ^^^^^^^^^^^^\n", + "2026-03-06 22:49:58,214 | INFO | segplus.clustering | K search: scores={2: np.float64(0.202), 3: np.float64(0.2145), 4: np.float64(0.1609), 5: np.float64(0.1639), 6: np.float64(0.1444), 7: np.float64(0.1399), 8: np.float64(0.141)} | best k=3 (sil=0.2145)\n", + "2026-03-06 22:50:00,159 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", + "2026-03-06 22:50:00,161 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", + "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-06 22:50:00,815 | INFO | segplus.clustering | [kmeans] clusters=3\n", + "2026-03-06 22:50:25,748 | INFO | segplus.clustering | [dbscan] clusters=178\n", + "2026-03-06 22:50:44,501 | INFO | segplus.clustering | [gmm] clusters=3\n", + "2026-03-06 22:50:44,663 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2115 | DB=1.5251 | CH=31125.2 | cov=1.00\n", + "2026-03-06 22:50:44,946 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.2252 | DB=0.8652 | CH=142.0 | cov=1.00\n", + "2026-03-06 22:50:45,068 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0667 | DB=3.5552 | CH=13484.7 | cov=1.00\n", + "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", + "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", + "2026-03-06 22:50:45,072 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2115 pass=True\n", + "2026-03-06 22:50:45,073 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2115 | DB=1.5251 | PASS=True\n", + "2026-03-06 22:50:45,074 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Best algorithm: kmeans\n", + "Clusters: 3\n", + "Silhouette: 0.2115\n", + "Davies-Bouldin: 1.5251\n", + "Passes gate: True\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    iterationtimestampkepsgmm_covbest_algorithmn_clusterssilhouettedavies_bouldincalinski_harabaszpassedreconfig_strategy
    012026-03-06T22:50:45.07245831.661fullkmeans30.21151.525131125.2TrueNone
    \n", + "
    " + ], + "text/plain": [ + " iteration timestamp k eps gmm_cov best_algorithm \\\n", + "0 1 2026-03-06T22:50:45.072458 3 1.661 full kmeans \n", + "\n", + " n_clusters silhouette davies_bouldin calinski_harabasz passed \\\n", + "0 3 0.2115 1.5251 31125.2 True \n", + "\n", + " reconfig_strategy \n", + "0 None " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 3) Modeling Loop (KMeans + DBSCAN + GMM with reconfiguration)\n", + "experiment_log = ExperimentLog()\n", + "\n", + "best_eval, best_cfg = modeling_loop(\n", + " X=X,\n", + " feature_names=feature_names,\n", + " config=config,\n", + " experiment_log=experiment_log,\n", + ")\n", + "\n", + "print(\"Best algorithm:\", best_eval.algorithm)\n", + "print(\"Clusters:\", best_eval.n_clusters)\n", + "print(\"Silhouette:\", best_eval.silhouette)\n", + "print(\"Davies-Bouldin:\", best_eval.davies_bouldin)\n", + "print(\"Passes gate:\", best_eval.passes)\n", + "\n", + "exp_df = experiment_log.to_dataframe()\n", + "exp_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7e9bafbb", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:50:57,856 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", + "2026-03-06 22:50:57,859 | INFO | segplus.explainability | Computing feature importances...\n", + "2026-03-06 22:51:08,907 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", + "2026-03-06 22:51:08,940 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", + "2026-03-06 22:51:08,944 | INFO | segplus.explainability | Computing PCA loadings...\n", + "2026-03-06 22:51:08,945 | INFO | segplus.explainability | Computing inertia curve...\n", + "2026-03-06 22:51:12,627 | INFO | segplus.explainability | Computing cluster profiles...\n", + "2026-03-06 22:51:12,729 | INFO | segplus.explainability | Building ordered convergence drivers...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stability ARI mean: 0.988\n", + "Stability algorithm used: kmeans\n", + "Ordered top drivers: ['risk_score', 'risk_score_cluster', 'risk_behavior_score', 'delinquency_flag_y', 'credit_score', 'credit_score_cluster', 'monthly_spend_y', 'value_score', 'annual_income', 'log_income']\n", + "Top SHAP % (original variables):\n", + " credit_score: 19.58%\n", + " credit_score_cluster: 19.05%\n", + " risk_score: 9.32%\n", + " risk_score_cluster: 7.35%\n", + " risk_behavior_score: 6.92%\n", + " monthly_spend_y: 5.59%\n", + " delinquency_flag_y: 5.43%\n", + " value_score: 5.40%\n", + " monthly_spend_x: 3.53%\n", + " annual_income: 3.00%\n", + "PC to original feature map (top 5):\n", + " PC1: ['credit_score', 'credit_score_cluster', 'risk_score', 'risk_score_cluster', 'log_income']\n", + " PC2: ['value_score', 'monthly_spend_y', 'monthly_spend_x', 'lifetime_value_proxy', 'utilization_ratio_x']\n", + " PC3: ['age', 'age_cluster', 'digital_affinity_cluster', 'digital_affinity', 'delinquency_flag_y']\n", + " PC4: ['tenure_months', 'tenure_months_cluster', 'lifetime_value_proxy', 'utilization_ratio_x', 'utilization_ratio_y']\n", + " PC5: ['annual_income', 'annual_income_cluster', 'log_income', 'delinquency_flag_y', 'risk_behavior_score']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    featureshap_importancepca_weighted_loadingshap_rankpca_rankshap_rank_normpca_rank_norminertia_elbow_strengthconvergence_score
    0risk_score0.093210.1696243.03.50.920.90158504.1408420.912
    1risk_score_cluster0.073450.1696244.03.50.880.90158504.1408420.888
    2risk_behavior_score0.069180.1701175.02.00.840.96158504.1408420.888
    3delinquency_flag_y0.054290.1702847.01.00.761.00158504.1408420.856
    4credit_score0.195770.1500411.012.51.000.54158504.1408420.816
    5credit_score_cluster0.190510.1500412.012.50.960.54158504.1408420.792
    6monthly_spend_y0.055910.1504126.010.50.800.62158504.1408420.728
    7value_score0.053970.1504128.010.50.720.62158504.1408420.680
    8annual_income0.030040.15700110.08.00.640.72158504.1408420.672
    9log_income0.029880.15923811.07.00.600.76158504.1408420.664
    10utilization_ratio_y0.028070.16146912.06.00.560.80158504.1408420.656
    11monthly_spend_x0.035330.1490169.014.00.680.48158504.1408420.600
    12utilization_ratio_x0.020780.16152515.05.00.440.84158504.1408420.600
    13annual_income_cluster0.027650.15700113.09.00.520.68158504.1408420.584
    14lifetime_value_proxy0.024850.14514214.015.00.480.44158504.1408420.464
    \n", + "
    " + ], + "text/plain": [ + " feature shap_importance pca_weighted_loading shap_rank \\\n", + "0 risk_score 0.09321 0.169624 3.0 \n", + "1 risk_score_cluster 0.07345 0.169624 4.0 \n", + "2 risk_behavior_score 0.06918 0.170117 5.0 \n", + "3 delinquency_flag_y 0.05429 0.170284 7.0 \n", + "4 credit_score 0.19577 0.150041 1.0 \n", + "5 credit_score_cluster 0.19051 0.150041 2.0 \n", + "6 monthly_spend_y 0.05591 0.150412 6.0 \n", + "7 value_score 0.05397 0.150412 8.0 \n", + "8 annual_income 0.03004 0.157001 10.0 \n", + "9 log_income 0.02988 0.159238 11.0 \n", + "10 utilization_ratio_y 0.02807 0.161469 12.0 \n", + "11 monthly_spend_x 0.03533 0.149016 9.0 \n", + "12 utilization_ratio_x 0.02078 0.161525 15.0 \n", + "13 annual_income_cluster 0.02765 0.157001 13.0 \n", + "14 lifetime_value_proxy 0.02485 0.145142 14.0 \n", + "\n", + " pca_rank shap_rank_norm pca_rank_norm inertia_elbow_strength \\\n", + "0 3.5 0.92 0.90 158504.140842 \n", + "1 3.5 0.88 0.90 158504.140842 \n", + "2 2.0 0.84 0.96 158504.140842 \n", + "3 1.0 0.76 1.00 158504.140842 \n", + "4 12.5 1.00 0.54 158504.140842 \n", + "5 12.5 0.96 0.54 158504.140842 \n", + "6 10.5 0.80 0.62 158504.140842 \n", + "7 10.5 0.72 0.62 158504.140842 \n", + "8 8.0 0.64 0.72 158504.140842 \n", + "9 7.0 0.60 0.76 158504.140842 \n", + "10 6.0 0.56 0.80 158504.140842 \n", + "11 14.0 0.68 0.48 158504.140842 \n", + "12 5.0 0.44 0.84 158504.140842 \n", + "13 9.0 0.52 0.68 158504.140842 \n", + "14 15.0 0.48 0.44 158504.140842 \n", + "\n", + " convergence_score \n", + "0 0.912 \n", + "1 0.888 \n", + "2 0.888 \n", + "3 0.856 \n", + "4 0.816 \n", + "5 0.792 \n", + "6 0.728 \n", + "7 0.680 \n", + "8 0.672 \n", + "9 0.664 \n", + "10 0.656 \n", + "11 0.600 \n", + "12 0.600 \n", + "13 0.584 \n", + "14 0.464 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 4) Stability + Explainability\n", + "stability = run_stability_test(\n", + " X=X,\n", + " labels=best_eval.labels,\n", + " n_clusters=best_eval.n_clusters,\n", + " config=config,\n", + " algorithm=best_eval.algorithm,\n", + " model=best_eval.model,\n", + ")\n", + "\n", + "explainability = build_explainability_report(\n", + " X=X,\n", + " labels=best_eval.labels,\n", + " feature_names=feature_names,\n", + " df_raw=fe_result.df_engineered,\n", + " pca=pca_for_explainability,\n", + " k_range=config.k_range,\n", + " random_state=config.random_state,\n", + " n_top=config.n_top_features,\n", + " X_original=X_original_for_shap,\n", + " original_feature_names=original_feature_names_for_shap,\n", + ")\n", + "\n", + "print(\"Stability ARI mean:\", stability.ari_mean)\n", + "print(\"Stability algorithm used:\", best_eval.algorithm)\n", + "print(\"Ordered top drivers:\", explainability.top_features[:10])\n", + "print(\"Top SHAP % (original variables):\")\n", + "for k, v in list(explainability.feature_importance_pct.items())[:10]:\n", + " print(f\" {k}: {v:.2f}%\")\n", + "\n", + "print(\"PC to original feature map (top 5):\")\n", + "for pc, cols in list(explainability.pc_feature_map.items())[:5]:\n", + " print(f\" {pc}: {cols}\")\n", + "\n", + "explainability.ordered_feature_drivers.head(15)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "000fb2d4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installed Ollama models: ['qwen2.5:7b']\n", + "Selected model tag: qwen2.5:7b\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:51:17,003 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", + "2026-03-06 22:53:19,121 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 22:54:37,832 | INFO | segplus.ollama_client | Ollama response received (534 chars)\n", + "2026-03-06 22:55:12,181 | INFO | segplus.ollama_client | Ollama response received (14 chars)\n", + "2026-03-06 22:55:12,184 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'Elite Spenders'\n", + "2026-03-06 22:55:12,202 | INFO | segplus.persona_generation | Persona generated: Cluster A -> Elite Spenders\n", + "2026-03-06 22:57:14,441 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 22:57:55,579 | INFO | segplus.ollama_client | Ollama response received (551 chars)\n", + "2026-03-06 22:58:37,127 | INFO | segplus.ollama_client | Ollama response received (17 chars)\n", + "2026-03-06 22:58:37,130 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", + "2026-03-06 23:00:39,228 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 23:02:14,255 | INFO | segplus.ollama_client | Ollama response received (839 chars)\n", + "2026-03-06 23:02:50,674 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", + "2026-03-06 23:02:50,678 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", + "2026-03-06 23:02:50,721 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", + "2026-03-06 23:04:52,791 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 23:06:56,881 | WARNING | segplus.ollama_client | Ollama attempt 2 failed (Timeout after 120s). Retrying in 4s...\n", + "2026-03-06 23:09:02,941 | WARNING | segplus.persona_generation | Business grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generated personas: 3\n", + "Executive summary: LLM grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n", + "persona_df columns: ['cluster', 'genai_persona_name', 'profile_descriptor', 'description', 'cluster_size', 'cluster_pct', 'ordered_top_features', 'genai_recommendations', 'categorization_basis', 'naming_rationale']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    clustergenai_persona_nameprofile_descriptordescriptioncluster_sizecluster_pctordered_top_featuresgenai_recommendationscategorization_basisnaming_rationale
    0Cluster AElite SpendersHigh Value Score & High Monthly Spend YHigh-Value Premium Spenders are among the most...87740.0731value_score:0.1, monthly_spend_y:25414.84, mon...Targeted Upselling of Premium Products | Perso...value_score, monthly_spend_y, monthly_spend_x,...Second-pass focused LLM naming from profile: H...
    1Cluster BCredit Risk Strategists – Higher Credit Score ...High Credit Score & Low Risk ScoreThese customers are highly creditworthy and lo...567820.4732credit_score:827.07, credit_score_cluster:827....Target with premium product promotions | Enhan...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    2Cluster CCredit Risk Strategists – Lower Credit Score C...Low Credit Score & High Risk ScoreBudget-conscious Credit Risk Takers are custom...544440.4537credit_score:692.54, credit_score_cluster:692....Offer tailored credit products with flexible t...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    \n", + "
    " + ], + "text/plain": [ + " cluster genai_persona_name \\\n", + "0 Cluster A Elite Spenders \n", + "1 Cluster B Credit Risk Strategists – Higher Credit Score ... \n", + "2 Cluster C Credit Risk Strategists – Lower Credit Score C... \n", + "\n", + " profile_descriptor \\\n", + "0 High Value Score & High Monthly Spend Y \n", + "1 High Credit Score & Low Risk Score \n", + "2 Low Credit Score & High Risk Score \n", + "\n", + " description cluster_size \\\n", + "0 High-Value Premium Spenders are among the most... 8774 \n", + "1 These customers are highly creditworthy and lo... 56782 \n", + "2 Budget-conscious Credit Risk Takers are custom... 54444 \n", + "\n", + " cluster_pct ordered_top_features \\\n", + "0 0.0731 value_score:0.1, monthly_spend_y:25414.84, mon... \n", + "1 0.4732 credit_score:827.07, credit_score_cluster:827.... \n", + "2 0.4537 credit_score:692.54, credit_score_cluster:692.... \n", + "\n", + " genai_recommendations \\\n", + "0 Targeted Upselling of Premium Products | Perso... \n", + "1 Target with premium product promotions | Enhan... \n", + "2 Offer tailored credit products with flexible t... \n", + "\n", + " categorization_basis \\\n", + "0 value_score, monthly_spend_y, monthly_spend_x,... \n", + "1 credit_score, credit_score_cluster, risk_score... \n", + "2 credit_score, credit_score_cluster, risk_score... \n", + "\n", + " naming_rationale \n", + "0 Second-pass focused LLM naming from profile: H... \n", + "1 LLM returned generic name; using business-styl... \n", + "2 LLM returned generic name; using business-styl... " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 5) Persona Generation + Business Grounding (Ollama local, with fallback)\n", + "import requests\n", + "\n", + "\n", + "def _list_local_ollama_models(host: str) -> list[str]:\n", + " try:\n", + " r = requests.get(f\"{host.rstrip('/')}/api/tags\", timeout=8)\n", + " r.raise_for_status()\n", + " return [m.get(\"name\", \"\") for m in r.json().get(\"models\", []) if m.get(\"name\")]\n", + " except Exception as e:\n", + " print(f\"Ollama model discovery failed: {e}\")\n", + " return []\n", + "\n", + "\n", + "def _choose_ollama_model(installed: list[str], preferred: list[str], configured: str) -> str:\n", + " if configured and configured in installed:\n", + " return configured\n", + " if configured:\n", + " matches = [m for m in installed if configured in m]\n", + " if matches:\n", + " return matches[0]\n", + " for pref in preferred:\n", + " matches = [m for m in installed if m.startswith(pref) or pref in m]\n", + " if matches:\n", + " return matches[0]\n", + " return installed[0] if installed else (configured or \"qwen2.5:7b\")\n", + "\n", + "\n", + "installed_models = _list_local_ollama_models(config.ollama_host)\n", + "selected_model = _choose_ollama_model(installed_models, PREFERRED_OLLAMA_MODELS, config.ollama_model)\n", + "config.ollama_model = selected_model\n", + "\n", + "print(\"Installed Ollama models:\", installed_models if installed_models else \"None found / Ollama offline\")\n", + "print(\"Selected model tag:\", config.ollama_model)\n", + "\n", + "ollama_client = OllamaClient(\n", + " host=config.ollama_host,\n", + " model=config.ollama_model,\n", + " timeout=config.ollama_timeout,\n", + ")\n", + "persona_generator = PersonaGenerator(ollama_client, config)\n", + "\n", + "# Step A: Cluster personas\n", + "personas = persona_generator.generate_personas(\n", + " evaluation=best_eval,\n", + " explainability=explainability,\n", + " raw_df=fe_result.df_original,\n", + " schema=schema,\n", + ")\n", + "\n", + "# Step B: Business grounding + GenAI per-cluster naming/actions\n", + "grounding = persona_generator.ground_in_business_objective(personas)\n", + "personas = persona_generator.apply_grounding_to_personas(personas, grounding)\n", + "\n", + "persona_df = pd.DataFrame([\n", + " {\n", + " \"cluster\": p.persona_name,\n", + " \"genai_persona_name\": p.archetype,\n", + " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", + " \"description\": getattr(p, \"description\", \"\"),\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": round(p.cluster_pct, 4),\n", + " \"ordered_top_features\": \", \".join([f\"{k}:{v}\" for k, v in p.top_features.items()]),\n", + " \"genai_recommendations\": \" | \".join(p.business_recommendations),\n", + " \"categorization_basis\": \", \".join(getattr(p, \"categorization_basis\", [])),\n", + " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", + " }\n", + " for p in personas\n", + "])\n", + "\n", + "# Exact output schema check\n", + "required_persona_cols = [\n", + " \"cluster\", \"genai_persona_name\", \"profile_descriptor\", \"description\",\n", + " \"cluster_size\", \"cluster_pct\", \"ordered_top_features\",\n", + " \"genai_recommendations\", \"categorization_basis\", \"naming_rationale\",\n", + "]\n", + "missing_cols = [c for c in required_persona_cols if c not in persona_df.columns]\n", + "if missing_cols:\n", + " raise ValueError(f\"persona_df missing required columns: {missing_cols}\")\n", + "\n", + "print(\"Generated personas:\", len(personas))\n", + "print(\"Executive summary:\", grounding.executive_summary)\n", + "print(\"persona_df columns:\", list(persona_df.columns))\n", + "persona_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "707cdc91", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 23:09:06,354 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", + "2026-03-06 23:09:06,629 | INFO | segplus.visualization | Saved: feature_importance.png\n", + "2026-03-06 23:09:38,632 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", + "2026-03-06 23:09:39,175 | INFO | segplus.visualization | Saved: pca_loadings.png\n", + "2026-03-06 23:09:39,422 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", + "2026-03-06 23:09:39,526 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", + "2026-03-06 23:09:40,057 | INFO | segplus.visualization | Saved: persona_radar.png\n", + "2026-03-06 23:09:40,212 | INFO | segplus.visualization | Saved: experiment_history.png\n", + "2026-03-06 23:09:40,356 | INFO | segplus.visualization | Saved: elbow_curve.png\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved charts to: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n" + ] + } + ], + "source": [ + "# 6) Visualizations\n", + "plot_cluster_scatter_2d(X, best_eval.labels, output_dir, best_eval)\n", + "plot_shap_importance(\n", + " explainability.feature_importances, output_dir, top_n=15,\n", + " importance_pct=explainability.feature_importance_pct,\n", + ")\n", + "plot_shap_summary(\n", + " X_original_for_shap,\n", + " best_eval.labels,\n", + " original_feature_names_for_shap,\n", + " output_dir,\n", + " random_state=config.random_state,\n", + " max_display=15,\n", + ")\n", + "plot_pca_loadings_heatmap(explainability.pca_loadings, output_dir)\n", + "plot_cluster_profiles_heatmap(explainability.cluster_profiles, explainability.top_features, output_dir)\n", + "plot_cluster_sizes(best_eval.labels, personas, output_dir)\n", + "plot_radar_charts(fe_result.df_original, best_eval.labels, personas, explainability.top_features, output_dir)\n", + "plot_experiment_history(experiment_log, output_dir)\n", + "plot_elbow_curve(explainability.inertia_curve, output_dir)\n", + "\n", + "print(\"Saved charts to:\", output_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "969da7d8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 23:09:42,767 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exported:\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\clustered_customers.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\cluster_profiles.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\ordered_feature_drivers.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\shap_feature_importance_pct.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\pc_feature_map.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\business_grounding.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + ] + } + ], + "source": [ + "# 7) Export Outputs\n", + "clustered_df = fe_result.df_original.copy()\n", + "clustered_df[\"cluster\"] = best_eval.labels\n", + "\n", + "clustered_path = output_dir / \"clustered_customers.csv\"\n", + "profiles_path = output_dir / \"cluster_profiles.csv\"\n", + "ordered_drivers_path = output_dir / \"ordered_feature_drivers.csv\"\n", + "shap_pct_path = output_dir / \"shap_feature_importance_pct.csv\"\n", + "pc_feature_map_path = output_dir / \"pc_feature_map.json\"\n", + "personas_path = output_dir / \"personas.csv\"\n", + "personas_json_path = output_dir / \"personas.json\"\n", + "grounding_path = output_dir / \"business_grounding.json\"\n", + "exp_log_path = output_dir / \"experiment_log.json\"\n", + "\n", + "clustered_df.to_csv(clustered_path, index=False)\n", + "explainability.cluster_profiles.to_csv(profiles_path)\n", + "if explainability.ordered_feature_drivers is not None:\n", + " explainability.ordered_feature_drivers.to_csv(ordered_drivers_path, index=False)\n", + "\n", + "shap_pct_df = pd.DataFrame([\n", + " {\"feature\": k, \"importance_pct\": v}\n", + " for k, v in explainability.feature_importance_pct.items()\n", + "]).sort_values(\"importance_pct\", ascending=False)\n", + "shap_pct_df.to_csv(shap_pct_path, index=False)\n", + "\n", + "with open(pc_feature_map_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(explainability.pc_feature_map, f, indent=2)\n", + "\n", + "# Export exact persona schema\n", + "persona_df.to_csv(personas_path, index=False)\n", + "\n", + "personas_payload = [\n", + " {\n", + " \"cluster\": p.persona_name,\n", + " \"genai_persona_name\": p.archetype,\n", + " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", + " \"description\": getattr(p, \"description\", \"\"),\n", + " \"key_traits\": p.key_traits,\n", + " \"genai_recommendations\": p.business_recommendations,\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": p.cluster_pct,\n", + " \"top_features\": p.top_features,\n", + " \"categorization_basis\": getattr(p, \"categorization_basis\", []),\n", + " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", + " }\n", + " for p in personas\n", + "]\n", + "with open(personas_json_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(personas_payload, f, indent=2)\n", + "\n", + "experiment_log.to_json(exp_log_path)\n", + "\n", + "with open(grounding_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(\n", + " {\n", + " \"executive_summary\": grounding.executive_summary,\n", + " \"cluster_priorities\": grounding.cluster_priorities,\n", + " \"cluster_actions\": grounding.cluster_actions,\n", + " \"quick_wins\": grounding.quick_wins,\n", + " },\n", + " f,\n", + " indent=2,\n", + " )\n", + "\n", + "print(\"Exported:\")\n", + "print(\" -\", clustered_path)\n", + "print(\" -\", profiles_path)\n", + "print(\" -\", ordered_drivers_path)\n", + "print(\" -\", shap_pct_path)\n", + "print(\" -\", pc_feature_map_path)\n", + "print(\" -\", personas_path)\n", + "print(\" -\", personas_json_path)\n", + "print(\" -\", grounding_path)\n", + "print(\" -\", exp_log_path)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notes\n", + "\n", + "- Architecture implemented: data input -> FE -> KMeans/DBSCAN/GMM -> eval gate loop -> explainability -> ordered drivers -> persona generation -> business grounding -> per-cluster rationale outputs.\n", + "- Local Ollama is first-class. `qwen2.5` is primary model and auto-selected when installed.\n", + "- Ordered feature driver list combines SHAP importance + weighted PCA loadings, with inertia elbow context.\n", + "- `pc_feature_map.json` provides exact mapping from each PC to top original variables.\n", + "- SHAP summary plot is saved as `shap_summary.png` when `shap` is installed.\n", + "- Optional autoencoder latent representation is available via `USE_AUTOENCODER_REPRESENTATION=True`.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.x" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/persona_generation.py b/persona_generation.py new file mode 100644 index 0000000..b7551be --- /dev/null +++ b/persona_generation.py @@ -0,0 +1,318 @@ +""" +Segmentation Plus — GenAI Persona Generation +============================================= +Generates rich marketing personas from cluster profiles +using Google Gemini API, with domain-aware prompt engineering. +""" + +from __future__ import annotations + +import json +import logging +import os +from pathlib import Path +from typing import Any, Dict, List, Optional + +import numpy as np +import pandas as pd + +from config import DomainConfig + +logger = logging.getLogger(__name__) + + +# ────────────────────────────────────────────── +# Cluster Profile Builder +# ────────────────────────────────────────────── + +def build_cluster_profiles( + df: pd.DataFrame, + labels: np.ndarray, + feature_columns: List[str], + shap_importance: Optional[Dict] = None, +) -> List[Dict[str, Any]]: + """ + Build statistical profiles for each cluster. + + Parameters + ---------- + df : pd.DataFrame + Original DataFrame (pre-scaling, for interpretable stats). + labels : np.ndarray + Cluster assignments. + feature_columns : list[str] + Feature columns to compute stats on. + shap_importance : dict, optional + Feature importance from SHAP (feature_name → importance). + + Returns + ------- + list[dict] + Per-cluster profile dictionaries. + """ + df = df.copy() + df["cluster"] = labels + + profiles = [] + available_cols = [c for c in feature_columns if c in df.columns] + + for cluster_id in sorted(df["cluster"].unique()): + if cluster_id == -1: + continue # Skip DBSCAN noise + + cluster_df = df[df["cluster"] == cluster_id] + profile = { + "segment_id": int(cluster_id), + "size": len(cluster_df), + "pct_of_total": round(len(cluster_df) / len(df) * 100, 1), + } + + # Compute mean for numeric columns + stats = {} + for col in available_cols: + if df[col].dtype in [np.float64, np.int64, float, int]: + stats[col] = { + "mean": round(float(cluster_df[col].mean()), 2), + "median": round(float(cluster_df[col].median()), 2), + "std": round(float(cluster_df[col].std()), 2), + } + profile["stats"] = stats + + # Top SHAP drivers for this cluster + if shap_importance: + sorted_feats = sorted( + shap_importance.items(), key=lambda x: abs(x[1]), reverse=True + ) + profile["shap_drivers"] = [ + {"feature": f, "importance": round(v, 4)} + for f, v in sorted_feats[:7] + ] + + profiles.append(profile) + + logger.info("Built profiles for %d clusters", len(profiles)) + return profiles + + +# ────────────────────────────────────────────── +# Prompt Builder +# ────────────────────────────────────────────── + +def build_persona_prompt( + profile: Dict, + domain_config: DomainConfig, +) -> str: + """ + Build the GenAI prompt for a single cluster. + + Parameters + ---------- + profile : dict + Cluster profile from build_cluster_profiles(). + domain_config : DomainConfig + Domain configuration with prompt template. + + Returns + ------- + str + Formatted prompt ready for the LLM. + """ + # Format stats as readable text + stats_lines = [] + for feature, vals in profile.get("stats", {}).items(): + stats_lines.append(f" - {feature}: mean={vals['mean']}, median={vals['median']}") + segment_stats = "\n".join(stats_lines) if stats_lines else " - No stats available" + + # Format SHAP drivers + shap_lines = [] + for driver in profile.get("shap_drivers", []): + shap_lines.append(f" - {driver['feature']}: {driver['importance']}") + shap_drivers = "\n".join(shap_lines) if shap_lines else " - No SHAP data available" + + # Fill template + template = domain_config.persona_prompt_template + if not template: + template = _DEFAULT_PROMPT_TEMPLATE + + prompt = template.format( + segment_id=profile["segment_id"], + segment_stats=segment_stats, + shap_drivers=shap_drivers, + segment_size=profile["size"], + segment_pct=profile["pct_of_total"], + ) + + return prompt + + +_DEFAULT_PROMPT_TEMPLATE = """ +You are a marketing strategist advising a company on their customer segments. + +Segment {segment_id} ({segment_size} customers, {segment_pct}% of total): +{segment_stats} + +Top Feature Drivers (SHAP importance): +{shap_drivers} + +Generate a detailed customer persona as structured JSON with keys: +name, tagline, demographics, goals, pain_points, product_recommendations, +channels, strategy +""" + + +# ────────────────────────────────────────────── +# Persona Generator +# ────────────────────────────────────────────── + +class PersonaGenerator: + """ + Generates marketing personas using Google Gemini API. + + Parameters + ---------- + domain_config : DomainConfig + Domain configuration. + output_dir : Path + Output directory for personas. + api_key : str, optional + Gemini API key. If None, reads from GOOGLE_API_KEY env var. + model_name : str + Gemini model name (default: 'gemini-pro'). + """ + + def __init__( + self, + domain_config: DomainConfig, + output_dir: Path, + api_key: Optional[str] = None, + model_name: str = "gemini-pro", + ) -> None: + self.config = domain_config + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + self.api_key = api_key or os.environ.get("GOOGLE_API_KEY", "") + self.model_name = model_name + self._model = None + + def _init_model(self): + """Lazily initialize the Gemini model.""" + if self._model is not None: + return + + if not self.api_key: + raise ValueError( + "Google API key not found. Set GOOGLE_API_KEY environment variable " + "or pass api_key parameter." + ) + + try: + import google.generativeai as genai + genai.configure(api_key=self.api_key) + self._model = genai.GenerativeModel(self.model_name) + logger.info("Gemini model '%s' initialized", self.model_name) + except ImportError: + raise ImportError( + "google-generativeai package not installed. " + "Run: pip install google-generativeai" + ) + + def generate_personas( + self, + profiles: List[Dict], + ) -> List[Dict]: + """ + Generate personas for all cluster profiles. + + Parameters + ---------- + profiles : list[dict] + Cluster profiles from build_cluster_profiles(). + + Returns + ------- + list[dict] + Generated persona dictionaries. + """ + self._init_model() + personas = [] + + for profile in profiles: + try: + prompt = build_persona_prompt(profile, self.config) + logger.info("Generating persona for Segment %d...", profile["segment_id"]) + + response = self._model.generate_content(prompt) + persona_text = response.text + + # Try to parse as JSON + persona = self._parse_persona(persona_text, profile["segment_id"]) + persona["segment_id"] = profile["segment_id"] + persona["segment_size"] = profile["size"] + persona["segment_pct"] = profile["pct_of_total"] + personas.append(persona) + + logger.info(" → Generated: %s", persona.get("name", "Unknown")) + + except Exception as e: + logger.error("Failed to generate persona for Segment %d: %s", profile["segment_id"], e) + personas.append({ + "segment_id": profile["segment_id"], + "error": str(e), + "raw_profile": profile, + }) + + # Save outputs + self._save_personas(personas) + return personas + + def _parse_persona(self, text: str, segment_id: int) -> Dict: + """Parse LLM response text into a structured persona dict.""" + # Try JSON extraction + try: + # Look for JSON block in the response + start = text.find("{") + end = text.rfind("}") + 1 + if start != -1 and end > start: + return json.loads(text[start:end]) + except json.JSONDecodeError: + pass + + # Fallback: return as raw text + logger.warning("Could not parse JSON for Segment %d — storing as raw text", segment_id) + return {"raw_text": text} + + def _save_personas(self, personas: List[Dict]) -> None: + """Save personas as JSON and Markdown.""" + # JSON + json_path = self.output_dir / "personas.json" + with open(json_path, "w", encoding="utf-8") as f: + json.dump(personas, f, indent=2, ensure_ascii=False) + logger.info("Personas saved to %s", json_path) + + # Markdown + md_path = self.output_dir / "personas.md" + md_lines = ["# Customer Personas\n"] + for p in personas: + md_lines.append(f"## Segment {p.get('segment_id', '?')}: {p.get('name', 'Unknown')}\n") + md_lines.append(f"**{p.get('tagline', '')}**\n") + md_lines.append(f"- Size: {p.get('segment_size', '?')} customers ({p.get('segment_pct', '?')}%)\n") + + for key in ["demographics", "goals", "pain_points", "product_recommendations", "channels", "strategy"]: + if key in p: + md_lines.append(f"\n### {key.replace('_', ' ').title()}\n") + val = p[key] + if isinstance(val, list): + for item in val: + md_lines.append(f"- {item}") + elif isinstance(val, str): + md_lines.append(val) + md_lines.append("") + + if "raw_text" in p: + md_lines.append(f"\n{p['raw_text']}\n") + + md_lines.append("\n---\n") + + with open(md_path, "w", encoding="utf-8") as f: + f.write("\n".join(md_lines)) + logger.info("Personas markdown saved to %s", md_path) diff --git a/persona_identification_pipeline.ipynb b/persona_identification_pipeline.ipynb new file mode 100644 index 0000000..30b52e2 --- /dev/null +++ b/persona_identification_pipeline.ipynb @@ -0,0 +1,2120 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 🧠 Profiling Plus Modeling Loop — Persona Identification Pipeline\n", + "### Full Architecture: Feature Engineering → Clustering → Evaluation → Explainability → LLM Persona ID (Ollama/llama3)\n", + "\n", + "**Architecture Flow:**\n", + "```\n", + "Start → Data Input → Feature Engineering → Select/Configure Clustering Runs\n", + " → [K-Means | DBSCAN | GMM] → Cluster Evaluation\n", + " → Evaluation Pass?\n", + " No → Reconfigure & Retry (up to N iterations)\n", + " Yes → Explainability (SHAP-style + PCA + Inertia)\n", + " → Feature List Driving Convergence\n", + " → Persona Identification Layer ← LOCAL LLM (Ollama llama3)\n", + " → Ground in Business Objective\n", + " → [Cluster A | Cluster B | Cluster C] → End\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 1 — Requirements\n", + "Install required packages (run once)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ All packages installed.\n", + "⚠️ Make sure Ollama is running: ollama serve\n", + "⚠️ Make sure llama3 is pulled: ollama pull llama3\n" + ] + } + ], + "source": [ + "# ── Requirements ─────────────────────────────────────────────────────────────\n", + "# Run this cell once to install dependencies.\n", + "# Ollama must be separately installed: https://ollama.com/download\n", + "# Then pull the model: ollama pull llama3\n", + "\n", + "import subprocess, sys\n", + "\n", + "PACKAGES = [\n", + " \"scikit-learn\",\n", + " \"pandas\",\n", + " \"numpy\",\n", + " \"matplotlib\",\n", + " \"seaborn\",\n", + " \"openpyxl\", # Excel support\n", + " \"pyarrow\", # Parquet support\n", + " \"requests\", # Ollama HTTP API\n", + "]\n", + "\n", + "for pkg in PACKAGES:\n", + " subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", pkg, \"-q\"])\n", + "\n", + "print(\"✅ All packages installed.\")\n", + "print(\"⚠️ Make sure Ollama is running: ollama serve\")\n", + "print(\"⚠️ Make sure llama3 is pulled: ollama pull llama3\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 2 — Imports & Global Config" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Imports complete.\n" + ] + } + ], + "source": [ + "# ── Imports ──────────────────────────────────────────────────────────────────\n", + "from __future__ import annotations\n", + "\n", + "import json\n", + "import logging\n", + "import math\n", + "import os\n", + "import re\n", + "import time\n", + "import warnings\n", + "from dataclasses import dataclass, field\n", + "from pathlib import Path\n", + "from typing import Literal, Optional\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.patches as mpatches\n", + "import numpy as np\n", + "import pandas as pd\n", + "import requests\n", + "import seaborn as sns\n", + "from sklearn.cluster import KMeans, DBSCAN\n", + "from sklearn.decomposition import PCA\n", + "from sklearn.impute import SimpleImputer\n", + "from sklearn.metrics import (\n", + " silhouette_score,\n", + " davies_bouldin_score,\n", + " calinski_harabasz_score,\n", + ")\n", + "from sklearn.mixture import GaussianMixture\n", + "from sklearn.preprocessing import StandardScaler, LabelEncoder\n", + "\n", + "warnings.filterwarnings(\"ignore\")\n", + "logging.basicConfig(\n", + " level=logging.INFO,\n", + " format=\"%(asctime)s | %(levelname)-8s | %(message)s\",\n", + " datefmt=\"%H:%M:%S\",\n", + ")\n", + "log = logging.getLogger(\"persona_pipeline\")\n", + "\n", + "# ── Global palette ────────────────────────────────────────────────────────────\n", + "PALETTE = [\"#4C72B0\", \"#DD8452\", \"#55A868\", \"#C44E52\", \"#8172B2\"]\n", + "sns.set_theme(style=\"whitegrid\", palette=PALETTE)\n", + "plt.rcParams.update({\"figure.dpi\": 130, \"axes.titlesize\": 13, \"axes.labelsize\": 11})\n", + "\n", + "print(\"✅ Imports complete.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 3 — Pipeline Configuration\n", + "Edit this cell to configure your run." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Configuration loaded.\n", + " Data source : synthetic\n", + " Ollama model : llama3 @ http://localhost:11434\n", + " Max retries : 5\n", + " Output dir : C:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\persona_output\n" + ] + } + ], + "source": [ + "# ═══════════════════════════════════════════════════════════════════════════\n", + "# PIPELINE CONFIGURATION ← Edit this block\n", + "# ═══════════════════════════════════════════════════════════════════════════\n", + "\n", + "# ── Data source ───────────────────────────────────────────────────────────────\n", + "DATA_SOURCE: Literal[\"csv\", \"parquet\", \"excel\", \"synthetic\"] = \"synthetic\"\n", + "DATA_PATH: str = \"\" # e.g. \"data/customers.csv\" — leave \"\" for synthetic\n", + "\n", + "# ── Target / ID columns to exclude from clustering ───────────────────────────\n", + "EXCLUDE_COLS: list[str] = [\"customer_id\", \"cluster_truth\"]\n", + "\n", + "# ── Clustering ────────────────────────────────────────────────────────────────\n", + "K_RANGE = (2, 6) # min/max k to search over for K-Means & GMM\n", + "DBSCAN_EPS = 0.5\n", + "DBSCAN_MIN_SAMP = 10\n", + "MAX_ITERATIONS = 5 # max modeling loop retries if eval fails\n", + "\n", + "# ── Evaluation thresholds ─────────────────────────────────────────────────────\n", + "SILHOUETTE_THRESHOLD = 0.25 # below this → loop again\n", + "DB_THRESHOLD = 2.0 # Davies-Bouldin: lower is better\n", + "\n", + "# ── Explainability ────────────────────────────────────────────────────────────\n", + "N_TOP_FEATURES = 8 # how many driving features to surface\n", + "\n", + "# ── Ollama / Local LLM ───────────────────────────────────────────────────────\n", + "OLLAMA_HOST = \"http://localhost:11434\"\n", + "OLLAMA_MODEL = \"llama3\"\n", + "OLLAMA_TIMEOUT = 120 # seconds\n", + "\n", + "# ── Business objective (used by LLM for grounding) ───────────────────────────\n", + "BUSINESS_OBJECTIVE = (\n", + " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", + " \"improve retention for high-value customers, and convert mid-tier customers \"\n", + " \"to premium products.\"\n", + ")\n", + "\n", + "# ── Output ────────────────────────────────────────────────────────────────────\n", + "OUTPUT_DIR = Path(\"persona_output\")\n", + "OUTPUT_DIR.mkdir(exist_ok=True)\n", + "\n", + "print(\"✅ Configuration loaded.\")\n", + "print(f\" Data source : {DATA_SOURCE}\")\n", + "print(f\" Ollama model : {OLLAMA_MODEL} @ {OLLAMA_HOST}\")\n", + "print(f\" Max retries : {MAX_ITERATIONS}\")\n", + "print(f\" Output dir : {OUTPUT_DIR.resolve()}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 4 — Data Input Layer\n", + "Supports CSV, Parquet, Excel, and synthetic data generation." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "13:07:49 | INFO | Loaded data: 2000 rows × 12 cols\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "📊 Dataset Overview\n", + " Rows : 2,000\n", + " Columns : 12\n", + " Numeric cols : ['age', 'annual_spend', 'purchase_frequency', 'avg_order_value', 'days_since_last_purchase', 'support_tickets_12m', 'nps_score', 'lifetime_months']\n", + " Categorical cols: ['channel', 'region', 'product_category', 'cluster_truth']\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    ageannual_spendpurchase_frequencyavg_order_valuedays_since_last_purchasesupport_tickets_12mnps_scorelifetime_monthschannelregionproduct_categorycluster_truth
    0413762.869240.431226.331mobileNorthpremiumC
    1409836.6029378.04909.029mobileSouthpremiumA
    2484082.7314246.092509.139mobileNorthstandardC
    3271541.50591.205716.749webSouthstandardB
    4271775.54687.414826.141webSouthstandardB
    \n", + "
    " + ], + "text/plain": [ + " age annual_spend purchase_frequency avg_order_value \\\n", + "0 41 3762.86 9 240.43 \n", + "1 40 9836.60 29 378.04 \n", + "2 48 4082.73 14 246.09 \n", + "3 27 1541.50 5 91.20 \n", + "4 27 1775.54 6 87.41 \n", + "\n", + " days_since_last_purchase support_tickets_12m nps_score lifetime_months \\\n", + "0 12 2 6.3 31 \n", + "1 9 0 9.0 29 \n", + "2 25 0 9.1 39 \n", + "3 57 1 6.7 49 \n", + "4 48 2 6.1 41 \n", + "\n", + " channel region product_category cluster_truth \n", + "0 mobile North premium C \n", + "1 mobile South premium A \n", + "2 mobile North standard C \n", + "3 web South standard B \n", + "4 web South standard B " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ── Data Input Layer ─────────────────────────────────────────────────────────\n", + "\n", + "@dataclass\n", + "class ColumnMeta:\n", + " name: str\n", + " dtype: Literal[\"numeric\", \"categorical\", \"datetime\", \"text\", \"boolean\"]\n", + " null_rate: float\n", + " n_unique: int\n", + "\n", + "@dataclass\n", + "class DataSchema:\n", + " n_rows: int\n", + " n_cols: int\n", + " columns: list[ColumnMeta] = field(default_factory=list)\n", + "\n", + " @property\n", + " def numeric_cols(self) -> list[str]:\n", + " return [c.name for c in self.columns if c.dtype == \"numeric\"]\n", + "\n", + " @property\n", + " def categorical_cols(self) -> list[str]:\n", + " return [c.name for c in self.columns if c.dtype == \"categorical\"]\n", + "\n", + "\n", + "def infer_schema(df: pd.DataFrame) -> DataSchema:\n", + " cols = []\n", + " for col in df.columns:\n", + " s = df[col]\n", + " nu = s.nunique()\n", + " if pd.api.types.is_bool_dtype(s):\n", + " dtype = \"boolean\"\n", + " elif pd.api.types.is_datetime64_any_dtype(s):\n", + " dtype = \"datetime\"\n", + " elif pd.api.types.is_numeric_dtype(s):\n", + " dtype = \"numeric\"\n", + " elif nu / max(len(s), 1) < 0.05 or nu <= 20:\n", + " dtype = \"categorical\"\n", + " else:\n", + " dtype = \"text\"\n", + " cols.append(ColumnMeta(col, dtype, s.isna().mean(), nu))\n", + " return DataSchema(len(df), len(df.columns), cols)\n", + "\n", + "\n", + "def _generate_synthetic() -> pd.DataFrame:\n", + " \"\"\"3-cluster synthetic customer dataset with realistic feature distributions.\"\"\"\n", + " rng = np.random.default_rng(42)\n", + " N = 2000\n", + "\n", + " def make_cluster(n, age_mu, spend_mu, freq_mu, aov_mu, days_mu, nps_mu,\n", + " mobile_p, premium_p, seed_offset=0):\n", + " return pd.DataFrame({\n", + " \"age\": rng.normal(age_mu, 6, n).clip(18, 75).astype(int),\n", + " \"annual_spend\": rng.normal(spend_mu, spend_mu*0.15, n).clip(100, 20000).round(2),\n", + " \"purchase_frequency\": rng.normal(freq_mu, freq_mu*0.2, n).clip(1, 52).astype(int),\n", + " \"avg_order_value\": rng.normal(aov_mu, aov_mu*0.18, n).clip(10, 1000).round(2),\n", + " \"days_since_last_purchase\": rng.normal(days_mu, days_mu*0.3, n).clip(1, 365).astype(int),\n", + " \"support_tickets_12m\": rng.poisson(0.5 + seed_offset*0.8, n),\n", + " \"nps_score\": rng.normal(nps_mu, 0.8, n).clip(1, 10).round(1),\n", + " \"lifetime_months\": rng.normal(24 + seed_offset*12, 8, n).clip(1, 120).astype(int),\n", + " \"channel\": rng.choice([\"mobile\",\"web\",\"in-store\"], n, p=[mobile_p, 1-mobile_p-0.05, 0.05]),\n", + " \"region\": rng.choice([\"North\",\"South\",\"East\",\"West\"], n),\n", + " \"product_category\": rng.choice([\"premium\",\"standard\",\"budget\"], n,\n", + " p=[premium_p, 1-premium_p-0.1, 0.1]),\n", + " })\n", + "\n", + " df_a = make_cluster(N//3, age_mu=36, spend_mu=9000, freq_mu=26, aov_mu=340,\n", + " days_mu=7, nps_mu=9.0, mobile_p=0.65, premium_p=0.80, seed_offset=0)\n", + " df_b = make_cluster(N//3, age_mu=28, spend_mu=1600, freq_mu=5, aov_mu=80,\n", + " days_mu=70, nps_mu=6.0, mobile_p=0.30, premium_p=0.08, seed_offset=2)\n", + " df_c = make_cluster(N-2*(N//3), age_mu=46, spend_mu=4200, freq_mu=13, aov_mu=190,\n", + " days_mu=28, nps_mu=7.5, mobile_p=0.50, premium_p=0.42, seed_offset=1)\n", + "\n", + " df_a[\"cluster_truth\"] = \"A\"\n", + " df_b[\"cluster_truth\"] = \"B\"\n", + " df_c[\"cluster_truth\"] = \"C\"\n", + "\n", + " df = pd.concat([df_a, df_b, df_c], ignore_index=True)\n", + " return df.sample(frac=1, random_state=42).reset_index(drop=True)\n", + "\n", + "\n", + "def load_data(source: str, path: str) -> pd.DataFrame:\n", + " loaders = {\n", + " \"csv\": lambda p: pd.read_csv(p),\n", + " \"parquet\": lambda p: pd.read_parquet(p),\n", + " \"excel\": lambda p: pd.read_excel(p),\n", + " \"synthetic\": lambda p: _generate_synthetic(),\n", + " }\n", + " if source not in loaders:\n", + " raise ValueError(f\"Unknown source {source!r}. Choose from {list(loaders)}\")\n", + " df = loaders[source](path or None)\n", + " log.info(\"Loaded data: %d rows × %d cols\", *df.shape)\n", + " return df\n", + "\n", + "\n", + "# ── Run Data Input ────────────────────────────────────────────────────────────\n", + "raw_df = load_data(DATA_SOURCE, DATA_PATH)\n", + "schema = infer_schema(raw_df)\n", + "\n", + "print(f\"\\n📊 Dataset Overview\")\n", + "print(f\" Rows : {schema.n_rows:,}\")\n", + "print(f\" Columns : {schema.n_cols}\")\n", + "print(f\" Numeric cols : {schema.numeric_cols}\")\n", + "print(f\" Categorical cols: {schema.categorical_cols}\")\n", + "print()\n", + "raw_df.head()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 5 — Feature Engineering\n", + "Imputation → Encoding → Outlier clipping → Scaling → PCA (optional)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "13:08:03 | INFO | Feature engineering complete: 11 features\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Feature matrix shape : (2000, 11)\n", + " Features : ['age', 'annual_spend', 'purchase_frequency', 'avg_order_value', 'days_since_last_purchase', 'support_tickets_12m', 'nps_score', 'lifetime_months', 'channel', 'region', 'product_category']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    ageannual_spendpurchase_frequencyavg_order_valuedays_since_last_purchasesupport_tickets_12mnps_scorelifetime_monthschannelregionproduct_category
    count2000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.000
    mean0.0000.000-0.0000.000-0.000-0.0000.000-0.000-0.000-0.0000.000
    std1.0001.0001.0001.0001.0001.0001.0001.0001.0001.0001.000
    min-1.911-1.185-1.222-1.322-1.088-1.001-2.026-2.121-2.494-1.373-2.062
    25%-0.741-1.005-1.000-1.008-0.913-1.001-0.824-0.768-0.756-0.469-0.534
    50%0.003-0.225-0.115-0.093-0.250-0.2230.024-0.052-0.7560.434-0.534
    75%0.7480.9910.7980.8290.7270.5560.8020.7440.9830.4340.994
    max2.2362.0582.3192.2512.5432.8921.7912.1770.9831.3380.994
    \n", + "
    " + ], + "text/plain": [ + " age annual_spend purchase_frequency avg_order_value \\\n", + "count 2000.000 2000.000 2000.000 2000.000 \n", + "mean 0.000 0.000 -0.000 0.000 \n", + "std 1.000 1.000 1.000 1.000 \n", + "min -1.911 -1.185 -1.222 -1.322 \n", + "25% -0.741 -1.005 -1.000 -1.008 \n", + "50% 0.003 -0.225 -0.115 -0.093 \n", + "75% 0.748 0.991 0.798 0.829 \n", + "max 2.236 2.058 2.319 2.251 \n", + "\n", + " days_since_last_purchase support_tickets_12m nps_score \\\n", + "count 2000.000 2000.000 2000.000 \n", + "mean -0.000 -0.000 0.000 \n", + "std 1.000 1.000 1.000 \n", + "min -1.088 -1.001 -2.026 \n", + "25% -0.913 -1.001 -0.824 \n", + "50% -0.250 -0.223 0.024 \n", + "75% 0.727 0.556 0.802 \n", + "max 2.543 2.892 1.791 \n", + "\n", + " lifetime_months channel region product_category \n", + "count 2000.000 2000.000 2000.000 2000.000 \n", + "mean -0.000 -0.000 -0.000 0.000 \n", + "std 1.000 1.000 1.000 1.000 \n", + "min -2.121 -2.494 -1.373 -2.062 \n", + "25% -0.768 -0.756 -0.469 -0.534 \n", + "50% -0.052 -0.756 0.434 -0.534 \n", + "75% 0.744 0.983 0.434 0.994 \n", + "max 2.177 0.983 1.338 0.994 " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ── Feature Engineering ──────────────────────────────────────────────────────\n", + "\n", + "class FeatureEngineer:\n", + " \"\"\"\n", + " Stateless-first feature engineering. Call .fit_transform() once;\n", + " subsequent calls to .transform() reuse fitted state for consistency.\n", + " \"\"\"\n", + "\n", + " def __init__(self, exclude_cols: list[str]):\n", + " self.exclude_cols = exclude_cols\n", + " self._imputer: SimpleImputer | None = None\n", + " self._scaler: StandardScaler | None = None\n", + " self._encoders: dict[str, LabelEncoder] = {}\n", + " self._feature_cols: list[str] = []\n", + " self._fitted = False\n", + "\n", + " def fit_transform(self, df: pd.DataFrame, schema: DataSchema) -> pd.DataFrame:\n", + " df = df.copy()\n", + " # Drop excluded\n", + " df.drop(columns=[c for c in self.exclude_cols if c in df.columns], inplace=True)\n", + "\n", + " num_cols = [c for c in schema.numeric_cols if c in df.columns]\n", + " cat_cols = [c for c in schema.categorical_cols if c in df.columns]\n", + "\n", + " # Encode categoricals\n", + " for col in cat_cols:\n", + " le = LabelEncoder()\n", + " df[col] = le.fit_transform(df[col].astype(str))\n", + " self._encoders[col] = le\n", + "\n", + " self._feature_cols = num_cols + cat_cols\n", + " X = df[self._feature_cols].copy()\n", + "\n", + " # Impute\n", + " self._imputer = SimpleImputer(strategy=\"median\")\n", + " X_arr = self._imputer.fit_transform(X)\n", + " X = pd.DataFrame(X_arr, columns=self._feature_cols)\n", + "\n", + " # Clip outliers (1st–99th percentile)\n", + " for col in num_cols:\n", + " lo, hi = X[col].quantile([0.01, 0.99])\n", + " X[col] = X[col].clip(lo, hi)\n", + "\n", + " # Scale\n", + " self._scaler = StandardScaler()\n", + " X_scaled = self._scaler.fit_transform(X)\n", + " X = pd.DataFrame(X_scaled, columns=self._feature_cols)\n", + "\n", + " self._fitted = True\n", + " log.info(\"Feature engineering complete: %s features\", len(self._feature_cols))\n", + " return X\n", + "\n", + " @property\n", + " def feature_names(self) -> list[str]:\n", + " return list(self._feature_cols)\n", + "\n", + "\n", + "fe = FeatureEngineer(exclude_cols=EXCLUDE_COLS)\n", + "features_df = fe.fit_transform(raw_df, schema)\n", + "X = features_df.values\n", + "\n", + "print(f\"✅ Feature matrix shape : {X.shape}\")\n", + "print(f\" Features : {fe.feature_names}\")\n", + "features_df.describe().round(3)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 6 — Clustering Algorithms\n", + "K-Means (distance-based), DBSCAN (density-based), GMM/EM (probabilistic)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Clustering algorithms defined (K-Means, DBSCAN, GMM).\n" + ] + } + ], + "source": [ + "# ── Clustering Configurator & Runners ────────────────────────────────────────\n", + "\n", + "@dataclass\n", + "class ClusteringConfig:\n", + " k: int = 3\n", + " kmeans_init: str = \"k-means++\"\n", + " kmeans_n_init: int = 10\n", + " kmeans_max_iter: int = 300\n", + " dbscan_eps: float = DBSCAN_EPS\n", + " dbscan_min_samples: int = DBSCAN_MIN_SAMP\n", + " gmm_covariance_type: str = \"full\"\n", + " gmm_n_init: int = 5\n", + " random_state: int = 42\n", + "\n", + "\n", + "@dataclass\n", + "class ClusterRunResult:\n", + " algorithm: str\n", + " labels: np.ndarray\n", + " n_clusters: int\n", + " model: object\n", + "\n", + "\n", + "class ClusteringConfigurator:\n", + " \"\"\"\n", + " Selects the optimal k for K-Means / GMM using elbow + silhouette.\n", + " Reconfigures on failed evaluation by nudging k and eps.\n", + " \"\"\"\n", + "\n", + " def __init__(self, k_range: tuple[int, int]):\n", + " self.k_range = k_range\n", + "\n", + " def configure(self, X: np.ndarray) -> ClusteringConfig:\n", + " best_k, best_score = self.k_range[0], -1.0\n", + " scores = {}\n", + " for k in range(self.k_range[0], self.k_range[1] + 1):\n", + " km = KMeans(n_clusters=k, init=\"k-means++\", n_init=5, random_state=42)\n", + " lbl = km.fit_predict(X)\n", + " if len(set(lbl)) < 2:\n", + " continue\n", + " s = silhouette_score(X, lbl, sample_size=min(1000, len(X)))\n", + " scores[k] = round(s, 4)\n", + " if s > best_score:\n", + " best_score, best_k = s, k\n", + " log.info(\" K search → scores: %s | selected k=%d (sil=%.4f)\", scores, best_k, best_score)\n", + " return ClusteringConfig(k=best_k)\n", + "\n", + " def reconfigure(self, X: np.ndarray, cfg: ClusteringConfig, iteration: int) -> ClusteringConfig:\n", + " \"\"\"Nudge parameters when evaluation fails.\"\"\"\n", + " new_k = min(cfg.k + 1, self.k_range[1])\n", + " new_eps = round(cfg.dbscan_eps * 1.2, 3)\n", + " log.info(\" Reconfiguring: k %d→%d, eps %.3f→%.3f\", cfg.k, new_k, cfg.dbscan_eps, new_eps)\n", + " return ClusteringConfig(k=new_k, dbscan_eps=new_eps)\n", + "\n", + "\n", + "def run_kmeans(X: np.ndarray, cfg: ClusteringConfig) -> ClusterRunResult:\n", + " model = KMeans(\n", + " n_clusters=cfg.k,\n", + " init=cfg.kmeans_init,\n", + " n_init=cfg.kmeans_n_init,\n", + " max_iter=cfg.kmeans_max_iter,\n", + " random_state=cfg.random_state,\n", + " )\n", + " labels = model.fit_predict(X)\n", + " return ClusterRunResult(\"kmeans\", labels, len(set(labels)), model)\n", + "\n", + "\n", + "def run_dbscan(X: np.ndarray, cfg: ClusteringConfig) -> ClusterRunResult:\n", + " model = DBSCAN(eps=cfg.dbscan_eps, min_samples=cfg.dbscan_min_samples)\n", + " labels = model.fit_predict(X)\n", + " n = len(set(labels)) - (1 if -1 in labels else 0)\n", + " return ClusterRunResult(\"dbscan\", labels, max(n, 1), model)\n", + "\n", + "\n", + "def run_gmm(X: np.ndarray, cfg: ClusteringConfig) -> ClusterRunResult:\n", + " model = GaussianMixture(\n", + " n_components=cfg.k,\n", + " covariance_type=cfg.gmm_covariance_type,\n", + " n_init=cfg.gmm_n_init,\n", + " random_state=cfg.random_state,\n", + " )\n", + " labels = model.fit_predict(X)\n", + " return ClusterRunResult(\"gmm\", labels, len(set(labels)), model)\n", + "\n", + "\n", + "print(\"✅ Clustering algorithms defined (K-Means, DBSCAN, GMM).\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 7 — Cluster Evaluator\n", + "Silhouette, Davies-Bouldin, Calinski-Harabasz scoring with pass/fail gate." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Evaluator and configurator ready.\n" + ] + } + ], + "source": [ + "# ── Cluster Evaluator ────────────────────────────────────────────────────────\n", + "\n", + "@dataclass\n", + "class EvaluationResult:\n", + " algorithm: str\n", + " labels: np.ndarray\n", + " n_clusters: int\n", + " silhouette: float\n", + " davies_bouldin: float\n", + " calinski_harabasz: float\n", + " passes: bool\n", + " all_scores: dict = field(default_factory=dict)\n", + "\n", + "\n", + "class ClusterEvaluator:\n", + " \"\"\"\n", + " Evaluates all three algorithm outputs and selects the best one.\n", + " Pass criteria: silhouette ≥ threshold AND davies_bouldin ≤ threshold.\n", + " \"\"\"\n", + "\n", + " def __init__(self, sil_threshold: float, db_threshold: float):\n", + " self.sil_threshold = sil_threshold\n", + " self.db_threshold = db_threshold\n", + "\n", + " def _score_one(self, X: np.ndarray, result: ClusterRunResult) -> dict:\n", + " lbl = result.labels\n", + " valid = lbl[lbl != -1] # exclude DBSCAN noise\n", + " X_v = X[lbl != -1]\n", + "\n", + " if len(set(valid)) < 2 or len(X_v) < 10:\n", + " return {\"silhouette\": -1.0, \"davies_bouldin\": 99.0, \"calinski_harabasz\": 0.0}\n", + "\n", + " sample = min(2000, len(X_v))\n", + " sil = silhouette_score(X_v, valid, sample_size=sample)\n", + " db = davies_bouldin_score(X_v, valid)\n", + " ch = calinski_harabasz_score(X_v, valid)\n", + " return {\"silhouette\": round(sil, 4), \"davies_bouldin\": round(db, 4),\n", + " \"calinski_harabasz\": round(ch, 2)}\n", + "\n", + " def evaluate(\n", + " self,\n", + " X: np.ndarray,\n", + " results: dict[str, ClusterRunResult],\n", + " ) -> EvaluationResult:\n", + " scored = {}\n", + " for name, res in results.items():\n", + " s = self._score_one(X, res)\n", + " s[\"n_clusters\"] = res.n_clusters\n", + " scored[name] = s\n", + " log.info(\n", + " \" [%s] k=%d | sil=%.4f | DB=%.4f | CH=%.1f\",\n", + " name, res.n_clusters, s[\"silhouette\"], s[\"davies_bouldin\"], s[\"calinski_harabasz\"]\n", + " )\n", + "\n", + " # Pick best by silhouette\n", + " best_name = max(scored, key=lambda n: scored[n][\"silhouette\"])\n", + " best_s = scored[best_name]\n", + " best_res = results[best_name]\n", + " passes = (best_s[\"silhouette\"] >= self.sil_threshold and\n", + " best_s[\"davies_bouldin\"] <= self.db_threshold)\n", + "\n", + " return EvaluationResult(\n", + " algorithm = best_name,\n", + " labels = best_res.labels,\n", + " n_clusters = best_res.n_clusters,\n", + " silhouette = best_s[\"silhouette\"],\n", + " davies_bouldin = best_s[\"davies_bouldin\"],\n", + " calinski_harabasz = best_s[\"calinski_harabasz\"],\n", + " passes = passes,\n", + " all_scores = scored,\n", + " )\n", + "\n", + "\n", + "evaluator = ClusterEvaluator(SILHOUETTE_THRESHOLD, DB_THRESHOLD)\n", + "configurator = ClusteringConfigurator(K_RANGE)\n", + "print(\"✅ Evaluator and configurator ready.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 8 — 🔁 Modeling Loop\n", + "Runs all three algorithms per iteration. Retries with reconfigured parameters if evaluation fails." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", + " cpu_info = subprocess.run(\n", + " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", + " capture_output=True,\n", + " text=True,\n", + " )\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", + " with Popen(*popenargs, **kwargs) as process:\n", + " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", + " self._execute_child(args, executable, preexec_fn, close_fds,\n", + " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " pass_fds, cwd, env,\n", + " ^^^^^^^^^^^^^^^^^^^\n", + " ...<5 lines>...\n", + " gid, gids, uid, umask,\n", + " ^^^^^^^^^^^^^^^^^^^^^^\n", + " start_new_session, process_group)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", + " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", + " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", + " # no special security\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " ...<4 lines>...\n", + " cwd,\n", + " ^^^^\n", + " startupinfo)\n", + " ^^^^^^^^^^^^\n", + "13:09:00 | INFO | K search → scores: {2: np.float64(0.3332), 3: np.float64(0.3), 4: np.float64(0.2545), 5: np.float64(0.1989), 6: np.float64(0.1822)} | selected k=2 (sil=0.3332)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "────────────────────────────────────────────────────────────\n", + " Modeling Loop — Iteration 1/5 | k=2\n", + "────────────────────────────────────────────────────────────\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "13:09:00 | INFO | [kmeans] k=2 | sil=0.3386 | DB=1.1594 | CH=1240.2\n", + "13:09:00 | INFO | [dbscan] k=1 | sil=-1.0000 | DB=99.0000 | CH=0.0\n", + "13:09:01 | INFO | [gmm] k=2 | sil=0.3412 | DB=1.1442 | CH=1232.0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " K-Means clusters : 2\n", + " DBSCAN clusters : 1 (excl. noise)\n", + " GMM clusters : 2\n", + "\n", + " Best algorithm : GMM\n", + " Silhouette score : 0.3412 (threshold ≥ 0.25)\n", + " Davies-Bouldin : 1.1442 (threshold ≤ 2.0)\n", + " Calinski-Harabasz: 1232.0\n", + " Evaluation PASS : ✅ YES\n", + "\n", + " 🎯 Accepted on iteration 1.\n", + "\n", + "════════════════════════════════════════════════════════════\n", + " MODELING LOOP COMPLETE in 1.0s\n", + " Algorithm : GMM\n", + " Clusters : 2\n", + " Silhouette: 0.3412\n", + "════════════════════════════════════════════════════════════\n" + ] + } + ], + "source": [ + "# ── Modeling Loop ────────────────────────────────────────────────────────────\n", + "\n", + "def modeling_loop(\n", + " X: np.ndarray,\n", + " configurator: ClusteringConfigurator,\n", + " evaluator: ClusterEvaluator,\n", + " max_iterations: int,\n", + ") -> tuple[EvaluationResult, ClusteringConfig]:\n", + " \"\"\"\n", + " Implements the core retry loop from the architecture diagram.\n", + " Returns the best EvaluationResult and the config that produced it.\n", + " \"\"\"\n", + " config = configurator.configure(X)\n", + " best_eval: EvaluationResult | None = None\n", + "\n", + " for iteration in range(1, max_iterations + 1):\n", + " print(f\"\\n{'─'*60}\")\n", + " print(f\" Modeling Loop — Iteration {iteration}/{max_iterations} | k={config.k}\")\n", + " print(f\"{'─'*60}\")\n", + "\n", + " # Run all three clustering algorithms\n", + " results: dict[str, ClusterRunResult] = {\n", + " \"kmeans\": run_kmeans(X, config),\n", + " \"dbscan\": run_dbscan(X, config),\n", + " \"gmm\": run_gmm(X, config),\n", + " }\n", + "\n", + " print(f\" K-Means clusters : {results['kmeans'].n_clusters}\")\n", + " print(f\" DBSCAN clusters : {results['dbscan'].n_clusters} (excl. noise)\")\n", + " print(f\" GMM clusters : {results['gmm'].n_clusters}\")\n", + "\n", + " # Evaluate\n", + " eval_result = evaluator.evaluate(X, results)\n", + " print(f\"\\n Best algorithm : {eval_result.algorithm.upper()}\")\n", + " print(f\" Silhouette score : {eval_result.silhouette:.4f} (threshold ≥ {SILHOUETTE_THRESHOLD})\")\n", + " print(f\" Davies-Bouldin : {eval_result.davies_bouldin:.4f} (threshold ≤ {DB_THRESHOLD})\")\n", + " print(f\" Calinski-Harabasz: {eval_result.calinski_harabasz:.1f}\")\n", + " print(f\" Evaluation PASS : {'✅ YES' if eval_result.passes else '❌ NO'}\")\n", + "\n", + " if eval_result.passes:\n", + " best_eval = eval_result\n", + " print(f\"\\n 🎯 Accepted on iteration {iteration}.\")\n", + " break\n", + " else:\n", + " print(f\"\\n ↩️ Poor separation. Reconfiguring for next iteration...\")\n", + " config = configurator.reconfigure(X, config, iteration)\n", + "\n", + " if best_eval is None:\n", + " print(\"\\n⚠️ Max iterations reached without passing. Using best found result.\")\n", + " best_eval = eval_result # use last iteration's result\n", + "\n", + " return best_eval, config\n", + "\n", + "\n", + "# ── Execute the loop ──────────────────────────────────────────────────────────\n", + "t0 = time.time()\n", + "best_eval, final_config = modeling_loop(X, configurator, evaluator, MAX_ITERATIONS)\n", + "elapsed = time.time() - t0\n", + "\n", + "print(f\"\\n{'═'*60}\")\n", + "print(f\" MODELING LOOP COMPLETE in {elapsed:.1f}s\")\n", + "print(f\" Algorithm : {best_eval.algorithm.upper()}\")\n", + "print(f\" Clusters : {best_eval.n_clusters}\")\n", + "print(f\" Silhouette: {best_eval.silhouette:.4f}\")\n", + "print(f\"{'═'*60}\")\n", + "\n", + "# Attach cluster labels back to raw data\n", + "labeled_df = raw_df.copy()\n", + "labeled_df[\"cluster_id\"] = best_eval.labels\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 9 — Cluster Visualisation (PCA 2D Projection)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABrgAAAfSCAYAAADUTv42AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAT/gAAE/4BB5Q5hAABAABJREFUeJzs3Xd4VGX2wPHv9EkPNYQUOqGE3pUOq9gpKwsoItZ1V+WHui6riA1U7AqKuyK6ooKCdAGV3pSyQZCShB4SQgjpk0mm3t8fcYYMmUlCOnA+z+PzmPvecqYy9577nqNSFEVBCCGEEEIIIYQQQgghhBBCiKuEurYDEEIIIYQQQgghhBBCCCGEEOJKSIJLCCGEEEIIIYQQQgghhBBCXFUkwSWEEEIIIYQQQgghhBBCCCGuKpLgEkIIIYQQQgghhBBCCCGEEFcVSXAJIYQQQgghhBBCCCGEEEKIq4okuIQQQgghhBBCCCGEEEIIIcRVRRJcQgghhBBCCCGEEEIIIYQQ4qoiCS4hhBBCCCGEEEIIIYQQQghxVZEElxBCCCGEEEIIIYQQQgghhLiqSIJLCCGEEEIIIYQQQgghhBBCXFUkwSWEEEIIIYQQQgghhBBCCCGuKpLgEkIIIYQQQgghhBBCCCGEEFcVSXAJIarMoUOHmDFjBiNGjKBz58507tyZm2++mRkzZpCYmOh1m2nTphETE8OcOXNqONoiJ06cqJXjXu22bdvGs88+y80330yXLl3o3LkzQ4cO5f/+7/9Yv349iqJ43W7OnDnExMQQExNDt27dsFqtZR7r2WefdW9z+fvEtTwmJoZ58+aVua+zZ896bFOVTpw4QadOnfjuu+8qtP3u3buJiYlh6NChHstdsSYnJ7uXTZw4kZiYGJYtW1apmOsaX5/HwsJCUlJSajiaktauXcu4cePo2rUrPXr04J577uHnn3+u0L527NjBAw88QM+ePenatSt33nkn//nPf8r1mXD58ssviYmJYdq0aeVaPz8/n0GDBjFx4kSv49u3b6ddu3b88ssv5Y5BCCGEEKIqbNy4kSeffJJBgwYRGxtLnz59GDlyJG+//bbP34HefhO7zjeK/z7y9Tv7alfab+SaOs91Op2sWLGCRx55hP79+xMbG0vfvn0ZO3Ysc+fOJTMzs0biqG115fxMURSGDh1KTEwMw4YN83le7uLtXLOuKO059fb+rsuPRQhRvSTBJYSoNLvdzqxZsxgzZgzffvstqampREdH07RpU1JSUvj2228ZNWoU//nPf2o7VDeTycT06dN55JFHajuUq0pKSgoTJkzg4YcfZuXKlaSnpxMdHU3r1q0xmUysW7eOKVOm8Je//IWMjIxS92U2m9m1a1ep69hsNrZs2VKu2DZs2FDmOj/99FO59nWlFEXhX//6F5GRkYwZM6ZajnEtK+3zuHXrVm699VZ2795dC5Fd8umnnzJ16lT2799PREQEDRs2ZN++fTz++OPlSq4Wt3jxYh588EF27tyJ0WgkOjqaU6dO8c477zBu3DhMJlOZ+0hNTeW9994r9zEVRWHGjBmcP3/e5zoDBgygb9++PP/88xQUFJR730IIIYQQFWWz2fj73//O3/72N3788Uc0Gg3t27cnODiY48eP8+mnn3LrrbeycuXK2g61TvH1G7kmz3NNJhMTJkzgn//8J9u3b8ff35/27dvj7+/PoUOHmDNnDiNGjCjznE9UnX379rmTnsnJyfz666+1HFHVslqtvP3229x11121HYoQog6RBJcQolIUReGvf/0rX375JeHh4cyePZu4uDjWrFnD+vXr+eWXX3jkkUdwOBy88847LFy4sLZDBuDw4cMsWbKkzDuaxCWpqamMGzeO//3vf7Rq1Yp58+axe/duVq9ezbJly/jll1/4z3/+Q/PmzTlw4AAPPPAAdrvd6760Wi1QdlJq9+7d5OTklBmbVqvl0KFDpV68Byo826Ysy5Yt48CBAzzxxBNoNJoK7aNz586sXbuWL774omqDuwqU9nmcP39+rc/eOnjwIO+++y7+/v4sXLiQH374gR9//JF58+ah1+v54IMPOHToULn2dezYMWbOnIlKpWLmzJns2LGDVatWsWHDBjp16sThw4d5++23y9zPyy+/jNlsLtcx7XY7L7zwAmvWrClz3f/7v/8jJSWF+fPnl2vfQgghhBCV8e6777Jhwwbat2/P2rVr2bRpE0uWLOHnn39m586dTJw4kcLCQp577jkOHjzose3s2bNZu3Ytf/rTn2op+trj6zdyTZ7nPvfcc+zfv58bbriBTZs28dNPP7FkyRI2bdrE5s2bufXWW8nJyeHxxx+v9d/z14tVq1YBcOONNwLw/fff12Y4leLt833hwgU+/fRTbDZbLUYmhKhrJMElhKiU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YPv27SxfvpwTJ06Qnp7O1KlTWbZsGYC7yoSvnlBGo5GYmBj335V9LbydM7mej++//96d7PLlzJkz5e7jW3zGU3GtW7cG4NSpU+5lUVFRdOvWjf3797Np0yb3bK0ffvgBuDTDqyyrV69GURSPkoQukZGRdOnShQMHDrB06VKGDx9e6r5cz0tpbSjatWvHuXPn3H9X9lyz+GzCquDt9XZ9xn2d03l7fV2JSm+l6l3nZOWpEiSEqH6S4BJCVFh0dDQ7d+50/wgqy8WLF3E4HOX+cXgloqKiWL58OR999BE//fQTubm5bNiwgQ0bNvDyyy9z11138eKLL7pLifniuih+7tw5jx9t3hTv7ePibf8hISEsXbqUefPm8cMPP3Dx4kV27NjBjh07eO211xg2bBgzZ84stcfP0qVLr6hu9pXyVrvaJSoqCoPBgMVi4eTJk17L6r355psllg0dOrTM2R8qlYphw4bx9ddfs3HjRu655x6OHTvGqVOnGDt27BU3bB42bBgvvvgimzZtwul0olar+emnn1CpVO7ZYlXJ9R7wVWLygw8+4KuvvuK7777jxIkT/P777/z+++989NFHtGvXjtdff73UE7WylPV+dnHdWebtbk0XVyLHVRe+Ii6/87C869bUcQ4dOlTuGUmu19ZVIiM3N9fnuuXp01Ueer2ee+65h1deecX9uBYuXMjBgwe55557yt2Priq43tPevueEEEIIIapb8+bNad68Offeey+LFy/mxRdfJD09nS1btlxRlYfiyvvbGWr+93NFzz/r2nFUKhXt2rWjXbt2PPjgg3zwwQd88sknHD58mMOHD9OxY0dycnIA3+dQl6vsa+HtdS9+M1xZCcoreT683QwKl2K/vKT5nXfeyf79+1m7di133nknDoeD9evXo1ary13lZfXq1UDRYymeGLzc9u3bSU9PLzWh5JrhVNprc/nrUB2vT2VUZH+lPd6KVOkQQtQsSXAJISpswIABLFq0iD179qAoSpn/8H/99dd8/PHHDBo0iP/85z9l7t/X3TAFBQVelzdt2pRZs2bx0ksv8dtvv7Fr1y42b97M0aNH+f777zEYDLz44oulHtN1x9HLL7/snkZfFerVq8dzzz3HtGnTOHToELt27WLr1q3s37+fDRs2YLPZSn1OUlNTy7yQX110Oh19+vRh27Zt/Pzzz17LelTGn/70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RbZt28bevXv59V//9bJjh4aG+OxnP8u+fftKrtnd3b2wX0AhRIkzZ87w8Y9/nL1797Jz504+9alPMTw8XPHYsbEx/vW//tfs3LmTXbt28fGPf5zz58+XHfflL3+ZRx55hO3bt7Nz504ef/xxnn322bLjRkdH+Y//8T/y4IMPsnXrVt761rfypS99iWw2W3LcgQMH+NVf/VXuueceNm3axN69e/nlX/5ljhw5UnLc448/zoMPPkhfXx9PPvkke/bsYdu2bXz4wx/m8OHDr/+LJIRYcJ2dnXzyk5/knnvuYfv27fzyL/8y58+f5+GHH+bxxx8HCvP/Nm7cyNjYGL/xG7/B3r172bFjBx/72Mfo6+sjnU7zH//jf+See+5h165dfPSjHy15T5qaJ/inf/qnfP/73+e9730vW7Zs4aGHHuL//J//A8CLL77IY489xtatW9m3bx9/9md/huu6i/I1WWqkRaG44Q4dOsTXvvY1Pv3pT8vNFbGg1q9fz/r16yvum/olec2aNTdzSeI2Z9s2nZ2d7Nixo+L+ZcuWcejQIfL5PKZp3uTViaXA5/Pxz/7ZP6u476WXXiKVSrF9+/abuyixJFmWxec+9zk2bNjAP/2n/1TaXgohrsn58+f55V/+ZQzD4C//8i9ZtWoVAMlkkve///20trbyT/7JP2H//v08/fTTxONxuru78fl8PProoxw/fpwf/OAHjI2N8dWvfrV43b/7u7/j3/7bf0tdXR3vfOc78fv9PPvss/zKr/wKn/vc5/jwhz9cPPaLX/wif/mXf8mmTZt45JFHcF2Xl156iaeeeoojR47w3e9+F1Wd/szu8ePH+X//7/+xe/duPvjBD3Lo0CGefvppzp07x7e+9S0Astksv/RLv1S8sfW2t72Ny5cv861vfYvnn3+eZ555hnA4fHO+yELcQU6cOMEv/uIvks/nefOb30wsFuO5555j//79FY//1Kc+hWEYvO9976O3t5cf/vCH7N+/n7/9278tvh/9/9m793Ar6zr//68NgQIqhgcUBUsbSSQ8MWgiKIiiJkgUGll5Gv16xFNjX7Vp0vyOMopHxmNqnpt0LEwFCsJTmAY4OpqAUXlMUskDKiBufn9w7T1uwQNK8XvX43FdXlf7Xvd9r89esddeez3X/flceumlOe+887LlllvmK1/5ShYtWpTx48fnqKOOygUXXJA99tgjydKove++++a5555L3759M3jw4DzyyCO56KKL8uijj+biiy9Oq1atMmnSpBxzzDFZd911M3jw4LRr1y4zZ87MPffckwceeCB33HFHunbt2jzG119/Pfvvv386dOiQL37xi5k7d24mTJiQAw88MD//+c9bzDIDrBp/+MMfMnLkyLz88svZbbfdstFGG2XKlCn56le/msbGxmywwQbN+y5ZsqT5dcjw4cPz2GOP5a677spRRx2VDh065E9/+lP23nvvPPvss5k0aVIOP/zw3HHHHS3eG5o4cWJ+97vfZc8990zv3r0zbty4nHbaafnDH/6QG2+8MYMGDcp2222X22+/PWPGjEmnTp3y5S9/+a/+uPytEbj4i1q0aFG+/e1vZ8stt2yu4vCXNn369Pz0pz/Nuuuum4EDB67q4VDI/PnzkyRrrbXWcm9fc801s2TJksyfPz+dOnX6aw6Nv3ELFy7MWWedlSTZb7/9VvFo+Ftw2WWXZc6cObnlllvSunXrVT0coJDnnnsuBx98cBYvXpwf/OAHLT5QNm/evOyxxx45//zz09DQkIULF2aXXXbJ3XffnZ122imXX355WrdunSVLlmTEiBH59a9/nblz56Zz5855/vnnc/rpp2fzzTfPddddl44dOyZJjjvuuHzta1/L6NGjM2DAgHTt2jVz587NNddckx122CFXX311c8hqbGzM/vvvnxkzZuQ3v/lNevbs2Ty22bNn5+STT27+IEljY2O+/vWvZ9q0aXnkkUfSq1evTJ06NbNmzcpRRx2VUaNGNR/btA7mpEmTMmzYsL/8gwx/Z84444wsWLAgV155ZT7/+c8nSUaNGpUDDjggL7zwwjL7d+jQITfffHPz32V33nlnjj/++Jx99tm59NJLkyRXX311unXrlh/96Ef5xCeWvr154IEHZvDgwbnpppuaA9fZZ5+d5557LqeffnqL19knnnhibr/99vzqV7/KjjvumHPOOSdrr712xo0b1+JvvXPPPTeXXXZZfv7znzcvhZAkL7/8crbffvuce+65zfd/3nnn5dJLL824ceNy6KGHrsyHEPgI/u3f/i3z5s3Lf/zHf2TQoEFJkuOPPz4HHnhgpk+f3mLfxsbGdOjQIddee23atm2bJUuWZNiwYXnsscey+eabZ9y4cc2zRY0aNSoTJ07Mo48+2uID0jNnzsyll16aAQMGJEn69OmTY445Jtdcc03OPvvsDB06NMnSgLb33nvnzjvvFLhWAlMUssL69++f7t27v+9/F110UZLk4osvzpNPPpkzzjjDmyt8aCvyb+zd5syZk6OPPjqNjY057bTT0q5du7/y6KmsaWq497o6q02bNkmWxntYWRYvXpwTTjghM2fOzKBBg7L77ruv6iFR3Jw5c3LppZfmwAMPTI8ePVb1cIBC5s2bl4MOOiivvvpqrrjiinzuc59bZp9vfOMbaWhoSLL0yuQtt9wySXLAAQc0/83X0NCQXr16JVkazJLktttuy6JFizJq1KjmuJUk7du3z5FHHpnFixfntttuS7L0tdjo0aNz8sknt7hKq1WrVvnHf/zH5rG+U/v27bP//vu32Ldv375Jlk5PlCz9dHay9GqSd05NdtBBB+Wee+7JPvvss2IPGPCB5s6dm+nTp6d///7NcStJ1l577Rx77LHLPeaII45o8aHDvfbaK1tttVXuueeevPbaa0mW/jzPmzcvv//975v369q1ayZOnJgrrrgiydK/237+85/nH/7hH5b5ENnRRx+dI444Ih07dkxjY2NOPPHEjB49epkPMjatY/ru55xk6XNHU9xKkn79+iVJnn766Q9+YIC/qHnz5uXee+/N9ttv3xy3kqWvMb75zW8u95ivfvWrze8HNTQ0ZOutt27e3hS3kmSrrbZK8r+vcZpssskmzXErSXP8Wm+99ZrjVrJ0tqn27dvn2Wef/RjfIU1cwcUK23PPPfPKK6+87z5bbLFFZs2ale9///s5+OCD33MaOVieD/tv7N1mzpyZQw45JPPmzcvxxx/f4hcYfBirrbZakqVTey1P03bhlJVl4cKFOf744zN58uRsueWWGT169KoeEsU1Njbm1FNPzQYbbJBjjjlmVQ8HKOab3/xmXnjhhXTr1q05XL3bJpts0uLr9u3bJ1k6lfM7Nb2uavpg0KOPPpok+eUvf5nHH3+8xb5Nr/1nzpyZJPnkJz+ZoUOHprGxMbNmzcqcOXPy1FNP5fHHH8/999+fJMusW7Hxxhs3fxipyZprrpnkf1/D7bjjjunatWumTJmSvn37pm/fvtl5552zyy67pHPnzu/72AAfTdPPe1P0fqf3mhp+eVN29+rVKw8//HBmz56d7bbbLvvtt18uv/zyDB06NFtttVX69euXAQMGtPhwz1NPPZU33nhjuff96U9/Oscdd1zz17vttluSpWvpzJ49O0899VRmz57dPI3i22+/vcw5PvWpT7X4+t3POcCq89hjj6WxsbE5Rr3TVltt1SJON/mor3GadOvWrcXXTe8dLW/JnrZt23quWEkELlbYySef/IH7vP3229lvv/2y4YYb5qijjvorjIq/JR/m39i73X///Tn66KMzf/78jBo1KocffvhfYGT8rVtjjTXSqlWr5k8FvlvTdmszsDK8+uqrOeKIIzJt2rT07NkzV155pX9bfGw33HBDHnrooVx11VViPLDCXn755fTv3z/33HNPLrnkkhZv/jZ5r+eWD1qftOl1VNNi68vz6quvNv/vCRMmZMyYMc1XX3Xo0CG9evXKP/zDP2TatGnNV2M1eXfcStJ8pVnTvu3atct//ud/5pJLLsmECRMyceLETJw4Ma1bt86ee+6Z0047ze9iWMmafvY7dOiwzG0dO3Zs/jl9p3XWWWeZbU3HN826ccIJJ6Rbt2754Q9/mP/+7//OQw89lAsvvDCf+cxn8r3vfS/bbrttczz/MD/XM2fOzBlnnJFf//rXSZY+p2y++ebp2bNnnnnmmeUe8+7nvXc/5wCrzp///Ocky38+ad269XKXnfior3GaNAWxj3o8H43AxV/EH//4x/zP//xPkiy3lD/22GPp3r17+vTpk+uuu+6vPTz+xvzsZz/LiSeemLfeemuZxalhRbRt2zZdunR5zz9gnnnmmWyyySamXOVje+GFF3LwwQdn9uzZ2X777XPxxRd7Q42V4mc/+1mStFgj4p2GDBmSJJk8efIyn0QEOOOMMzJ48OB84QtfyPe///0MGTIkm2222Uo5d9ObPlOmTEmXLl3ed9+HH344xx9/fDbccMOMGTMmW221VTbeeOM0NDRkzJgxmTZt2kcexzrrrJNvf/vbOfXUU/P444/nvvvuy3/913/l9ttvT4cOHXL66ad/5HMDy2qaanB5HyJ88803lxuDXnvttWVeG//pT39qcb6GhoaMGDEiI0aMyAsvvJCpU6dm4sSJmTx5co444ohMmTKlOYq9/vrryx3bG2+8kfbt22f+/Pk55JBDMn/+/HzrW9/KjjvumM022yxt2rTJvffemwkTJnz0BwBYJZqeQ5rWWn+393peoB6Bi7+ItdZaK0cfffRybxs7dmzWW2+97Lfffsu9RBNWxNSpU3PCCSeksbExo0ePNm8+H9t2222XcePG5emnn07Xrl2btz/11FOZO3euf2N8bE1/QM+ePTu77rprzj//fJ/oYqX54he/2LxWxDtNmjQpM2fOzMiRI7POOuu0WNcCoEmPHj3Srl27nHLKKTnqqKPyne98J9dff/1yr7BYUd27d8+kSZPy6KOPLhO4Zs2alZ/85Cfp27dvdtppp9x+++3Na+o2rWnTZM6cOUk+2hUS06ZNy8SJE/P1r3893bp1S48ePdKjR4+MHDkyn//85z9WOAOWr0ePHmloaMiMGTOWue2RRx5Z7jGPPfZYNtxww+avlyxZkocffrj5qqpXXnkl1157bbp27Zphw4ZlvfXWyz777JN99tknxx13XMaPH5/f/va36d69e9q0abPc+5kzZ0722muvHHzwwdluu+3y4osv5rDDDlvmQ0If5zkHWHW23HLLNDQ05OGHH17mtt/+9rcC198QgYu/iLXWWus9130YO3Zs1l9/fetC8LG9/PLL+eY3v5m33nor//7v/y48sFIMGzYs48aNy7nnnptzzz03DQ0NWbJkSc4777wkyb777ruKR0h1Z555ZmbNmpV+/frlwgsvXO7c3/BRDR8+fLnbn3322cycOTNf/epXs/nmm/+VRwVUM2jQoOyyyy656667csstt2TEiBEf+5xDhw7NpZdemnPPPTfbbbdd85RBixYtyve+9738+te/bl7MvWkh95deeqnFOSZNmpQpU6YkSRYvXrzCY3jppZdy7bXXprGxMf/yL//SvP1Pf/pT3nrrrRZvqAMrx3rrrZd+/frl3nvvzcSJEzN48OAkS6+euPDCC5d7zOWXX55+/fo1r3Nz4403Zs6cOdlnn32y+uqrp3Xr1rnuuuvSvn37DBw4sPmDO42NjXn++efTqlWrdO7cOauttlp222233Hnnnbn11ltbvE66/PLLkyR9+/Ztjlcvvvhii3H8/ve/zxVXXJHkoz3nAKtO586d07dv39x33325++67s/POOydZ+rrj7LPPXsWjY2XyjgpQ1vXXX5+XXnop66+/fp566qlcdNFFy+yzzTbbZKeddloFo6OqHXfcMXvttVfuvPPO/PGPf0zv3r0zbdq0PPTQQxk+fHh69+69qodIYU8//XRuvfXWJEnXrl1zySWXLLPP6quvnkMPPfSvPTQAaOHb3/527r///pxzzjnZddddP/b5PvWpT+Wf//mfc9ZZZ+ULX/hCBg4cmDXXXDNTpkzJk08+mcGDB2e33XZLkuy11165+uqr853vfCcPPPBA1llnnfzmN7/J1KlT06lTp7z00kt5+eWXV3gMAwYMyDbbbJPrr78+s2bNylZbbZXXXnst48ePT5s2bXLEEUd87O8TWNZ3vvOdfOUrX8mxxx6bQYMGZYMNNsjdd9/9nvu//PLLGTZsWAYMGJDf/e53mTJlSjbaaKOcdNJJSZaujzVq1Kh873vfyxe+8IXstttuWW211fKrX/0qv/nNbzJy5Mh07tw5SfJ//+//zfTp03PyySdnwoQJ2WyzzfLQQw/loYceytChQ7PTTjvljTfeyEYbbZRbb7018+bNy+abb55nn302kydPbp7msGk9H6COU089Nfvtt1+OOOKIDBo0KJ07d859993X/PPcqlWrVTxCVgaBCyiraQqRP/3pTxk7duxy9zn44IMFLlbY6NGjs9lmm+XHP/5xrrnmmnTp0iUnnnhiDjrooFU9NIqbMWNGGhsbkyz9JOryrL322gIXAKtc165dc9hhh+Wiiy7KmWeeuVLOedBBB+XTn/50rrrqqkyYMCFLlixJt27dcuqpp2bkyJHNbzRtscUWueyyy3LRRRdl4sSJadOmTTbeeOOcdNJJGThwYAYPHpz77rtvha+sb9u2bS677LJcccUVmTRpUq6//vqsttpq2W677XLkkUemV69eK+X7BFrq2rVr/vM//zPnn39+fvnLX2bBggXZfvvtc+qpp2bQoEHL7H/ZZZdlzJgxuemmm9K2bdsMGzYsJ554YtZdd93mfb72ta+lU6dOufbaa3PHHXdkwYIF+fSnP51/+Zd/yciRI5v369y5c26++eaMHTs2U6ZMydSpU7PBBhtk1KhROeyww5IsXSPwqquuytlnn50ZM2bkwQcfTJcuXTJixIgceeSR+dKXvpT7778/b7/9tvWYoZBNN900N910U8aMGZOpU6dm8eLF2WGHHXL++edn6NChadeu3aoeIitBwxKTyAIAAAAAAH8DGhsb8/TTT6dLly5p06ZNi9uefvrpDBo0KCNHjsx3v/vdVTNAVhrX4QEAAAAAAH8TGhoaMmzYsAwZMiSLFi1qcduVV16ZJNl+++1XxdBYyUxRCAAAAAAA/E1oaGjIV77ylVx11VUZOnRo+vfvn9atW2fGjBn57//+7+y0007ZY489VvUwWQlMUQgAAAAAAPzNaGxszH/913/l5ptvzu9///ssXrw4G2+8cYYMGZKDDjpomakLqUngAgAAAAAAoBRrcAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAC1cdNFF6d69+zL/bbnlltlhhx1y4IEHZtKkSe95/PPPP58LL7ww++yzT3r37p1evXplyJAhueCCC/Laa6994P1ff/316d69e15//fUVHvsFF1yQL3/5y1myZEnztt13332530/37t0zderUFsfPmzcv//qv/5pddtklW221VYYPH57x48d/6PtfvHhxLrvssgwePDif+9znsuuuu2bMmDHL/b4nT56c3XffPdtss02+8Y1vZM6cOcvsM2/evGy77bb5yU9+8uEfhL+ysWPHZsSIEWlsbFzVQwEAAADg70jDkne+CwjA372LLrooY8eOza677potttiiefvixYvzwgsv5M4778ybb76Z7373uxk5cmSLYydMmJBTTjklr7/+evr06ZPu3btnyZIlmTZtWmbOnJmNN944N954Yzp37rzc+542bVoOOeSQLFiwIDNmzEiHDh0+9Lh/+9vfZtiwYfnBD36Q3r17J0nefPPNbLvtttliiy0yYMCAZY4ZNmxYunbtmiSZP39+Ro4cmd/+9rfZa6+9sv7662fChAl57rnncsYZZ2TEiBHve/+NjY058sgjM2XKlGy00UYZMGBAXnrppfzsZz/LZpttlmuuuSadOnVKksydOzeDBg1Kt27d0q9fv0ycODFJMn78+Ky++urN5xw9enTuuuuu3H777WnduvWHfiz+mt54443svvvuOfTQQ3PAAQes6uEAAAAA8HfiE6t6AAD8/9OgQYMyfPjwZbaPGDEiI0eOzDnnnJNhw4alXbt2SZJf/epXOe6447LOOuvkBz/4QXr16tV8zJIlS3LFFVdkzJgxOeSQQzJu3Lhlgs0dd9yRU089NQsWLPhI4z3ttNOy/fbbN8etJHniiSfS2NiYPffcM4ceeuj7Hv+DH/wgs2fPbhGzDj/88IwYMSKjR4/OHnvskTXXXPM9j//JT36SKVOmZJtttsn3v//9rLHGGkmSu+++O4cddljOOeec/Nu//VuS5Kc//WkWL16cq666Kp07d86ee+6ZfffdN/fcc0923333JEsj2I033pgzzzzz/7dxK0nat2+ff/qnf8r555+fL3zhC1l33XVX9ZAAAAAA+DtgikIAVsg222yTbbfdNvPnz8/06dOTJG+//XZOPvnkLFmyJBdffHGLuJUkDQ0NOeywwzJgwIA88cQTmTBhQvNt8+bNy9FHH50TTjghnTp1yiabbLLCY3r44Yfz4IMPZv/992+xfdasWUmSzTff/APPcfPNN6dz58750pe+1LytY8eOOfTQQ/Paa6/lZz/72fsef8cddyRJTjnllOa4lSQ777xz+vbtm5/85CeZN29ekuSZZ55Jp06dmq9k++xnP5skefrpp5uPu+SSS9KtW7fsueeeHzj2Ve3LX/5yGhsbc8MNN6zqoQAAAADwd0LgAmCFrb/++kmSl19+OUly//3357nnnkvfvn2z1VZbvedxRx99dL7zne+0CGBPPPFEJk2alOHDh+fHP/7xe05f+H6uvvrqdOzYMf3792+x/cMGrueffz7PP/98evfunVatWv5q7NOnT5Kl0ye+n2eeeSZt2rTJlltuucxt3bt3z9tvv52HH344ydJw9uabbzavFda0RlfTFWLPPPNMbrnllowaNSoNDQ3ve7/v9Oijj6Z79+456aSTlrltyZIl2WWXXdK/f//m9bJeeumlnHXWWdljjz3Sq1evbL311hk6dGiuvvrqFuuY3XrrrenevXvuvPPOHHDAAenZs2cGDhyYuXPnJknWWGONDBgwIDfddNNHvgIPAAAAAFaEKQoBWGFPPfVUkjTHqPvuuy9JsuOOO77vcT179kzPnj1bbOvWrVvGjRuX7t27f6SxLFiwIJMnT86AAQPyiU+0/LU2a9astGvXLhMnTswtt9ySp556Kuutt16GDh2aI444Im3btk2S/P73v0+S5vW43qlLly5paGho3ue9tG3bNo2NjXn77beXmVKwKWA988wzSZJevXrl9ddfz/XXX5/hw4fnyiuvTENDQ7beeuskydixY7P55ptnt912W6HHomfPntl0000zefLkLFq0qPn7S5Lp06fnj3/8Yw4++OC0atUqr732Wvbdd9/MnTs3AwcOzG677ZYXX3wxEydOzFlnnZWFCxfm8MMPb3H+M844IxtssEG+/vWvZ+7cuS1iZN++fTN+/PhMnTo1AwcOXKFxAwAAAMCKcgUXACvkF7/4RR577LGst956zVdrPf/880mST33qUyt8vg033PAjx60keeihh7Jo0aLlXjk1e/bsvPnmm7n88svTu3fvjBgxIp/4xCdy8cUX57DDDsvixYuT/G+AWmuttZY5R5s2bdKuXbvMnz//fcfRs2fPvP3225k0aVKL7QsWLMgvf/nLJGk+x6677poBAwbkjDPOyLbbbpurrroqBx98cDbffPPMmTMnt912W4499tjmczRdcfVhDBkyJPPnz88999zTYvudd96ZJBk6dGiS5KabbsozzzyT008/PRdeeGFOPPHEnHnmmbnlllvS0NDQPOXiO6222mq58cYb861vfSvnnntui9s+97nPJUkeeOCBDz1WAAAAAPioXMEFwHJNmjQpzz77bPPXixYtyhNPPJF77703rVu3zr/+6782XyHUFIjat2//Vx/nY489liT5zGc+02L7/Pnz06VLl2y22Wa5+OKLs/baaydJFi5cmGOPPTZTpkzJD3/4w3zta1/LG2+8kSQtrnh6pzZt2mThwoXvO45vfOMbue222/Ld7343jY2N2XnnnfPCCy/k3//935uncnzntH+XXHJJfvGLX+TJJ59Mr1690rt37yTJhRdemM997nPZeeedM2fOnJx00kl57LHH0q1bt3z3u9/9wKvkhgwZkgsuuCDjx4/PoEGDkiwNZBMnTsxnPvOZbLHFFkmSnXbaKR07dmwOXk023XTTrLvuus3rhb1T//79s/rqqy/3fjfddNO0atWq+f8PAAAAAPhLErgAWK7Jkydn8uTJzV+3adMm66yzTgYNGpQDDjgg2267bfNtTfHolVde+WsPMy+99FKS5JOf/GSL7WussUZ+/OMfL7P/aqutllNPPTVTpkzJnXfema997WtZbbXVkiRvvfXWcu/jrbfeSrt27d53HFtssUVGjx6dU089NSeeeGLz9p49e+aEE07IGWec0eIcDQ0N2XXXXVuc4/HHH8/EiRNz1VVXJUlOOumkNDY25vLLL8+4ceNyzDHHZPLkyc2P9/J07do122yzTX7xi19k4cKFWW211fLAAw/kxRdfzNe//vXm/Xr06JEePXpk/vz5efzxx/OHP/whv/vd7/I///M/eemll9KxY8dlzr3xxhu/5/22bds2a6yxxnLDGAAAAACsbAIXAMt15plnZvjw4R9q36bw0bQ213t5++238/TTT3+kqQzfS9O0fx8UoN6pa9eu6dixY/OaWE0xp+lKtHd66623smDBgqy55pofeN699947ffr0yZQpU/LKK6+ke/fu6devX2666aYkyTrrrPO+x59//vnp3bt3dtxxx8ycOTOPPvpoLr300vTv3z9bb711xo8fn5/+9KctQtXyDBkyJA899FDuvvvu7L777rnjjjvS0NCQvffeu3mfhQsX5uyzz86PfvSj5qvTunTpkj59+mT27NktrjZr8kGPcbt27fLqq6++7z4AAAAAsDJYgwuAj61fv35J0rzW1Hv51a9+lcGDB+eoo45aaff9XnHqz3/+c6ZNm9Ycsd5pyZIlzVc3Jf+7dtjy9n3uuefS2NiYT3/60x9qPOuvv37222+/HHbYYdl5553TqlWrPProo0mWnUbxnR566KHcddddzWtv/eEPf0iSdOvWLcnS9cE++clPfmBETJI999wzbdq0yfjx47N48eL8/Oc/zzbbbNPiCqyzzjor1113XQYMGJBrrrkmDz74YKZMmZLRo0e/51SNH+S1115rfkwBAAAA4C9J4ALgY9tmm23yqU99Kg888ECmT5/+nvtdd911SfKB60itiHXXXTfJ0qD1Tvfff3/233//XHzxxcsc8+ijj2bBggXp2bNnkqVXLnXp0iXTp09f5sqlBx98MEmy9dZbv+84rrnmmvTp0ye/+c1vWmxftGhR7rrrrqy33nr57Gc/+57Hn3feeenbt2/+8R//McnSdbOSpVe9vfNcrVp98K/uTp06pW/fvrn33nvzy1/+Mi+//HKGDBnSYp+f/vSnWW+99XLBBRdkhx12aA6Ff/7zn5unfVwRCxcuzBtvvJENN9xwhY8FAAAAgBUlcAHwsbVu3TqnnHJKkuTYY4/NI4880uL2xYsX59xzz82UKVOy6aab5stf/vJKu+/u3bsnSZ544okW23faaad06NAht99+e2bNmtW8ff78+fl//+//JUn233//5u1Dhw7Ns88+2zydYJK8+uqr+f73v5+11lore+yxxweO45VXXsmNN97YvG3JkiU5/fTTM2/evBxyyCHvGafuv//+PPDAAxk1alTztqYrxpoeyyeffDKvvvpqNtlkk/cdxzu/n9deey3nnntu2rRps8z4V1999SxcuLDFlW+LFi3K6aefnsbGxvdcj+y9zJ49O0neN+IBAAAAwMpiDS4AVoqdd945p512Wk477bTsu+++2X777bPFFltk/vz5efDBB/Pkk09mo402yqWXXrpSp7Hbbrvt0qFDhzz00EMttq+11lr59re/nVNOOSX77bdf9tprr6y++uq566678uyzz+b//J//k969ezfvf+ihh2bChAk5/fTT88ADD6RLly6ZOHFinn322Zx11llZY401mvd94IEH8uCDD6ZPnz7ZfvvtkyQ77LBDBg4cmJtvvjl//OMf89nPfjYzZszIjBkz0r9//xYx7d3OO++87LLLLi2uEttiiy3So0ePnHXWWZk1a1buvffedOzYcZkrsd7LwIED0759+8ycOTMDBgxIp06dWtw+dOjQXHnllfnSl76UXXfdNW+99VbzY7P22mvn1VdfzaJFiz70dIVNj//nP//5D7U/AAAAAHwcruACYKX5yle+knHjxmXffffNiy++mB/96Ee57bbbsvrqq+eYY47Jbbfd9qGvQPqw2rZtm379+mXGjBl54403Wtw2fPjwXHXVVenVq1fGjx+fW2+9Neuss07OOeecnHDCCS32XWONNXLDDTfki1/8Yh544IH88Ic/TKdOnTJ27Nh88YtfbLHvgw8+mLFjxzZPX9jkvPPOy+GHH56nn346N9xwQ1599dX88z//c/7jP/7jPUPRL37xizz88MMtrt5qctFFF6VHjx656aab0qZNm1x88cVZc801P9Tj0q5du+y2225Jkr333nuZ24877rgcc8wxSZIbbrghkydPzmabbZZrr702+++/fxobGz9wTbV3mjp1ajp27Ni8HhsAAAAA/CU1LHn3YiMAUMz06dPz1a9+NWedddYyMYq/vBdffDE777xzDj300Bx33HGrejgAAAAA/B1wBRcA5W233Xbp06dPfvSjH63qofxduvXWW9OmTZt84xvfWNVDAQAAAODvhMAFwN+Eb33rW3nkkUdWaFo9Pr758+fn6quvzpFHHrnMOl8AAAAA8JcicAHwN6Fnz575p3/6p4wZMyZm3/3rufrqq7PhhhvmkEMOWdVDAQAAAODviDW4AAAAAAAAKMUVXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAA8P+1d8euXtV9AMc/Ny+RJklBtykbHDLcJChMGlyChlpbDNJJ0KGtlhqa/Ata6tbaEBhhoxCh1B/g3YrgIqJFEGKkDbfh4cYjFo8+3evvvuH1grN8z+d7fmd//845kCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAA7zocffjjHjh275/lffvll3n333Tly5MgcPnx4Tp06Nevr69s+B8BiLG1sbGws+iYAAAAAADZ98803c+rUqVlZWZkLFy78z/nbt2/PG2+8MT/++OO89dZbs3fv3lldXZ2lpaX54osv5vHHH9+WOQAWZ3nRNwAAAAAAsOmzzz6bDz74YP7444973nPu3Lm5fPnyrK6uzksvvTQzMy+//PK89tpr8+mnn87bb7+9LXMALI5XFAIAAAAAO8KJEyfmvffemxdeeGEOHTp0z/vOnz8/+/fv/ytGzcwcOHBgXnzxxTl//vy2zQGwOAIXAAAAALAjXLlyZd5///356KOP5tFHH73nfZcvX/7bIHbo0KFZX1+fX3/9dVvmAFgcrygEAAAAAHaEL7/8ch5++OH72nPz5s25cePGPPXUU3ede/LJJ2dm5urVq7O8vLylc/v27buv+wRga3mCCwAAAADYEe43bs38J3DNzDzyyCN3ndtc++2337Z8DoDFErgAAAAAgKyNjY2ZmVlaWvrHmYceemjL5wBYLK8oBAAAAAAemN9//31u3Lhxx9qePXvu65tb/21z361bt/72tzZntnoOgMXyVwMAAAAA4IH56quv5ujRo3ccq6ur//f19u7dO4899thcv379rnObaysrK1s+B8BieYILAAAAAHhgjh49Op988skda08//fS/uuZzzz03a2trd62vra3NM888M/v27duWOQAWxxNcAAAAAMADs7KyMkeOHLnj+LeB65VXXpkffvhhLl269Nfa999/P99+++28+uqr2zYHwOIsbWx+NREAAAAAYIc4fvz4XLlyZS5cuHDH+s8//zwXL16cZ599dg4ePDgzM7dv357XX399fvrppzl58uTs3r17Pv7441leXp7PP/98nnjiiW2ZA2BxBC4AAAAAYMf5p8D13XffzZtvvjmnT5+eM2fO/LV+7dq1OXv27Hz99deza9euef755+edd96Z/fv337F/q+cAWAyBCwAAAAAAgBTf4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACDlTzaRUfhVNuY+AAAAAElFTkSuQmCC", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Saved: cluster_visualisation.png\n" + ] + } + ], + "source": [ + "# ── PCA 2D Cluster Visualisation ─────────────────────────────────────────────\n", + "\n", + "pca2 = PCA(n_components=2, random_state=42)\n", + "X_2d = pca2.fit_transform(X)\n", + "var_explained = pca2.explained_variance_ratio_\n", + "\n", + "fig, axes = plt.subplots(1, 2, figsize=(16, 6))\n", + "\n", + "# ── Left: cluster scatter ─────────────────────────────────────────────────────\n", + "labels_for_plot = best_eval.labels\n", + "unique_labels = sorted(set(labels_for_plot))\n", + "colors = PALETTE[:len(unique_labels)]\n", + "\n", + "for lbl, col in zip(unique_labels, colors):\n", + " mask = labels_for_plot == lbl\n", + " label_name = f\"Cluster {lbl}\" if lbl != -1 else \"Noise\"\n", + " axes[0].scatter(X_2d[mask, 0], X_2d[mask, 1],\n", + " c=col, alpha=0.55, s=18, label=label_name, edgecolors=\"none\")\n", + "\n", + "axes[0].set_title(\n", + " f\"Clusters — {best_eval.algorithm.upper()} \"\n", + " f\"(silhouette={best_eval.silhouette:.3f})\"\n", + ")\n", + "axes[0].set_xlabel(f\"PC1 ({var_explained[0]*100:.1f}% var)\")\n", + "axes[0].set_ylabel(f\"PC2 ({var_explained[1]*100:.1f}% var)\")\n", + "axes[0].legend(framealpha=0.8)\n", + "\n", + "# ── Right: evaluation score comparison bar chart ──────────────────────────────\n", + "algos = list(best_eval.all_scores.keys())\n", + "sil_sc = [best_eval.all_scores[a][\"silhouette\"] for a in algos]\n", + "bar_colors = [PALETTE[2] if a == best_eval.algorithm else PALETTE[0] for a in algos]\n", + "\n", + "bars = axes[1].bar(algos, sil_sc, color=bar_colors, width=0.4, edgecolor=\"white\")\n", + "axes[1].axhline(SILHOUETTE_THRESHOLD, color=\"red\", linestyle=\"--\",\n", + " linewidth=1.5, label=f\"Threshold ({SILHOUETTE_THRESHOLD})\")\n", + "axes[1].set_ylim(0, max(sil_sc) * 1.3)\n", + "axes[1].set_title(\"Silhouette Score by Algorithm\")\n", + "axes[1].set_ylabel(\"Silhouette Score\")\n", + "axes[1].legend()\n", + "for bar, val in zip(bars, sil_sc):\n", + " axes[1].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.005,\n", + " f\"{val:.3f}\", ha=\"center\", va=\"bottom\", fontsize=10)\n", + "\n", + "plt.tight_layout()\n", + "fig.savefig(OUTPUT_DIR / \"cluster_visualisation.png\", dpi=150, bbox_inches=\"tight\")\n", + "plt.show()\n", + "print(\"✅ Saved: cluster_visualisation.png\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 10 — Explainability Layer\n", + "Permutation-based feature importance (SHAP-style), PCA loadings, and inertia movement analysis." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⏳ Building explainability report (may take ~30s)...\n", + " Computing permutation feature importances...\n", + " Computing PCA loadings...\n", + " Computing per-cluster profiles...\n", + "✅ Explainability complete in 1.9s\n", + " Top 8 driving features: ['days_since_last_purchase', 'age', 'avg_order_value', 'nps_score', 'annual_spend', 'purchase_frequency', 'lifetime_months', 'product_category']\n" + ] + } + ], + "source": [ + "# ── Explainability Layer ─────────────────────────────────────────────────────\n", + "# Computes: (1) permutation feature importance, (2) PCA component loadings,\n", + "# (3) per-cluster feature means for interpretability.\n", + "\n", + "@dataclass\n", + "class ExplainabilityReport:\n", + " top_features: list[str]\n", + " feature_importances: dict[str, float] # feature → importance score\n", + " pca_loadings: pd.DataFrame # component × feature\n", + " cluster_profiles: pd.DataFrame # cluster × feature mean (raw scale)\n", + " pca_variance_ratio: list[float]\n", + "\n", + "\n", + "def compute_permutation_importance(\n", + " X: np.ndarray,\n", + " labels: np.ndarray,\n", + " feature_names: list[str],\n", + " n_repeats: int = 10,\n", + ") -> dict[str, float]:\n", + " \"\"\"\n", + " Permutation importance: how much does silhouette drop when feature is shuffled?\n", + " Higher drop → feature is more important for cluster separation.\n", + " \"\"\"\n", + " rng = np.random.default_rng(0)\n", + " valid_mask = labels != -1\n", + " Xv, lv = X[valid_mask], labels[valid_mask]\n", + "\n", + " if len(set(lv)) < 2:\n", + " return {f: 0.0 for f in feature_names}\n", + "\n", + " baseline = silhouette_score(Xv, lv, sample_size=min(1000, len(Xv)))\n", + " importances: dict[str, float] = {}\n", + "\n", + " for i, fname in enumerate(feature_names):\n", + " drops = []\n", + " for _ in range(n_repeats):\n", + " Xp = Xv.copy()\n", + " rng.shuffle(Xp[:, i])\n", + " s = silhouette_score(Xp, lv, sample_size=min(1000, len(Xv)))\n", + " drops.append(baseline - s)\n", + " importances[fname] = round(float(np.mean(drops)), 5)\n", + "\n", + " return dict(sorted(importances.items(), key=lambda x: -x[1]))\n", + "\n", + "\n", + "def build_explainability_report(\n", + " X: np.ndarray,\n", + " labels: np.ndarray,\n", + " feature_names: list[str],\n", + " raw_df: pd.DataFrame,\n", + " n_top: int,\n", + ") -> ExplainabilityReport:\n", + " print(\" Computing permutation feature importances...\")\n", + " importances = compute_permutation_importance(X, labels, feature_names)\n", + " top_features = list(importances.keys())[:n_top]\n", + "\n", + " print(\" Computing PCA loadings...\")\n", + " n_components = min(5, len(feature_names))\n", + " pca_full = PCA(n_components=n_components, random_state=42)\n", + " pca_full.fit(X)\n", + " loadings_df = pd.DataFrame(\n", + " np.abs(pca_full.components_),\n", + " columns=feature_names,\n", + " index=[f\"PC{i+1}\" for i in range(n_components)],\n", + " )\n", + "\n", + " print(\" Computing per-cluster profiles...\")\n", + " profiled = raw_df.copy()\n", + " profiled[\"_cluster\"] = labels\n", + " num_cols = [c for c in schema.numeric_cols if c in profiled.columns]\n", + " cluster_profiles = profiled.groupby(\"_cluster\")[num_cols].mean().round(2)\n", + "\n", + " return ExplainabilityReport(\n", + " top_features = top_features,\n", + " feature_importances = importances,\n", + " pca_loadings = loadings_df,\n", + " cluster_profiles = cluster_profiles,\n", + " pca_variance_ratio = pca_full.explained_variance_ratio_.tolist(),\n", + " )\n", + "\n", + "\n", + "print(\"⏳ Building explainability report (may take ~30s)...\")\n", + "t0 = time.time()\n", + "explain_report = build_explainability_report(\n", + " X, best_eval.labels, fe.feature_names, raw_df, N_TOP_FEATURES\n", + ")\n", + "print(f\"✅ Explainability complete in {time.time()-t0:.1f}s\")\n", + "print(f\" Top {N_TOP_FEATURES} driving features: {explain_report.top_features}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 11 — Explainability Plots" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "ename": "KeyError", + "evalue": "\"['product_category'] not in index\"", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[11], line 19\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[38;5;66;03m# ── Right: cluster profile heatmap ───────────────────────────────────────────\u001b[39;00m\n\u001b[0;32m 17\u001b[0m profile_z \u001b[38;5;241m=\u001b[39m (explain_report\u001b[38;5;241m.\u001b[39mcluster_profiles \u001b[38;5;241m-\u001b[39m explain_report\u001b[38;5;241m.\u001b[39mcluster_profiles\u001b[38;5;241m.\u001b[39mmean()) \\\n\u001b[0;32m 18\u001b[0m \u001b[38;5;241m/\u001b[39m explain_report\u001b[38;5;241m.\u001b[39mcluster_profiles\u001b[38;5;241m.\u001b[39mstd()\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m---> 19\u001b[0m profile_z \u001b[38;5;241m=\u001b[39m profile_z[explain_report\u001b[38;5;241m.\u001b[39mtop_features[:\u001b[38;5;241m8\u001b[39m]] \u001b[38;5;66;03m# keep top features\u001b[39;00m\n\u001b[0;32m 21\u001b[0m sns\u001b[38;5;241m.\u001b[39mheatmap(\n\u001b[0;32m 22\u001b[0m profile_z\u001b[38;5;241m.\u001b[39mT, ax\u001b[38;5;241m=\u001b[39maxes[\u001b[38;5;241m1\u001b[39m],\n\u001b[0;32m 23\u001b[0m cmap\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRdBu_r\u001b[39m\u001b[38;5;124m\"\u001b[39m, center\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, annot\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, fmt\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.2f\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 24\u001b[0m linewidths\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.5\u001b[39m, cbar_kws\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlabel\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mZ-score vs. mean\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[0;32m 25\u001b[0m )\n\u001b[0;32m 26\u001b[0m axes[\u001b[38;5;241m1\u001b[39m]\u001b[38;5;241m.\u001b[39mset_title(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCluster Profiles — Top Driving Features\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m(Z-scored mean values)\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "File \u001b[1;32mc:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\pandas\\core\\frame.py:4108\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 4106\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_iterator(key):\n\u001b[0;32m 4107\u001b[0m key \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(key)\n\u001b[1;32m-> 4108\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39m_get_indexer_strict(key, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcolumns\u001b[39m\u001b[38;5;124m\"\u001b[39m)[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m 4110\u001b[0m \u001b[38;5;66;03m# take() does not accept boolean indexers\u001b[39;00m\n\u001b[0;32m 4111\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(indexer, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdtype\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mbool\u001b[39m:\n", + "File \u001b[1;32mc:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:6200\u001b[0m, in \u001b[0;36mIndex._get_indexer_strict\u001b[1;34m(self, key, axis_name)\u001b[0m\n\u001b[0;32m 6197\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 6198\u001b[0m keyarr, indexer, new_indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reindex_non_unique(keyarr)\n\u001b[1;32m-> 6200\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_raise_if_missing(keyarr, indexer, axis_name)\n\u001b[0;32m 6202\u001b[0m keyarr \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtake(indexer)\n\u001b[0;32m 6203\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(key, Index):\n\u001b[0;32m 6204\u001b[0m \u001b[38;5;66;03m# GH 42790 - Preserve name from an Index\u001b[39;00m\n", + "File \u001b[1;32mc:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:6252\u001b[0m, in \u001b[0;36mIndex._raise_if_missing\u001b[1;34m(self, key, indexer, axis_name)\u001b[0m\n\u001b[0;32m 6249\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNone of [\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkey\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m] are in the [\u001b[39m\u001b[38;5;132;01m{\u001b[39;00maxis_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m]\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 6251\u001b[0m not_found \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(ensure_index(key)[missing_mask\u001b[38;5;241m.\u001b[39mnonzero()[\u001b[38;5;241m0\u001b[39m]]\u001b[38;5;241m.\u001b[39munique())\n\u001b[1;32m-> 6252\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mnot_found\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not in index\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;31mKeyError\u001b[0m: \"['product_category'] not in index\"" + ] + }, + { + "data": { + "image/png": "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Dz8oLi5OX375ZY6X8G7fvr1Wr16tV155RW3atFGJEiVM7xx/5JFHdPnyZcXFxZmu4dtvv9W0adO0c+dOubi46O+//9YPP/wgJycnBQcHS5Jq1Kih119/XVOmTFGbNm3UrFkzOTk5afPmzfrrr7/k7++vFi1a5KjO+zVu3Di99NJLCgkJUePGjfX444/r999/17Zt2/TII49ozJgxpr6vvfaadu7cqenTp2vnzp16/PHH9dNPP2X5soGUEWb/97//1RdffKHTp0+rcuXK2rZtm5KTk/Xoo4+a9e3fv7+2b9+ur776Srt375a3t7fi4uK0du1apaamavz48dl6Z/o/BQYGat26dVq6dKmOHj2qevXq6ezZs1q/fr1q1aqlAQMGZKl52rRpio2N1euvv57j8wEAAAAAAAAAAAC4M2ao30V4eLjKlSunb7/9VmfOnFG/fv00f/58FS1aVJL01FNPafbs2apdu7ZWr16tlStXqkmTJvryyy9N7+POji5duujLL7+Ui4uL1qxZo6VLl6pWrVqaN2+e/vOf/+S47iZNmmjGjBmqUqWKVqxYoRUrVkiSJk6cqA8//FCSTMuzlypVSuHh4XrhhRd06tQphYWFadu2bWrevLmWLFlimoUvScHBwfr888/l4uKitWvXavHixSpevLjeeustffjhh/n27u5atWpp6dKl6tKli44cOaL58+fr999/V+fOnbVkyRJVr17d1NfJyUkLFixQt27ddOTIES1evFg1atRQaGholuM++uijmj9/vnx8fLRlyxZ99913ql27thYsWGD27nIpYxWAsLAwDR48WImJiVq4cKG2b98uX19fhYeH3/eXC+zs7DRnzhwNGTJEiYmJWrBggaKjoxUQEKCIiAiVLFkyS83e3t6ytbVVu3bt7uucAAAAAAAAAAAAACyzMd6+XjUkSUFBQYqKitKePXuyBJgoGGJiYtS8eXP5+/vrk08+sXY59y01NVWNGjVS7dq1NXfu3Fw9dlJSkuld9V8fXaoLRa7m6vEBAMCD+7z9FJUtXtraZeAO9u/fL0lyd3e3ciXIbYV5bG//nODq6mr6wjmQF3jekJ8K8+925D+eN+QnnjfkJ5435AdrfE5ghjrwL7Zo0SJdvnxZXbt2tXYpAAAAAAAAAAAAQIHDO9SRqzZs2KAjR45ku//gwYPzsJqCa8iQITpx4oRO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Gj9+vPbs2aOSJUtm2b5lyxbNnTtXBw8eVFpammrWrKlu3brpxRdfzNc6AQAAAACFl4ODg0JCQhQSEnLHPr6+vjp27JhZ2/r16/O6NAAAAAB4aPAO9UKqR48emj179n3vf/ToUbVv31779u0zaw8JCdELL7zwgNXljjvVmNeio6P1wQcf3HH7N998owEDBuj48eNq06aNunbtqvj4eL377rsaP358PlYKAAAAAAAAAAAA4G6YoV5IXb58+YH2v3btmlJSUrK0Dx48+IGOm5vuVGNeWr16td566y3dunXL4vb4+HhNmzZNjz76qCIjI1WhQgVJ0rBhw9S9e3dFRESoc+fOevrpp/OzbAAAAAAAAAAAAAAWMEMdyAVXrlxRSEiIhg8frnLlyql69eoW+23fvl03btzQSy+9ZArTJcnR0VEvv/yyqQ8AAAAAAAAAAAAA6yNQ/38pKSn6+OOP1a5dO7m7u8vX11f9+/dXdHS0qU+zZs3k6+ubZd/NmzfLYDBo5syZZn27deumI0eO6KWXXpK7u7saN26syZMnKyEhwWz/nPSVpJMnT2r48OFq0KCBXF1d5e/vr48//lg3b97MctygoCAtXrxY9evXl4eHh15//XUZDAbFxsYqLi5OBoNBo0ePztG9mjlzpnr27ClJmjdvngwGg3bt2iUp4x3qAQEBZv1v3Lihjz76SP7+/nJ3d5efn58mTZqkuLi4u57nwIED8vDwUIMGDXTy5ElTe0JCgqZNm6bmzZvL1dVVjRs31oQJE3T16tVs1Xjq1CkNGTJETZo0kaurq5o3b64JEyboypUrOboPtztx4oQ2bNiggIAARUZGqmLFihb71apVS8OGDVOTJk2ybCtWrJikjPslSTExMTIYDJo1a5bWrVunjh07ys3NTc2bN9fChQslSTt27FBgYKDpvs6ZM0fp6en3fR0AAAAAAAAAAAAA/ocl3//fuHHjtHjxYvn4+KhRo0aKj4/X6tWr9fPPP2vBggWqW7dujo958eJF9ezZU9WqVVP37t21d+9eff311/r111+1cOFCOTg45Ljv3r17FRwcrOTkZDVr1kyVK1dWdHS0Zs2apW3btikiIkLFixc3HffEiROaOHGiOnTooFu3bqlhw4aqVq2awsLClJKSor59+6p27do5ui4fHx916tRJkZGR8vDw0H/+8x85Oztb7Hvz5k1169ZNR48elYeHh5o2bao//vhDYWFh+vXXX7VgwQJTkHy7kydPql+/frK3t9dXX32lxx9/XJJ0/fp1de/eXcePH9ezzz6rli1b6s8//1RERIR++uknffvttypbtuwda7x8+bJ69+6ta9euqWXLlipfvrwOHz6s8PBw7d69W8uWLZOdnV2O7ockVatWTStWrJDBYLhrv6eeekpPPfWUxW2bNm2SJD355JNm7evWrdMff/yhVq1aydvbWytWrND777+vP//8UwsXLpSfn5+8vLy0atUqffjhhypXrpy6dOmS42sAAAAAAAAAAAAAYI5AXRkh7Xfffad69eopPDzc1N6uXTvTDO/7CdRjYmLUokULffLJJ7K1tZXRaNRbb72lpUuXatGiRQoKCspR37S0NI0aNUqpqamaO3euGjRoIElKT0/XuHHj9M033yg0NFSvv/666bhXr17VO++8o5deesmstsjISCUmJt7XO88zZ+lnhtV3O8acOXN09OhRDRw4UMOGDTO1f/TRR5o9e7ZWrlyprl27mu1z9uxZvfzyy0pNTdXXX39tFkDPmDFDx48f18SJE81C49WrV2v48OH64IMPNGnSpDvWGB4ervPnz2vSpEnq3Lmzaf8xY8Zo2bJl2rt3r7y9vXN8Tx577DE99thjOd4v06+//qqVK1fq0UcfVbNmzcy2HT16VLNnz1bTpk0lZXyhYfDgwQoLC9MHH3yg9u3bS5ICAgLUtm1brVmzhkAdyGUpKSk6fPiwtcvIltTUVEnS/v37rVwJchtjW3AxtgUXY1twFeaxNRqN1i4BAAAAAIB8xZLv/89oNOrs2bM6d+6cqc3Hx0fr16/XuHHj7uuYtra2euONN2Rrm3GbbWxsNHz4cNnb22vVqlU57rtnzx799ddf6tChgylMz9x35MiRKl26tJYuXZrlLzj8/f3vq/7csHr1apUuXVohISFm7b1791a/fv1UrVo1s/YrV64oODhY8fHx+uKLL1SnTh3TttTUVC1fvly1a9fOEhi3adNGTz31lFavXq3k5OQ71pN5b/bv36+0tDRT++jRo/XLL7/cV5j+oE6ePKmQkBClp6fr/fffN1thQJKqV69uCtMlydPTU5JUvnx5U5guZcxsL1GihGJjY/OncAAAAAAAAAAAAKCAY4a6JCcnJ7Vu3VqrV69WixYt5OXlpUaNGqlp06aq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JNWsWVNffPGFjEajGjRooDZt2mj58uX2VgV4LBXktRGePPb2N8ZOyCl7+1o6rveRE/b2N65RYQt7+1vZsmVlNBr1888/a9asWbp69aouXryosWPH6uLFi+rdu3c+lh6PowkTJmj16tVq3LixTfnye5zAbR9AIXTr1i1Jf979lZmbm5tMJpNu3bqlcuXKZZvfzc0ty770i/mbN2/anBb2c2TbSlLt2rXtLjNyxtFta826deu0b98+GQwG+fj42FR+ZK+g2vb8+fPy9/c3v/7ggw8UGBhoewWQLUe37dWrVzVlyhQFBwcrMDBQCQkJdtcB2XNk+/7yyy9KSUnRwYMHdevWLRmNRl27dk2xsbEaPny4zp07p0GDBuVJveDYtv39998lSR999JF56bkXX3xRmzdv1pgxY/T7779bLJsIPAn+Cte9eHLY29+yw9gJmeVFX+N6Hzllb3/jGhW2yIvvt48//lju7u6KiIhQRESEefvQoUP1zjvv5H2h8Vh76aWXcpUvv8cJBNSBQuju3buSZPH83IycnZ0lKdu7xtKXK7OWPz3vH3/8YXNa2M+RbQvHKui2jY+P1+jRo+Xs7KzJkyfLyckp54XHQxVU26akpKhr1666f/++YmNjFR4erps3b2rgwIG2VwJWObptw8PDlZKSojFjxuS+0MgxR7bv9evXVatWLTVp0kTjx49X0aJFJUlJSUnq0qWLPv30UwUHB8tgMNhRI6RzZNumn2vv3r1atmyZ6tatK0kaOHCgOnbsqLlz56pt27aqXr16bqsDPHYK+roXTxZ7+5s1jJ1gTV70Na73kVP29jeuUWGLvPh+W7FihaKiolS1alW1bNlSd+/e1ZYtWzR//nzVqFFDrVq1yvuC44mT3+MElnwHCqHixYtLSgumWJO+vWTJkjbnz5zXlrSwnyPbFo5VkG27a9cu9e/fX3/88YemTJkib29v2wqPhyqotq1Ro4bGjRuniRMnat26dapdu7Zmz56tw4cP214JWOXIto2Li9OaNWv03nvvqXLlyvYVHDniyPZt2rSpoqOjNWnSJHMwXZIqV66sgQMHymQyKTo6Opc1QWaObNsiRdKG3J07dzb/UClJFStWVL9+/XT//n1t3LgxN9UAHluMaeBI9va3zBg7ITv29jWu92ELe/sb16iwhb39bd++fZo4caLq1aunqKgoffjhhwoP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", + "text/plain": [ + "
    " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Explainability Plots ─────────────────────────────────────────────────────\n", + "\n", + "fig, axes = plt.subplots(1, 2, figsize=(17, 6))\n", + "\n", + "# ── Left: feature importance bar ─────────────────────────────────────────────\n", + "top_n = 10\n", + "names = list(explain_report.feature_importances.keys())[:top_n]\n", + "scores = list(explain_report.feature_importances.values())[:top_n]\n", + "bar_c = [PALETTE[2] if n in explain_report.top_features else PALETTE[0] for n in names]\n", + "\n", + "axes[0].barh(names[::-1], scores[::-1], color=bar_c[::-1], edgecolor=\"white\")\n", + "axes[0].set_title(\"Feature Importance\\n(Silhouette drop on permutation)\")\n", + "axes[0].set_xlabel(\"Mean silhouette drop\")\n", + "axes[0].axvline(0, color=\"gray\", linewidth=0.8)\n", + "\n", + "# ── Right: cluster profile heatmap ───────────────────────────────────────────\n", + "profile_z = (explain_report.cluster_profiles - explain_report.cluster_profiles.mean()) \\\n", + " / explain_report.cluster_profiles.std().replace(0, 1)\n", + "profile_z = profile_z[explain_report.top_features[:8]] # keep top features\n", + "\n", + "sns.heatmap(\n", + " profile_z.T, ax=axes[1],\n", + " cmap=\"RdBu_r\", center=0, annot=True, fmt=\".2f\",\n", + " linewidths=0.5, cbar_kws={\"label\": \"Z-score vs. mean\"},\n", + ")\n", + "axes[1].set_title(\"Cluster Profiles — Top Driving Features\\n(Z-scored mean values)\")\n", + "axes[1].set_xlabel(\"Cluster ID\")\n", + "axes[1].set_ylabel(\"\")\n", + "\n", + "plt.tight_layout()\n", + "fig.savefig(OUTPUT_DIR / \"explainability.png\", dpi=150, bbox_inches=\"tight\")\n", + "plt.show()\n", + "print(\"✅ Saved: explainability.png\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 12 — Local LLM Client (Ollama)\n", + "Thin client wrapping the Ollama `/api/generate` endpoint. Handles streaming, retries, and JSON extraction." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "❌ Ollama not reachable at http://localhost:11434: HTTPConnectionPool(host='localhost', port=11434): Max retries exceeded with url: /api/tags (Caused by NewConnectionError(': Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it'))\n", + "\n", + "⚠️ Ollama is not running. Start it with: ollama serve\n", + " Then pull the model with: ollama pull llama3\n", + "\n", + " Persona identification will use FALLBACK mode (rule-based).\n" + ] + } + ], + "source": [ + "# ── Ollama Local LLM Client ──────────────────────────────────────────────────\n", + "\n", + "class OllamaClient:\n", + " \"\"\"\n", + " Thin, production-grade client for Ollama's local LLM API.\n", + " Supports streaming, retries, timeout, and structured JSON extraction.\n", + " \"\"\"\n", + "\n", + " def __init__(self, host: str, model: str, timeout: int = 120):\n", + " self.host = host.rstrip(\"/\")\n", + " self.model = model\n", + " self.timeout = timeout\n", + " self._endpoint = f\"{self.host}/api/generate\"\n", + "\n", + " def health_check(self) -> bool:\n", + " try:\n", + " r = requests.get(f\"{self.host}/api/tags\", timeout=5)\n", + " models = [m[\"name\"] for m in r.json().get(\"models\", [])]\n", + " available = any(self.model in m for m in models)\n", + " if not available:\n", + " print(f\"⚠️ Model '{self.model}' not found. Available: {models}\")\n", + " return True\n", + " except Exception as e:\n", + " print(f\"❌ Ollama not reachable at {self.host}: {e}\")\n", + " return False\n", + "\n", + " def generate(\n", + " self,\n", + " prompt: str,\n", + " system: str | None = None,\n", + " temperature: float = 0.3,\n", + " max_retries: int = 2,\n", + " ) -> str:\n", + " \"\"\"\n", + " Generate a response. Returns the full text.\n", + " Retries on transient errors.\n", + " \"\"\"\n", + " payload: dict = {\n", + " \"model\": self.model,\n", + " \"prompt\": prompt,\n", + " \"stream\": False,\n", + " \"options\": {\n", + " \"temperature\": temperature,\n", + " \"num_predict\": 1024,\n", + " },\n", + " }\n", + " if system:\n", + " payload[\"system\"] = system\n", + "\n", + " last_error = None\n", + " for attempt in range(1, max_retries + 2):\n", + " try:\n", + " r = requests.post(\n", + " self._endpoint,\n", + " json=payload,\n", + " timeout=self.timeout,\n", + " )\n", + " r.raise_for_status()\n", + " return r.json().get(\"response\", \"\").strip()\n", + " except requests.Timeout:\n", + " last_error = f\"Timeout after {self.timeout}s\"\n", + " except requests.RequestException as e:\n", + " last_error = str(e)\n", + " if attempt <= max_retries:\n", + " wait = 2 ** attempt\n", + " log.warning(\"Ollama attempt %d failed (%s). Retrying in %ds...\", attempt, last_error, wait)\n", + " time.sleep(wait)\n", + "\n", + " raise RuntimeError(f\"Ollama failed after {max_retries+1} attempts: {last_error}\")\n", + "\n", + " def extract_json(self, text: str) -> dict | list:\n", + " \"\"\"Extract the first JSON object/array from LLM output.\"\"\"\n", + " match = re.search(r\"(\\{.*\\}|\\[.*\\])\", text, re.DOTALL)\n", + " if not match:\n", + " raise ValueError(f\"No JSON found in LLM response:\\n{text[:400]}\")\n", + " return json.loads(match.group(1))\n", + "\n", + "\n", + "# ── Initialise and health-check ───────────────────────────────────────────────\n", + "ollama = OllamaClient(OLLAMA_HOST, OLLAMA_MODEL, OLLAMA_TIMEOUT)\n", + "is_up = ollama.health_check()\n", + "\n", + "if is_up:\n", + " print(f\"✅ Ollama is reachable at {OLLAMA_HOST}\")\n", + " print(f\" Model: {OLLAMA_MODEL}\")\n", + "else:\n", + " print(f\"\\n⚠️ Ollama is not running. Start it with: ollama serve\")\n", + " print(f\" Then pull the model with: ollama pull {OLLAMA_MODEL}\")\n", + " print(f\"\\n Persona identification will use FALLBACK mode (rule-based).\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 13 — 🤖 Persona Identification Layer (Local LLM)\n", + "For each cluster, builds a rich statistical profile and asks llama3 to generate a named persona with description, traits, and business recommendations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# ── Persona Identification Layer ─────────────────────────────────────────────\n", + "\n", + "@dataclass\n", + "class PersonaResult:\n", + " cluster_id: int | str\n", + " persona_name: str # e.g. \"Cluster A\"\n", + " archetype: str # e.g. \"The Loyal Champion\"\n", + " description: str\n", + " key_traits: list[str]\n", + " business_recommendations: list[str]\n", + " cluster_size: int\n", + " cluster_pct: float\n", + " top_features: dict[str, float] # feature → mean value\n", + "\n", + "\n", + "PERSONA_SYSTEM_PROMPT = \"\"\"You are a senior customer analytics expert and strategic advisor.\n", + "You analyse customer cluster profiles and generate precise, actionable personas.\n", + "Always respond with ONLY valid JSON — no preamble, no explanation, no markdown fences.\n", + "The JSON must contain exactly these keys:\n", + " archetype: string (2-5 word evocative label, e.g. 'The Loyal Champion')\n", + " description: string (2-3 sentences describing who this customer is)\n", + " key_traits: list of 4 strings (concise behavioural characteristics)\n", + " business_recommendations: list of 3 strings (specific, actionable strategies)\n", + "\"\"\"\n", + "\n", + "def build_cluster_profile_text(\n", + " cluster_id: int,\n", + " profile_row: pd.Series,\n", + " cluster_pct: float,\n", + " top_features: dict[str, float],\n", + " top_feature_names: list[str],\n", + ") -> str:\n", + " \"\"\"Build a rich textual summary of a cluster's statistical profile.\"\"\"\n", + " lines = [\n", + " f\"CLUSTER {cluster_id} PROFILE\",\n", + " f\" Size: {int(cluster_pct*100)}% of total customers\",\n", + " \"\",\n", + " \" Key metrics (mean values):\",\n", + " ]\n", + " for feat in top_feature_names[:8]:\n", + " if feat in profile_row.index:\n", + " lines.append(f\" - {feat}: {profile_row[feat]:.2f}\")\n", + " lines += [\"\", \" Feature importances (contribution to separation):\"]\n", + " for feat, imp in list(top_features.items())[:5]:\n", + " lines.append(f\" - {feat}: {imp:.4f}\")\n", + " return \"\\n\".join(lines)\n", + "\n", + "\n", + "def identify_personas_with_llm(\n", + " client: OllamaClient,\n", + " best_eval: EvaluationResult,\n", + " explain_report: ExplainabilityReport,\n", + " raw_df: pd.DataFrame,\n", + " business_objective: str,\n", + " fallback: bool = False,\n", + ") -> list[PersonaResult]:\n", + " \"\"\"\n", + " For each cluster: build profile → call local LLM → parse persona JSON.\n", + " Falls back to rule-based persona labels if Ollama is unavailable.\n", + " \"\"\"\n", + " personas: list[PersonaResult] = []\n", + " labels = best_eval.labels\n", + " total = (labels != -1).sum()\n", + "\n", + " cluster_ids = sorted(c for c in set(labels) if c != -1)\n", + "\n", + " for cid in cluster_ids:\n", + " mask = labels == cid\n", + " size = mask.sum()\n", + " pct = size / total\n", + " name_map = {0: \"A\", 1: \"B\", 2: \"C\", 3: \"D\", 4: \"E\"}\n", + " letter = name_map.get(cid, str(cid))\n", + "\n", + " # Numeric profile\n", + " num_cols = [c for c in schema.numeric_cols if c in raw_df.columns]\n", + " profile_row = raw_df[mask][num_cols].mean()\n", + " top_features_dict = {\n", + " k: v for k, v in explain_report.feature_importances.items()\n", + " if v > 0\n", + " }\n", + "\n", + " profile_text = build_cluster_profile_text(\n", + " cluster_id = letter,\n", + " profile_row = profile_row,\n", + " cluster_pct = pct,\n", + " top_features = top_features_dict,\n", + " top_feature_names = explain_report.top_features,\n", + " )\n", + "\n", + " if fallback:\n", + " # Rule-based fallback when Ollama is unavailable\n", + " archetype = f\"Cluster {letter} Persona\"\n", + " description = f\"Cluster {letter} contains {size:,} customers ({pct*100:.1f}% of total). Statistical profiling complete; LLM descriptions require Ollama.\"\n", + " key_traits = [f\"Cluster size: {size:,}\", f\"Share: {pct*100:.1f}%\",\n", + " \"LLM offline — run ollama serve\", \"Retrigger Cell 13\"]\n", + " recs = [\"Start Ollama: ollama serve\", f\"Pull model: ollama pull {OLLAMA_MODEL}\", \"Re-run this cell\"]\n", + " else:\n", + " prompt = (\n", + " f\"Business objective: {business_objective}\\n\\n\"\n", + " f\"{profile_text}\\n\\n\"\n", + " f\"Generate a precise customer persona for Cluster {letter}. \"\n", + " f\"The persona must be grounded in the metrics above and serve the stated business objective. \"\n", + " f\"Respond ONLY with valid JSON.\"\n", + " )\n", + " print(f\" 🤖 Calling {OLLAMA_MODEL} for Cluster {letter} ({size:,} customers)...\")\n", + " t0 = time.time()\n", + " raw_response = client.generate(prompt, system=PERSONA_SYSTEM_PROMPT, temperature=0.3)\n", + " elapsed_llm = time.time() - t0\n", + " print(f\" Response in {elapsed_llm:.1f}s\")\n", + "\n", + " try:\n", + " parsed = client.extract_json(raw_response)\n", + " archetype = parsed.get(\"archetype\", f\"Cluster {letter} Persona\")\n", + " description = parsed.get(\"description\", \"\")\n", + " key_traits = parsed.get(\"key_traits\", [])\n", + " recs = parsed.get(\"business_recommendations\", [])\n", + " except (ValueError, json.JSONDecodeError) as e:\n", + " log.warning(\" JSON parse failed for cluster %s: %s\", letter, e)\n", + " archetype = f\"Cluster {letter}\"\n", + " description = raw_response[:300]\n", + " key_traits = []\n", + " recs = []\n", + "\n", + " personas.append(PersonaResult(\n", + " cluster_id = cid,\n", + " persona_name = f\"Cluster {letter}\",\n", + " archetype = archetype,\n", + " description = description,\n", + " key_traits = key_traits,\n", + " business_recommendations = recs,\n", + " cluster_size = int(size),\n", + " cluster_pct = round(float(pct), 4),\n", + " top_features = {k: round(float(profile_row.get(k, 0)), 2)\n", + " for k in explain_report.top_features[:5]\n", + " if k in profile_row.index},\n", + " ))\n", + "\n", + " return personas\n", + "\n", + "\n", + "# ── Execute Persona Identification ────────────────────────────────────────────\n", + "use_fallback = not is_up\n", + "\n", + "print(\"\\n\" + \"═\"*60)\n", + "print(\" PERSONA IDENTIFICATION LAYER\")\n", + "print(\" Using local LLM:\" if not use_fallback else \" ⚠️ Using rule-based FALLBACK (Ollama offline)\")\n", + "print(\"═\"*60)\n", + "\n", + "personas = identify_personas_with_llm(\n", + " client = ollama,\n", + " best_eval = best_eval,\n", + " explain_report = explain_report,\n", + " raw_df = raw_df,\n", + " business_objective = BUSINESS_OBJECTIVE,\n", + " fallback = use_fallback,\n", + ")\n", + "\n", + "print(f\"\\n✅ {len(personas)} personas identified.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 14 — Ground in Business Objective\n", + "LLM synthesises a strategic summary mapping all personas to the business objective, then assigns each to Cluster A / B / C buckets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# ── Business Objective Grounding ─────────────────────────────────────────────\n", + "\n", + "GROUNDING_SYSTEM = \"\"\"You are a Chief Strategy Officer synthesising customer segmentation results\n", + "into an executive-level strategic report.\n", + "Respond with ONLY valid JSON containing:\n", + " executive_summary: string (3-4 sentences — overall findings and strategic implication)\n", + " cluster_priority: list of objects, each with:\n", + " cluster: string\n", + " archetype: string\n", + " priority: string (\"High\" | \"Medium\" | \"Low\")\n", + " strategic_action: string (one concrete next action)\n", + " quick_wins: list of 3 strings (immediate actions any team can take this week)\n", + "\"\"\"\n", + "\n", + "def ground_in_business_objective(\n", + " client: OllamaClient,\n", + " personas: list[PersonaResult],\n", + " objective: str,\n", + " fallback: bool = False,\n", + ") -> dict:\n", + " if fallback:\n", + " return {\n", + " \"executive_summary\": \"Ollama offline. Start Ollama and re-run to get LLM-generated strategic grounding.\",\n", + " \"cluster_priority\": [{\"cluster\": p.persona_name, \"archetype\": p.archetype,\n", + " \"priority\": \"TBD\", \"strategic_action\": \"Run Ollama to generate\"} for p in personas],\n", + " \"quick_wins\": [\"Start Ollama: ollama serve\", f\"Pull model: ollama pull {OLLAMA_MODEL}\", \"Re-run notebook\"],\n", + " }\n", + "\n", + " persona_summaries = []\n", + " for p in personas:\n", + " persona_summaries.append(\n", + " f\" {p.persona_name} — {p.archetype}\\n\"\n", + " f\" Size: {p.cluster_size:,} ({p.cluster_pct*100:.1f}%)\\n\"\n", + " f\" Description: {p.description[:200]}\\n\"\n", + " f\" Top traits: {'; '.join(p.key_traits[:3])}\"\n", + " )\n", + "\n", + " prompt = (\n", + " f\"Business Objective:\\n{objective}\\n\\n\"\n", + " f\"Identified Customer Personas:\\n\" + \"\\n\\n\".join(persona_summaries) + \"\\n\\n\"\n", + " f\"Ground these personas in the stated business objective. \"\n", + " f\"Identify priorities and strategic actions. Respond ONLY with valid JSON.\"\n", + " )\n", + "\n", + " print(\" 🤖 Grounding personas in business objective...\")\n", + " t0 = time.time()\n", + " raw = client.generate(prompt, system=GROUNDING_SYSTEM, temperature=0.2)\n", + " print(f\" LLM response in {time.time()-t0:.1f}s\")\n", + "\n", + " try:\n", + " return client.extract_json(raw)\n", + " except Exception as e:\n", + " log.warning(\"Grounding JSON parse failed: %s\", e)\n", + " return {\"executive_summary\": raw[:500], \"cluster_priority\": [], \"quick_wins\": []}\n", + "\n", + "\n", + "grounding = ground_in_business_objective(ollama, personas, BUSINESS_OBJECTIVE, fallback=use_fallback)\n", + "\n", + "print(\"\\n\" + \"═\"*60)\n", + "print(\" BUSINESS OBJECTIVE GROUNDING COMPLETE\")\n", + "print(\"═\"*60)\n", + "print(\"\\n📋 Executive Summary:\")\n", + "print(f\" {grounding.get('executive_summary', 'N/A')}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 15 — 📊 Final Persona Report\n", + "Prints the full structured output: Cluster A, B, C with archetypes, traits, recommendations, and strategic grounding." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# ── Final Persona Report ─────────────────────────────────────────────────────\n", + "\n", + "CLUSTER_LETTERS = {0: \"A\", 1: \"B\", 2: \"C\", 3: \"D\", 4: \"E\"}\n", + "\n", + "def print_persona_report(personas: list[PersonaResult], grounding: dict, objective: str):\n", + " divider = \"═\" * 68\n", + " subdiv = \"─\" * 68\n", + "\n", + " print(f\"\\n{divider}\")\n", + " print(f\" PERSONA IDENTIFICATION REPORT\")\n", + " print(f\" Business Objective: {objective[:70]}...\")\n", + " print(f\"{divider}\")\n", + "\n", + " for p in personas:\n", + " letter = CLUSTER_LETTERS.get(p.cluster_id, str(p.cluster_id))\n", + " print(f\"\\n{'▌'} CLUSTER {letter} ╔══ {p.archetype} ══╗\")\n", + " print(f\" Size : {p.cluster_size:,} customers ({p.cluster_pct*100:.1f}% of total)\")\n", + " print(f\" Description :\")\n", + " # Word-wrap the description\n", + " words, line = p.description.split(), \"\"\n", + " for word in words:\n", + " if len(line) + len(word) + 1 > 65:\n", + " print(f\" {line}\")\n", + " line = word\n", + " else:\n", + " line = f\"{line} {word}\".strip()\n", + " if line:\n", + " print(f\" {line}\")\n", + "\n", + " if p.key_traits:\n", + " print(f\" Key Traits :\")\n", + " for t in p.key_traits:\n", + " print(f\" • {t}\")\n", + "\n", + " if p.top_features:\n", + " print(f\" Top Metrics (mean):\")\n", + " for feat, val in p.top_features.items():\n", + " print(f\" {feat:<30}: {val:>10.2f}\")\n", + "\n", + " if p.business_recommendations:\n", + " print(f\" Recommendations:\")\n", + " for r in p.business_recommendations:\n", + " print(f\" → {r}\")\n", + " print(f\" {subdiv}\")\n", + "\n", + " # Strategic priorities\n", + " priorities = grounding.get(\"cluster_priority\", [])\n", + " if priorities:\n", + " print(f\"\\n{'▌'} STRATEGIC PRIORITIES\")\n", + " for cp in priorities:\n", + " print(f\" [{cp.get('priority','?'):6}] {cp.get('cluster','')} — {cp.get('strategic_action','')}\")\n", + "\n", + " # Quick wins\n", + " qw = grounding.get(\"quick_wins\", [])\n", + " if qw:\n", + " print(f\"\\n{'▌'} QUICK WINS (This Week)\")\n", + " for i, w in enumerate(qw, 1):\n", + " print(f\" {i}. {w}\")\n", + "\n", + " print(f\"\\n{divider}\\n\")\n", + "\n", + "\n", + "print_persona_report(personas, grounding, BUSINESS_OBJECTIVE)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 16 — Persona Visualisation\n", + "Radar chart per cluster + cluster size distribution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# ── Persona Visualisation ────────────────────────────────────────────────────\n", + "\n", + "fig = plt.figure(figsize=(18, 7))\n", + "\n", + "# ── Left: cluster size pie ────────────────────────────────────────────────────\n", + "ax_pie = fig.add_subplot(1, 3, 1)\n", + "sizes = [p.cluster_size for p in personas]\n", + "labels_pie = [f\"{p.persona_name}\\n{p.archetype[:20]}\" for p in personas]\n", + "wedge_colors = PALETTE[:len(personas)]\n", + "\n", + "wedges, texts, autotexts = ax_pie.pie(\n", + " sizes, labels=labels_pie, colors=wedge_colors,\n", + " autopct=\"%1.1f%%\", startangle=140,\n", + " wedgeprops={\"edgecolor\": \"white\", \"linewidth\": 1.5},\n", + ")\n", + "for at in autotexts:\n", + " at.set_fontsize(10)\n", + "ax_pie.set_title(\"Cluster Size Distribution\", fontsize=13, pad=15)\n", + "\n", + "# ── Right: radar charts ───────────────────────────────────────────────────────\n", + "top_radar_feats = explain_report.top_features[:6]\n", + "num_cols_radar = [f for f in top_radar_feats if f in raw_df.columns\n", + " and pd.api.types.is_numeric_dtype(raw_df[f])][:6]\n", + "n_feats = len(num_cols_radar)\n", + "\n", + "if n_feats >= 3:\n", + " angles = np.linspace(0, 2 * np.pi, n_feats, endpoint=False).tolist()\n", + " angles += angles[:1]\n", + "\n", + " for idx, p in enumerate(personas[:3]):\n", + " ax = fig.add_subplot(1, 3, idx + 2, polar=True) if idx < 2 else None\n", + " if idx == 0:\n", + " ax = fig.add_subplot(1, 3, 2, polar=True)\n", + " elif idx == 1:\n", + " ax = fig.add_subplot(1, 3, 3, polar=True)\n", + " else:\n", + " break\n", + "\n", + " mask = best_eval.labels == p.cluster_id\n", + " means = raw_df[mask][num_cols_radar].mean()\n", + " global_min = raw_df[num_cols_radar].min()\n", + " global_max = raw_df[num_cols_radar].max()\n", + " normed = ((means - global_min) / (global_max - global_min + 1e-9)).values.tolist()\n", + " normed += normed[:1]\n", + "\n", + " ax.plot(angles, normed, color=PALETTE[idx], linewidth=2)\n", + " ax.fill(angles, normed, color=PALETTE[idx], alpha=0.25)\n", + " ax.set_xticks(angles[:-1])\n", + " ax.set_xticklabels(num_cols_radar, size=8)\n", + " ax.set_ylim(0, 1)\n", + " ax.set_title(f\"{p.persona_name}\\n{p.archetype[:18]}\", size=10, pad=14,\n", + " color=PALETTE[idx], fontweight=\"bold\")\n", + "\n", + "plt.suptitle(\"Customer Persona Profiles\", fontsize=15, fontweight=\"bold\", y=1.01)\n", + "plt.tight_layout()\n", + "fig.savefig(OUTPUT_DIR / \"persona_profiles.png\", dpi=150, bbox_inches=\"tight\")\n", + "plt.show()\n", + "print(\"✅ Saved: persona_profiles.png\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cell 17 — Export Results\n", + "Saves labeled dataset (CSV), persona report (JSON), and pipeline metadata." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# ── Export Results ───────────────────────────────────────────────────────────\n", + "\n", + "# 1. Labeled dataset\n", + "cluster_letter_map = {p.cluster_id: p.persona_name for p in personas}\n", + "labeled_df[\"persona\"] = labeled_df[\"cluster_id\"].map(cluster_letter_map).fillna(\"Noise\")\n", + "labeled_df[\"archetype\"] = labeled_df[\"cluster_id\"].map(\n", + " {p.cluster_id: p.archetype for p in personas}\n", + ").fillna(\"N/A\")\n", + "\n", + "output_csv = OUTPUT_DIR / \"labeled_customers.csv\"\n", + "labeled_df.to_csv(output_csv, index=False)\n", + "print(f\"✅ Labeled dataset → {output_csv}\")\n", + "\n", + "# 2. Persona report JSON\n", + "report = {\n", + " \"pipeline_metadata\": {\n", + " \"algorithm\": best_eval.algorithm,\n", + " \"n_clusters\": best_eval.n_clusters,\n", + " \"silhouette_score\": best_eval.silhouette,\n", + " \"davies_bouldin\": best_eval.davies_bouldin,\n", + " \"calinski_harabasz\": best_eval.calinski_harabasz,\n", + " \"top_features\": explain_report.top_features,\n", + " \"ollama_model\": OLLAMA_MODEL,\n", + " \"business_objective\": BUSINESS_OBJECTIVE,\n", + " },\n", + " \"personas\": [\n", + " {\n", + " \"cluster_id\": p.cluster_id,\n", + " \"persona_name\": p.persona_name,\n", + " \"archetype\": p.archetype,\n", + " \"description\": p.description,\n", + " \"key_traits\": p.key_traits,\n", + " \"business_recommendations\": p.business_recommendations,\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": p.cluster_pct,\n", + " \"top_feature_means\": p.top_features,\n", + " }\n", + " for p in personas\n", + " ],\n", + " \"strategic_grounding\": grounding,\n", + "}\n", + "\n", + "output_json = OUTPUT_DIR / \"persona_report.json\"\n", + "with open(output_json, \"w\") as f:\n", + " json.dump(report, f, indent=2)\n", + "print(f\"✅ Persona report → {output_json}\")\n", + "\n", + "# 3. Per-cluster CSVs\n", + "for p in personas:\n", + " mask = labeled_df[\"cluster_id\"] == p.cluster_id\n", + " out = OUTPUT_DIR / f\"{p.persona_name.replace(' ','_').lower()}_customers.csv\"\n", + " labeled_df[mask].to_csv(out, index=False)\n", + " print(f\"✅ {p.persona_name} customers → {out} ({mask.sum():,} rows)\")\n", + "\n", + "print(f\"\\n🎉 Pipeline complete. All outputs in: {OUTPUT_DIR.resolve()}/\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ✅ Pipeline Architecture Summary\n", + "\n", + "| Step | Module | Description |\n", + "|------|--------|-------------|\n", + "| 1 | **Data Input** | CSV / Parquet / Excel / Synthetic loader with schema inference |\n", + "| 2 | **Feature Engineering** | Imputation → Label encoding → IQR clipping → StandardScaler |\n", + "| 3 | **Clustering Config** | Silhouette-guided k selection over configurable k range |\n", + "| 4 | **K-Means Runner** | Distance-based clustering with k-means++ initialisation |\n", + "| 5 | **DBSCAN Runner** | Density-based clustering; handles irregular cluster shapes |\n", + "| 6 | **GMM Runner** | Probabilistic soft assignment via Expectation-Maximization |\n", + "| 7 | **Cluster Evaluator** | Silhouette + Davies-Bouldin + Calinski-Harabasz; pass/fail gate |\n", + "| 8 | **Modeling Loop** | Retries up to `MAX_ITERATIONS` with reconfiguration on failure |\n", + "| 9 | **Explainability** | Permutation feature importance + PCA loadings + cluster profiles |\n", + "| 10 | **Persona ID (LLM)** | Ollama/llama3 generates archetype, traits, recommendations per cluster |\n", + "| 11 | **Business Grounding** | LLM synthesises executive summary + strategic priorities |\n", + "| 12 | **Export** | Labeled CSV, per-cluster CSVs, full JSON report, PNG plots |\n", + "\n", + "### Local LLM Setup\n", + "```bash\n", + "# 1. Install Ollama\n", + "curl -fsSL https://ollama.com/install.sh | sh\n", + "\n", + "# 2. Start the server\n", + "ollama serve\n", + "\n", + "# 3. Pull the model\n", + "ollama pull llama3\n", + "\n", + "# 4. Run this notebook end-to-end\n", + "```\n", + "\n", + "### Extending the Pipeline\n", + "- **Swap LLM**: Change `OLLAMA_MODEL` to `mistral`, `llama3:70b`, `phi3`, etc.\n", + "- **Real data**: Set `DATA_SOURCE = \"csv\"` and `DATA_PATH = \"your_file.csv\"`\n", + "- **More algorithms**: Add new runner functions following the `run_kmeans` pattern\n", + "- **SHAP values**: Install `shap` and replace `compute_permutation_importance()` with `shap.KernelExplainer`\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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e48c250 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +pandas>=2.0.0 +numpy>=1.24.0 +scikit-learn>=1.3.0 +matplotlib>=3.7.0 +seaborn>=0.12.0 +plotly>=5.15.0 +shap>=0.42.0 +pyyaml>=6.0 +openpyxl>=3.1.0 +requests>=2.31.0 +scipy>=1.11.0 +google-generativeai>=0.3.0 +kaleido>=0.2.1 diff --git a/segplus/clustering.py b/segplus/clustering.py new file mode 100644 index 0000000..fa9423b --- /dev/null +++ b/segplus/clustering.py @@ -0,0 +1,131 @@ +"""Clustering algorithm runners: K-Means, DBSCAN, GMM.""" +from __future__ import annotations + +import logging + +import numpy as np +from sklearn.cluster import DBSCAN, KMeans +from sklearn.metrics import silhouette_score +from sklearn.mixture import GaussianMixture +from sklearn.neighbors import NearestNeighbors + +from .types import ClusteringConfig, ClusterRunResult + +log = logging.getLogger("segplus.clustering") + + +def run_kmeans(X: np.ndarray, config: ClusteringConfig) -> ClusterRunResult: + """Run K-Means clustering.""" + model = KMeans( + n_clusters=config.k, + init=config.kmeans_init, + n_init=config.kmeans_n_init, + max_iter=config.kmeans_max_iter, + random_state=config.random_state, + ) + labels = model.fit_predict(X) + return ClusterRunResult( + algorithm="kmeans", + labels=labels, + n_clusters=len(set(labels)), + model=model, + extra={"inertia": float(model.inertia_)}, + ) + + +def run_dbscan(X: np.ndarray, config: ClusteringConfig) -> ClusterRunResult: + """Run DBSCAN density-based clustering.""" + model = DBSCAN(eps=config.dbscan_eps, min_samples=config.dbscan_min_samples) + labels = model.fit_predict(X) + n_clusters = len(set(labels)) - (1 if -1 in labels else 0) + noise_count = int((labels == -1).sum()) + return ClusterRunResult( + algorithm="dbscan", + labels=labels, + n_clusters=max(n_clusters, 1), + model=model, + extra={"noise_count": noise_count, "noise_pct": noise_count / len(labels)}, + ) + + +def run_gmm(X: np.ndarray, config: ClusteringConfig) -> ClusterRunResult: + """Run Gaussian Mixture Model clustering.""" + model = GaussianMixture( + n_components=config.k, + covariance_type=config.gmm_covariance_type, + n_init=config.gmm_n_init, + random_state=config.random_state, + ) + labels = model.fit_predict(X) + probs = model.predict_proba(X) + return ClusterRunResult( + algorithm="gmm", + labels=labels, + n_clusters=len(set(labels)), + model=model, + probabilities=probs, + extra={"bic": float(model.bic(X)), "aic": float(model.aic(X))}, + ) + + +def run_all_algorithms(X: np.ndarray, config: ClusteringConfig) -> dict[str, ClusterRunResult]: + """Run all three clustering algorithms, applying feature subset if configured.""" + X_work = X + if config.feature_subset_indices is not None: + X_work = X[:, config.feature_subset_indices] + + results = {} + for name, runner in [("kmeans", run_kmeans), ("dbscan", run_dbscan), ("gmm", run_gmm)]: + try: + results[name] = runner(X_work, config) + log.info( + " [%s] clusters=%d", + name, results[name].n_clusters, + ) + except Exception as e: + log.warning(" [%s] failed: %s", name, e) + return results + + +def find_optimal_k( + X: np.ndarray, + k_range: tuple[int, int], + random_state: int = 42, +) -> tuple[int, dict[int, float]]: + """Silhouette sweep to find optimal K for K-Means.""" + best_k, best_score = k_range[0], -1.0 + scores: dict[int, float] = {} + + for k in range(k_range[0], k_range[1] + 1): + km = KMeans(n_clusters=k, init="k-means++", n_init=5, random_state=random_state) + labels = km.fit_predict(X) + if len(set(labels)) < 2: + continue + s = silhouette_score(X, labels, sample_size=min(2000, len(X))) + scores[k] = round(s, 4) + if s > best_score: + best_score, best_k = s, k + + log.info("K search: scores=%s | best k=%d (sil=%.4f)", scores, best_k, best_score) + return best_k, scores + + +def estimate_dbscan_eps(X: np.ndarray, min_samples: int = 5) -> float: + """Estimate DBSCAN eps using k-distance knee detection.""" + nn = NearestNeighbors(n_neighbors=min_samples) + nn.fit(X) + distances, _ = nn.kneighbors(X) + k_dist = np.sort(distances[:, -1]) + + # Simple knee detection: max second derivative + if len(k_dist) < 10: + return float(np.median(k_dist)) + + diffs = np.diff(k_dist) + diffs2 = np.diff(diffs) + knee_idx = int(np.argmax(diffs2)) + 2 + eps = float(k_dist[min(knee_idx, len(k_dist) - 1)]) + eps = max(eps, 0.1) # floor + + log.info("DBSCAN eps estimated: %.3f (knee at index %d)", eps, knee_idx) + return round(eps, 3) diff --git a/segplus/config.py b/segplus/config.py new file mode 100644 index 0000000..e771370 --- /dev/null +++ b/segplus/config.py @@ -0,0 +1,146 @@ +"""Pipeline and domain configuration management.""" +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from pathlib import Path +from typing import Optional + +import yaml + +log = logging.getLogger("segplus.config") + +_DOMAINS_DIR = Path(__file__).resolve().parent.parent / "domains" + + +# ── Domain Config (parsed from YAML) ──────────────────────────────────────── + +@dataclass +class FeatureEngineeringRule: + name: str + formula: str + bins: list[str] | None = None + description: str = "" + + +@dataclass +class DomainConfig: + domain_key: str + display_name: str + features: dict[str, list[str]] = field(default_factory=dict) + required_columns: list[str] = field(default_factory=list) + feature_engineering: list[FeatureEngineeringRule] = field(default_factory=list) + eda_analyses: list[str] = field(default_factory=list) + persona_prompt_template: str = "" + scaling_exclude: list[str] = field(default_factory=list) + categorical_columns: list[str] = field(default_factory=list) + metadata: dict = field(default_factory=dict) + + @property + def all_feature_columns(self) -> list[str]: + cols: list[str] = [] + for group_cols in self.features.values(): + cols.extend(group_cols) + return cols + + @property + def numerical_columns(self) -> list[str]: + return [c for c in self.all_feature_columns if c not in self.categorical_columns] + + +def load_domain_config(domain_key: str, domains_dir: Path | None = None) -> DomainConfig: + """Load a domain configuration from YAML.""" + d = domains_dir or _DOMAINS_DIR + yaml_path = d / f"{domain_key}.yaml" + if not yaml_path.exists(): + available = [f.stem for f in d.glob("*.yaml") if not f.stem.startswith("_")] + raise FileNotFoundError( + f"Domain '{domain_key}' not found at {yaml_path}. " + f"Available: {available}" + ) + + with open(yaml_path, "r", encoding="utf-8") as f: + raw = yaml.safe_load(f) + + fe_rules = [] + for rule in raw.get("feature_engineering", []): + fe_rules.append(FeatureEngineeringRule( + name=rule["name"], + formula=rule["formula"], + bins=rule.get("bins"), + description=rule.get("description", ""), + )) + + eda_analyses = [] + eda_block = raw.get("eda", {}) + if isinstance(eda_block, dict): + eda_analyses = eda_block.get("domain_analyses", []) + + return DomainConfig( + domain_key=raw.get("domain", domain_key), + display_name=raw.get("display_name", domain_key), + features=raw.get("features", {}), + required_columns=raw.get("required_columns", []), + feature_engineering=fe_rules, + eda_analyses=eda_analyses, + persona_prompt_template=raw.get("persona_prompt_template", ""), + scaling_exclude=raw.get("scaling_exclude", []), + categorical_columns=raw.get("categorical_columns", []), + metadata=raw.get("metadata", {}), + ) + + +def list_available_domains(domains_dir: Path | None = None) -> list[str]: + d = domains_dir or _DOMAINS_DIR + return sorted(f.stem for f in d.glob("*.yaml") if not f.stem.startswith("_")) + + +# ── Pipeline Config ────────────────────────────────────────────────────────── + +@dataclass +class PipelineConfig: + """All tunable pipeline parameters with sensible defaults.""" + + # Data + data_path: str = "final_enterprise_clustering_dataset.xlsx" + domain_key: str = "financial_services" + sheet_name: Optional[str] = None + exclude_cols: list[str] = field(default_factory=lambda: ["customer_id"]) + + # Feature Engineering + pca_variance_threshold: float = 0.85 + winsorize_lower: float = 0.01 + winsorize_upper: float = 0.99 + imputation_strategy: str = "median" + + # Clustering + k_range: tuple[int, int] = (2, 8) + random_state: int = 42 + + # Evaluation Gate + silhouette_threshold: float = 0.15 + davies_bouldin_threshold: float = 2.5 + stability_ari_threshold: float = 0.7 + stability_n_bootstraps: int = 30 + + # Modeling Loop + max_iterations: int = 5 + + # Explainability + n_top_features: int = 10 + shap_n_repeats: int = 10 + + # Ollama + ollama_host: str = "http://localhost:11434" + ollama_model: str = "llama3" + ollama_timeout: int = 120 + + # Business Objective + business_objective: str = ( + "Identify distinct customer segments to personalise marketing campaigns, " + "improve retention for high-value customers, and convert mid-tier customers " + "to premium products." + ) + + # Output + output_dir: str = "segplus_output" diff --git a/segplus/data_input.py b/segplus/data_input.py new file mode 100644 index 0000000..931975b --- /dev/null +++ b/segplus/data_input.py @@ -0,0 +1,140 @@ +"""Data loading, schema inference, and validation.""" +from __future__ import annotations + +import logging +from pathlib import Path +from typing import Optional + +import pandas as pd + +from .config import DomainConfig +from .types import ColumnMeta, DataQualityReport, DataSchema + +log = logging.getLogger("segplus.data_input") + + +def load_data(file_path: str | Path, sheet_name: Optional[str] = None) -> pd.DataFrame: + """Load data from CSV, Excel, or Parquet.""" + p = Path(file_path) + if not p.exists(): + raise FileNotFoundError(f"Data file not found: {p}") + + suffix = p.suffix.lower() + if suffix == ".csv": + df = pd.read_csv(p) + elif suffix in (".xlsx", ".xls"): + df = pd.read_excel(p, sheet_name=sheet_name or 0, engine="openpyxl") + elif suffix == ".parquet": + df = pd.read_parquet(p) + else: + raise ValueError(f"Unsupported file format: {suffix}") + + log.info("Loaded %s: %d rows x %d cols", p.name, len(df), len(df.columns)) + return df + + +def infer_schema(df: pd.DataFrame) -> DataSchema: + """Infer column types and build a DataSchema.""" + columns: list[ColumnMeta] = [] + for col in df.columns: + s = df[col] + n_unique = s.nunique() + if pd.api.types.is_bool_dtype(s): + dtype = "boolean" + elif pd.api.types.is_datetime64_any_dtype(s): + dtype = "datetime" + elif pd.api.types.is_numeric_dtype(s): + dtype = "numeric" + elif n_unique / max(len(s), 1) < 0.05 or n_unique <= 20: + dtype = "categorical" + else: + dtype = "text" + columns.append(ColumnMeta(col, dtype, round(s.isna().mean(), 4), n_unique)) + return DataSchema(len(df), len(df.columns), columns) + + +def validate_schema( + df: pd.DataFrame, + domain_config: DomainConfig, + schema: DataSchema, +) -> DataQualityReport: + """Validate the dataframe against domain requirements.""" + report = DataQualityReport( + total_rows=len(df), + total_columns=len(df.columns), + ) + + # Column type map + report.column_types = {c.name: c.dtype for c in schema.columns} + + # Missing values + missing = df.isnull().sum() + report.missing_values = {c: int(v) for c, v in missing.items() if v > 0} + report.missing_pct = {c: round(v / len(df), 4) for c, v in report.missing_values.items()} + + # Duplicates + report.duplicate_rows = int(df.duplicated().sum()) + if report.duplicate_rows > 0: + report.warnings.append(f"{report.duplicate_rows} duplicate rows found") + + # Required columns check + df_cols_lower = {c.lower(): c for c in df.columns} + for req in domain_config.required_columns: + if req.lower() not in df_cols_lower: + report.errors.append(f"Required column missing: '{req}'") + report.passed = False + + # Row count check + if len(df) < 50: + report.warnings.append(f"Very few rows ({len(df)}). Results may be unreliable.") + + # High-missing columns + for col, pct in report.missing_pct.items(): + if pct > 0.5: + report.warnings.append(f"Column '{col}' is {pct:.0%} missing") + + if report.errors: + report.passed = False + + return report + + +def auto_map_columns( + df: pd.DataFrame, + domain_config: DomainConfig, +) -> tuple[pd.DataFrame, dict[str, str]]: + """Case-insensitive column mapping to domain config names.""" + df_cols_lower = {c.lower().replace(" ", "_").replace("-", "_"): c for c in df.columns} + mapping: dict[str, str] = {} + + all_expected = set(domain_config.all_feature_columns + domain_config.required_columns) + + for expected in all_expected: + norm = expected.lower().replace(" ", "_").replace("-", "_") + if norm in df_cols_lower and df_cols_lower[norm] != expected: + mapping[df_cols_lower[norm]] = expected + + if mapping: + df = df.rename(columns=mapping) + log.info("Auto-mapped %d columns: %s", len(mapping), mapping) + + return df, mapping + + +def import_and_validate( + file_path: str | Path, + domain_config: DomainConfig, + auto_map: bool = True, + sheet_name: Optional[str] = None, +) -> tuple[pd.DataFrame, DataQualityReport, DataSchema]: + """Full import pipeline: load -> auto-map -> infer schema -> validate.""" + df = load_data(file_path, sheet_name) + + if auto_map: + df, _ = auto_map_columns(df, domain_config) + + schema = infer_schema(df) + report = validate_schema(df, domain_config, schema) + + log.info("Data quality: %s", "PASSED" if report.passed else "FAILED") + return df, report, schema diff --git a/segplus/evaluation.py b/segplus/evaluation.py new file mode 100644 index 0000000..a14feb8 --- /dev/null +++ b/segplus/evaluation.py @@ -0,0 +1,212 @@ +"""Cluster evaluation: scoring, pass/fail gate, stability testing.""" +from __future__ import annotations + +import logging + +import numpy as np +from sklearn.cluster import KMeans +from sklearn.metrics import ( + adjusted_rand_score, + calinski_harabasz_score, + davies_bouldin_score, + silhouette_score, +) + +from .config import PipelineConfig +from .types import ClusterRunResult, EvaluationResult, StabilityResult + +log = logging.getLogger("segplus.evaluation") + + +class ClusterEvaluator: + """Evaluates clustering results and applies the pass/fail gate.""" + + def __init__(self, config: PipelineConfig): + self.config = config + + def evaluate( + self, + X: np.ndarray, + results: dict[str, ClusterRunResult], + ) -> EvaluationResult: + """Score all algorithm results, pick the best via composite ranking, apply pass/fail gate.""" + # Filter to valid results first (>= 2 non-noise clusters) + valid_results = {name: res for name, res in results.items() if res.is_valid} + if not valid_results: + log.warning("No algorithm produced >= 2 valid clusters; scoring all results as fallback.") + valid_results = results + + scored: dict[str, dict[str, float]] = {} + + for name, res in valid_results.items(): + s = self._score_one(X, res) + s["n_clusters"] = float(res.n_clusters) + # Coverage: fraction of data points actually clustered (penalises heavy noise) + n_clustered = int((res.labels != -1).sum()) + s["coverage"] = n_clustered / max(len(res.labels), 1) + scored[name] = s + log.info( + " [%s] k=%d | sil=%.4f | DB=%.4f | CH=%.1f | cov=%.2f", + name, res.n_clusters, + s["silhouette"], s["davies_bouldin"], s["calinski_harabasz"], + s["coverage"], + ) + + # Pick best using composite rank across all three metrics + coverage + best_name = self._pick_best_composite(scored) + best_s = scored[best_name] + best_res = valid_results[best_name] + + passes = self._check_pass(best_s["silhouette"], best_s["davies_bouldin"]) + + return EvaluationResult( + algorithm=best_name, + labels=best_res.labels, + n_clusters=best_res.n_clusters, + silhouette=best_s["silhouette"], + davies_bouldin=best_s["davies_bouldin"], + calinski_harabasz=best_s["calinski_harabasz"], + passes=passes, + all_scores=scored, + model=best_res.model, + ) + + def _pick_best_composite(self, scored: dict[str, dict[str, float]]) -> str: + """ + Rank-based composite selection using all computed metrics. + + Each algorithm is ranked per metric (1=best), ranks are normalised to [0,1], + then blended: + composite = 0.40 * silhouette_rank (higher is better) + + 0.25 * db_rank (lower is better → inverted) + + 0.20 * ch_rank (higher is better) + + 0.15 * coverage_rank (higher is better, penalises DBSCAN noise) + + If there is only one algorithm, it wins by default. + """ + names = list(scored.keys()) + if len(names) == 1: + return names[0] + + n = len(names) + + def _rank_higher_better(metric: str) -> dict[str, float]: + """Rank so that higher value → rank 1 (best).""" + ordered = sorted(names, key=lambda nm: scored[nm][metric], reverse=True) + return {nm: (i + 1) for i, nm in enumerate(ordered)} + + def _rank_lower_better(metric: str) -> dict[str, float]: + """Rank so that lower value → rank 1 (best).""" + ordered = sorted(names, key=lambda nm: scored[nm][metric]) + return {nm: (i + 1) for i, nm in enumerate(ordered)} + + sil_ranks = _rank_higher_better("silhouette") + db_ranks = _rank_lower_better("davies_bouldin") + ch_ranks = _rank_higher_better("calinski_harabasz") + cov_ranks = _rank_higher_better("coverage") + + # Normalise ranks to [0,1] where 1=best + def _norm(rank: float) -> float: + return 1.0 - (rank - 1.0) / max(n - 1, 1) + + composite: dict[str, float] = {} + for nm in names: + composite[nm] = ( + 0.40 * _norm(sil_ranks[nm]) + + 0.25 * _norm(db_ranks[nm]) + + 0.20 * _norm(ch_ranks[nm]) + + 0.15 * _norm(cov_ranks[nm]) + ) + + best = max(composite, key=lambda nm: composite[nm]) + log.info( + "Composite ranking: %s", + " | ".join(f"{nm}={composite[nm]:.3f}" for nm in names), + ) + log.info("Winner: %s (composite=%.3f)", best, composite[best]) + return best + + def _score_one(self, X: np.ndarray, result: ClusterRunResult) -> dict[str, float]: + """Compute metrics for a single clustering result.""" + labels = result.labels + valid_mask = labels != -1 + X_v = X[valid_mask] + labels_v = labels[valid_mask] + + if len(set(labels_v)) < 2 or len(X_v) < 10: + return {"silhouette": -1.0, "davies_bouldin": 99.0, "calinski_harabasz": 0.0} + + sample_size = min(2000, len(X_v)) + sil = silhouette_score(X_v, labels_v, sample_size=sample_size) + db = davies_bouldin_score(X_v, labels_v) + ch = calinski_harabasz_score(X_v, labels_v) + + return { + "silhouette": round(sil, 4), + "davies_bouldin": round(db, 4), + "calinski_harabasz": round(ch, 2), + } + + def _check_pass(self, silhouette: float, davies_bouldin: float) -> bool: + """Pure pass/fail gate.""" + return ( + silhouette >= self.config.silhouette_threshold + and davies_bouldin <= self.config.davies_bouldin_threshold + ) + + +def run_stability_test( + X: np.ndarray, + labels: np.ndarray, + n_clusters: int, + config: PipelineConfig, + algorithm: str = "kmeans", + model: object = None, +) -> StabilityResult: + """Bootstrap ARI stability test using the winning algorithm.""" + from sklearn.mixture import GaussianMixture + + rng = np.random.default_rng(config.random_state) + n = len(X) + ari_scores: list[float] = [] + + for _ in range(config.stability_n_bootstraps): + idx = rng.choice(n, size=n, replace=True) + X_boot = X[idx] + + if algorithm == "gmm": + cov_type = ( + model.covariance_type + if model is not None and hasattr(model, "covariance_type") + else "full" + ) + boot_model = GaussianMixture( + n_components=n_clusters, covariance_type=cov_type, + n_init=3, random_state=config.random_state, + ) + else: + # KMeans for kmeans winner; also used as proxy for DBSCAN + # (DBSCAN is density-based so bootstrap changes density structure) + boot_model = KMeans( + n_clusters=n_clusters, n_init=5, + random_state=config.random_state, + ) + + boot_labels = boot_model.fit_predict(X_boot) + ari = adjusted_rand_score(labels[idx], boot_labels) + ari_scores.append(ari) + + ari_mean = float(np.mean(ari_scores)) + ari_std = float(np.std(ari_scores)) + stable = ari_mean >= config.stability_ari_threshold + + log.info( + "Stability (%s): ARI=%.3f +/- %.3f (threshold=%.2f, stable=%s)", + algorithm, ari_mean, ari_std, config.stability_ari_threshold, stable, + ) + return StabilityResult( + ari_mean=round(ari_mean, 4), + ari_std=round(ari_std, 4), + n_bootstraps=config.stability_n_bootstraps, + stable=stable, + ) diff --git a/segplus/experiment_log.py b/segplus/experiment_log.py new file mode 100644 index 0000000..a6fc6c1 --- /dev/null +++ b/segplus/experiment_log.py @@ -0,0 +1,135 @@ +"""Experiment tracking: logs every modeling loop iteration.""" +from __future__ import annotations + +import json +import logging +from pathlib import Path + +import pandas as pd + +from .types import ExperimentRecord + +log = logging.getLogger("segplus.experiment_log") + + +def _to_native(value): + """Recursively convert numpy/pandas scalars and containers to JSON-safe Python types.""" + # Dict + if isinstance(value, dict): + return {str(k): _to_native(v) for k, v in value.items()} + # List / tuple + if isinstance(value, (list, tuple)): + return [_to_native(v) for v in value] + # Numpy scalars / arrays (without importing numpy directly) + if hasattr(value, "item") and callable(getattr(value, "item")): + try: + return value.item() + except Exception: + pass + if hasattr(value, "tolist") and callable(getattr(value, "tolist")): + try: + return value.tolist() + except Exception: + pass + # Path + if isinstance(value, Path): + return str(value) + return value + + +def _json_default(obj): + """Fallback serializer for json.dump to handle numpy/pandas scalar objects.""" + if hasattr(obj, "item") and callable(getattr(obj, "item")): + try: + return obj.item() + except Exception: + pass + if hasattr(obj, "tolist") and callable(getattr(obj, "tolist")): + try: + return obj.tolist() + except Exception: + pass + return str(obj) + + +class ExperimentLog: + """Tracks config, metrics, and results for every modeling loop iteration.""" + + def __init__(self) -> None: + self._records: list[ExperimentRecord] = [] + + @property + def records(self) -> list[ExperimentRecord]: + return list(self._records) + + def add(self, record: ExperimentRecord) -> None: + self._records.append(record) + log.info( + "Experiment %d: %s k=%d sil=%.4f pass=%s", + record.iteration, record.best_algorithm, + record.n_clusters, record.silhouette, record.passed, + ) + + def to_dataframe(self) -> pd.DataFrame: + if not self._records: + return pd.DataFrame() + rows = [] + for r in self._records: + rows.append({ + "iteration": r.iteration, + "timestamp": r.timestamp, + "k": r.config_k, + "eps": r.config_eps, + "gmm_cov": r.config_gmm_cov, + "best_algorithm": r.best_algorithm, + "n_clusters": r.n_clusters, + "silhouette": r.silhouette, + "davies_bouldin": r.davies_bouldin, + "calinski_harabasz": r.calinski_harabasz, + "passed": r.passed, + "reconfig_strategy": r.reconfiguration_strategy, + }) + return pd.DataFrame(rows) + + def to_json(self, path: Path) -> None: + data = [ + { + "iteration": int(r.iteration), + "timestamp": r.timestamp, + "config": { + "k": int(r.config_k), + "eps": float(r.config_eps), + "gmm_cov": str(r.config_gmm_cov), + }, + "best_algorithm": r.best_algorithm, + "n_clusters": int(r.n_clusters), + "silhouette": float(r.silhouette), + "davies_bouldin": float(r.davies_bouldin), + "calinski_harabasz": float(r.calinski_harabasz), + "passed": bool(r.passed), + "reconfiguration_strategy": r.reconfiguration_strategy, + } + for r in self._records + ] + data = _to_native(data) + with open(path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2, default=_json_default) + log.info("Experiment log saved: %s", path) + + def summary(self) -> str: + if not self._records: + return "No experiments recorded." + lines = ["Experiment Log Summary:", f" Total iterations: {len(self._records)}"] + for r in self._records: + status = "PASS" if r.passed else "FAIL" + strategy = f" (reconfig: {r.reconfiguration_strategy})" if r.reconfiguration_strategy else "" + lines.append( + f" [{r.iteration}] {r.best_algorithm:8s} k={r.n_clusters} " + f"sil={r.silhouette:.4f} DB={r.davies_bouldin:.4f} " + f"{status}{strategy}" + ) + best = max(self._records, key=lambda r: r.silhouette) + lines.append( + f" Best: iter {best.iteration} ({best.best_algorithm}, sil={best.silhouette:.4f})" + ) + return "\n".join(lines) diff --git a/segplus/explainability.py b/segplus/explainability.py new file mode 100644 index 0000000..1f07a30 --- /dev/null +++ b/segplus/explainability.py @@ -0,0 +1,300 @@ +"""Explainability: SHAP importance, PCA loadings, inertia curve, cluster profiles.""" +from __future__ import annotations + +import logging +from typing import Optional + +import numpy as np +import pandas as pd +from sklearn.cluster import KMeans +from sklearn.decomposition import PCA +from sklearn.ensemble import RandomForestClassifier +from sklearn.metrics import silhouette_score + +from .types import ExplainabilityReport + +log = logging.getLogger("segplus.explainability") + + +def compute_shap_importance( + X: np.ndarray, + labels: np.ndarray, + feature_names: list[str], + random_state: int = 42, +) -> dict[str, float]: + """ + Feature importance using three-tier fallback: + 1. TreeSHAP (if shap is installed) + 2. RF feature_importances_ + 3. Permutation importance + """ + valid_mask = labels != -1 + Xv, lv = X[valid_mask], labels[valid_mask] + + if len(set(lv)) < 2: + return {f: 0.0 for f in feature_names} + + # Train RF classifier on cluster labels + rf = RandomForestClassifier( + n_estimators=100, max_depth=10, random_state=random_state, n_jobs=-1 + ) + rf.fit(Xv, lv) + + # Tier 1: Try TreeSHAP + try: + import shap + explainer = shap.TreeExplainer(rf) + sample_size = min(500, len(Xv)) + rng = np.random.default_rng(random_state) + idx = rng.choice(len(Xv), size=sample_size, replace=False) + shap_values = explainer.shap_values(Xv[idx]) + + if isinstance(shap_values, list): + mean_abs = np.mean([np.abs(sv).mean(axis=0) for sv in shap_values], axis=0) + else: + mean_abs = np.abs(shap_values).mean(axis=0) + + importances = {feature_names[i]: round(float(mean_abs[i]), 5) for i in range(len(feature_names))} + log.info("SHAP importance computed via TreeSHAP") + return dict(sorted(importances.items(), key=lambda x: -x[1])) + + except ImportError: + log.info("shap not installed, falling back to RF feature_importances_") + except Exception as e: + log.warning("TreeSHAP failed (%s), falling back to RF feature_importances_", e) + + # Tier 2: RF feature importances + try: + imp = rf.feature_importances_ + importances = {feature_names[i]: round(float(imp[i]), 5) for i in range(len(feature_names))} + log.info("Feature importance computed via RF feature_importances_") + return dict(sorted(importances.items(), key=lambda x: -x[1])) + except Exception as e: + log.warning("RF importances failed (%s), falling back to permutation", e) + + # Tier 3: Permutation importance + return _compute_permutation_importance(Xv, lv, feature_names, random_state=random_state) + + +def to_importance_percentages(importances: dict[str, float]) -> dict[str, float]: + """Convert absolute importance scores to percentage contribution.""" + total = float(sum(max(v, 0.0) for v in importances.values())) + if total <= 0: + return {k: 0.0 for k in importances.keys()} + return {k: round((max(v, 0.0) / total) * 100.0, 4) for k, v in importances.items()} + + +def _compute_permutation_importance( + X: np.ndarray, + labels: np.ndarray, + feature_names: list[str], + n_repeats: int = 10, + random_state: int = 0, +) -> dict[str, float]: + """Permutation importance: silhouette drop when feature is shuffled.""" + rng = np.random.default_rng(random_state) + baseline = silhouette_score(X, labels, sample_size=min(1000, len(X))) + importances: dict[str, float] = {} + + for i, fname in enumerate(feature_names): + drops = [] + for _ in range(n_repeats): + Xp = X.copy() + rng.shuffle(Xp[:, i]) + s = silhouette_score(Xp, labels, sample_size=min(1000, len(X))) + drops.append(baseline - s) + importances[fname] = round(float(np.mean(drops)), 5) + + log.info("Feature importance computed via permutation importance") + return dict(sorted(importances.items(), key=lambda x: -x[1])) + + +def compute_pca_loadings( + pca: PCA, + feature_names: list[str], +) -> pd.DataFrame: + """PCA component loadings as a DataFrame.""" + n_components = pca.n_components_ + return pd.DataFrame( + np.abs(pca.components_), + columns=feature_names, + index=[f"PC{i+1}" for i in range(n_components)], + ) + + +def compute_inertia_curve( + X: np.ndarray, + k_range: tuple[int, int], + random_state: int = 42, +) -> dict[int, float]: + """Elbow curve: k -> inertia for K-Means.""" + curve: dict[int, float] = {} + for k in range(k_range[0], k_range[1] + 1): + km = KMeans(n_clusters=k, n_init=5, random_state=random_state) + km.fit(X) + curve[k] = float(km.inertia_) + return curve + + +def build_pc_feature_map( + pca_loadings: pd.DataFrame, + top_n: int = 5, +) -> dict[str, list[str]]: + """Map each principal component to its top contributing original features.""" + pc_map: dict[str, list[str]] = {} + for pc in pca_loadings.index: + top_features = ( + pca_loadings.loc[pc] + .sort_values(ascending=False) + .head(top_n) + .index + .tolist() + ) + pc_map[str(pc)] = top_features + return pc_map + + +def build_ordered_feature_drivers( + feature_importances: dict[str, float], + pca_loadings: pd.DataFrame, + pca_variance_ratio: list[float], + inertia_curve: dict[int, float] | None, +) -> pd.DataFrame: + """ + Build ordered feature drivers of convergence by combining: + - SHAP/RF feature importance + - Weighted PCA loading strength + - Global inertia elbow strength (reported as context) + """ + shap_series = pd.Series(feature_importances, dtype=float) + + # Weighted PCA contribution score per original feature + if len(pca_variance_ratio) > 0: + comp_weights = np.array(pca_variance_ratio[: len(pca_loadings.index)], dtype=float) + else: + comp_weights = np.ones(len(pca_loadings.index), dtype=float) + comp_weights = comp_weights / max(comp_weights.sum(), 1e-12) + pca_score = (pca_loadings.T * comp_weights).sum(axis=1) + + df = pd.DataFrame({ + "feature": sorted(set(shap_series.index).union(set(pca_score.index))), + }) + df["shap_importance"] = df["feature"].map(shap_series).fillna(0.0).astype(float) + df["pca_weighted_loading"] = df["feature"].map(pca_score).fillna(0.0).astype(float) + + # Rank normalize to [0,1], then blend. + df["shap_rank"] = df["shap_importance"].rank(ascending=False, method="average") + df["pca_rank"] = df["pca_weighted_loading"].rank(ascending=False, method="average") + n = max(len(df), 1) + df["shap_rank_norm"] = 1.0 - (df["shap_rank"] - 1.0) / max(n - 1, 1) + df["pca_rank_norm"] = 1.0 - (df["pca_rank"] - 1.0) / max(n - 1, 1) + + # Inertia is cluster-level evidence, not feature-specific. Keep as metadata/context column. + elbow_strength = 0.0 + if inertia_curve and len(inertia_curve) >= 3: + ks = sorted(inertia_curve.keys()) + vals = np.array([inertia_curve[k] for k in ks], dtype=float) + second_diff = np.diff(vals, n=2) + if len(second_diff) > 0: + elbow_strength = float(np.max(np.abs(second_diff))) + df["inertia_elbow_strength"] = elbow_strength + + df["convergence_score"] = ( + 0.6 * df["shap_rank_norm"] + + 0.4 * df["pca_rank_norm"] + ) + df = df.sort_values("convergence_score", ascending=False).reset_index(drop=True) + return df + + +def build_cluster_profiles( + df: pd.DataFrame, + labels: np.ndarray, + feature_names: list[str], +) -> pd.DataFrame: + """Cluster x feature mean table on raw/unscaled data.""" + profiled = df.copy() + profiled["_cluster"] = labels + # Use only numeric columns that exist in the dataframe + num_cols = [c for c in feature_names if c in profiled.columns and pd.api.types.is_numeric_dtype(profiled[c])] + if not num_cols: + num_cols = [c for c in profiled.select_dtypes(include="number").columns if c != "_cluster"] + profiles = profiled[profiled["_cluster"] != -1].groupby("_cluster")[num_cols].mean().round(2) + return profiles + + +def build_explainability_report( + X: np.ndarray, + labels: np.ndarray, + feature_names: list[str], + df_raw: pd.DataFrame, + pca: Optional[PCA], + k_range: tuple[int, int], + random_state: int = 42, + n_top: int = 10, + X_original: np.ndarray | None = None, + original_feature_names: list[str] | None = None, +) -> ExplainabilityReport: + """Orchestrate all explainability analyses into one report.""" + log.info("Computing feature importances...") + shap_X = X_original if X_original is not None else X + shap_feature_names = ( + original_feature_names + if original_feature_names is not None and len(original_feature_names) == shap_X.shape[1] + else feature_names + ) + importances = compute_shap_importance(shap_X, labels, shap_feature_names, random_state) + importance_pct = to_importance_percentages(importances) + top_features = list(importances.keys())[:n_top] + + # PCA loadings are defined on the original pre-PCA feature space. + # When clustering uses PCA output, `feature_names` may be ["PC1", ...], + # so derive a compatible name list for loadings to avoid shape mismatch. + n_pca_input_features = int(pca.components_.shape[1]) if pca is not None else len(feature_names) + numeric_raw_cols = [c for c in df_raw.columns if pd.api.types.is_numeric_dtype(df_raw[c])] + if len(feature_names) == n_pca_input_features: + loading_feature_names = feature_names + elif len(numeric_raw_cols) == n_pca_input_features: + loading_feature_names = numeric_raw_cols + else: + loading_feature_names = [f"feature_{i+1}" for i in range(n_pca_input_features)] + + log.info("Computing PCA loadings...") + if pca is not None: + pca_loadings = compute_pca_loadings(pca, loading_feature_names) + pca_var = pca.explained_variance_ratio_.tolist() + else: + # Fit a quick PCA for loadings analysis + n_comp = min(5, len(feature_names)) + pca_temp = PCA(n_components=n_comp, random_state=random_state) + pca_temp.fit(X) + pca_loadings = compute_pca_loadings(pca_temp, loading_feature_names) + pca_var = pca_temp.explained_variance_ratio_.tolist() + + log.info("Computing inertia curve...") + inertia = compute_inertia_curve(X, k_range, random_state) + + log.info("Computing cluster profiles...") + profiles = build_cluster_profiles(df_raw, labels, feature_names) + + log.info("Building ordered convergence drivers...") + ordered_drivers = build_ordered_feature_drivers( + feature_importances=importances, + pca_loadings=pca_loadings, + pca_variance_ratio=pca_var, + inertia_curve=inertia, + ) + pc_map = build_pc_feature_map(pca_loadings, top_n=5) + top_features = ordered_drivers["feature"].head(n_top).tolist() + + return ExplainabilityReport( + top_features=top_features, + feature_importances=importances, + feature_importance_pct=importance_pct, + pca_loadings=pca_loadings, + cluster_profiles=profiles, + pca_variance_ratio=pca_var, + inertia_curve=inertia, + ordered_feature_drivers=ordered_drivers, + pc_feature_map=pc_map, + ) diff --git a/segplus/feature_engineering.py b/segplus/feature_engineering.py new file mode 100644 index 0000000..77910c6 --- /dev/null +++ b/segplus/feature_engineering.py @@ -0,0 +1,141 @@ +"""Feature engineering: domain rules, imputation, encoding, scaling, PCA.""" +from __future__ import annotations + +import logging +from typing import Optional + +import numpy as np +import pandas as pd +from sklearn.decomposition import PCA +from sklearn.impute import SimpleImputer +from sklearn.preprocessing import LabelEncoder, StandardScaler + +from .config import DomainConfig, PipelineConfig +from .types import DataSchema, FeatureEngineeringResult + +log = logging.getLogger("segplus.feature_engineering") + + +class FeatureEngineer: + """Full feature engineering pipeline: FE rules -> impute -> encode -> winsorize -> scale -> PCA.""" + + def __init__(self, domain_config: DomainConfig, pipeline_config: PipelineConfig): + self.domain = domain_config + self.config = pipeline_config + self._scaler: StandardScaler | None = None + self._pca: PCA | None = None + self._imputer: SimpleImputer | None = None + self._label_encoders: dict[str, LabelEncoder] = {} + self._feature_cols: list[str] = [] + + def run(self, df: pd.DataFrame) -> FeatureEngineeringResult: + """Execute the full FE pipeline and return results.""" + df_original = df.copy() + + # Step 1: Apply domain-specific FE rules + df = self._apply_domain_rules(df) + + # Step 2: Drop excluded columns + drop_cols = [c for c in self.config.exclude_cols if c in df.columns] + df_work = df.drop(columns=drop_cols, errors="ignore") + + # Step 3: Identify column types + num_cols = [c for c in df_work.columns if pd.api.types.is_numeric_dtype(df_work[c])] + cat_cols = [c for c in self.domain.categorical_columns if c in df_work.columns] + + # Step 4: Encode categoricals + for col in cat_cols: + le = LabelEncoder() + df_work[col] = le.fit_transform(df_work[col].astype(str)) + self._label_encoders[col] = le + if col not in num_cols: + num_cols.append(col) + + # Step 5: Select feature columns (numeric + encoded categoricals) + self._feature_cols = [c for c in num_cols if c in df_work.columns] + X = df_work[self._feature_cols].copy() + + # Step 6: Impute missing values + self._imputer = SimpleImputer(strategy=self.config.imputation_strategy) + X_arr = self._imputer.fit_transform(X) + X = pd.DataFrame(X_arr, columns=self._feature_cols, index=df_work.index) + + # Step 7: Winsorize outliers + X = self._winsorize(X, self._feature_cols) + + df_engineered = X.copy() + + # Step 8: Scale + self._scaler = StandardScaler() + X_scaled = self._scaler.fit_transform(X) + + # Step 9: PCA (optional) + pca = None + if self.config.pca_variance_threshold < 1.0: + pca, X_scaled = self._apply_pca(X_scaled) + pca_names = [f"PC{i+1}" for i in range(X_scaled.shape[1])] + log.info( + "PCA: %d components explain %.1f%% variance", + X_scaled.shape[1], + sum(pca.explained_variance_ratio_[:X_scaled.shape[1]]) * 100, + ) + else: + pca_names = None + + feature_names = pca_names if pca_names else self._feature_cols + + log.info("Feature engineering complete: %d features -> %d-dim output", len(self._feature_cols), X_scaled.shape[1]) + + return FeatureEngineeringResult( + df_original=df_original, + df_engineered=df_engineered, + X_scaled=X_scaled, + feature_names=feature_names if pca_names else list(self._feature_cols), + pca=pca, + scaler=self._scaler, + label_encoders=self._label_encoders, + ) + + def _apply_domain_rules(self, df: pd.DataFrame) -> pd.DataFrame: + """Apply feature engineering rules from domain config using df.eval().""" + df = df.copy() + for rule in self.domain.feature_engineering: + try: + result = df.eval(rule.formula) + if rule.bins: + n_bins = len(rule.bins) + df[rule.name] = pd.qcut(result, q=n_bins, labels=rule.bins, duplicates="drop") + else: + df[rule.name] = result + log.info(" FE rule applied: %s", rule.name) + except Exception as e: + log.warning(" FE rule '%s' failed: %s", rule.name, e) + return df + + def _winsorize(self, X: pd.DataFrame, num_cols: list[str]) -> pd.DataFrame: + """Clip outliers to [lower, upper] percentiles.""" + for col in num_cols: + if col in X.columns: + lo = X[col].quantile(self.config.winsorize_lower) + hi = X[col].quantile(self.config.winsorize_upper) + X[col] = X[col].clip(lo, hi) + return X + + def _apply_pca(self, X_scaled: np.ndarray) -> tuple[PCA, np.ndarray]: + """Apply PCA with automatic component selection.""" + pca = PCA(random_state=self.config.random_state) + pca.fit(X_scaled) + + cumvar = np.cumsum(pca.explained_variance_ratio_) + n_components = int(np.searchsorted(cumvar, self.config.pca_variance_threshold) + 1) + n_components = max(2, min(n_components, X_scaled.shape[1])) + + pca_final = PCA(n_components=n_components, random_state=self.config.random_state) + X_pca = pca_final.fit_transform(X_scaled) + self._pca = pca_final + return pca_final, X_pca + + @property + def original_feature_names(self) -> list[str]: + """Original feature column names before PCA.""" + return list(self._feature_cols) diff --git a/segplus/final_segplus_pipeline.ipynb b/segplus/final_segplus_pipeline.ipynb new file mode 100644 index 0000000..d2b827e --- /dev/null +++ b/segplus/final_segplus_pipeline.ipynb @@ -0,0 +1,1295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SegPlus Final End-to-End Pipeline\n", + "\n", + "This notebook runs the full architecture:\n", + "- Data input and validation\n", + "- Feature engineering\n", + "- KMeans + DBSCAN + GMM modeling loop\n", + "- Cluster evaluation + stability\n", + "- Explainability (feature drivers, PCA loadings, profiles)\n", + "- Persona generation and business grounding (Ollama with fallback)\n", + "- Visualization and export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "64579db4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Missing required: ['scikit-learn', 'pyyaml']\n", + "Missing optional: []\n" + ] + } + ], + "source": [ + "# Optional dependency installer/check\n", + "import importlib\n", + "import subprocess\n", + "import sys\n", + "\n", + "REQUIRED_PACKAGES = [\n", + " \"numpy\", \"pandas\", \"scikit-learn\", \"matplotlib\", \"seaborn\",\n", + " \"pyyaml\", \"openpyxl\", \"requests\", \"scipy\"\n", + "]\n", + "OPTIONAL_PACKAGES = [\"shap\"]\n", + "AUTO_INSTALL_MISSING = False # set True if you want notebook to install missing packages\n", + "\n", + "missing_required = []\n", + "missing_optional = []\n", + "\n", + "for pkg in REQUIRED_PACKAGES:\n", + " mod = pkg.replace(\"-\", \"_\")\n", + " try:\n", + " importlib.import_module(mod)\n", + " except Exception:\n", + " missing_required.append(pkg)\n", + "\n", + "for pkg in OPTIONAL_PACKAGES:\n", + " try:\n", + " importlib.import_module(pkg)\n", + " except Exception:\n", + " missing_optional.append(pkg)\n", + "\n", + "print(\"Missing required:\", missing_required)\n", + "print(\"Missing optional:\", missing_optional)\n", + "\n", + "if missing_required and AUTO_INSTALL_MISSING:\n", + " cmd = [sys.executable, \"-m\", \"pip\", \"install\", *missing_required]\n", + " print(\"Installing:\", \" \".join(missing_required))\n", + " subprocess.check_call(cmd)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "32c77bb2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Project root: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\n" + ] + } + ], + "source": [ + "import logging\n", + "import json\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# Ensure project root is importable when notebook is inside segplus/\n", + "cwd = Path.cwd()\n", + "project_root = cwd.parent if cwd.name.lower() == \"segplus\" else cwd\n", + "if str(project_root) not in sys.path:\n", + " sys.path.insert(0, str(project_root))\n", + "\n", + "from segplus.config import PipelineConfig, load_domain_config\n", + "from segplus.data_input import import_and_validate\n", + "from segplus.feature_engineering import FeatureEngineer\n", + "from segplus.modeling_loop import modeling_loop\n", + "from segplus.evaluation import run_stability_test\n", + "from segplus.experiment_log import ExperimentLog\n", + "from segplus.explainability import build_explainability_report\n", + "from segplus.ollama_client import OllamaClient\n", + "from segplus.persona_generation import PersonaGenerator\n", + "from segplus.visualization import (\n", + " plot_cluster_scatter_2d,\n", + " plot_shap_importance,\n", + " plot_shap_summary,\n", + " plot_pca_loadings_heatmap,\n", + " plot_cluster_profiles_heatmap,\n", + " plot_cluster_sizes,\n", + " plot_radar_charts,\n", + " plot_experiment_history,\n", + " plot_elbow_curve,\n", + ")\n", + "\n", + "logging.basicConfig(\n", + " level=logging.INFO,\n", + " format=\"%(asctime)s | %(levelname)-8s | %(name)-30s | %(message)s\",\n", + ")\n", + "\n", + "print(\"Project root:\", project_root)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e0196175", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Domain: Financial Services\n", + "Data: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\final_enterprise_clustering_dataset_single_sheet.xlsx\n", + "Output: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n", + "Ollama host: http://localhost:11434\n", + "Primary LLM: qwen2.5:7b\n" + ] + } + ], + "source": [ + "# Configuration (edit these as needed)\n", + "default_data_path = project_root / \"final_enterprise_clustering_dataset_single_sheet.xlsx\"\n", + "default_output_dir = project_root / \"segplus_output\"\n", + "\n", + "config = PipelineConfig(\n", + " data_path=str(default_data_path),\n", + " domain_key=\"financial_services\", # or \"retail\"\n", + " sheet_name=None,\n", + " k_range=(2, 8),\n", + " max_iterations=5,\n", + " pca_variance_threshold=0.85,\n", + " output_dir=str(default_output_dir),\n", + " ollama_host=\"http://localhost:11434\", # local Ollama endpoint\n", + " ollama_model=\"qwen2.5:7b\", # primary local model`n ollama_timeout=240,\n", + " business_objective=(\n", + " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", + " \"improve retention for high-value customers, and convert mid-tier customers \"\n", + " \"to premium products.\"\n", + " ),\n", + ")\n", + "\n", + "# Preferred model order for local Ollama auto-selection\n", + "PREFERRED_OLLAMA_MODELS = [\n", + " \"qwen2.5\",\n", + " \"qwen2\",\n", + " \"llama3.2\",\n", + " \"llama3.1\",\n", + " \"llama3\",\n", + " \"mistral\",\n", + "]\n", + "\n", + "output_dir = Path(config.output_dir)\n", + "output_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + "domain_config = load_domain_config(config.domain_key, domains_dir=project_root / \"domains\")\n", + "print(\"Domain:\", domain_config.display_name)\n", + "print(\"Data:\", config.data_path)\n", + "print(\"Output:\", output_dir)\n", + "print(\"Ollama host:\", config.ollama_host)\n", + "print(\"Primary LLM:\", config.ollama_model)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "85b24976", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:49:51,635 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n", + "2026-03-06 22:49:51,833 | INFO | segplus.data_input | Data quality: PASSED\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Data Quality Report\n", + " Rows: 120,000 | Columns: 27\n", + " Duplicates: 0\n", + " Status: PASSED\n", + "Raw shape: (120000, 27)\n" + ] + } + ], + "source": [ + "# 1) Data Input + Validation\n", + "df_raw, quality_report, schema = import_and_validate(\n", + " file_path=config.data_path,\n", + " domain_config=domain_config,\n", + " auto_map=True,\n", + " sheet_name=config.sheet_name,\n", + ")\n", + "\n", + "print(quality_report.summary())\n", + "if not quality_report.passed:\n", + " raise ValueError(\"Data quality checks failed. Fix input data and rerun.\")\n", + "\n", + "print(\"Raw shape:\", df_raw.shape)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7e4bf552", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:49:51,888 | WARNING | segplus.feature_engineering | FE rule 'wealth_tier' failed: name 'investment_portfolio_value' is not defined\n", + "2026-03-06 22:49:51,902 | WARNING | segplus.feature_engineering | FE rule 'digital_vs_branch_ratio' failed: name 'digital_engagement_score' is not defined\n", + "2026-03-06 22:49:51,918 | WARNING | segplus.feature_engineering | FE rule 'product_depth' failed: name 'has_credit_card' is not defined\n", + "2026-03-06 22:49:51,926 | WARNING | segplus.feature_engineering | FE rule 'spending_to_income_ratio' failed: name 'monthly_spending' is not defined\n", + "2026-03-06 22:49:51,942 | WARNING | segplus.feature_engineering | FE rule 'risk_category' failed: name 'debt_to_income_ratio' is not defined\n", + "2026-03-06 22:49:52,618 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", + "2026-03-06 22:49:52,619 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Engineered dataframe shape: (120000, 26)\n", + "Model matrix shape used for clustering: (120000, 7)\n", + "Feature count used for clustering: 7\n", + "SHAP source feature count (original vars): 26\n", + "First SHAP source vars: ['month', 'monthly_spend_x', 'utilization_ratio_x', 'delinquency_flag_x', 'age', 'annual_income', 'risk_score', 'credit_score', 'digital_affinity', 'tenure_months']\n" + ] + } + ], + "source": [ + "# 2) Feature Engineering\n", + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "feature_engineer = FeatureEngineer(domain_config, config)\n", + "fe_result = feature_engineer.run(df_raw)\n", + "\n", + "# Original-variable matrix for SHAP (never PCA names)\n", + "original_feature_names_for_shap = fe_result.df_engineered.columns.tolist()\n", + "X_original_for_shap = StandardScaler().fit_transform(fe_result.df_engineered.values)\n", + "\n", + "# Optional latent representation via local autoencoder (if tensorflow is installed)\n", + "USE_AUTOENCODER_REPRESENTATION = False\n", + "AE_LATENT_DIM = 8\n", + "AE_EPOCHS = 40\n", + "AE_BATCH_SIZE = 256\n", + "\n", + "X = fe_result.X_scaled\n", + "feature_names = fe_result.feature_names\n", + "pca_for_explainability = fe_result.pca\n", + "\n", + "if USE_AUTOENCODER_REPRESENTATION:\n", + " try:\n", + " import tensorflow as tf\n", + " from tensorflow.keras import Model\n", + " from tensorflow.keras.layers import Dense, Input\n", + " from tensorflow.keras.callbacks import EarlyStopping\n", + "\n", + " tf.random.set_seed(config.random_state)\n", + " input_dim = X.shape[1]\n", + " latent_dim = max(2, min(AE_LATENT_DIM, input_dim - 1))\n", + "\n", + " inp = Input(shape=(input_dim,))\n", + " x = Dense(max(16, input_dim // 2), activation=\"relu\")(inp)\n", + " latent = Dense(latent_dim, activation=\"linear\", name=\"latent\")(x)\n", + " x = Dense(max(16, input_dim // 2), activation=\"relu\")(latent)\n", + " out = Dense(input_dim, activation=\"linear\")(x)\n", + "\n", + " autoencoder = Model(inp, out)\n", + " encoder = Model(inp, latent)\n", + " autoencoder.compile(optimizer=\"adam\", loss=\"mse\")\n", + " autoencoder.fit(\n", + " X,\n", + " X,\n", + " epochs=AE_EPOCHS,\n", + " batch_size=min(AE_BATCH_SIZE, len(X)),\n", + " verbose=0,\n", + " callbacks=[EarlyStopping(monitor=\"loss\", patience=5, restore_best_weights=True)],\n", + " )\n", + "\n", + " X = encoder.predict(X, verbose=0)\n", + " feature_names = [f\"AE{i+1}\" for i in range(X.shape[1])]\n", + " pca_for_explainability = None # PCA loadings no longer match AE latent space\n", + " print(f\"Autoencoder latent representation enabled: {X.shape}\")\n", + " except Exception as e:\n", + " print(f\"Autoencoder path unavailable ({e}); continuing with FE output.\")\n", + "\n", + "print(\"Engineered dataframe shape:\", fe_result.df_engineered.shape)\n", + "print(\"Model matrix shape used for clustering:\", X.shape)\n", + "print(\"Feature count used for clustering:\", len(feature_names))\n", + "print(\"SHAP source feature count (original vars):\", len(original_feature_names_for_shap))\n", + "print(\"First SHAP source vars:\", original_feature_names_for_shap[:10])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ca7f19aa", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:\n", + "[WinError 2] The system cannot find the file specified\n", + "Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.\n", + " warnings.warn(\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", + " cpu_info = subprocess.run(\n", + " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", + " capture_output=True,\n", + " text=True,\n", + " )\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", + " with Popen(*popenargs, **kwargs) as process:\n", + " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", + " self._execute_child(args, executable, preexec_fn, close_fds,\n", + " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " pass_fds, cwd, env,\n", + " ^^^^^^^^^^^^^^^^^^^\n", + " ...<5 lines>...\n", + " gid, gids, uid, umask,\n", + " ^^^^^^^^^^^^^^^^^^^^^^\n", + " start_new_session, process_group)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", + " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", + " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", + " # no special security\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " ...<4 lines>...\n", + " cwd,\n", + " ^^^^\n", + " startupinfo)\n", + " ^^^^^^^^^^^^\n", + "2026-03-06 22:49:58,214 | INFO | segplus.clustering | K search: scores={2: np.float64(0.202), 3: np.float64(0.2145), 4: np.float64(0.1609), 5: np.float64(0.1639), 6: np.float64(0.1444), 7: np.float64(0.1399), 8: np.float64(0.141)} | best k=3 (sil=0.2145)\n", + "2026-03-06 22:50:00,159 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", + "2026-03-06 22:50:00,161 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", + "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-06 22:50:00,815 | INFO | segplus.clustering | [kmeans] clusters=3\n", + "2026-03-06 22:50:25,748 | INFO | segplus.clustering | [dbscan] clusters=178\n", + "2026-03-06 22:50:44,501 | INFO | segplus.clustering | [gmm] clusters=3\n", + "2026-03-06 22:50:44,663 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2115 | DB=1.5251 | CH=31125.2 | cov=1.00\n", + "2026-03-06 22:50:44,946 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.2252 | DB=0.8652 | CH=142.0 | cov=1.00\n", + "2026-03-06 22:50:45,068 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0667 | DB=3.5552 | CH=13484.7 | cov=1.00\n", + "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", + "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", + "2026-03-06 22:50:45,072 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2115 pass=True\n", + "2026-03-06 22:50:45,073 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2115 | DB=1.5251 | PASS=True\n", + "2026-03-06 22:50:45,074 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Best algorithm: kmeans\n", + "Clusters: 3\n", + "Silhouette: 0.2115\n", + "Davies-Bouldin: 1.5251\n", + "Passes gate: True\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    iterationtimestampkepsgmm_covbest_algorithmn_clusterssilhouettedavies_bouldincalinski_harabaszpassedreconfig_strategy
    012026-03-06T22:50:45.07245831.661fullkmeans30.21151.525131125.2TrueNone
    \n", + "
    " + ], + "text/plain": [ + " iteration timestamp k eps gmm_cov best_algorithm \\\n", + "0 1 2026-03-06T22:50:45.072458 3 1.661 full kmeans \n", + "\n", + " n_clusters silhouette davies_bouldin calinski_harabasz passed \\\n", + "0 3 0.2115 1.5251 31125.2 True \n", + "\n", + " reconfig_strategy \n", + "0 None " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 3) Modeling Loop (KMeans + DBSCAN + GMM with reconfiguration)\n", + "experiment_log = ExperimentLog()\n", + "\n", + "best_eval, best_cfg = modeling_loop(\n", + " X=X,\n", + " feature_names=feature_names,\n", + " config=config,\n", + " experiment_log=experiment_log,\n", + ")\n", + "\n", + "print(\"Best algorithm:\", best_eval.algorithm)\n", + "print(\"Clusters:\", best_eval.n_clusters)\n", + "print(\"Silhouette:\", best_eval.silhouette)\n", + "print(\"Davies-Bouldin:\", best_eval.davies_bouldin)\n", + "print(\"Passes gate:\", best_eval.passes)\n", + "\n", + "exp_df = experiment_log.to_dataframe()\n", + "exp_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7e9bafbb", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:50:57,856 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", + "2026-03-06 22:50:57,859 | INFO | segplus.explainability | Computing feature importances...\n", + "2026-03-06 22:51:08,907 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", + "2026-03-06 22:51:08,940 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", + "2026-03-06 22:51:08,944 | INFO | segplus.explainability | Computing PCA loadings...\n", + "2026-03-06 22:51:08,945 | INFO | segplus.explainability | Computing inertia curve...\n", + "2026-03-06 22:51:12,627 | INFO | segplus.explainability | Computing cluster profiles...\n", + "2026-03-06 22:51:12,729 | INFO | segplus.explainability | Building ordered convergence drivers...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stability ARI mean: 0.988\n", + "Stability algorithm used: kmeans\n", + "Ordered top drivers: ['risk_score', 'risk_score_cluster', 'risk_behavior_score', 'delinquency_flag_y', 'credit_score', 'credit_score_cluster', 'monthly_spend_y', 'value_score', 'annual_income', 'log_income']\n", + "Top SHAP % (original variables):\n", + " credit_score: 19.58%\n", + " credit_score_cluster: 19.05%\n", + " risk_score: 9.32%\n", + " risk_score_cluster: 7.35%\n", + " risk_behavior_score: 6.92%\n", + " monthly_spend_y: 5.59%\n", + " delinquency_flag_y: 5.43%\n", + " value_score: 5.40%\n", + " monthly_spend_x: 3.53%\n", + " annual_income: 3.00%\n", + "PC to original feature map (top 5):\n", + " PC1: ['credit_score', 'credit_score_cluster', 'risk_score', 'risk_score_cluster', 'log_income']\n", + " PC2: ['value_score', 'monthly_spend_y', 'monthly_spend_x', 'lifetime_value_proxy', 'utilization_ratio_x']\n", + " PC3: ['age', 'age_cluster', 'digital_affinity_cluster', 'digital_affinity', 'delinquency_flag_y']\n", + " PC4: ['tenure_months', 'tenure_months_cluster', 'lifetime_value_proxy', 'utilization_ratio_x', 'utilization_ratio_y']\n", + " PC5: ['annual_income', 'annual_income_cluster', 'log_income', 'delinquency_flag_y', 'risk_behavior_score']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    featureshap_importancepca_weighted_loadingshap_rankpca_rankshap_rank_normpca_rank_norminertia_elbow_strengthconvergence_score
    0risk_score0.093210.1696243.03.50.920.90158504.1408420.912
    1risk_score_cluster0.073450.1696244.03.50.880.90158504.1408420.888
    2risk_behavior_score0.069180.1701175.02.00.840.96158504.1408420.888
    3delinquency_flag_y0.054290.1702847.01.00.761.00158504.1408420.856
    4credit_score0.195770.1500411.012.51.000.54158504.1408420.816
    5credit_score_cluster0.190510.1500412.012.50.960.54158504.1408420.792
    6monthly_spend_y0.055910.1504126.010.50.800.62158504.1408420.728
    7value_score0.053970.1504128.010.50.720.62158504.1408420.680
    8annual_income0.030040.15700110.08.00.640.72158504.1408420.672
    9log_income0.029880.15923811.07.00.600.76158504.1408420.664
    10utilization_ratio_y0.028070.16146912.06.00.560.80158504.1408420.656
    11monthly_spend_x0.035330.1490169.014.00.680.48158504.1408420.600
    12utilization_ratio_x0.020780.16152515.05.00.440.84158504.1408420.600
    13annual_income_cluster0.027650.15700113.09.00.520.68158504.1408420.584
    14lifetime_value_proxy0.024850.14514214.015.00.480.44158504.1408420.464
    \n", + "
    " + ], + "text/plain": [ + " feature shap_importance pca_weighted_loading shap_rank \\\n", + "0 risk_score 0.09321 0.169624 3.0 \n", + "1 risk_score_cluster 0.07345 0.169624 4.0 \n", + "2 risk_behavior_score 0.06918 0.170117 5.0 \n", + "3 delinquency_flag_y 0.05429 0.170284 7.0 \n", + "4 credit_score 0.19577 0.150041 1.0 \n", + "5 credit_score_cluster 0.19051 0.150041 2.0 \n", + "6 monthly_spend_y 0.05591 0.150412 6.0 \n", + "7 value_score 0.05397 0.150412 8.0 \n", + "8 annual_income 0.03004 0.157001 10.0 \n", + "9 log_income 0.02988 0.159238 11.0 \n", + "10 utilization_ratio_y 0.02807 0.161469 12.0 \n", + "11 monthly_spend_x 0.03533 0.149016 9.0 \n", + "12 utilization_ratio_x 0.02078 0.161525 15.0 \n", + "13 annual_income_cluster 0.02765 0.157001 13.0 \n", + "14 lifetime_value_proxy 0.02485 0.145142 14.0 \n", + "\n", + " pca_rank shap_rank_norm pca_rank_norm inertia_elbow_strength \\\n", + "0 3.5 0.92 0.90 158504.140842 \n", + "1 3.5 0.88 0.90 158504.140842 \n", + "2 2.0 0.84 0.96 158504.140842 \n", + "3 1.0 0.76 1.00 158504.140842 \n", + "4 12.5 1.00 0.54 158504.140842 \n", + "5 12.5 0.96 0.54 158504.140842 \n", + "6 10.5 0.80 0.62 158504.140842 \n", + "7 10.5 0.72 0.62 158504.140842 \n", + "8 8.0 0.64 0.72 158504.140842 \n", + "9 7.0 0.60 0.76 158504.140842 \n", + "10 6.0 0.56 0.80 158504.140842 \n", + "11 14.0 0.68 0.48 158504.140842 \n", + "12 5.0 0.44 0.84 158504.140842 \n", + "13 9.0 0.52 0.68 158504.140842 \n", + "14 15.0 0.48 0.44 158504.140842 \n", + "\n", + " convergence_score \n", + "0 0.912 \n", + "1 0.888 \n", + "2 0.888 \n", + "3 0.856 \n", + "4 0.816 \n", + "5 0.792 \n", + "6 0.728 \n", + "7 0.680 \n", + "8 0.672 \n", + "9 0.664 \n", + "10 0.656 \n", + "11 0.600 \n", + "12 0.600 \n", + "13 0.584 \n", + "14 0.464 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 4) Stability + Explainability\n", + "stability = run_stability_test(\n", + " X=X,\n", + " labels=best_eval.labels,\n", + " n_clusters=best_eval.n_clusters,\n", + " config=config,\n", + " algorithm=best_eval.algorithm,\n", + " model=best_eval.model,\n", + ")\n", + "\n", + "explainability = build_explainability_report(\n", + " X=X,\n", + " labels=best_eval.labels,\n", + " feature_names=feature_names,\n", + " df_raw=fe_result.df_engineered,\n", + " pca=pca_for_explainability,\n", + " k_range=config.k_range,\n", + " random_state=config.random_state,\n", + " n_top=config.n_top_features,\n", + " X_original=X_original_for_shap,\n", + " original_feature_names=original_feature_names_for_shap,\n", + ")\n", + "\n", + "print(\"Stability ARI mean:\", stability.ari_mean)\n", + "print(\"Stability algorithm used:\", best_eval.algorithm)\n", + "print(\"Ordered top drivers:\", explainability.top_features[:10])\n", + "print(\"Top SHAP % (original variables):\")\n", + "for k, v in list(explainability.feature_importance_pct.items())[:10]:\n", + " print(f\" {k}: {v:.2f}%\")\n", + "\n", + "print(\"PC to original feature map (top 5):\")\n", + "for pc, cols in list(explainability.pc_feature_map.items())[:5]:\n", + " print(f\" {pc}: {cols}\")\n", + "\n", + "explainability.ordered_feature_drivers.head(15)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "000fb2d4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installed Ollama models: ['qwen2.5:7b']\n", + "Selected model tag: qwen2.5:7b\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:51:17,003 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", + "2026-03-06 22:53:19,121 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 22:54:37,832 | INFO | segplus.ollama_client | Ollama response received (534 chars)\n", + "2026-03-06 22:55:12,181 | INFO | segplus.ollama_client | Ollama response received (14 chars)\n", + "2026-03-06 22:55:12,184 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'Elite Spenders'\n", + "2026-03-06 22:55:12,202 | INFO | segplus.persona_generation | Persona generated: Cluster A -> Elite Spenders\n", + "2026-03-06 22:57:14,441 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 22:57:55,579 | INFO | segplus.ollama_client | Ollama response received (551 chars)\n", + "2026-03-06 22:58:37,127 | INFO | segplus.ollama_client | Ollama response received (17 chars)\n", + "2026-03-06 22:58:37,130 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", + "2026-03-06 23:00:39,228 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 23:02:14,255 | INFO | segplus.ollama_client | Ollama response received (839 chars)\n", + "2026-03-06 23:02:50,674 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", + "2026-03-06 23:02:50,678 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", + "2026-03-06 23:02:50,721 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", + "2026-03-06 23:04:52,791 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 23:06:56,881 | WARNING | segplus.ollama_client | Ollama attempt 2 failed (Timeout after 120s). Retrying in 4s...\n", + "2026-03-06 23:09:02,941 | WARNING | segplus.persona_generation | Business grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generated personas: 3\n", + "Executive summary: LLM grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n", + "persona_df columns: ['cluster', 'genai_persona_name', 'profile_descriptor', 'description', 'cluster_size', 'cluster_pct', 'ordered_top_features', 'genai_recommendations', 'categorization_basis', 'naming_rationale']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    clustergenai_persona_nameprofile_descriptordescriptioncluster_sizecluster_pctordered_top_featuresgenai_recommendationscategorization_basisnaming_rationale
    0Cluster AElite SpendersHigh Value Score & High Monthly Spend YHigh-Value Premium Spenders are among the most...87740.0731value_score:0.1, monthly_spend_y:25414.84, mon...Targeted Upselling of Premium Products | Perso...value_score, monthly_spend_y, monthly_spend_x,...Second-pass focused LLM naming from profile: H...
    1Cluster BCredit Risk Strategists – Higher Credit Score ...High Credit Score & Low Risk ScoreThese customers are highly creditworthy and lo...567820.4732credit_score:827.07, credit_score_cluster:827....Target with premium product promotions | Enhan...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    2Cluster CCredit Risk Strategists – Lower Credit Score C...Low Credit Score & High Risk ScoreBudget-conscious Credit Risk Takers are custom...544440.4537credit_score:692.54, credit_score_cluster:692....Offer tailored credit products with flexible t...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    \n", + "
    " + ], + "text/plain": [ + " cluster genai_persona_name \\\n", + "0 Cluster A Elite Spenders \n", + "1 Cluster B Credit Risk Strategists – Higher Credit Score ... \n", + "2 Cluster C Credit Risk Strategists – Lower Credit Score C... \n", + "\n", + " profile_descriptor \\\n", + "0 High Value Score & High Monthly Spend Y \n", + "1 High Credit Score & Low Risk Score \n", + "2 Low Credit Score & High Risk Score \n", + "\n", + " description cluster_size \\\n", + "0 High-Value Premium Spenders are among the most... 8774 \n", + "1 These customers are highly creditworthy and lo... 56782 \n", + "2 Budget-conscious Credit Risk Takers are custom... 54444 \n", + "\n", + " cluster_pct ordered_top_features \\\n", + "0 0.0731 value_score:0.1, monthly_spend_y:25414.84, mon... \n", + "1 0.4732 credit_score:827.07, credit_score_cluster:827.... \n", + "2 0.4537 credit_score:692.54, credit_score_cluster:692.... \n", + "\n", + " genai_recommendations \\\n", + "0 Targeted Upselling of Premium Products | Perso... \n", + "1 Target with premium product promotions | Enhan... \n", + "2 Offer tailored credit products with flexible t... \n", + "\n", + " categorization_basis \\\n", + "0 value_score, monthly_spend_y, monthly_spend_x,... \n", + "1 credit_score, credit_score_cluster, risk_score... \n", + "2 credit_score, credit_score_cluster, risk_score... \n", + "\n", + " naming_rationale \n", + "0 Second-pass focused LLM naming from profile: H... \n", + "1 LLM returned generic name; using business-styl... \n", + "2 LLM returned generic name; using business-styl... " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 5) Persona Generation + Business Grounding (Ollama local, with fallback)\n", + "import requests\n", + "\n", + "\n", + "def _list_local_ollama_models(host: str) -> list[str]:\n", + " try:\n", + " r = requests.get(f\"{host.rstrip('/')}/api/tags\", timeout=8)\n", + " r.raise_for_status()\n", + " return [m.get(\"name\", \"\") for m in r.json().get(\"models\", []) if m.get(\"name\")]\n", + " except Exception as e:\n", + " print(f\"Ollama model discovery failed: {e}\")\n", + " return []\n", + "\n", + "\n", + "def _choose_ollama_model(installed: list[str], preferred: list[str], configured: str) -> str:\n", + " if configured and configured in installed:\n", + " return configured\n", + " if configured:\n", + " matches = [m for m in installed if configured in m]\n", + " if matches:\n", + " return matches[0]\n", + " for pref in preferred:\n", + " matches = [m for m in installed if m.startswith(pref) or pref in m]\n", + " if matches:\n", + " return matches[0]\n", + " return installed[0] if installed else (configured or \"qwen2.5:7b\")\n", + "\n", + "\n", + "installed_models = _list_local_ollama_models(config.ollama_host)\n", + "selected_model = _choose_ollama_model(installed_models, PREFERRED_OLLAMA_MODELS, config.ollama_model)\n", + "config.ollama_model = selected_model\n", + "\n", + "print(\"Installed Ollama models:\", installed_models if installed_models else \"None found / Ollama offline\")\n", + "print(\"Selected model tag:\", config.ollama_model)\n", + "\n", + "ollama_client = OllamaClient(\n", + " host=config.ollama_host,\n", + " model=config.ollama_model,\n", + " timeout=config.ollama_timeout,\n", + ")\n", + "persona_generator = PersonaGenerator(ollama_client, config)\n", + "\n", + "# Step A: Cluster personas\n", + "personas = persona_generator.generate_personas(\n", + " evaluation=best_eval,\n", + " explainability=explainability,\n", + " raw_df=fe_result.df_original,\n", + " schema=schema,\n", + ")\n", + "\n", + "# Step B: Business grounding + GenAI per-cluster naming/actions\n", + "grounding = persona_generator.ground_in_business_objective(personas)\n", + "personas = persona_generator.apply_grounding_to_personas(personas, grounding)\n", + "\n", + "persona_df = pd.DataFrame([\n", + " {\n", + " \"cluster\": p.persona_name,\n", + " \"genai_persona_name\": p.archetype,\n", + " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", + " \"description\": getattr(p, \"description\", \"\"),\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": round(p.cluster_pct, 4),\n", + " \"ordered_top_features\": \", \".join([f\"{k}:{v}\" for k, v in p.top_features.items()]),\n", + " \"genai_recommendations\": \" | \".join(p.business_recommendations),\n", + " \"categorization_basis\": \", \".join(getattr(p, \"categorization_basis\", [])),\n", + " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", + " }\n", + " for p in personas\n", + "])\n", + "\n", + "# Exact output schema check\n", + "required_persona_cols = [\n", + " \"cluster\", \"genai_persona_name\", \"profile_descriptor\", \"description\",\n", + " \"cluster_size\", \"cluster_pct\", \"ordered_top_features\",\n", + " \"genai_recommendations\", \"categorization_basis\", \"naming_rationale\",\n", + "]\n", + "missing_cols = [c for c in required_persona_cols if c not in persona_df.columns]\n", + "if missing_cols:\n", + " raise ValueError(f\"persona_df missing required columns: {missing_cols}\")\n", + "\n", + "print(\"Generated personas:\", len(personas))\n", + "print(\"Executive summary:\", grounding.executive_summary)\n", + "print(\"persona_df columns:\", list(persona_df.columns))\n", + "persona_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "707cdc91", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 23:09:06,354 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", + "2026-03-06 23:09:06,629 | INFO | segplus.visualization | Saved: feature_importance.png\n", + "2026-03-06 23:09:38,632 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", + "2026-03-06 23:09:39,175 | INFO | segplus.visualization | Saved: pca_loadings.png\n", + "2026-03-06 23:09:39,422 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", + "2026-03-06 23:09:39,526 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", + "2026-03-06 23:09:40,057 | INFO | segplus.visualization | Saved: persona_radar.png\n", + "2026-03-06 23:09:40,212 | INFO | segplus.visualization | Saved: experiment_history.png\n", + "2026-03-06 23:09:40,356 | INFO | segplus.visualization | Saved: elbow_curve.png\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved charts to: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n" + ] + } + ], + "source": [ + "# 6) Visualizations\n", + "plot_cluster_scatter_2d(X, best_eval.labels, output_dir, best_eval)\n", + "plot_shap_importance(\n", + " explainability.feature_importances, output_dir, top_n=15,\n", + " importance_pct=explainability.feature_importance_pct,\n", + ")\n", + "plot_shap_summary(\n", + " X_original_for_shap,\n", + " best_eval.labels,\n", + " original_feature_names_for_shap,\n", + " output_dir,\n", + " random_state=config.random_state,\n", + " max_display=15,\n", + ")\n", + "plot_pca_loadings_heatmap(explainability.pca_loadings, output_dir)\n", + "plot_cluster_profiles_heatmap(explainability.cluster_profiles, explainability.top_features, output_dir)\n", + "plot_cluster_sizes(best_eval.labels, personas, output_dir)\n", + "plot_radar_charts(fe_result.df_original, best_eval.labels, personas, explainability.top_features, output_dir)\n", + "plot_experiment_history(experiment_log, output_dir)\n", + "plot_elbow_curve(explainability.inertia_curve, output_dir)\n", + "\n", + "print(\"Saved charts to:\", output_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "969da7d8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 23:09:42,767 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exported:\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\clustered_customers.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\cluster_profiles.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\ordered_feature_drivers.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\shap_feature_importance_pct.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\pc_feature_map.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\business_grounding.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + ] + } + ], + "source": [ + "# 7) Export Outputs\n", + "clustered_df = fe_result.df_original.copy()\n", + "clustered_df[\"cluster\"] = best_eval.labels\n", + "\n", + "clustered_path = output_dir / \"clustered_customers.csv\"\n", + "profiles_path = output_dir / \"cluster_profiles.csv\"\n", + "ordered_drivers_path = output_dir / \"ordered_feature_drivers.csv\"\n", + "shap_pct_path = output_dir / \"shap_feature_importance_pct.csv\"\n", + "pc_feature_map_path = output_dir / \"pc_feature_map.json\"\n", + "personas_path = output_dir / \"personas.csv\"\n", + "personas_json_path = output_dir / \"personas.json\"\n", + "grounding_path = output_dir / \"business_grounding.json\"\n", + "exp_log_path = output_dir / \"experiment_log.json\"\n", + "\n", + "clustered_df.to_csv(clustered_path, index=False)\n", + "explainability.cluster_profiles.to_csv(profiles_path)\n", + "if explainability.ordered_feature_drivers is not None:\n", + " explainability.ordered_feature_drivers.to_csv(ordered_drivers_path, index=False)\n", + "\n", + "shap_pct_df = pd.DataFrame([\n", + " {\"feature\": k, \"importance_pct\": v}\n", + " for k, v in explainability.feature_importance_pct.items()\n", + "]).sort_values(\"importance_pct\", ascending=False)\n", + "shap_pct_df.to_csv(shap_pct_path, index=False)\n", + "\n", + "with open(pc_feature_map_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(explainability.pc_feature_map, f, indent=2)\n", + "\n", + "# Export exact persona schema\n", + "persona_df.to_csv(personas_path, index=False)\n", + "\n", + "personas_payload = [\n", + " {\n", + " \"cluster\": p.persona_name,\n", + " \"genai_persona_name\": p.archetype,\n", + " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", + " \"description\": getattr(p, \"description\", \"\"),\n", + " \"key_traits\": p.key_traits,\n", + " \"genai_recommendations\": p.business_recommendations,\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": p.cluster_pct,\n", + " \"top_features\": p.top_features,\n", + " \"categorization_basis\": getattr(p, \"categorization_basis\", []),\n", + " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", + " }\n", + " for p in personas\n", + "]\n", + "with open(personas_json_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(personas_payload, f, indent=2)\n", + "\n", + "experiment_log.to_json(exp_log_path)\n", + "\n", + "with open(grounding_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(\n", + " {\n", + " \"executive_summary\": grounding.executive_summary,\n", + " \"cluster_priorities\": grounding.cluster_priorities,\n", + " \"cluster_actions\": grounding.cluster_actions,\n", + " \"quick_wins\": grounding.quick_wins,\n", + " },\n", + " f,\n", + " indent=2,\n", + " )\n", + "\n", + "print(\"Exported:\")\n", + "print(\" -\", clustered_path)\n", + "print(\" -\", profiles_path)\n", + "print(\" -\", ordered_drivers_path)\n", + "print(\" -\", shap_pct_path)\n", + "print(\" -\", pc_feature_map_path)\n", + "print(\" -\", personas_path)\n", + "print(\" -\", personas_json_path)\n", + "print(\" -\", grounding_path)\n", + "print(\" -\", exp_log_path)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notes\n", + "\n", + "- Architecture implemented: data input -> FE -> KMeans/DBSCAN/GMM -> eval gate loop -> explainability -> ordered drivers -> persona generation -> business grounding -> per-cluster rationale outputs.\n", + "- Local Ollama is first-class. `qwen2.5` is primary model and auto-selected when installed.\n", + "- Ordered feature driver list combines SHAP importance + weighted PCA loadings, with inertia elbow context.\n", + "- `pc_feature_map.json` provides exact mapping from each PC to top original variables.\n", + "- SHAP summary plot is saved as `shap_summary.png` when `shap` is installed.\n", + "- Optional autoencoder latent representation is available via `USE_AUTOENCODER_REPRESENTATION=True`.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.x" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/segplus/final_segplus_pipeline2.ipynb b/segplus/final_segplus_pipeline2.ipynb new file mode 100644 index 0000000..d2b827e --- /dev/null +++ b/segplus/final_segplus_pipeline2.ipynb @@ -0,0 +1,1295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SegPlus Final End-to-End Pipeline\n", + "\n", + "This notebook runs the full architecture:\n", + "- Data input and validation\n", + "- Feature engineering\n", + "- KMeans + DBSCAN + GMM modeling loop\n", + "- Cluster evaluation + stability\n", + "- Explainability (feature drivers, PCA loadings, profiles)\n", + "- Persona generation and business grounding (Ollama with fallback)\n", + "- Visualization and export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "64579db4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Missing required: ['scikit-learn', 'pyyaml']\n", + "Missing optional: []\n" + ] + } + ], + "source": [ + "# Optional dependency installer/check\n", + "import importlib\n", + "import subprocess\n", + "import sys\n", + "\n", + "REQUIRED_PACKAGES = [\n", + " \"numpy\", \"pandas\", \"scikit-learn\", \"matplotlib\", \"seaborn\",\n", + " \"pyyaml\", \"openpyxl\", \"requests\", \"scipy\"\n", + "]\n", + "OPTIONAL_PACKAGES = [\"shap\"]\n", + "AUTO_INSTALL_MISSING = False # set True if you want notebook to install missing packages\n", + "\n", + "missing_required = []\n", + "missing_optional = []\n", + "\n", + "for pkg in REQUIRED_PACKAGES:\n", + " mod = pkg.replace(\"-\", \"_\")\n", + " try:\n", + " importlib.import_module(mod)\n", + " except Exception:\n", + " missing_required.append(pkg)\n", + "\n", + "for pkg in OPTIONAL_PACKAGES:\n", + " try:\n", + " importlib.import_module(pkg)\n", + " except Exception:\n", + " missing_optional.append(pkg)\n", + "\n", + "print(\"Missing required:\", missing_required)\n", + "print(\"Missing optional:\", missing_optional)\n", + "\n", + "if missing_required and AUTO_INSTALL_MISSING:\n", + " cmd = [sys.executable, \"-m\", \"pip\", \"install\", *missing_required]\n", + " print(\"Installing:\", \" \".join(missing_required))\n", + " subprocess.check_call(cmd)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "32c77bb2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Project root: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\n" + ] + } + ], + "source": [ + "import logging\n", + "import json\n", + "from pathlib import Path\n", + "import sys\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# Ensure project root is importable when notebook is inside segplus/\n", + "cwd = Path.cwd()\n", + "project_root = cwd.parent if cwd.name.lower() == \"segplus\" else cwd\n", + "if str(project_root) not in sys.path:\n", + " sys.path.insert(0, str(project_root))\n", + "\n", + "from segplus.config import PipelineConfig, load_domain_config\n", + "from segplus.data_input import import_and_validate\n", + "from segplus.feature_engineering import FeatureEngineer\n", + "from segplus.modeling_loop import modeling_loop\n", + "from segplus.evaluation import run_stability_test\n", + "from segplus.experiment_log import ExperimentLog\n", + "from segplus.explainability import build_explainability_report\n", + "from segplus.ollama_client import OllamaClient\n", + "from segplus.persona_generation import PersonaGenerator\n", + "from segplus.visualization import (\n", + " plot_cluster_scatter_2d,\n", + " plot_shap_importance,\n", + " plot_shap_summary,\n", + " plot_pca_loadings_heatmap,\n", + " plot_cluster_profiles_heatmap,\n", + " plot_cluster_sizes,\n", + " plot_radar_charts,\n", + " plot_experiment_history,\n", + " plot_elbow_curve,\n", + ")\n", + "\n", + "logging.basicConfig(\n", + " level=logging.INFO,\n", + " format=\"%(asctime)s | %(levelname)-8s | %(name)-30s | %(message)s\",\n", + ")\n", + "\n", + "print(\"Project root:\", project_root)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e0196175", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Domain: Financial Services\n", + "Data: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\final_enterprise_clustering_dataset_single_sheet.xlsx\n", + "Output: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n", + "Ollama host: http://localhost:11434\n", + "Primary LLM: qwen2.5:7b\n" + ] + } + ], + "source": [ + "# Configuration (edit these as needed)\n", + "default_data_path = project_root / \"final_enterprise_clustering_dataset_single_sheet.xlsx\"\n", + "default_output_dir = project_root / \"segplus_output\"\n", + "\n", + "config = PipelineConfig(\n", + " data_path=str(default_data_path),\n", + " domain_key=\"financial_services\", # or \"retail\"\n", + " sheet_name=None,\n", + " k_range=(2, 8),\n", + " max_iterations=5,\n", + " pca_variance_threshold=0.85,\n", + " output_dir=str(default_output_dir),\n", + " ollama_host=\"http://localhost:11434\", # local Ollama endpoint\n", + " ollama_model=\"qwen2.5:7b\", # primary local model`n ollama_timeout=240,\n", + " business_objective=(\n", + " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", + " \"improve retention for high-value customers, and convert mid-tier customers \"\n", + " \"to premium products.\"\n", + " ),\n", + ")\n", + "\n", + "# Preferred model order for local Ollama auto-selection\n", + "PREFERRED_OLLAMA_MODELS = [\n", + " \"qwen2.5\",\n", + " \"qwen2\",\n", + " \"llama3.2\",\n", + " \"llama3.1\",\n", + " \"llama3\",\n", + " \"mistral\",\n", + "]\n", + "\n", + "output_dir = Path(config.output_dir)\n", + "output_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + "domain_config = load_domain_config(config.domain_key, domains_dir=project_root / \"domains\")\n", + "print(\"Domain:\", domain_config.display_name)\n", + "print(\"Data:\", config.data_path)\n", + "print(\"Output:\", output_dir)\n", + "print(\"Ollama host:\", config.ollama_host)\n", + "print(\"Primary LLM:\", config.ollama_model)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "85b24976", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:49:51,635 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n", + "2026-03-06 22:49:51,833 | INFO | segplus.data_input | Data quality: PASSED\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Data Quality Report\n", + " Rows: 120,000 | Columns: 27\n", + " Duplicates: 0\n", + " Status: PASSED\n", + "Raw shape: (120000, 27)\n" + ] + } + ], + "source": [ + "# 1) Data Input + Validation\n", + "df_raw, quality_report, schema = import_and_validate(\n", + " file_path=config.data_path,\n", + " domain_config=domain_config,\n", + " auto_map=True,\n", + " sheet_name=config.sheet_name,\n", + ")\n", + "\n", + "print(quality_report.summary())\n", + "if not quality_report.passed:\n", + " raise ValueError(\"Data quality checks failed. Fix input data and rerun.\")\n", + "\n", + "print(\"Raw shape:\", df_raw.shape)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7e4bf552", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:49:51,888 | WARNING | segplus.feature_engineering | FE rule 'wealth_tier' failed: name 'investment_portfolio_value' is not defined\n", + "2026-03-06 22:49:51,902 | WARNING | segplus.feature_engineering | FE rule 'digital_vs_branch_ratio' failed: name 'digital_engagement_score' is not defined\n", + "2026-03-06 22:49:51,918 | WARNING | segplus.feature_engineering | FE rule 'product_depth' failed: name 'has_credit_card' is not defined\n", + "2026-03-06 22:49:51,926 | WARNING | segplus.feature_engineering | FE rule 'spending_to_income_ratio' failed: name 'monthly_spending' is not defined\n", + "2026-03-06 22:49:51,942 | WARNING | segplus.feature_engineering | FE rule 'risk_category' failed: name 'debt_to_income_ratio' is not defined\n", + "2026-03-06 22:49:52,618 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", + "2026-03-06 22:49:52,619 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Engineered dataframe shape: (120000, 26)\n", + "Model matrix shape used for clustering: (120000, 7)\n", + "Feature count used for clustering: 7\n", + "SHAP source feature count (original vars): 26\n", + "First SHAP source vars: ['month', 'monthly_spend_x', 'utilization_ratio_x', 'delinquency_flag_x', 'age', 'annual_income', 'risk_score', 'credit_score', 'digital_affinity', 'tenure_months']\n" + ] + } + ], + "source": [ + "# 2) Feature Engineering\n", + "from sklearn.preprocessing import StandardScaler\n", + "\n", + "feature_engineer = FeatureEngineer(domain_config, config)\n", + "fe_result = feature_engineer.run(df_raw)\n", + "\n", + "# Original-variable matrix for SHAP (never PCA names)\n", + "original_feature_names_for_shap = fe_result.df_engineered.columns.tolist()\n", + "X_original_for_shap = StandardScaler().fit_transform(fe_result.df_engineered.values)\n", + "\n", + "# Optional latent representation via local autoencoder (if tensorflow is installed)\n", + "USE_AUTOENCODER_REPRESENTATION = False\n", + "AE_LATENT_DIM = 8\n", + "AE_EPOCHS = 40\n", + "AE_BATCH_SIZE = 256\n", + "\n", + "X = fe_result.X_scaled\n", + "feature_names = fe_result.feature_names\n", + "pca_for_explainability = fe_result.pca\n", + "\n", + "if USE_AUTOENCODER_REPRESENTATION:\n", + " try:\n", + " import tensorflow as tf\n", + " from tensorflow.keras import Model\n", + " from tensorflow.keras.layers import Dense, Input\n", + " from tensorflow.keras.callbacks import EarlyStopping\n", + "\n", + " tf.random.set_seed(config.random_state)\n", + " input_dim = X.shape[1]\n", + " latent_dim = max(2, min(AE_LATENT_DIM, input_dim - 1))\n", + "\n", + " inp = Input(shape=(input_dim,))\n", + " x = Dense(max(16, input_dim // 2), activation=\"relu\")(inp)\n", + " latent = Dense(latent_dim, activation=\"linear\", name=\"latent\")(x)\n", + " x = Dense(max(16, input_dim // 2), activation=\"relu\")(latent)\n", + " out = Dense(input_dim, activation=\"linear\")(x)\n", + "\n", + " autoencoder = Model(inp, out)\n", + " encoder = Model(inp, latent)\n", + " autoencoder.compile(optimizer=\"adam\", loss=\"mse\")\n", + " autoencoder.fit(\n", + " X,\n", + " X,\n", + " epochs=AE_EPOCHS,\n", + " batch_size=min(AE_BATCH_SIZE, len(X)),\n", + " verbose=0,\n", + " callbacks=[EarlyStopping(monitor=\"loss\", patience=5, restore_best_weights=True)],\n", + " )\n", + "\n", + " X = encoder.predict(X, verbose=0)\n", + " feature_names = [f\"AE{i+1}\" for i in range(X.shape[1])]\n", + " pca_for_explainability = None # PCA loadings no longer match AE latent space\n", + " print(f\"Autoencoder latent representation enabled: {X.shape}\")\n", + " except Exception as e:\n", + " print(f\"Autoencoder path unavailable ({e}); continuing with FE output.\")\n", + "\n", + "print(\"Engineered dataframe shape:\", fe_result.df_engineered.shape)\n", + "print(\"Model matrix shape used for clustering:\", X.shape)\n", + "print(\"Feature count used for clustering:\", len(feature_names))\n", + "print(\"SHAP source feature count (original vars):\", len(original_feature_names_for_shap))\n", + "print(\"First SHAP source vars:\", original_feature_names_for_shap[:10])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ca7f19aa", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:\n", + "[WinError 2] The system cannot find the file specified\n", + "Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.\n", + " warnings.warn(\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", + " cpu_info = subprocess.run(\n", + " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", + " capture_output=True,\n", + " text=True,\n", + " )\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", + " with Popen(*popenargs, **kwargs) as process:\n", + " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", + " self._execute_child(args, executable, preexec_fn, close_fds,\n", + " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " pass_fds, cwd, env,\n", + " ^^^^^^^^^^^^^^^^^^^\n", + " ...<5 lines>...\n", + " gid, gids, uid, umask,\n", + " ^^^^^^^^^^^^^^^^^^^^^^\n", + " start_new_session, process_group)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", + " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", + " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", + " # no special security\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " ...<4 lines>...\n", + " cwd,\n", + " ^^^^\n", + " startupinfo)\n", + " ^^^^^^^^^^^^\n", + "2026-03-06 22:49:58,214 | INFO | segplus.clustering | K search: scores={2: np.float64(0.202), 3: np.float64(0.2145), 4: np.float64(0.1609), 5: np.float64(0.1639), 6: np.float64(0.1444), 7: np.float64(0.1399), 8: np.float64(0.141)} | best k=3 (sil=0.2145)\n", + "2026-03-06 22:50:00,159 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", + "2026-03-06 22:50:00,161 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", + "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-06 22:50:00,815 | INFO | segplus.clustering | [kmeans] clusters=3\n", + "2026-03-06 22:50:25,748 | INFO | segplus.clustering | [dbscan] clusters=178\n", + "2026-03-06 22:50:44,501 | INFO | segplus.clustering | [gmm] clusters=3\n", + "2026-03-06 22:50:44,663 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2115 | DB=1.5251 | CH=31125.2 | cov=1.00\n", + "2026-03-06 22:50:44,946 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.2252 | DB=0.8652 | CH=142.0 | cov=1.00\n", + "2026-03-06 22:50:45,068 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0667 | DB=3.5552 | CH=13484.7 | cov=1.00\n", + "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", + "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", + "2026-03-06 22:50:45,072 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2115 pass=True\n", + "2026-03-06 22:50:45,073 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2115 | DB=1.5251 | PASS=True\n", + "2026-03-06 22:50:45,074 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Best algorithm: kmeans\n", + "Clusters: 3\n", + "Silhouette: 0.2115\n", + "Davies-Bouldin: 1.5251\n", + "Passes gate: True\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    iterationtimestampkepsgmm_covbest_algorithmn_clusterssilhouettedavies_bouldincalinski_harabaszpassedreconfig_strategy
    012026-03-06T22:50:45.07245831.661fullkmeans30.21151.525131125.2TrueNone
    \n", + "
    " + ], + "text/plain": [ + " iteration timestamp k eps gmm_cov best_algorithm \\\n", + "0 1 2026-03-06T22:50:45.072458 3 1.661 full kmeans \n", + "\n", + " n_clusters silhouette davies_bouldin calinski_harabasz passed \\\n", + "0 3 0.2115 1.5251 31125.2 True \n", + "\n", + " reconfig_strategy \n", + "0 None " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 3) Modeling Loop (KMeans + DBSCAN + GMM with reconfiguration)\n", + "experiment_log = ExperimentLog()\n", + "\n", + "best_eval, best_cfg = modeling_loop(\n", + " X=X,\n", + " feature_names=feature_names,\n", + " config=config,\n", + " experiment_log=experiment_log,\n", + ")\n", + "\n", + "print(\"Best algorithm:\", best_eval.algorithm)\n", + "print(\"Clusters:\", best_eval.n_clusters)\n", + "print(\"Silhouette:\", best_eval.silhouette)\n", + "print(\"Davies-Bouldin:\", best_eval.davies_bouldin)\n", + "print(\"Passes gate:\", best_eval.passes)\n", + "\n", + "exp_df = experiment_log.to_dataframe()\n", + "exp_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7e9bafbb", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:50:57,856 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", + "2026-03-06 22:50:57,859 | INFO | segplus.explainability | Computing feature importances...\n", + "2026-03-06 22:51:08,907 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", + "2026-03-06 22:51:08,940 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", + "2026-03-06 22:51:08,944 | INFO | segplus.explainability | Computing PCA loadings...\n", + "2026-03-06 22:51:08,945 | INFO | segplus.explainability | Computing inertia curve...\n", + "2026-03-06 22:51:12,627 | INFO | segplus.explainability | Computing cluster profiles...\n", + "2026-03-06 22:51:12,729 | INFO | segplus.explainability | Building ordered convergence drivers...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Stability ARI mean: 0.988\n", + "Stability algorithm used: kmeans\n", + "Ordered top drivers: ['risk_score', 'risk_score_cluster', 'risk_behavior_score', 'delinquency_flag_y', 'credit_score', 'credit_score_cluster', 'monthly_spend_y', 'value_score', 'annual_income', 'log_income']\n", + "Top SHAP % (original variables):\n", + " credit_score: 19.58%\n", + " credit_score_cluster: 19.05%\n", + " risk_score: 9.32%\n", + " risk_score_cluster: 7.35%\n", + " risk_behavior_score: 6.92%\n", + " monthly_spend_y: 5.59%\n", + " delinquency_flag_y: 5.43%\n", + " value_score: 5.40%\n", + " monthly_spend_x: 3.53%\n", + " annual_income: 3.00%\n", + "PC to original feature map (top 5):\n", + " PC1: ['credit_score', 'credit_score_cluster', 'risk_score', 'risk_score_cluster', 'log_income']\n", + " PC2: ['value_score', 'monthly_spend_y', 'monthly_spend_x', 'lifetime_value_proxy', 'utilization_ratio_x']\n", + " PC3: ['age', 'age_cluster', 'digital_affinity_cluster', 'digital_affinity', 'delinquency_flag_y']\n", + " PC4: ['tenure_months', 'tenure_months_cluster', 'lifetime_value_proxy', 'utilization_ratio_x', 'utilization_ratio_y']\n", + " PC5: ['annual_income', 'annual_income_cluster', 'log_income', 'delinquency_flag_y', 'risk_behavior_score']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    featureshap_importancepca_weighted_loadingshap_rankpca_rankshap_rank_normpca_rank_norminertia_elbow_strengthconvergence_score
    0risk_score0.093210.1696243.03.50.920.90158504.1408420.912
    1risk_score_cluster0.073450.1696244.03.50.880.90158504.1408420.888
    2risk_behavior_score0.069180.1701175.02.00.840.96158504.1408420.888
    3delinquency_flag_y0.054290.1702847.01.00.761.00158504.1408420.856
    4credit_score0.195770.1500411.012.51.000.54158504.1408420.816
    5credit_score_cluster0.190510.1500412.012.50.960.54158504.1408420.792
    6monthly_spend_y0.055910.1504126.010.50.800.62158504.1408420.728
    7value_score0.053970.1504128.010.50.720.62158504.1408420.680
    8annual_income0.030040.15700110.08.00.640.72158504.1408420.672
    9log_income0.029880.15923811.07.00.600.76158504.1408420.664
    10utilization_ratio_y0.028070.16146912.06.00.560.80158504.1408420.656
    11monthly_spend_x0.035330.1490169.014.00.680.48158504.1408420.600
    12utilization_ratio_x0.020780.16152515.05.00.440.84158504.1408420.600
    13annual_income_cluster0.027650.15700113.09.00.520.68158504.1408420.584
    14lifetime_value_proxy0.024850.14514214.015.00.480.44158504.1408420.464
    \n", + "
    " + ], + "text/plain": [ + " feature shap_importance pca_weighted_loading shap_rank \\\n", + "0 risk_score 0.09321 0.169624 3.0 \n", + "1 risk_score_cluster 0.07345 0.169624 4.0 \n", + "2 risk_behavior_score 0.06918 0.170117 5.0 \n", + "3 delinquency_flag_y 0.05429 0.170284 7.0 \n", + "4 credit_score 0.19577 0.150041 1.0 \n", + "5 credit_score_cluster 0.19051 0.150041 2.0 \n", + "6 monthly_spend_y 0.05591 0.150412 6.0 \n", + "7 value_score 0.05397 0.150412 8.0 \n", + "8 annual_income 0.03004 0.157001 10.0 \n", + "9 log_income 0.02988 0.159238 11.0 \n", + "10 utilization_ratio_y 0.02807 0.161469 12.0 \n", + "11 monthly_spend_x 0.03533 0.149016 9.0 \n", + "12 utilization_ratio_x 0.02078 0.161525 15.0 \n", + "13 annual_income_cluster 0.02765 0.157001 13.0 \n", + "14 lifetime_value_proxy 0.02485 0.145142 14.0 \n", + "\n", + " pca_rank shap_rank_norm pca_rank_norm inertia_elbow_strength \\\n", + "0 3.5 0.92 0.90 158504.140842 \n", + "1 3.5 0.88 0.90 158504.140842 \n", + "2 2.0 0.84 0.96 158504.140842 \n", + "3 1.0 0.76 1.00 158504.140842 \n", + "4 12.5 1.00 0.54 158504.140842 \n", + "5 12.5 0.96 0.54 158504.140842 \n", + "6 10.5 0.80 0.62 158504.140842 \n", + "7 10.5 0.72 0.62 158504.140842 \n", + "8 8.0 0.64 0.72 158504.140842 \n", + "9 7.0 0.60 0.76 158504.140842 \n", + "10 6.0 0.56 0.80 158504.140842 \n", + "11 14.0 0.68 0.48 158504.140842 \n", + "12 5.0 0.44 0.84 158504.140842 \n", + "13 9.0 0.52 0.68 158504.140842 \n", + "14 15.0 0.48 0.44 158504.140842 \n", + "\n", + " convergence_score \n", + "0 0.912 \n", + "1 0.888 \n", + "2 0.888 \n", + "3 0.856 \n", + "4 0.816 \n", + "5 0.792 \n", + "6 0.728 \n", + "7 0.680 \n", + "8 0.672 \n", + "9 0.664 \n", + "10 0.656 \n", + "11 0.600 \n", + "12 0.600 \n", + "13 0.584 \n", + "14 0.464 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 4) Stability + Explainability\n", + "stability = run_stability_test(\n", + " X=X,\n", + " labels=best_eval.labels,\n", + " n_clusters=best_eval.n_clusters,\n", + " config=config,\n", + " algorithm=best_eval.algorithm,\n", + " model=best_eval.model,\n", + ")\n", + "\n", + "explainability = build_explainability_report(\n", + " X=X,\n", + " labels=best_eval.labels,\n", + " feature_names=feature_names,\n", + " df_raw=fe_result.df_engineered,\n", + " pca=pca_for_explainability,\n", + " k_range=config.k_range,\n", + " random_state=config.random_state,\n", + " n_top=config.n_top_features,\n", + " X_original=X_original_for_shap,\n", + " original_feature_names=original_feature_names_for_shap,\n", + ")\n", + "\n", + "print(\"Stability ARI mean:\", stability.ari_mean)\n", + "print(\"Stability algorithm used:\", best_eval.algorithm)\n", + "print(\"Ordered top drivers:\", explainability.top_features[:10])\n", + "print(\"Top SHAP % (original variables):\")\n", + "for k, v in list(explainability.feature_importance_pct.items())[:10]:\n", + " print(f\" {k}: {v:.2f}%\")\n", + "\n", + "print(\"PC to original feature map (top 5):\")\n", + "for pc, cols in list(explainability.pc_feature_map.items())[:5]:\n", + " print(f\" {pc}: {cols}\")\n", + "\n", + "explainability.ordered_feature_drivers.head(15)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "000fb2d4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installed Ollama models: ['qwen2.5:7b']\n", + "Selected model tag: qwen2.5:7b\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 22:51:17,003 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", + "2026-03-06 22:53:19,121 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 22:54:37,832 | INFO | segplus.ollama_client | Ollama response received (534 chars)\n", + "2026-03-06 22:55:12,181 | INFO | segplus.ollama_client | Ollama response received (14 chars)\n", + "2026-03-06 22:55:12,184 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'Elite Spenders'\n", + "2026-03-06 22:55:12,202 | INFO | segplus.persona_generation | Persona generated: Cluster A -> Elite Spenders\n", + "2026-03-06 22:57:14,441 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 22:57:55,579 | INFO | segplus.ollama_client | Ollama response received (551 chars)\n", + "2026-03-06 22:58:37,127 | INFO | segplus.ollama_client | Ollama response received (17 chars)\n", + "2026-03-06 22:58:37,130 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", + "2026-03-06 23:00:39,228 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 23:02:14,255 | INFO | segplus.ollama_client | Ollama response received (839 chars)\n", + "2026-03-06 23:02:50,674 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", + "2026-03-06 23:02:50,678 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", + "2026-03-06 23:02:50,721 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", + "2026-03-06 23:04:52,791 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", + "2026-03-06 23:06:56,881 | WARNING | segplus.ollama_client | Ollama attempt 2 failed (Timeout after 120s). Retrying in 4s...\n", + "2026-03-06 23:09:02,941 | WARNING | segplus.persona_generation | Business grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generated personas: 3\n", + "Executive summary: LLM grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n", + "persona_df columns: ['cluster', 'genai_persona_name', 'profile_descriptor', 'description', 'cluster_size', 'cluster_pct', 'ordered_top_features', 'genai_recommendations', 'categorization_basis', 'naming_rationale']\n" + ] + }, + { + "data": { + "text/html": [ + "
    \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    clustergenai_persona_nameprofile_descriptordescriptioncluster_sizecluster_pctordered_top_featuresgenai_recommendationscategorization_basisnaming_rationale
    0Cluster AElite SpendersHigh Value Score & High Monthly Spend YHigh-Value Premium Spenders are among the most...87740.0731value_score:0.1, monthly_spend_y:25414.84, mon...Targeted Upselling of Premium Products | Perso...value_score, monthly_spend_y, monthly_spend_x,...Second-pass focused LLM naming from profile: H...
    1Cluster BCredit Risk Strategists – Higher Credit Score ...High Credit Score & Low Risk ScoreThese customers are highly creditworthy and lo...567820.4732credit_score:827.07, credit_score_cluster:827....Target with premium product promotions | Enhan...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    2Cluster CCredit Risk Strategists – Lower Credit Score C...Low Credit Score & High Risk ScoreBudget-conscious Credit Risk Takers are custom...544440.4537credit_score:692.54, credit_score_cluster:692....Offer tailored credit products with flexible t...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    \n", + "
    " + ], + "text/plain": [ + " cluster genai_persona_name \\\n", + "0 Cluster A Elite Spenders \n", + "1 Cluster B Credit Risk Strategists – Higher Credit Score ... \n", + "2 Cluster C Credit Risk Strategists – Lower Credit Score C... \n", + "\n", + " profile_descriptor \\\n", + "0 High Value Score & High Monthly Spend Y \n", + "1 High Credit Score & Low Risk Score \n", + "2 Low Credit Score & High Risk Score \n", + "\n", + " description cluster_size \\\n", + "0 High-Value Premium Spenders are among the most... 8774 \n", + "1 These customers are highly creditworthy and lo... 56782 \n", + "2 Budget-conscious Credit Risk Takers are custom... 54444 \n", + "\n", + " cluster_pct ordered_top_features \\\n", + "0 0.0731 value_score:0.1, monthly_spend_y:25414.84, mon... \n", + "1 0.4732 credit_score:827.07, credit_score_cluster:827.... \n", + "2 0.4537 credit_score:692.54, credit_score_cluster:692.... \n", + "\n", + " genai_recommendations \\\n", + "0 Targeted Upselling of Premium Products | Perso... \n", + "1 Target with premium product promotions | Enhan... \n", + "2 Offer tailored credit products with flexible t... \n", + "\n", + " categorization_basis \\\n", + "0 value_score, monthly_spend_y, monthly_spend_x,... \n", + "1 credit_score, credit_score_cluster, risk_score... \n", + "2 credit_score, credit_score_cluster, risk_score... \n", + "\n", + " naming_rationale \n", + "0 Second-pass focused LLM naming from profile: H... \n", + "1 LLM returned generic name; using business-styl... \n", + "2 LLM returned generic name; using business-styl... " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 5) Persona Generation + Business Grounding (Ollama local, with fallback)\n", + "import requests\n", + "\n", + "\n", + "def _list_local_ollama_models(host: str) -> list[str]:\n", + " try:\n", + " r = requests.get(f\"{host.rstrip('/')}/api/tags\", timeout=8)\n", + " r.raise_for_status()\n", + " return [m.get(\"name\", \"\") for m in r.json().get(\"models\", []) if m.get(\"name\")]\n", + " except Exception as e:\n", + " print(f\"Ollama model discovery failed: {e}\")\n", + " return []\n", + "\n", + "\n", + "def _choose_ollama_model(installed: list[str], preferred: list[str], configured: str) -> str:\n", + " if configured and configured in installed:\n", + " return configured\n", + " if configured:\n", + " matches = [m for m in installed if configured in m]\n", + " if matches:\n", + " return matches[0]\n", + " for pref in preferred:\n", + " matches = [m for m in installed if m.startswith(pref) or pref in m]\n", + " if matches:\n", + " return matches[0]\n", + " return installed[0] if installed else (configured or \"qwen2.5:7b\")\n", + "\n", + "\n", + "installed_models = _list_local_ollama_models(config.ollama_host)\n", + "selected_model = _choose_ollama_model(installed_models, PREFERRED_OLLAMA_MODELS, config.ollama_model)\n", + "config.ollama_model = selected_model\n", + "\n", + "print(\"Installed Ollama models:\", installed_models if installed_models else \"None found / Ollama offline\")\n", + "print(\"Selected model tag:\", config.ollama_model)\n", + "\n", + "ollama_client = OllamaClient(\n", + " host=config.ollama_host,\n", + " model=config.ollama_model,\n", + " timeout=config.ollama_timeout,\n", + ")\n", + "persona_generator = PersonaGenerator(ollama_client, config)\n", + "\n", + "# Step A: Cluster personas\n", + "personas = persona_generator.generate_personas(\n", + " evaluation=best_eval,\n", + " explainability=explainability,\n", + " raw_df=fe_result.df_original,\n", + " schema=schema,\n", + ")\n", + "\n", + "# Step B: Business grounding + GenAI per-cluster naming/actions\n", + "grounding = persona_generator.ground_in_business_objective(personas)\n", + "personas = persona_generator.apply_grounding_to_personas(personas, grounding)\n", + "\n", + "persona_df = pd.DataFrame([\n", + " {\n", + " \"cluster\": p.persona_name,\n", + " \"genai_persona_name\": p.archetype,\n", + " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", + " \"description\": getattr(p, \"description\", \"\"),\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": round(p.cluster_pct, 4),\n", + " \"ordered_top_features\": \", \".join([f\"{k}:{v}\" for k, v in p.top_features.items()]),\n", + " \"genai_recommendations\": \" | \".join(p.business_recommendations),\n", + " \"categorization_basis\": \", \".join(getattr(p, \"categorization_basis\", [])),\n", + " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", + " }\n", + " for p in personas\n", + "])\n", + "\n", + "# Exact output schema check\n", + "required_persona_cols = [\n", + " \"cluster\", \"genai_persona_name\", \"profile_descriptor\", \"description\",\n", + " \"cluster_size\", \"cluster_pct\", \"ordered_top_features\",\n", + " \"genai_recommendations\", \"categorization_basis\", \"naming_rationale\",\n", + "]\n", + "missing_cols = [c for c in required_persona_cols if c not in persona_df.columns]\n", + "if missing_cols:\n", + " raise ValueError(f\"persona_df missing required columns: {missing_cols}\")\n", + "\n", + "print(\"Generated personas:\", len(personas))\n", + "print(\"Executive summary:\", grounding.executive_summary)\n", + "print(\"persona_df columns:\", list(persona_df.columns))\n", + "persona_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "707cdc91", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 23:09:06,354 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", + "2026-03-06 23:09:06,629 | INFO | segplus.visualization | Saved: feature_importance.png\n", + "2026-03-06 23:09:38,632 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", + "2026-03-06 23:09:39,175 | INFO | segplus.visualization | Saved: pca_loadings.png\n", + "2026-03-06 23:09:39,422 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", + "2026-03-06 23:09:39,526 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", + "2026-03-06 23:09:40,057 | INFO | segplus.visualization | Saved: persona_radar.png\n", + "2026-03-06 23:09:40,212 | INFO | segplus.visualization | Saved: experiment_history.png\n", + "2026-03-06 23:09:40,356 | INFO | segplus.visualization | Saved: elbow_curve.png\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved charts to: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n" + ] + } + ], + "source": [ + "# 6) Visualizations\n", + "plot_cluster_scatter_2d(X, best_eval.labels, output_dir, best_eval)\n", + "plot_shap_importance(\n", + " explainability.feature_importances, output_dir, top_n=15,\n", + " importance_pct=explainability.feature_importance_pct,\n", + ")\n", + "plot_shap_summary(\n", + " X_original_for_shap,\n", + " best_eval.labels,\n", + " original_feature_names_for_shap,\n", + " output_dir,\n", + " random_state=config.random_state,\n", + " max_display=15,\n", + ")\n", + "plot_pca_loadings_heatmap(explainability.pca_loadings, output_dir)\n", + "plot_cluster_profiles_heatmap(explainability.cluster_profiles, explainability.top_features, output_dir)\n", + "plot_cluster_sizes(best_eval.labels, personas, output_dir)\n", + "plot_radar_charts(fe_result.df_original, best_eval.labels, personas, explainability.top_features, output_dir)\n", + "plot_experiment_history(experiment_log, output_dir)\n", + "plot_elbow_curve(explainability.inertia_curve, output_dir)\n", + "\n", + "print(\"Saved charts to:\", output_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "969da7d8", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-06 23:09:42,767 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exported:\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\clustered_customers.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\cluster_profiles.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\ordered_feature_drivers.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\shap_feature_importance_pct.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\pc_feature_map.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.csv\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\business_grounding.json\n", + " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + ] + } + ], + "source": [ + "# 7) Export Outputs\n", + "clustered_df = fe_result.df_original.copy()\n", + "clustered_df[\"cluster\"] = best_eval.labels\n", + "\n", + "clustered_path = output_dir / \"clustered_customers.csv\"\n", + "profiles_path = output_dir / \"cluster_profiles.csv\"\n", + "ordered_drivers_path = output_dir / \"ordered_feature_drivers.csv\"\n", + "shap_pct_path = output_dir / \"shap_feature_importance_pct.csv\"\n", + "pc_feature_map_path = output_dir / \"pc_feature_map.json\"\n", + "personas_path = output_dir / \"personas.csv\"\n", + "personas_json_path = output_dir / \"personas.json\"\n", + "grounding_path = output_dir / \"business_grounding.json\"\n", + "exp_log_path = output_dir / \"experiment_log.json\"\n", + "\n", + "clustered_df.to_csv(clustered_path, index=False)\n", + "explainability.cluster_profiles.to_csv(profiles_path)\n", + "if explainability.ordered_feature_drivers is not None:\n", + " explainability.ordered_feature_drivers.to_csv(ordered_drivers_path, index=False)\n", + "\n", + "shap_pct_df = pd.DataFrame([\n", + " {\"feature\": k, \"importance_pct\": v}\n", + " for k, v in explainability.feature_importance_pct.items()\n", + "]).sort_values(\"importance_pct\", ascending=False)\n", + "shap_pct_df.to_csv(shap_pct_path, index=False)\n", + "\n", + "with open(pc_feature_map_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(explainability.pc_feature_map, f, indent=2)\n", + "\n", + "# Export exact persona schema\n", + "persona_df.to_csv(personas_path, index=False)\n", + "\n", + "personas_payload = [\n", + " {\n", + " \"cluster\": p.persona_name,\n", + " \"genai_persona_name\": p.archetype,\n", + " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", + " \"description\": getattr(p, \"description\", \"\"),\n", + " \"key_traits\": p.key_traits,\n", + " \"genai_recommendations\": p.business_recommendations,\n", + " \"cluster_size\": p.cluster_size,\n", + " \"cluster_pct\": p.cluster_pct,\n", + " \"top_features\": p.top_features,\n", + " \"categorization_basis\": getattr(p, \"categorization_basis\", []),\n", + " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", + " }\n", + " for p in personas\n", + "]\n", + "with open(personas_json_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(personas_payload, f, indent=2)\n", + "\n", + "experiment_log.to_json(exp_log_path)\n", + "\n", + "with open(grounding_path, \"w\", encoding=\"utf-8\") as f:\n", + " json.dump(\n", + " {\n", + " \"executive_summary\": grounding.executive_summary,\n", + " \"cluster_priorities\": grounding.cluster_priorities,\n", + " \"cluster_actions\": grounding.cluster_actions,\n", + " \"quick_wins\": grounding.quick_wins,\n", + " },\n", + " f,\n", + " indent=2,\n", + " )\n", + "\n", + "print(\"Exported:\")\n", + "print(\" -\", clustered_path)\n", + "print(\" -\", profiles_path)\n", + "print(\" -\", ordered_drivers_path)\n", + "print(\" -\", shap_pct_path)\n", + "print(\" -\", pc_feature_map_path)\n", + "print(\" -\", personas_path)\n", + "print(\" -\", personas_json_path)\n", + "print(\" -\", grounding_path)\n", + "print(\" -\", exp_log_path)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notes\n", + "\n", + "- Architecture implemented: data input -> FE -> KMeans/DBSCAN/GMM -> eval gate loop -> explainability -> ordered drivers -> persona generation -> business grounding -> per-cluster rationale outputs.\n", + "- Local Ollama is first-class. `qwen2.5` is primary model and auto-selected when installed.\n", + "- Ordered feature driver list combines SHAP importance + weighted PCA loadings, with inertia elbow context.\n", + "- `pc_feature_map.json` provides exact mapping from each PC to top original variables.\n", + "- SHAP summary plot is saved as `shap_summary.png` when `shap` is installed.\n", + "- Optional autoencoder latent representation is available via `USE_AUTOENCODER_REPRESENTATION=True`.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.x" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/segplus/modeling_loop.py b/segplus/modeling_loop.py new file mode 100644 index 0000000..8ec42b7 --- /dev/null +++ b/segplus/modeling_loop.py @@ -0,0 +1,273 @@ +"""Core modeling loop: configure -> cluster -> evaluate -> reconfigure retry cycle.""" +from __future__ import annotations + +import logging +from datetime import datetime +from enum import Enum + +import numpy as np +from sklearn.metrics import silhouette_score + +from .clustering import ( + estimate_dbscan_eps, + find_optimal_k, + run_all_algorithms, +) +from .config import PipelineConfig +from .evaluation import ClusterEvaluator +from .experiment_log import ExperimentLog +from .types import ClusteringConfig, EvaluationResult, ExperimentRecord + +log = logging.getLogger("segplus.modeling_loop") + + +class ReconfigStrategy(str, Enum): + ADJUST_K = "adjust_k" + ADJUST_EPS = "adjust_eps" + FEATURE_SUBSET = "feature_subset" + CHANGE_GMM_COV = "change_gmm_covariance" + WIDEN_K = "widen_k_range" + + +class ClusteringConfigurator: + """Initial configuration and smart reconfiguration on evaluation failure.""" + + def __init__(self, config: PipelineConfig, feature_names: list[str]): + self.config = config + self.feature_names = feature_names + self._k_scores: dict[int, float] = {} + + def initial_configure(self, X: np.ndarray) -> ClusteringConfig: + """Silhouette-guided K selection + DBSCAN eps estimation.""" + best_k, self._k_scores = find_optimal_k( + X, self.config.k_range, self.config.random_state + ) + eps = estimate_dbscan_eps(X, min_samples=5) + + return ClusteringConfig( + k=best_k, + dbscan_eps=eps, + dbscan_min_samples=5, + random_state=self.config.random_state, + ) + + def reconfigure( + self, + X: np.ndarray, + current: ClusteringConfig, + eval_result: EvaluationResult, + iteration: int, + history: list[ExperimentRecord], + ) -> tuple[ClusteringConfig, str]: + """Smart reconfiguration. Returns (new_config, strategy_name).""" + strategy = self._select_strategy(iteration, eval_result, history) + new = ClusteringConfig( + k=current.k, + dbscan_eps=current.dbscan_eps, + dbscan_min_samples=current.dbscan_min_samples, + gmm_covariance_type=current.gmm_covariance_type, + random_state=current.random_state, + feature_subset_indices=current.feature_subset_indices, + ) + + if strategy == ReconfigStrategy.ADJUST_K: + new = self._adjust_k(new, eval_result) + elif strategy == ReconfigStrategy.ADJUST_EPS: + new = self._adjust_eps(new, eval_result) + elif strategy == ReconfigStrategy.FEATURE_SUBSET: + new = self._try_feature_subset(X, eval_result, new) + elif strategy == ReconfigStrategy.CHANGE_GMM_COV: + new = self._change_gmm_cov(new) + elif strategy == ReconfigStrategy.WIDEN_K: + new = self._widen_k(X, new) + + log.info( + "Reconfigured (strategy=%s): k=%d, eps=%.3f, gmm_cov=%s, subset=%s", + strategy.value, new.k, new.dbscan_eps, new.gmm_covariance_type, + new.feature_subset_indices is not None, + ) + return new, strategy.value + + def _select_strategy( + self, iteration: int, eval_result: EvaluationResult, history: list[ExperimentRecord] + ) -> ReconfigStrategy: + """Deterministic strategy selection based on iteration and history.""" + strategies = [ + ReconfigStrategy.ADJUST_K, + ReconfigStrategy.ADJUST_EPS, + ReconfigStrategy.FEATURE_SUBSET, + ReconfigStrategy.CHANGE_GMM_COV, + ReconfigStrategy.WIDEN_K, + ] + idx = min(iteration - 1, len(strategies) - 1) + return strategies[idx] + + def _adjust_k(self, cfg: ClusteringConfig, eval_result: EvaluationResult) -> ClusteringConfig: + """Adjust K based on silhouette trend.""" + # If we have k_scores from initial scan, use them to decide direction + current_k = cfg.k + k_min, k_max = self.config.k_range + + # Check if higher K had better scores during initial scan + higher_better = any( + self._k_scores.get(k, -1) > self._k_scores.get(current_k, -1) + for k in range(current_k + 1, k_max + 1) + ) + lower_better = any( + self._k_scores.get(k, -1) > self._k_scores.get(current_k, -1) + for k in range(k_min, current_k) + ) + + if higher_better and current_k < k_max: + cfg.k = current_k + 1 + elif lower_better and current_k > k_min: + cfg.k = current_k - 1 + elif current_k < k_max: + cfg.k = current_k + 1 + else: + cfg.k = max(k_min, current_k - 1) + + return cfg + + def _adjust_eps(self, cfg: ClusteringConfig, eval_result: EvaluationResult) -> ClusteringConfig: + """Adjust DBSCAN eps based on noise ratio.""" + dbscan_scores = eval_result.all_scores.get("dbscan", {}) + # If DBSCAN silhouette was very low or negative, try larger eps + dbscan_sil = dbscan_scores.get("silhouette", -1) + if dbscan_sil < 0: + cfg.dbscan_eps = round(cfg.dbscan_eps * 1.5, 3) + else: + cfg.dbscan_eps = round(cfg.dbscan_eps * 1.2, 3) + cfg.dbscan_min_samples = max(3, cfg.dbscan_min_samples - 1) + return cfg + + def _try_feature_subset( + self, X: np.ndarray, eval_result: EvaluationResult, cfg: ClusteringConfig + ) -> ClusteringConfig: + """Drop lowest-importance features using quick permutation check.""" + labels = eval_result.labels + valid_mask = labels != -1 + Xv, lv = X[valid_mask], labels[valid_mask] + + if len(set(lv)) < 2 or Xv.shape[1] <= 3: + return cfg + + rng = np.random.default_rng(0) + baseline = silhouette_score(Xv, lv, sample_size=min(1000, len(Xv))) + + drops = [] + for i in range(Xv.shape[1]): + Xp = Xv.copy() + rng.shuffle(Xp[:, i]) + s = silhouette_score(Xp, lv, sample_size=min(1000, len(Xv))) + drops.append(baseline - s) + + # Keep features whose removal hurts silhouette the most + n_keep = max(3, int(len(drops) * 0.7)) + top_indices = sorted(range(len(drops)), key=lambda i: -drops[i])[:n_keep] + cfg.feature_subset_indices = sorted(top_indices) + return cfg + + def _change_gmm_cov(self, cfg: ClusteringConfig) -> ClusteringConfig: + """Cycle GMM covariance type.""" + cov_types = ["full", "tied", "diag", "spherical"] + current_idx = cov_types.index(cfg.gmm_covariance_type) if cfg.gmm_covariance_type in cov_types else 0 + cfg.gmm_covariance_type = cov_types[(current_idx + 1) % len(cov_types)] + return cfg + + def _widen_k(self, X: np.ndarray, cfg: ClusteringConfig) -> ClusteringConfig: + """Widen K range and re-search.""" + wider_min = max(2, self.config.k_range[0] - 1) + wider_max = min(self.config.k_range[1] + 2, len(X) // 10) + best_k, scores = find_optimal_k(X, (wider_min, wider_max), self.config.random_state) + self._k_scores.update(scores) + cfg.k = best_k + return cfg + + +def modeling_loop( + X: np.ndarray, + feature_names: list[str], + config: PipelineConfig, + experiment_log: ExperimentLog, +) -> tuple[EvaluationResult, ClusteringConfig]: + """ + Core retry loop: + 1. Configure initial clustering params + 2. Run all 3 algorithms (KMeans, DBSCAN, GMM) + 3. Evaluate -> pass/fail gate + 4. If fail -> reconfigure (smart strategy) -> goto 2 + 5. If pass or max_iterations -> return best result + """ + configurator = ClusteringConfigurator(config, feature_names) + evaluator = ClusterEvaluator(config) + + cluster_config = configurator.initial_configure(X) + best_eval: EvaluationResult | None = None + best_config: ClusteringConfig | None = None + + for iteration in range(1, config.max_iterations + 1): + log.info("=" * 60) + log.info("Modeling Loop - Iteration %d/%d | k=%d", iteration, config.max_iterations, cluster_config.k) + log.info("=" * 60) + + # Run all algorithms + results = run_all_algorithms(X, cluster_config) + if not results: + log.warning("No clustering algorithms succeeded in iteration %d", iteration) + continue + + # Evaluate + eval_result = evaluator.evaluate(X, results) + + # Log experiment + record = ExperimentRecord( + iteration=iteration, + timestamp=datetime.now().isoformat(), + config_k=cluster_config.k, + config_eps=cluster_config.dbscan_eps, + config_gmm_cov=cluster_config.gmm_covariance_type, + best_algorithm=eval_result.algorithm, + n_clusters=eval_result.n_clusters, + silhouette=eval_result.silhouette, + davies_bouldin=eval_result.davies_bouldin, + calinski_harabasz=eval_result.calinski_harabasz, + passed=eval_result.passes, + ) + experiment_log.add(record) + + # Track global best + if best_eval is None or eval_result.silhouette > best_eval.silhouette: + best_eval = eval_result + best_config = cluster_config + + log.info( + "Best: %s | sil=%.4f | DB=%.4f | PASS=%s", + eval_result.algorithm, eval_result.silhouette, + eval_result.davies_bouldin, eval_result.passes, + ) + + # Gate check + if eval_result.passes: + log.info("Evaluation PASSED on iteration %d.", iteration) + break + + # Reconfigure for next iteration + if iteration < config.max_iterations: + log.info("Evaluation FAILED. Reconfiguring...") + cluster_config, strategy = configurator.reconfigure( + X, cluster_config, eval_result, iteration, experiment_log.records + ) + # Update the record with reconfiguration strategy + record.reconfiguration_strategy = strategy + + if best_eval is None: + raise RuntimeError("No valid clustering result produced across all iterations.") + + if not best_eval.passes: + log.warning( + "Max iterations reached without passing gate. Using best result " + "(sil=%.4f, algorithm=%s).", best_eval.silhouette, best_eval.algorithm, + ) + + return best_eval, best_config diff --git a/segplus/ollama_client.py b/segplus/ollama_client.py new file mode 100644 index 0000000..7edb462 --- /dev/null +++ b/segplus/ollama_client.py @@ -0,0 +1,162 @@ +"""Robust HTTP client for Ollama's local LLM API.""" +from __future__ import annotations + +import json +import logging +import re +import time +from typing import Iterator, Optional + +import requests + +log = logging.getLogger("segplus.ollama_client") + + +class OllamaClient: + """ + Production-grade client for Ollama's local LLM API. + Features: health checks, exponential backoff retries, timeout, + streaming support, structured JSON extraction. + """ + + def __init__(self, host: str, model: str, timeout: int = 120): + self.host = host.rstrip("/") + self.model = model + self.timeout = timeout + self._endpoint = f"{self.host}/api/generate" + + def health_check(self) -> bool: + """Check if Ollama is reachable and the model is available.""" + try: + r = requests.get(f"{self.host}/api/tags", timeout=5) + r.raise_for_status() + models = [m["name"] for m in r.json().get("models", [])] + available = any(self.model in m for m in models) + if not available: + log.warning("Model '%s' not found. Available: %s", self.model, models) + else: + log.info("Ollama reachable. Model '%s' available.", self.model) + return available + except requests.RequestException as e: + log.error("Ollama not reachable at %s: %s", self.host, e) + return False + + def generate( + self, + prompt: str, + system: Optional[str] = None, + temperature: float = 0.3, + max_retries: int = 2, + max_tokens: int = 2048, + ) -> str: + """Generate a response with retry logic. Returns full text.""" + payload: dict = { + "model": self.model, + "prompt": prompt, + "stream": False, + "options": { + "temperature": temperature, + "num_predict": max_tokens, + }, + } + if system: + payload["system"] = system + + last_error = None + for attempt in range(1, max_retries + 2): + try: + r = requests.post( + self._endpoint, + json=payload, + timeout=self.timeout, + ) + r.raise_for_status() + response_text = r.json().get("response", "").strip() + log.info("Ollama response received (%d chars)", len(response_text)) + return response_text + + except requests.Timeout: + last_error = f"Timeout after {self.timeout}s" + except requests.RequestException as e: + last_error = str(e) + + if attempt <= max_retries: + wait = 2 ** attempt + log.warning( + "Ollama attempt %d failed (%s). Retrying in %ds...", + attempt, last_error, wait, + ) + time.sleep(wait) + + raise RuntimeError(f"Ollama failed after {max_retries + 1} attempts: {last_error}") + + def generate_stream( + self, + prompt: str, + system: Optional[str] = None, + temperature: float = 0.3, + max_tokens: int = 2048, + ) -> Iterator[str]: + """Streaming generation, yields tokens as they arrive.""" + payload: dict = { + "model": self.model, + "prompt": prompt, + "stream": True, + "options": { + "temperature": temperature, + "num_predict": max_tokens, + }, + } + if system: + payload["system"] = system + + r = requests.post( + self._endpoint, + json=payload, + timeout=self.timeout, + stream=True, + ) + r.raise_for_status() + + for line in r.iter_lines(): + if line: + data = json.loads(line) + token = data.get("response", "") + if token: + yield token + if data.get("done", False): + break + + def extract_json(self, text: str) -> dict: + """Extract the first valid JSON object from LLM output. + Handles markdown fences, preamble text, and trailing text. + """ + # Strip markdown code fences + cleaned = re.sub(r"```(?:json)?\s*", "", text) + cleaned = re.sub(r"```", "", cleaned) + + # Try to find a JSON object + match = re.search(r"(\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\})", cleaned, re.DOTALL) + if match: + try: + return json.loads(match.group(1)) + except json.JSONDecodeError: + pass + + # Broader match: find outermost braces + depth = 0 + start = None + for i, ch in enumerate(cleaned): + if ch == "{": + if depth == 0: + start = i + depth += 1 + elif ch == "}": + depth -= 1 + if depth == 0 and start is not None: + try: + return json.loads(cleaned[start:i + 1]) + except json.JSONDecodeError: + start = None + + raise ValueError(f"No valid JSON found in LLM response:\n{text[:400]}") diff --git a/segplus/persona_generation.py b/segplus/persona_generation.py new file mode 100644 index 0000000..1981d2d --- /dev/null +++ b/segplus/persona_generation.py @@ -0,0 +1,675 @@ +"""LLM persona generation and business objective grounding.""" +from __future__ import annotations + +import logging +import re + +import pandas as pd + +from .config import PipelineConfig +from .ollama_client import OllamaClient +from .types import ( + BusinessGrounding, + DataSchema, + EvaluationResult, + ExplainabilityReport, + PersonaResult, +) + +log = logging.getLogger("segplus.persona_generation") + +CLUSTER_LETTERS = {0: "A", 1: "B", 2: "C", 3: "D", 4: "E", 5: "F", 6: "G", 7: "H"} + +PERSONA_SYSTEM_PROMPT = """You are a senior customer analytics expert and strategic advisor. +You analyse customer cluster profiles and generate precise, actionable personas. +Always respond with ONLY valid JSON - no preamble, no explanation, no markdown fences. + +CRITICAL NAMING RULES: +- The archetype MUST be a unique, descriptive 2-5 word business label. +- Base the name on the ACTUAL DATA VALUES shown (high/low/above/below average), not just feature column names. +- NEVER use generic names like 'Segment A', 'Cluster Profile', 'Credit Score Optimizers', or names that merely repeat feature column names. +- NEVER include raw column names like 'credit_score' or 'risk_score' directly in the archetype. +- Good examples: 'Premium Low-Risk Elite', 'Budget-Conscious Rebuilders', 'High-Value Dormant Accounts', 'Creditworthy Loyalists', 'At-Risk High-Spenders' +- The name should instantly convey WHO these customers are to a business stakeholder. + +The JSON must contain exactly these keys: + archetype: string (2-5 word evocative business label reflecting this cluster's actual value profile) + description: string (2-3 sentences describing who this customer is, referencing specific data patterns) + key_traits: list of 4 strings (concise behavioural characteristics derived from the data) + business_recommendations: list of 3 strings (specific, actionable strategies tied to this cluster's profile) +""" + +GROUNDING_SYSTEM_PROMPT = """You are a Chief Strategy Officer synthesising customer segmentation results +into an executive-level strategic report. +Respond with ONLY valid JSON containing: + executive_summary: string (3-4 sentences - overall findings and strategic implication) + cluster_priority: list of objects, each with: + cluster: string + archetype: string + priority: string ("High" | "Medium" | "Low") + strategic_action: string (one concrete next action) + cluster_actions: list of objects, each with: + cluster: string + grounded_persona_name: string (business-ready segment label) + grounded_recommendations: list of 3 strings (specific actions for this cluster) + quick_wins: list of 3 strings (immediate actions any team can take this week) +""" + + +def build_cluster_profile_text( + cluster_letter: str, + profile_row: pd.Series, + cluster_pct: float, + top_features: dict[str, float], + top_feature_names: list[str], + business_objective: str, + global_means: pd.Series | None = None, + global_stds: pd.Series | None = None, +) -> str: + """Build a rich textual summary of a cluster's statistical profile with population comparison.""" + lines = [ + f"CLUSTER {cluster_letter} PROFILE", + f" Size: {int(cluster_pct * 100)}% of total customers", + "", + f" Business Objective: {business_objective}", + "", + " Key metrics (cluster mean vs population mean):", + ] + for feat in top_feature_names[:8]: + if feat in profile_row.index: + val = profile_row[feat] + if global_means is not None and feat in global_means.index: + pop_mean = float(global_means[feat]) + if pop_mean != 0: + pct_diff = ((val - pop_mean) / abs(pop_mean)) * 100 + direction = "above" if val > pop_mean else "below" + lines.append( + f" - {feat}: {val:.2f} ({direction} pop. avg {pop_mean:.2f}, {pct_diff:+.0f}%)" + ) + else: + lines.append(f" - {feat}: {val:.2f} (pop. avg {pop_mean:.2f})") + else: + lines.append(f" - {feat}: {val:.2f}") + + lines += ["", " Feature importances (contribution to cluster separation):"] + for feat, imp in list(top_features.items())[:5]: + lines.append(f" - {feat}: {imp:.4f}") + + return "\n".join(lines) + + +class PersonaGenerator: + """Generate LLM-powered personas for each cluster and ground in business objective.""" + + def __init__(self, client: OllamaClient, config: PipelineConfig): + self.client = client + self.config = config + self._is_available: bool | None = None + + def _check_availability(self) -> bool: + if self._is_available is None: + self._is_available = self.client.health_check() + return self._is_available + + def generate_personas( + self, + evaluation: EvaluationResult, + explainability: ExplainabilityReport, + raw_df: pd.DataFrame, + schema: DataSchema, + ) -> list[PersonaResult]: + """For each cluster: build profile -> call LLM -> parse JSON -> create PersonaResult.""" + use_fallback = not self._check_availability() + labels = evaluation.labels + total = int((labels != -1).sum()) + cluster_ids = sorted(c for c in set(labels) if c != -1) + + num_cols = [c for c in schema.numeric_cols if c in raw_df.columns] + global_means = raw_df[num_cols].mean() if num_cols else pd.Series(dtype=float) + global_stds = raw_df[num_cols].std().replace(0, 1.0) if num_cols else pd.Series(dtype=float) + self._global_means = global_means + self._global_stds = global_stds + personas: list[PersonaResult] = [] + + for cid in cluster_ids: + mask = labels == cid + size = int(mask.sum()) + pct = size / total + letter = CLUSTER_LETTERS.get(cid, str(cid)) + persona_name = f"Cluster {letter}" + + # Compute profile from raw data + profile_row = raw_df[mask][num_cols].mean() + top_features_dict = { + k: v for k, v in explainability.feature_importances.items() if v > 0 + } + cluster_top_features = self._cluster_specific_feature_order( + profile_row=profile_row, + global_means=global_means, + global_stds=global_stds, + candidate_features=list(top_features_dict.keys()), + ) + + if use_fallback: + persona = self._build_fallback_persona( + cid, persona_name, size, pct, profile_row, top_features_dict, cluster_top_features + ) + else: + persona = self._generate_llm_persona( + cid, letter, persona_name, size, pct, + profile_row, top_features_dict, cluster_top_features, + ) + + personas.append(persona) + log.info("Persona generated: %s -> %s", persona_name, persona.archetype) + + return self._ensure_unique_archetypes(personas) + + def _generate_focused_name(self, profile_descriptor: str, letter: str) -> str: + """Second-pass LLM call: given a data profile, generate a catchy 2-4 word business name.""" + prompt = ( + f"A customer segment has this data profile: {profile_descriptor}\n\n" + f"Business context: {self.config.business_objective}\n\n" + f"Generate ONE catchy 2-4 word business persona name for this segment.\n" + f"Rules:\n" + f"- Must be a memorable business label, e.g. 'Premium Loyalists', 'Budget Pragmatists', " + f"'Rising Stars', 'At-Risk Big Spenders', 'Creditworthy Savers'\n" + f"- Do NOT use generic words like 'Segment', 'Cluster', 'Group', 'Profile', 'Optimizers'\n" + f"- Do NOT just repeat data column names or metrics\n" + f"- Respond with ONLY the persona name, nothing else. No quotes, no explanation." + ) + try: + raw = self.client.generate(prompt, temperature=0.6, max_tokens=30) + name = raw.strip().strip('"').strip("'").strip() + # Remove any JSON wrapper if LLM over-formats + if "{" in name or "}" in name: + return "" + # Validate length + words = name.split() + if 2 <= len(words) <= 5 and not self._is_generic_archetype(name): + log.info("Focused naming for Cluster %s: '%s'", letter, name) + return name + return "" + except Exception as e: + log.debug("Focused naming failed for Cluster %s: %s", letter, e) + return "" + + def _generate_llm_persona( + self, + cid: int, + letter: str, + persona_name: str, + size: int, + pct: float, + profile_row: pd.Series, + top_features_dict: dict[str, float], + top_feature_names: list[str], + ) -> PersonaResult: + """Generate persona via Ollama LLM with two-pass naming.""" + # Always compute the data-driven profile descriptor + profile_descriptor = self._derive_data_driven_archetype(profile_row, top_feature_names, letter) + + profile_text = build_cluster_profile_text( + cluster_letter=letter, + profile_row=profile_row, + cluster_pct=pct, + top_features=top_features_dict, + top_feature_names=top_feature_names, + business_objective=self.config.business_objective, + global_means=self._global_means, + global_stds=self._global_stds, + ) + + prompt = ( + f"{profile_text}\n\n" + f"Generate a customer persona for this cluster. " + f"Respond ONLY with valid JSON." + ) + + try: + raw = self.client.generate(prompt, system=PERSONA_SYSTEM_PROMPT, temperature=0.3) + parsed = self.client.extract_json(raw) + llm_archetype = parsed.get("archetype", f"Segment {letter}") + naming_rationale = ( + f"LLM-generated persona name using cluster-specific drivers: " + f"{', '.join(top_feature_names[:3])}." + ) + + # If the first pass returned a generic name, try a focused second pass + if self._is_generic_archetype(llm_archetype): + focused_name = self._generate_focused_name(profile_descriptor, letter) + if focused_name: + llm_archetype = focused_name + naming_rationale = ( + f"Second-pass focused LLM naming from profile: {profile_descriptor}." + ) + else: + llm_archetype = self._business_fallback_name(top_feature_names, letter) + naming_rationale = ( + f"LLM returned generic name; using business-style fallback from drivers: " + f"{', '.join(top_feature_names[:2])}." + ) + elif self._needs_business_rewrite(llm_archetype): + focused_name = self._generate_focused_name(profile_descriptor, letter) + if focused_name: + llm_archetype = focused_name + naming_rationale = ( + f"LLM returned metric-literal name; rewritten via focused naming from profile: " + f"{profile_descriptor}." + ) + else: + llm_archetype = self._business_fallback_name(top_feature_names, letter) + naming_rationale = ( + f"LLM returned metric-literal name; rewritten to business-style fallback " + f"from drivers: {', '.join(top_feature_names[:2])}." + ) + + return PersonaResult( + cluster_id=cid, + persona_name=persona_name, + archetype=llm_archetype, + description=parsed.get("description", ""), + key_traits=parsed.get("key_traits", []), + business_recommendations=parsed.get("business_recommendations", []), + cluster_size=size, + cluster_pct=pct, + top_features={ + k: round(float(profile_row.get(k, 0)), 2) + for k in top_feature_names[:5] + if k in profile_row.index + }, + naming_rationale=naming_rationale, + categorization_basis=top_feature_names[:5], + profile_descriptor=profile_descriptor, + ) + except Exception as e: + log.warning("LLM persona generation failed for cluster %s: %s", letter, e) + return self._build_fallback_persona( + cid, persona_name, size, pct, profile_row, top_features_dict, top_feature_names + ) + + def _is_generic_archetype(self, name: str) -> bool: + n = (name or "").strip().lower() + if not n: + return True + generic_tokens = ["segment", "cluster", "profile", "group", "persona", "a", "b", "c", "d"] + if n in {"segment a", "segment b", "segment c", "cluster a", "cluster b", "cluster c"}: + return True + if sum(1 for t in generic_tokens if t in n) >= 2: + return True + # Reject names that are just column names glued together (e.g. "Credit Score Risk Score Optimizers") + raw_col_tokens = set() + for tok in n.replace("-", " ").replace("_", " ").split(): + raw_col_tokens.add(tok) + filler_words = {"optimizers", "drivers", "segment", "cluster", "profile", "group", "and", "&", "the"} + meaningful_words = raw_col_tokens - filler_words + if len(meaningful_words) < 2: + return True + # Reject literal metric-style labels; force focused renaming pass + if "&" in n and ("high " in n or "low " in n): + return True + if " score" in n and ("high " in n or "low " in n): + return True + return False + + def _needs_business_rewrite(self, name: str) -> bool: + """Detect literal metric-style names that should be rewritten as business labels.""" + n = (name or "").strip().lower() + if not n: + return True + bad_patterns = [ + r"\bhigh\b.*\blow\b", + r"\blow\b.*\bhigh\b", + r"\bcredit score\b", + r"\brisk score\b", + r"&", + ] + return any(re.search(p, n) for p in bad_patterns) + + def _business_fallback_name(self, top_feature_names: list[str], letter: str) -> str: + """Create a compact business-style name from top drivers when LLM naming is literal/generic.""" + roots = [] + for f in self._deduplicate_feature_roots(top_feature_names): + pretty = f.replace("_score", "").replace("_cluster", "").replace("_", " ").title().strip() + if pretty: + roots.append(pretty.split()[0]) + if len(roots) >= 2: + break + if len(roots) >= 2: + return f"{roots[0]} {roots[1]} Strategists" + if len(roots) == 1: + return f"{roots[0]} Navigators" + return f"Business Segment {letter}" + + @staticmethod + def _deduplicate_feature_roots(features: list[str]) -> list[str]: + """Remove semantically duplicate features (e.g. credit_score vs credit_score_cluster).""" + seen_roots: set[str] = set() + unique: list[str] = [] + for f in features: + # Strip common suffixes that create near-duplicate feature names + root = re.sub( + r'_(cluster|group|bin|cat|flag|encoded|scaled|norm|raw|[xy]|bucket|band)$', + '', f.lower(), + ) + root = re.sub(r'_+$', '', root) + if root not in seen_roots: + seen_roots.add(root) + unique.append(f) + return unique + + def _classify_feature_level(self, feat: str, profile_row: pd.Series) -> str: + """Classify a feature value as High/Moderate/Low relative to global population.""" + if not hasattr(self, '_global_means') or self._global_means is None: + return "" + if feat not in self._global_means.index or feat not in self._global_stds.index: + return "" + if feat not in profile_row.index: + return "" + + value = float(profile_row[feat]) + mean = float(self._global_means[feat]) + std = float(self._global_stds[feat]) + if std < 1e-10: + return "" + + z = (value - mean) / std + if z >= 0.5: + return "High" + elif z <= -0.5: + return "Low" + else: + return "Moderate" + + def _derive_data_driven_archetype( + self, + profile_row: pd.Series, + top_feature_names: list[str], + letter: str, + ) -> str: + """Derive a descriptive archetype using feature VALUES (not just names).""" + usable = [f for f in top_feature_names if f in profile_row.index] + # Remove semantically duplicate features (credit_score vs credit_score_cluster) + usable = self._deduplicate_feature_roots(usable) + if not usable: + return f"Strategic Segment {letter}" + + parts: list[str] = [] + for feat in usable[:3]: + pretty = feat.replace("_", " ").title() + level = self._classify_feature_level(feat, profile_row) + if level: + parts.append(f"{level} {pretty}") + else: + parts.append(pretty) + if len(parts) >= 2: + break + + if len(parts) >= 2: + return f"{parts[0]} & {parts[1]}" + if len(parts) == 1: + return f"{parts[0]} Segment" + return f"Strategic Segment {letter}" + + def _build_fallback_persona( + self, + cid: int, + persona_name: str, + size: int, + pct: float, + profile_row: pd.Series, + top_features_dict: dict[str, float], + top_feature_names: list[str] | None = None, + ) -> PersonaResult: + """Rule-based fallback when Ollama is unavailable.""" + letter = CLUSTER_LETTERS.get(cid, str(cid)) + + # Derive data-driven descriptor from top feature values + top_feats = top_feature_names if top_feature_names else list(top_features_dict.keys())[:5] + if top_feats: + profile_descriptor = self._derive_data_driven_archetype(profile_row, top_feats, letter) + else: + profile_descriptor = f"Cluster {letter} Profile" + + # Try focused LLM naming even in fallback (persona JSON failed but naming might work) + archetype = profile_descriptor + naming_rationale = ( + "Fallback rule-based name from cluster-specific top movers: " + + ", ".join(top_feats[:3]) + ) + if self._check_availability(): + focused_name = self._generate_focused_name(profile_descriptor, letter) + if focused_name: + archetype = focused_name + naming_rationale = f"Focused LLM naming from profile: {profile_descriptor}." + + return PersonaResult( + cluster_id=cid, + persona_name=persona_name, + archetype=archetype, + description=f"Cluster {letter} represents {pct:.0%} of customers. " + f"Key differentiators: {', '.join(top_feats[:3])}.", + key_traits=[f"Distinctive {f.replace('_', ' ').title()}" for f in top_feats[:4]], + business_recommendations=[ + "Run Ollama to generate detailed recommendations", + f"Investigate {top_feats[0].replace('_', ' ') if top_feats else 'key features'} patterns", + "Conduct qualitative research with cluster members", + ], + cluster_size=size, + cluster_pct=pct, + top_features={ + k: round(float(profile_row.get(k, 0)), 2) + for k in top_feats[:5] + if k in profile_row.index + }, + naming_rationale=naming_rationale, + categorization_basis=top_feats[:5], + profile_descriptor=profile_descriptor, + ) + + def _cluster_specific_feature_order( + self, + profile_row: pd.Series, + global_means: pd.Series, + global_stds: pd.Series, + candidate_features: list[str], + ) -> list[str]: + """Sort features by absolute standardized movement for this cluster vs total population.""" + scored: list[tuple[str, float]] = [] + for f in candidate_features: + if f in profile_row.index and f in global_means.index and f in global_stds.index: + z_move = abs(float(profile_row[f] - global_means[f]) / float(global_stds[f])) + scored.append((f, z_move)) + scored.sort(key=lambda x: x[1], reverse=True) + return [f for f, _ in scored] + + def ground_in_business_objective( + self, + personas: list[PersonaResult], + ) -> BusinessGrounding: + """LLM synthesises executive summary mapping personas to business objective.""" + if not self._check_availability(): + return BusinessGrounding( + executive_summary="Ollama offline. Start Ollama and re-run for LLM-generated strategic grounding.", + cluster_priorities=[ + {"cluster": p.persona_name, "archetype": p.archetype, + "priority": "TBD", "strategic_action": "Run Ollama to generate"} + for p in personas + ], + quick_wins=[ + "Start Ollama: ollama serve", + f"Pull model: ollama pull {self.config.ollama_model}", + "Re-run notebook", + ], + cluster_actions=[ + { + "cluster": p.persona_name, + "grounded_persona_name": p.archetype, + "grounded_recommendations": p.business_recommendations[:3], + } + for p in personas + ], + ) + + persona_summaries = [] + for p in personas: + persona_summaries.append( + f" {p.persona_name} - {p.archetype}\n" + f" Size: {p.cluster_size:,} ({p.cluster_pct * 100:.1f}%)\n" + f" Description: {p.description[:140]}\n" + f" Top traits: {'; '.join(p.key_traits[:2])}\n" + f" Drivers: {', '.join(p.categorization_basis[:3])}" + ) + + prompt = ( + f"Business Objective:\n{self.config.business_objective}\n\n" + f"Identified Customer Personas:\n" + "\n\n".join(persona_summaries) + "\n\n" + f"Ground these personas in the stated business objective. " + f"Identify priorities and strategic actions. Respond ONLY with valid JSON." + ) + + try: + log.info("Grounding personas in business objective...") + raw = self.client.generate( + prompt, + system=GROUNDING_SYSTEM_PROMPT, + temperature=0.2, + max_tokens=900, + ) + parsed = self.client.extract_json(raw) + return BusinessGrounding( + executive_summary=parsed.get("executive_summary", ""), + cluster_priorities=parsed.get("cluster_priority", []), + quick_wins=parsed.get("quick_wins", []), + cluster_actions=parsed.get("cluster_actions", []), + ) + except Exception as e: + log.warning("Business grounding failed: %s", e) + return BusinessGrounding( + executive_summary=f"LLM grounding failed: {e}", + cluster_priorities=[], + quick_wins=[], + cluster_actions=[], + ) + + def apply_grounding_to_personas( + self, + personas: list[PersonaResult], + grounding: BusinessGrounding, + ) -> list[PersonaResult]: + """Apply grounded persona names and recommendations returned by the grounding LLM step.""" + if not grounding.cluster_actions: + return self._ensure_unique_archetypes(personas) + + action_map = {} + for a in grounding.cluster_actions: + cluster_key = str(a.get("cluster", "")).strip().lower() + if cluster_key: + action_map[cluster_key] = a + + updated: list[PersonaResult] = [] + for p in personas: + key = str(p.persona_name).strip().lower() + action = action_map.get(key) + if action: + grounded_name = action.get("grounded_persona_name") + grounded_recs = action.get("grounded_recommendations", []) + if isinstance(grounded_name, str) and grounded_name.strip(): + p.archetype = grounded_name.strip() + p.naming_rationale = ( + p.naming_rationale + " " + + "Business grounding renamed this persona to align with objective." + ).strip() + if isinstance(grounded_recs, list) and grounded_recs: + p.business_recommendations = [str(x) for x in grounded_recs[:3]] + updated.append(p) + return self._ensure_unique_archetypes(updated) + + def _ensure_unique_archetypes(self, personas: list[PersonaResult]) -> list[PersonaResult]: + """Enforce unique archetype names using distinguishing cluster characteristics.""" + groups: dict[str, list[PersonaResult]] = {} + for p in personas: + base = self._clean_archetype_text(p.archetype) + p.archetype = base + key = self._archetype_key(base) + groups.setdefault(key, []).append(p) + + for _, group in groups.items(): + if len(group) <= 1: + continue + self._differentiate_duplicate_group(group) + + # Final hard guarantee of uniqueness + seen_exact: dict[str, int] = {} + for p in personas: + k = p.archetype.strip().lower() + seen_exact[k] = seen_exact.get(k, 0) + 1 + if seen_exact[k] > 1: + cluster_tag = str(p.persona_name).replace("Cluster ", "").strip() or str(seen_exact[k]) + p.archetype = f"{p.archetype} ({cluster_tag})" + p.naming_rationale = ( + p.naming_rationale + " " + + f"Appended cluster tag '{cluster_tag}' to guarantee unique persona naming." + ).strip() + return personas + + def _differentiate_duplicate_group(self, group: list[PersonaResult]) -> None: + """Rename duplicate archetypes using the feature that most distinguishes them.""" + # Collect all features present across the group's top_features + all_feats: set[str] = set() + for p in group: + all_feats.update(p.top_features.keys()) + + # Deduplicate feature roots to avoid credit_score vs credit_score_cluster + deduped_feats = self._deduplicate_feature_roots(list(all_feats)) + + # Find the feature with the largest value spread across the duplicate group + best_feat, best_spread = None, -1.0 + for feat in deduped_feats: + values = [p.top_features.get(feat, 0.0) for p in group] + spread = max(values) - min(values) + if spread > best_spread: + best_spread = spread + best_feat = feat + + if best_feat is None or best_spread < 1e-10: + # No distinguishing feature found; fall back to cluster letters + for p in group: + letter = str(p.persona_name).replace("Cluster ", "").strip() + p.archetype = f"{p.archetype} ({letter})" + p.naming_rationale += f" Differentiated by cluster label '{letter}'." + return + + # Rank clusters by the distinguishing feature and assign descriptive modifiers + ranked = sorted(group, key=lambda p: p.top_features.get(best_feat, 0.0), reverse=True) + pretty_feat = best_feat.replace("_", " ").title() + n = len(ranked) + + for i, p in enumerate(ranked): + val = p.top_features.get(best_feat, 0.0) + if n == 2: + modifier = "Higher" if i == 0 else "Lower" + else: + if i == 0: + modifier = "High" + elif i == n - 1: + modifier = "Low" + else: + modifier = "Mid" + p.archetype = f"{p.archetype} – {modifier} {pretty_feat}" + p.naming_rationale += ( + f" Differentiated by {best_feat} (value={val:.2f}, " + f"ranked {i + 1}/{n} across duplicate names)." + ) + + def _clean_archetype_text(self, name: str) -> str: + n = (name or "").strip() + n = re.sub(r"\s+", " ", n) + n = re.sub(r"[-\s]+$", "", n) # remove trailing hyphen/space + return n or "Strategic Segment" + + def _archetype_key(self, name: str) -> str: + n = name.lower() + n = re.sub(r"[^a-z0-9\s]", " ", n) + n = re.sub(r"\s+", " ", n).strip() + return n diff --git a/segplus/persona_generator.py b/segplus/persona_generator.py new file mode 100644 index 0000000..5fb2c6e --- /dev/null +++ b/segplus/persona_generator.py @@ -0,0 +1,5 @@ +"""Compatibility wrapper for persona generator naming.""" + +from .persona_generation import PersonaGenerator + +__all__ = ["PersonaGenerator"] diff --git a/segplus/pipeline.py b/segplus/pipeline.py new file mode 100644 index 0000000..5a0f863 --- /dev/null +++ b/segplus/pipeline.py @@ -0,0 +1,16 @@ +"""Pipeline entrypoint wrapper for segplus notebook workflow.""" + +from dataclasses import dataclass + +from .config import PipelineConfig + + +@dataclass +class Pipeline: + """Thin pipeline wrapper used by notebook and future CLI orchestration.""" + + config: PipelineConfig + + +def build_pipeline(config: PipelineConfig) -> Pipeline: + return Pipeline(config=config) diff --git a/segplus/types.py b/segplus/types.py new file mode 100644 index 0000000..a7dd9b1 --- /dev/null +++ b/segplus/types.py @@ -0,0 +1,210 @@ +"""Shared dataclasses and type definitions for the segplus pipeline.""" +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Literal, Optional + +import numpy as np +import pandas as pd + + +# ── Data Layer ─────────────────────────────────────────────────────────────── + +@dataclass +class ColumnMeta: + name: str + dtype: Literal["numeric", "categorical", "datetime", "text", "boolean"] + null_rate: float + n_unique: int + + +@dataclass +class DataSchema: + n_rows: int + n_cols: int + columns: list[ColumnMeta] = field(default_factory=list) + + @property + def numeric_cols(self) -> list[str]: + return [c.name for c in self.columns if c.dtype == "numeric"] + + @property + def categorical_cols(self) -> list[str]: + return [c.name for c in self.columns if c.dtype == "categorical"] + + +@dataclass +class DataQualityReport: + total_rows: int + total_columns: int + missing_values: dict[str, int] = field(default_factory=dict) + missing_pct: dict[str, float] = field(default_factory=dict) + duplicate_rows: int = 0 + column_types: dict[str, str] = field(default_factory=dict) + warnings: list[str] = field(default_factory=list) + errors: list[str] = field(default_factory=list) + passed: bool = True + + def summary(self) -> str: + lines = [ + f"Data Quality Report", + f" Rows: {self.total_rows:,} | Columns: {self.total_columns}", + f" Duplicates: {self.duplicate_rows:,}", + ] + if self.missing_values: + top = sorted(self.missing_pct.items(), key=lambda x: -x[1])[:5] + lines.append(" Top missing:") + for col, pct in top: + if pct > 0: + lines.append(f" {col}: {pct:.1%}") + if self.warnings: + lines.append(f" Warnings ({len(self.warnings)}):") + for w in self.warnings[:5]: + lines.append(f" - {w}") + if self.errors: + lines.append(f" Errors ({len(self.errors)}):") + for e in self.errors[:5]: + lines.append(f" - {e}") + lines.append(f" Status: {'PASSED' if self.passed else 'FAILED'}") + return "\n".join(lines) + + +# ── Feature Engineering Layer ──────────────────────────────────────────────── + +@dataclass +class FeatureEngineeringResult: + df_original: pd.DataFrame + df_engineered: pd.DataFrame + X_scaled: np.ndarray + feature_names: list[str] + pca: object | None = None # Optional[PCA] + scaler: object | None = None # Optional[StandardScaler] + label_encoders: dict = field(default_factory=dict) + + +# ── Clustering Layer ───────────────────────────────────────────────────────── + +@dataclass +class ClusteringConfig: + k: int = 3 + kmeans_init: str = "k-means++" + kmeans_n_init: int = 10 + kmeans_max_iter: int = 300 + dbscan_eps: float = 0.5 + dbscan_min_samples: int = 5 + gmm_covariance_type: str = "full" + gmm_n_init: int = 5 + random_state: int = 42 + feature_subset_indices: list[int] | None = None + + +@dataclass +class ClusterRunResult: + algorithm: str + labels: np.ndarray + n_clusters: int + model: object + probabilities: np.ndarray | None = None + extra: dict = field(default_factory=dict) + + @property + def is_valid(self) -> bool: + unique = set(self.labels) + unique.discard(-1) + return len(unique) >= 2 + + +# ── Evaluation Layer ───────────────────────────────────────────────────────── + +@dataclass +class EvaluationResult: + algorithm: str + labels: np.ndarray + n_clusters: int + silhouette: float + davies_bouldin: float + calinski_harabasz: float + passes: bool + all_scores: dict[str, dict[str, float]] = field(default_factory=dict) + model: object = None + + +@dataclass +class StabilityResult: + ari_mean: float + ari_std: float + n_bootstraps: int + stable: bool + + +# ── Explainability Layer ───────────────────────────────────────────────────── + +@dataclass +class ExplainabilityReport: + top_features: list[str] + feature_importances: dict[str, float] + pca_loadings: pd.DataFrame + cluster_profiles: pd.DataFrame + pca_variance_ratio: list[float] + inertia_curve: dict[int, float] | None = None + feature_importance_pct: dict[str, float] = field(default_factory=dict) + ordered_feature_drivers: pd.DataFrame | None = None + pc_feature_map: dict[str, list[str]] = field(default_factory=dict) + + +# ── Persona Layer ──────────────────────────────────────────────────────────── + +@dataclass +class PersonaResult: + cluster_id: int | str + persona_name: str + archetype: str + description: str + key_traits: list[str] + business_recommendations: list[str] + cluster_size: int + cluster_pct: float + top_features: dict[str, float] = field(default_factory=dict) + naming_rationale: str = "" + categorization_basis: list[str] = field(default_factory=list) + profile_descriptor: str = "" # Data-driven descriptor (e.g. "High Credit Score & Low Risk") + + +@dataclass +class BusinessGrounding: + executive_summary: str + cluster_priorities: list[dict] = field(default_factory=list) + quick_wins: list[str] = field(default_factory=list) + cluster_actions: list[dict] = field(default_factory=list) + + +# ── Experiment Tracking ────────────────────────────────────────────────────── + +@dataclass +class ExperimentRecord: + iteration: int + timestamp: str + config_k: int + config_eps: float + config_gmm_cov: str + best_algorithm: str + n_clusters: int + silhouette: float + davies_bouldin: float + calinski_harabasz: float + passed: bool + reconfiguration_strategy: str | None = None + + +# ── Pipeline Result ────────────────────────────────────────────────────────── + +@dataclass +class PipelineResult: + data_quality: DataQualityReport + feature_engineering: FeatureEngineeringResult + best_evaluation: EvaluationResult + stability: StabilityResult + explainability: ExplainabilityReport + personas: list[PersonaResult] + grounding: BusinessGrounding + experiment_log: list[ExperimentRecord] diff --git a/segplus/visualization.py b/segplus/visualization.py new file mode 100644 index 0000000..a1274c7 --- /dev/null +++ b/segplus/visualization.py @@ -0,0 +1,439 @@ +"""Visualization: all matplotlib/seaborn charts for the pipeline.""" +from __future__ import annotations + +import logging +from pathlib import Path + +import matplotlib.patches as mpatches +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns +from sklearn.decomposition import PCA +from sklearn.ensemble import RandomForestClassifier + +from .experiment_log import ExperimentLog +from .types import ExplainabilityReport, EvaluationResult, PersonaResult + +log = logging.getLogger("segplus.visualization") + +PALETTE = ["#4C72B0", "#DD8452", "#55A868", "#C44E52", "#8172B2", "#937860", "#DA8BC3"] + + +def _setup_style() -> None: + sns.set_theme(style="whitegrid", palette=PALETTE) + plt.rcParams.update({"figure.dpi": 130, "axes.titlesize": 13, "axes.labelsize": 11}) + + +def plot_cluster_scatter_2d( + X: np.ndarray, + labels: np.ndarray, + output_dir: Path, + eval_result: EvaluationResult | None = None, +) -> None: + """PCA 2D scatter plot of clusters with optional silhouette comparison.""" + _setup_style() + pca2 = PCA(n_components=2, random_state=42) + X_2d = pca2.fit_transform(X) + var_explained = pca2.explained_variance_ratio_ + + n_subplots = 2 if eval_result else 1 + fig, axes = plt.subplots(1, n_subplots, figsize=(8 * n_subplots, 6)) + if n_subplots == 1: + axes = [axes] + + # Cluster scatter + unique_labels = sorted(set(labels)) + colors = PALETTE[:len(unique_labels)] + for lbl, col in zip(unique_labels, colors): + mask = labels == lbl + name = f"Cluster {lbl}" if lbl != -1 else "Noise" + axes[0].scatter(X_2d[mask, 0], X_2d[mask, 1], c=col, alpha=0.55, s=18, + label=name, edgecolors="none") + + algo = eval_result.algorithm.upper() if eval_result else "Clustering" + sil = f" (sil={eval_result.silhouette:.3f})" if eval_result else "" + axes[0].set_title(f"Clusters - {algo}{sil}") + axes[0].set_xlabel(f"PC1 ({var_explained[0] * 100:.1f}% var)") + axes[0].set_ylabel(f"PC2 ({var_explained[1] * 100:.1f}% var)") + axes[0].legend(framealpha=0.8) + + # Silhouette comparison bar chart + if eval_result and eval_result.all_scores: + algos = list(eval_result.all_scores.keys()) + sil_scores = [eval_result.all_scores[a].get("silhouette", 0) for a in algos] + bar_colors = [PALETTE[2] if a == eval_result.algorithm else PALETTE[0] for a in algos] + bars = axes[1].bar(algos, sil_scores, color=bar_colors, width=0.4, edgecolor="white") + axes[1].set_title("Silhouette Score by Algorithm") + axes[1].set_ylabel("Silhouette Score") + for bar, val in zip(bars, sil_scores): + axes[1].text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.005, + f"{val:.3f}", ha="center", va="bottom", fontsize=10) + + plt.tight_layout() + fig.savefig(output_dir / "cluster_scatter.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: cluster_scatter.png") + + +def plot_shap_importance( + importances: dict[str, float], + output_dir: Path, + top_n: int = 15, + importance_pct: dict[str, float] | None = None, +) -> None: + """Horizontal bar chart of feature importances with percentage labels.""" + _setup_style() + names = list(importances.keys())[:top_n] + scores = list(importances.values())[:top_n] + + # Compute percentages from raw scores if not provided + if importance_pct: + pcts = [importance_pct.get(n, 0.0) for n in names] + else: + total = sum(abs(s) for s in scores) or 1.0 + pcts = [(abs(s) / total) * 100 for s in scores] + + fig, ax = plt.subplots(figsize=(10, max(4, len(names) * 0.45))) + colors = [PALETTE[2] if s > 0 else PALETTE[3] for s in scores] + bars = ax.barh(names[::-1], scores[::-1], color=colors[::-1], edgecolor="white") + + # Add percentage labels on each bar + for bar, pct in zip(bars, pcts[::-1]): + width = bar.get_width() + label_x = width + (ax.get_xlim()[1] - ax.get_xlim()[0]) * 0.01 + ax.text( + label_x, bar.get_y() + bar.get_height() / 2, + f"{pct:.1f}%", + va="center", ha="left", fontsize=9, fontweight="bold", color="#333333", + ) + + ax.set_title("Feature Importance (Cluster Separation Drivers)") + ax.set_xlabel("Importance Score") + ax.axvline(0, color="gray", linewidth=0.8) + # Extend x-axis slightly for percentage labels + xlim = ax.get_xlim() + ax.set_xlim(xlim[0], xlim[1] * 1.15) + + plt.tight_layout() + fig.savefig(output_dir / "feature_importance.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: feature_importance.png") + + +def plot_shap_summary( + X: np.ndarray, + labels: np.ndarray, + feature_names: list[str], + output_dir: Path, + random_state: int = 42, + max_display: int = 15, +) -> None: + """SHAP summary plots (beeswarm + bar) with robust multiclass handling.""" + valid_mask = labels != -1 + Xv, lv = X[valid_mask], labels[valid_mask] + if len(set(lv)) < 2: + log.warning("Skipping SHAP summary: need at least 2 clusters after excluding noise.") + return + + try: + import shap + except ImportError: + log.warning("Skipping SHAP summary: shap is not installed.") + return + + try: + model = RandomForestClassifier( + n_estimators=120, max_depth=12, random_state=random_state, n_jobs=-1 + ) + model.fit(Xv, lv) + + sample_n = min(1000, len(Xv)) + rng = np.random.default_rng(random_state) + idx = rng.choice(len(Xv), size=sample_n, replace=False) + X_sample = Xv[idx] + + explainer = shap.TreeExplainer(model) + raw_shap = explainer.shap_values(X_sample) + + # Normalize shap outputs to 2D (n_samples, n_features) for clean beeswarm plots. + major_class = pd.Series(lv).value_counts().index[0] + if isinstance(raw_shap, list): + class_idx = int(major_class) if int(major_class) < len(raw_shap) else 0 + shap_2d = np.array(raw_shap[class_idx], dtype=float) + else: + arr = np.array(raw_shap) + if arr.ndim == 2: + shap_2d = arr + elif arr.ndim == 3: + # Common shape: (n_samples, n_features, n_classes) + if arr.shape[0] == X_sample.shape[0] and arr.shape[1] == X_sample.shape[1]: + class_idx = int(major_class) if int(major_class) < arr.shape[2] else 0 + shap_2d = arr[:, :, class_idx] + # Alternate shape: (n_classes, n_samples, n_features) + elif arr.shape[1] == X_sample.shape[0] and arr.shape[2] == X_sample.shape[1]: + class_idx = int(major_class) if int(major_class) < arr.shape[0] else 0 + shap_2d = arr[class_idx, :, :] + else: + # Last-resort aggregation across class axis. + shap_2d = np.mean(arr, axis=-1) + if shap_2d.ndim != 2: + shap_2d = shap_2d.reshape(X_sample.shape[0], X_sample.shape[1]) + else: + log.warning("Unexpected SHAP output shape %s; skipping SHAP summary.", arr.shape) + return + + # Human-readable labels (no hardcoding; generated from column names) + pretty_feature_names = [f.replace("_", " ").title() for f in feature_names] + display_n = min(max_display, len(pretty_feature_names)) + plot_h = max(6, int(display_n * 0.45)) + + # Build interpretation table: importance % + directionality hint. + mean_abs = np.mean(np.abs(shap_2d), axis=0) + total_abs = float(np.sum(mean_abs)) if np.sum(mean_abs) > 0 else 1.0 + rows = [] + for i, fname in enumerate(feature_names): + xi = X_sample[:, i] + si = shap_2d[:, i] + if np.std(xi) > 1e-12 and np.std(si) > 1e-12: + corr = float(np.corrcoef(xi, si)[0, 1]) + else: + corr = 0.0 + if corr > 0.1: + effect = "Higher value tends to increase model score" + elif corr < -0.1: + effect = "Higher value tends to decrease model score" + else: + effect = "Mixed / nonlinear effect" + rows.append({ + "feature": fname, + "feature_pretty": pretty_feature_names[i], + "mean_abs_shap": float(mean_abs[i]), + "importance_pct": float((mean_abs[i] / total_abs) * 100.0), + "value_shap_corr": corr, + "effect_hint": effect, + }) + interp_df = pd.DataFrame(rows).sort_values("mean_abs_shap", ascending=False).reset_index(drop=True) + interp_df.to_csv(output_dir / "shap_interpretation.csv", index=False) + + # Beeswarm summary + plt.figure(figsize=(12, plot_h)) + shap.summary_plot( + shap_2d, + features=X_sample, + feature_names=pretty_feature_names, + max_display=display_n, + show=False, + plot_size=(12, plot_h), + ) + plt.tight_layout() + plt.savefig(output_dir / "shap_summary.png", dpi=180, bbox_inches="tight") + plt.close() + + # Custom bar summary with percentage labels (replaces shap's default bar chart) + top_interp = interp_df.head(display_n).copy() + fig_bar, ax_bar = plt.subplots(figsize=(11, max(5, int(display_n * 0.45)))) + bar_names = top_interp["feature_pretty"].tolist()[::-1] + bar_pcts = top_interp["importance_pct"].tolist()[::-1] + bar_colors = [PALETTE[2]] * len(bar_names) + bars = ax_bar.barh(bar_names, bar_pcts, color=bar_colors, edgecolor="white", height=0.6) + + for bar, pct in zip(bars, bar_pcts): + label_x = bar.get_width() + 0.3 + ax_bar.text( + label_x, bar.get_y() + bar.get_height() / 2, + f"{pct:.1f}%", + va="center", ha="left", fontsize=10, fontweight="bold", color="#333333", + ) + + ax_bar.set_xlabel("Importance (%)", fontsize=11) + ax_bar.set_title("SHAP Feature Importance (%)", fontsize=13, fontweight="bold") + xlim = ax_bar.get_xlim() + ax_bar.set_xlim(xlim[0], xlim[1] * 1.12) + plt.tight_layout() + fig_bar.savefig(output_dir / "shap_summary_bar.png", dpi=180, bbox_inches="tight") + plt.close(fig_bar) + + log.info("Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv") + except Exception as e: + log.warning("SHAP summary plot failed: %s", e) + + +def plot_pca_loadings_heatmap( + loadings: pd.DataFrame, + output_dir: Path, +) -> None: + """Heatmap of PCA component loadings.""" + _setup_style() + fig, ax = plt.subplots(figsize=(max(10, len(loadings.columns) * 0.6), max(4, len(loadings) * 0.8))) + sns.heatmap(loadings, ax=ax, cmap="YlOrRd", annot=True, fmt=".2f", + linewidths=0.5, cbar_kws={"label": "|Loading|"}) + ax.set_title("PCA Component Loadings") + ax.set_ylabel("Component") + + plt.tight_layout() + fig.savefig(output_dir / "pca_loadings.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: pca_loadings.png") + + +def plot_cluster_profiles_heatmap( + profiles: pd.DataFrame, + top_features: list[str], + output_dir: Path, +) -> None: + """Z-scored cluster profile heatmap for top features.""" + _setup_style() + cols = [c for c in top_features if c in profiles.columns][:10] + if not cols: + return + + sub = profiles[cols] + z_scored = (sub - sub.mean()) / sub.std().replace(0, 1) + + fig, ax = plt.subplots(figsize=(max(10, len(cols) * 0.8), max(4, len(z_scored) * 0.8))) + sns.heatmap(z_scored.T, ax=ax, cmap="RdBu_r", center=0, annot=True, fmt=".2f", + linewidths=0.5, cbar_kws={"label": "Z-score vs. mean"}) + ax.set_title("Cluster Profiles - Top Driving Features") + ax.set_xlabel("Cluster ID") + + plt.tight_layout() + fig.savefig(output_dir / "cluster_profiles.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: cluster_profiles.png") + + +def plot_cluster_sizes( + labels: np.ndarray, + personas: list[PersonaResult] | None, + output_dir: Path, +) -> None: + """Pie chart of cluster size distribution.""" + _setup_style() + unique = sorted(c for c in set(labels) if c != -1) + + fig, ax = plt.subplots(figsize=(8, 6)) + sizes = [int((labels == c).sum()) for c in unique] + + if personas and len(personas) == len(unique): + pie_labels = [f"{p.persona_name}\n{p.archetype[:20]}" for p in personas] + else: + pie_labels = [f"Cluster {c}" for c in unique] + + colors = PALETTE[:len(unique)] + wedges, texts, autotexts = ax.pie( + sizes, labels=pie_labels, colors=colors, + autopct="%1.1f%%", startangle=140, + wedgeprops={"edgecolor": "white", "linewidth": 1.5}, + ) + for at in autotexts: + at.set_fontsize(10) + ax.set_title("Cluster Size Distribution", fontsize=13, pad=15) + + plt.tight_layout() + fig.savefig(output_dir / "cluster_sizes.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: cluster_sizes.png") + + +def plot_radar_charts( + df_raw: pd.DataFrame, + labels: np.ndarray, + personas: list[PersonaResult], + top_features: list[str], + output_dir: Path, +) -> None: + """Radar chart per cluster for top features.""" + _setup_style() + num_feats = [f for f in top_features if f in df_raw.columns + and pd.api.types.is_numeric_dtype(df_raw[f])][:6] + n = len(num_feats) + if n < 3: + log.warning("Not enough numeric features for radar chart (need >= 3, got %d)", n) + return + + n_personas = min(len(personas), 3) + fig = plt.figure(figsize=(6 * n_personas, 6)) + angles = np.linspace(0, 2 * np.pi, n, endpoint=False).tolist() + angles += angles[:1] + + global_min = df_raw[num_feats].min() + global_max = df_raw[num_feats].max() + + for idx, p in enumerate(personas[:n_personas]): + ax = fig.add_subplot(1, n_personas, idx + 1, polar=True) + mask = labels == p.cluster_id + means = df_raw[mask][num_feats].mean() + normed = ((means - global_min) / (global_max - global_min + 1e-9)).values.tolist() + normed += normed[:1] + + ax.plot(angles, normed, color=PALETTE[idx], linewidth=2) + ax.fill(angles, normed, color=PALETTE[idx], alpha=0.25) + ax.set_xticks(angles[:-1]) + ax.set_xticklabels(num_feats, size=8) + ax.set_ylim(0, 1) + ax.set_title(f"{p.persona_name}\n{p.archetype[:18]}", size=10, pad=14, + color=PALETTE[idx], fontweight="bold") + + plt.suptitle("Customer Persona Profiles", fontsize=15, fontweight="bold", y=1.01) + plt.tight_layout() + fig.savefig(output_dir / "persona_radar.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: persona_radar.png") + + +def plot_experiment_history( + exp_log: ExperimentLog, + output_dir: Path, +) -> None: + """Line chart of silhouette score across modeling loop iterations.""" + _setup_style() + df = exp_log.to_dataframe() + if df.empty: + return + + fig, ax = plt.subplots(figsize=(10, 5)) + ax.plot(df["iteration"], df["silhouette"], "o-", color=PALETTE[0], linewidth=2, markersize=8) + + for _, row in df.iterrows(): + marker = "o" if not row["passed"] else "s" + color = PALETTE[3] if not row["passed"] else PALETTE[2] + ax.scatter(row["iteration"], row["silhouette"], c=color, s=100, zorder=5, marker=marker) + if row.get("reconfig_strategy"): + ax.annotate(row["reconfig_strategy"], (row["iteration"], row["silhouette"]), + textcoords="offset points", xytext=(5, 10), fontsize=8, alpha=0.7) + + ax.set_xlabel("Iteration") + ax.set_ylabel("Silhouette Score") + ax.set_title("Modeling Loop - Silhouette Score per Iteration") + ax.legend(handles=[ + mpatches.Patch(color=PALETTE[2], label="Passed"), + mpatches.Patch(color=PALETTE[3], label="Failed"), + ]) + + plt.tight_layout() + fig.savefig(output_dir / "experiment_history.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: experiment_history.png") + + +def plot_elbow_curve( + inertia_curve: dict[int, float], + output_dir: Path, +) -> None: + """Elbow curve (K vs inertia).""" + _setup_style() + ks = sorted(inertia_curve.keys()) + inertias = [inertia_curve[k] for k in ks] + + fig, ax = plt.subplots(figsize=(8, 5)) + ax.plot(ks, inertias, "o-", color=PALETTE[0], linewidth=2, markersize=8) + ax.set_xlabel("Number of Clusters (K)") + ax.set_ylabel("Inertia") + ax.set_title("Elbow Curve - K-Means Inertia") + ax.set_xticks(ks) + + plt.tight_layout() + fig.savefig(output_dir / "elbow_curve.png", dpi=150, bbox_inches="tight") + plt.close(fig) + log.info("Saved: elbow_curve.png") From d0fa1c14937da237d721c9afb8b47fad44b94f76 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 11:55:54 +0530 Subject: [PATCH 02/13] Updated README --- README.md | 86 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 64616c2..57785cb 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,83 @@ -# Segmentation_Plus +# Segmentation Plus -End-to-end customer segmentation and GenAI persona workflow. +Customer segmentation and persona pipeline using the `segplus` module and a single Excel input file. -## Project Structure +## What This Project Uses + +- Input data: **Excel file** +- Core code: `segplus/` +- Final runnable notebook: `segplus/final_segplus_pipeline2.ipynb` +- Required support files: + - `requirements.txt` + - `main.py` + +## Minimal Project Structure ```text -Segmentation_Plus -│ -├── data -│ └── dataset.xlsx -│ -├── segplus +Segmentation_Plus/ +├── final_enterprise_clustering_dataset_single_sheet.xlsx # Excel input +├── requirements.txt +├── segplus/ │ ├── clustering.py +│ ├── config.py +│ ├── data_input.py +│ ├── evaluation.py +│ ├── experiment_log.py +│ ├── explainability.py +│ ├── feature_engineering.py +│ ├── modeling_loop.py +│ ├── ollama_client.py +│ ├── persona_generation.py │ ├── persona_generator.py │ ├── pipeline.py -│ -├── notebook.ipynb -└── requirements.txt +│ ├── types.py +│ ├── visualization.py +│ └── final_segplus_pipeline2.ipynb # Run this notebook +└── README.md ``` -## Main Notebook - -Use `notebook.ipynb` as the final runnable notebook. -It is synced from `segplus/final_segplus_pipeline.ipynb`. - ## Setup ```bash pip install -r requirements.txt ``` +## Ollama (Local LLM) + +```bash +ollama serve +ollama list +ollama pull qwen2.5:7b +``` + +The notebook is configured for local Ollama and selects `qwen2.5:7b`. + ## Run -1. Open `notebook.ipynb`. -2. Run cells top-to-bottom. -3. Outputs are written under `segplus_output/`. +1. Open `segplus/final_segplus_pipeline2.ipynb` +2. Run cells top-to-bottom +3. Ensure the Excel file path is correct in the config cell + +## Outputs + +Pipeline outputs are written to `segplus_output/` and include: + +- `clustered_customers.csv` +- `cluster_profiles.csv` +- `ordered_feature_drivers.csv` +- `shap_feature_importance_pct.csv` +- `shap_summary.png` +- `shap_summary_bar.png` +- `shap_interpretation.csv` +- `pc_feature_map.json` +- `personas.csv` +- `personas.json` +- `business_grounding.json` +- `experiment_log.json` + +## Notes + +- Persona names are generated by the model (no hardcoded cluster names). +- `profile_descriptor` and `description` are included in persona outputs. +- If grounding times out, fallback logic still returns persona outputs. + From 5aa91066cb326ed54198e6c8c093483fd71b87cd Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:18:49 +0530 Subject: [PATCH 03/13] Delete Clustering1.ipynb --- Clustering1.ipynb | 347 ---------------------------------------------- 1 file changed, 347 deletions(-) delete mode 100644 Clustering1.ipynb diff --git a/Clustering1.ipynb b/Clustering1.ipynb deleted file mode 100644 index 2ca7357..0000000 --- a/Clustering1.ipynb +++ /dev/null @@ -1,347 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "81ef225d", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "from dataclasses import dataclass\n", - "from typing import Dict, List, Tuple\n", - "\n", - "from sklearn.preprocessing import StandardScaler\n", - "from sklearn.decomposition import PCA\n", - "\n", - "from sklearn.cluster import KMeans, DBSCAN\n", - "from sklearn.mixture import GaussianMixture\n", - "\n", - "from sklearn.metrics import (\n", - " silhouette_score,\n", - " calinski_harabasz_score,\n", - " davies_bouldin_score\n", - ")\n", - "\n", - "import warnings\n", - "warnings.filterwarnings(\"ignore\")" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "af3ca3d7", - "metadata": {}, - "outputs": [], - "source": [ - "@dataclass\n", - "class ClusterResult:\n", - " \n", - " algorithm: str\n", - " labels: np.ndarray\n", - " metadata: Dict\n", - "\n", - "\n", - "@dataclass\n", - "class EvaluationResult:\n", - "\n", - " algorithm: str\n", - " silhouette: float\n", - " calinski: float\n", - " davies: float\n", - "\n", - "\n", - "@dataclass\n", - "class PipelineState:\n", - "\n", - " raw_df: pd.DataFrame\n", - " feature_df: pd.DataFrame\n", - " X_scaled: np.ndarray\n", - " X_embedding: np.ndarray\n", - "\n", - " cluster_results: Dict[str, ClusterResult] = None\n", - " evaluation_results: Dict[str, EvaluationResult] = None" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "13982a78", - "metadata": {}, - "outputs": [], - "source": [ - "class DataInputService:\n", - "\n", - " def __init__(self, file_path: str):\n", - " self.file_path = file_path\n", - "\n", - " def load(self) -> pd.DataFrame:\n", - "\n", - " df = pd.read_csv(self.file_path)\n", - "\n", - " if df.empty:\n", - " raise ValueError(\"Dataset is empty\")\n", - "\n", - " return df\n", - "\n", - "\n", - " def validate(self, df: pd.DataFrame) -> Dict:\n", - "\n", - " report = {\n", - " \"rows\": len(df),\n", - " \"columns\": len(df.columns),\n", - " \"missing_values\": df.isna().sum().to_dict(),\n", - " \"duplicates\": int(df.duplicated().sum())\n", - " }\n", - "\n", - " return report" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "1a83d30c", - "metadata": {}, - "outputs": [], - "source": [ - "class FeatureEngineeringPipeline:\n", - "\n", - " def __init__(self, pca_variance: float = 0.85):\n", - "\n", - " self.scaler = StandardScaler()\n", - " self.pca = PCA(n_components=pca_variance)\n", - "\n", - "\n", - " def run(self, df: pd.DataFrame):\n", - "\n", - " numeric_df = df.select_dtypes(include=[\"int64\",\"float64\"]).copy()\n", - "\n", - " X_scaled = self.scaler.fit_transform(numeric_df)\n", - "\n", - " X_emb = self.pca.fit_transform(X_scaled)\n", - "\n", - " return numeric_df, X_scaled, X_emb" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "385f0fcf", - "metadata": {}, - "outputs": [], - "source": [ - "class BaseClustering:\n", - "\n", - " def fit(self, X: np.ndarray):\n", - " raise NotImplementedError" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "77c31356", - "metadata": {}, - "outputs": [], - "source": [ - "class KMeansRunner(BaseClustering):\n", - "\n", - " def __init__(self, k_min=2, k_max=10):\n", - "\n", - " self.k_min = k_min\n", - " self.k_max = k_max\n", - "\n", - "\n", - " def fit(self, X):\n", - "\n", - " best_k = None\n", - " best_score = -1\n", - " best_labels = None\n", - "\n", - " for k in range(self.k_min, self.k_max):\n", - "\n", - " model = KMeans(n_clusters=k, random_state=42)\n", - "\n", - " labels = model.fit_predict(X)\n", - "\n", - " score = silhouette_score(X, labels)\n", - "\n", - " if score > best_score:\n", - "\n", - " best_score = score\n", - " best_k = k\n", - " best_labels = labels\n", - "\n", - " metadata = {\n", - " \"best_k\": best_k,\n", - " \"silhouette\": best_score\n", - " }\n", - "\n", - " return ClusterResult(\"kmeans\", best_labels, metadata)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "1be0e821", - "metadata": {}, - "outputs": [], - "source": [ - "class DBSCANRunner(BaseClustering):\n", - "\n", - " def __init__(self, eps=0.5, min_samples=5):\n", - "\n", - " self.eps = eps\n", - " self.min_samples = min_samples\n", - "\n", - "\n", - " def fit(self, X):\n", - "\n", - " model = DBSCAN(eps=self.eps, min_samples=self.min_samples)\n", - "\n", - " labels = model.fit_predict(X)\n", - "\n", - " metadata = {\n", - " \"clusters\": len(set(labels)) - (1 if -1 in labels else 0)\n", - " }\n", - "\n", - " return ClusterResult(\"dbscan\", labels, metadata)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "fee767e0", - "metadata": {}, - "outputs": [], - "source": [ - "class GMMRunner(BaseClustering):\n", - "\n", - " def __init__(self, k_min=2, k_max=10):\n", - "\n", - " self.k_min = k_min\n", - " self.k_max = k_max\n", - "\n", - "\n", - " def fit(self, X):\n", - "\n", - " best_k = None\n", - " best_bic = np.inf\n", - " best_labels = None\n", - "\n", - " for k in range(self.k_min, self.k_max):\n", - "\n", - " model = GaussianMixture(n_components=k)\n", - "\n", - " model.fit(X)\n", - "\n", - " bic = model.bic(X)\n", - "\n", - " if bic < best_bic:\n", - "\n", - " best_bic = bic\n", - " best_k = k\n", - " best_labels = model.predict(X)\n", - "\n", - " metadata = {\n", - " \"best_k\": best_k,\n", - " \"bic\": best_bic\n", - " }\n", - "\n", - " return ClusterResult(\"gmm\", best_labels, metadata)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "d9f6db6e", - "metadata": {}, - "outputs": [], - "source": [ - "class ClusteringEngine:\n", - "\n", - " def __init__(self):\n", - "\n", - " self.runners = {\n", - " \"kmeans\": KMeansRunner(),\n", - " \"dbscan\": DBSCANRunner(),\n", - " \"gmm\": GMMRunner()\n", - " }\n", - "\n", - "\n", - " def run(self, X):\n", - "\n", - " results = {}\n", - "\n", - " for name, runner in self.runners.items():\n", - "\n", - " result = runner.fit(X)\n", - "\n", - " results[name] = result\n", - "\n", - " return results" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "5a042e6a", - "metadata": {}, - "outputs": [], - "source": [ - "class ClusterEvaluationEngine:\n", - "\n", - " def evaluate(self, X, cluster_results):\n", - "\n", - " evaluations = {}\n", - "\n", - " for name, result in cluster_results.items():\n", - "\n", - " labels = result.labels\n", - "\n", - " if len(set(labels)) <= 1:\n", - " continue\n", - "\n", - " metrics = EvaluationResult(\n", - " algorithm=name,\n", - " silhouette=silhouette_score(X, labels),\n", - " calinski=calinski_harabasz_score(X, labels),\n", - " davies=davies_bouldin_score(X, labels)\n", - " )\n", - "\n", - " evaluations[name] = metrics\n", - "\n", - " return evaluations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8570bf88", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.13.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From d995ee0e1a9b8cc5594abf4589a9679e8dcda997 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:19:03 +0530 Subject: [PATCH 04/13] Delete Data_generator.ipynb --- Data_generator.ipynb | 272 ------------------------------------------- 1 file changed, 272 deletions(-) delete mode 100644 Data_generator.ipynb diff --git a/Data_generator.ipynb b/Data_generator.ipynb deleted file mode 100644 index f5dd20f..0000000 --- a/Data_generator.ipynb +++ /dev/null @@ -1,272 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cf9ddabf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Customer Master: (150000, 8)\n", - "Transactions: (3001170, 5)\n", - "Digital: (150000, 4)\n", - "Churn: (150000, 2)\n", - "MMM Weekly: (120, 8)\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "from scipy.special import expit\n", - "from scipy.stats import multivariate_normal\n", - "from datetime import timedelta\n", - "\n", - "np.random.seed(42)\n", - "\n", - "# ============================================================\n", - "# CONFIG\n", - "# ============================================================\n", - "\n", - "N_CUSTOMERS = 150_000\n", - "WEEKS = 120\n", - "START_DATE = pd.to_datetime(\"2023-01-01\")\n", - "\n", - "# ============================================================\n", - "# 1️⃣ CUSTOMER MASTER (Correlated Structure)\n", - "# ============================================================\n", - "\n", - "def generate_customer_master(n):\n", - "\n", - " # Correlated latent variables: income, age, risk_factor\n", - " mean = [12, 40, 0] # log-income, age, latent risk\n", - " cov = [\n", - " [1.2, -0.3, -0.5],\n", - " [-0.3, 25, 0.2],\n", - " [-0.5, 0.2, 1]\n", - " ]\n", - "\n", - " latent = multivariate_normal(mean, cov).rvs(n)\n", - "\n", - " log_income = latent[:,0]\n", - " age = np.clip(latent[:,1], 21, 75)\n", - " latent_risk = latent[:,2]\n", - "\n", - " income = np.exp(log_income) * 1000\n", - " credit_score = np.clip(750 + 40*(log_income - log_income.mean()) - 60*latent_risk, 300, 900)\n", - " risk_score = expit(latent_risk)\n", - "\n", - " digital_affinity = np.clip(1 - (age - 21)/60 + np.random.normal(0,0.1,n), 0,1)\n", - " tenure = np.random.randint(6, 180, n)\n", - "\n", - " credit_limit = income * np.random.uniform(0.2, 0.5, n)\n", - "\n", - " df = pd.DataFrame({\n", - " \"customer_id\": [f\"CUST_{i}\" for i in range(n)],\n", - " \"age\": age,\n", - " \"annual_income\": income,\n", - " \"credit_score\": credit_score,\n", - " \"risk_score\": risk_score,\n", - " \"digital_affinity\": digital_affinity,\n", - " \"tenure_months\": tenure,\n", - " \"credit_limit\": credit_limit\n", - " })\n", - "\n", - " return df\n", - "\n", - "# ============================================================\n", - "# 2️⃣ TRANSACTION ENGINE (Heavy-Tailed + Utilization)\n", - "# ============================================================\n", - "\n", - "def generate_transactions(customers):\n", - "\n", - " txn_rows = []\n", - "\n", - " for _, row in customers.iterrows():\n", - "\n", - " base_spend = np.random.lognormal(mean=10, sigma=1.0)\n", - " utilization = base_spend / row.credit_limit\n", - "\n", - " delinquency_prob = expit(4*utilization + 3*row.risk_score - 3)\n", - " delinquency_flag = np.random.binomial(1, delinquency_prob)\n", - "\n", - " n_txn = np.random.poisson(20)\n", - "\n", - " for _ in range(n_txn):\n", - " txn_rows.append([\n", - " row.customer_id,\n", - " START_DATE + timedelta(days=int(np.random.uniform(0,365))),\n", - " np.random.lognormal(mean=8, sigma=1.2),\n", - " utilization,\n", - " delinquency_flag\n", - " ])\n", - "\n", - " txn_df = pd.DataFrame(txn_rows, columns=[\n", - " \"customer_id\",\n", - " \"txn_date\",\n", - " \"txn_amount\",\n", - " \"utilization_ratio\",\n", - " \"delinquency_flag\"\n", - " ])\n", - "\n", - " return txn_df\n", - "\n", - "# ============================================================\n", - "# 3️⃣ DIGITAL ENGAGEMENT\n", - "# ============================================================\n", - "\n", - "def generate_digital(customers):\n", - "\n", - " df = customers.copy()\n", - "\n", - " df[\"app_sessions_30d\"] = (\n", - " df.digital_affinity * 35 + np.random.normal(0,5,len(df))\n", - " ).astype(int)\n", - "\n", - " df[\"email_open_rate\"] = np.clip(\n", - " df.digital_affinity + np.random.normal(0,0.1,len(df)),0,1\n", - " )\n", - "\n", - " df[\"complaints\"] = np.random.poisson(df.risk_score * 3)\n", - "\n", - " return df[[\n", - " \"customer_id\",\n", - " \"app_sessions_30d\",\n", - " \"email_open_rate\",\n", - " \"complaints\"\n", - " ]]\n", - "\n", - "# ============================================================\n", - "# 4️⃣ CHURN SIMULATION\n", - "# ============================================================\n", - "\n", - "def generate_churn(customers, digital):\n", - "\n", - " merged = customers.merge(digital, on=\"customer_id\")\n", - "\n", - " logit = (\n", - " -2.5\n", - " + 3*merged.risk_score\n", - " + 2*(merged.complaints > 2)\n", - " - 0.02*merged.tenure_months\n", - " - 1.5*merged.digital_affinity\n", - " )\n", - "\n", - " churn_prob = expit(logit)\n", - " merged[\"churn_flag\"] = np.random.binomial(1, churn_prob)\n", - "\n", - " return merged[[\"customer_id\", \"churn_flag\"]]\n", - "\n", - "# ============================================================\n", - "# 5️⃣ MMM ENGINE (Correlated + Adstock + Saturation + Shock)\n", - "# ============================================================\n", - "\n", - "def adstock(x, decay=0.6):\n", - " result = np.zeros_like(x)\n", - " for t in range(len(x)):\n", - " result[t] = x[t] + (decay * result[t-1] if t > 0 else 0)\n", - " return result\n", - "\n", - "def hill(x, alpha=1.5):\n", - " return x**alpha / (x**alpha + 1)\n", - "\n", - "def generate_mmm(weeks):\n", - "\n", - " mean = [10, 8, 7]\n", - " cov = [\n", - " [1, 0.6, 0.4],\n", - " [0.6, 1, 0.5],\n", - " [0.4, 0.5, 1]\n", - " ]\n", - "\n", - " latent_spend = multivariate_normal(mean, cov).rvs(weeks)\n", - " tv = np.exp(latent_spend[:,0]) * 1e5\n", - " meta = np.exp(latent_spend[:,1]) * 8e4\n", - " search = np.exp(latent_spend[:,2]) * 5e4\n", - "\n", - " seasonality = 1 + 0.2*np.sin(np.linspace(0, 4*np.pi, weeks))\n", - "\n", - " macro = np.ones(weeks)\n", - " macro[50:60] *= 0.85 # recession shock\n", - "\n", - " competitor = np.ones(weeks)\n", - " competitor[70:80] *= 1.2\n", - "\n", - " tv_ad = adstock(tv)\n", - " meta_ad = hill(adstock(meta))\n", - " search_ad = search\n", - "\n", - " sales = (\n", - " 0.00002 * tv_ad\n", - " + 0.00004 * meta_ad\n", - " + 0.00005 * search_ad\n", - " + 2000 * seasonality\n", - " + 1500 * macro\n", - " - 1000 * (competitor - 1)\n", - " + np.random.normal(0, 800, weeks)\n", - " )\n", - "\n", - " df = pd.DataFrame({\n", - " \"week\": np.arange(weeks),\n", - " \"tv_spend\": tv,\n", - " \"meta_spend\": meta,\n", - " \"search_spend\": search,\n", - " \"seasonality\": seasonality,\n", - " \"macro_index\": macro,\n", - " \"competitor_index\": competitor,\n", - " \"sales\": sales\n", - " })\n", - "\n", - " return df\n", - "\n", - "# ============================================================\n", - "# RUN FULL PIPELINE\n", - "# ============================================================\n", - "\n", - "customers = generate_customer_master(N_CUSTOMERS)\n", - "transactions = generate_transactions(customers)\n", - "digital = generate_digital(customers)\n", - "churn = generate_churn(customers, digital)\n", - "mmm_weekly = generate_mmm(WEEKS)\n", - "\n", - "print(\"Customer Master:\", customers.shape)\n", - "print(\"Transactions:\", transactions.shape)\n", - "print(\"Digital:\", digital.shape)\n", - "print(\"Churn:\", churn.shape)\n", - "print(\"MMM Weekly:\", mmm_weekly.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "56531166", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.13.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 60ade20ab034b22c999343ea3902dfb80696d1fc Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:19:24 +0530 Subject: [PATCH 05/13] Delete domains/_template.yaml --- domains/_template.yaml | 51 ------------------------------------------ 1 file changed, 51 deletions(-) delete mode 100644 domains/_template.yaml diff --git a/domains/_template.yaml b/domains/_template.yaml deleted file mode 100644 index a18d032..0000000 --- a/domains/_template.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# Domain Configuration Template -# Copy this file and customize for your domain. - -domain: my_domain -display_name: "My Domain" - -required_columns: - - customer_id - -features: - demographics: [] - # Add your feature groups here: - # financial: [col1, col2] - # behavioral: [col3, col4] - -categorical_columns: [] - -scaling_exclude: - - customer_id - -feature_engineering: [] - # - name: derived_feature - # formula: "col1 * col2" - # description: "Description of what this feature captures" - -eda: - domain_analyses: [] - # - my_custom_analysis - -persona_prompt_template: | - You are a marketing strategist advising a company on their customer segments. - - Segment {segment_id} Profile: - {segment_stats} - - Top SHAP Feature Drivers: - {shap_drivers} - - Generate a detailed customer persona with: - 1. Persona Name - 2. One-Line Description - 3. Demographics & Lifestyle - 4. Goals - 5. Pain Points - 6. Product Recommendations - 7. Preferred Channels - 8. Marketing Strategy - - Output as structured JSON. - -metadata: {} From c6c9580bf3e264df72a8dc9216b43aca30d364d9 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:19:39 +0530 Subject: [PATCH 06/13] Delete domains/financial_services.yaml --- domains/financial_services.yaml | 113 -------------------------------- 1 file changed, 113 deletions(-) delete mode 100644 domains/financial_services.yaml diff --git a/domains/financial_services.yaml b/domains/financial_services.yaml deleted file mode 100644 index beeed7c..0000000 --- a/domains/financial_services.yaml +++ /dev/null @@ -1,113 +0,0 @@ -domain: financial_services -display_name: "Financial Services" - -required_columns: - - customer_id - - age - - annual_income - -features: - demographics: - - age - - gender - - annual_income - - education - - marital_status - - dependents - - occupation - financial: - - account_balance - - credit_score - - monthly_spending - - savings_rate - - debt_to_income_ratio - - investment_portfolio_value - products: - - has_credit_card - - has_mortgage - - has_personal_loan - - has_investment_account - - has_insurance - - num_products - behavioral: - - digital_engagement_score - - branch_visits_monthly - - customer_tenure_years - - transaction_frequency_monthly - - avg_transaction_amount - satisfaction: - - nps_score - - complaint_count_yearly - - churn_risk_score - -categorical_columns: - - gender - - education - - marital_status - - occupation - -scaling_exclude: - - customer_id - - has_credit_card - - has_mortgage - - has_personal_loan - - has_investment_account - - has_insurance - -feature_engineering: - - name: wealth_tier - formula: "annual_income * investment_portfolio_value" - bins: [low, medium, high, ultra_high] - description: "Combined wealth indicator from income and portfolio" - - - name: digital_vs_branch_ratio - formula: "digital_engagement_score / (digital_engagement_score + branch_visits_monthly + 1)" - description: "Channel preference ratio: higher = more digital" - - - name: product_depth - formula: "has_credit_card + has_mortgage + has_personal_loan + has_investment_account + has_insurance" - description: "Total number of product types held" - - - name: spending_to_income_ratio - formula: "monthly_spending / (annual_income / 12 + 1)" - description: "Monthly spending as fraction of monthly income" - - - name: risk_category - formula: "credit_score * (1 - debt_to_income_ratio)" - description: "Combined credit-risk indicator" - -eda: - domain_analyses: - - income_distribution_by_segment - - credit_score_vs_product_holdings - - debt_to_income_analysis - - high_value_customer_identification - - product_cross_holding_matrix - - digital_vs_branch_preference - -persona_prompt_template: | - You are a marketing strategist advising a financial services institution - (bank, insurer, or wealth management firm) on their customer segments. - - Segment {segment_id} Profile: - {segment_stats} - - Top SHAP Feature Drivers: - {shap_drivers} - - Based on this data, generate a detailed customer persona including: - 1. Persona Name — a memorable, representative name - 2. One-Line Description — a concise tagline - 3. Demographics & Lifestyle — age range, income bracket, life stage - 4. Financial Goals — what they want to achieve - 5. Pain Points — frustrations, unmet needs - 6. Product Recommendations — cross-sell / upsell opportunities - 7. Preferred Communication Channels — email, app, branch, phone - 8. Marketing Strategy — tone, timing, offer types, campaign ideas - - Output as structured JSON with keys: name, tagline, demographics, - goals, pain_points, product_recommendations, channels, strategy. - -metadata: - institution_types: [bank, insurer, wealth_manager, credit_union] - typical_customer_count: "10K - 5M" From 7e7eac9c657512d2564d8ed8fe4437cb91547890 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:20:34 +0530 Subject: [PATCH 07/13] Delete segplus/final_segplus_pipeline.ipynb --- segplus/final_segplus_pipeline.ipynb | 1295 -------------------------- 1 file changed, 1295 deletions(-) delete mode 100644 segplus/final_segplus_pipeline.ipynb diff --git a/segplus/final_segplus_pipeline.ipynb b/segplus/final_segplus_pipeline.ipynb deleted file mode 100644 index d2b827e..0000000 --- a/segplus/final_segplus_pipeline.ipynb +++ /dev/null @@ -1,1295 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# SegPlus Final End-to-End Pipeline\n", - "\n", - "This notebook runs the full architecture:\n", - "- Data input and validation\n", - "- Feature engineering\n", - "- KMeans + DBSCAN + GMM modeling loop\n", - "- Cluster evaluation + stability\n", - "- Explainability (feature drivers, PCA loadings, profiles)\n", - "- Persona generation and business grounding (Ollama with fallback)\n", - "- Visualization and export\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "64579db4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Missing required: ['scikit-learn', 'pyyaml']\n", - "Missing optional: []\n" - ] - } - ], - "source": [ - "# Optional dependency installer/check\n", - "import importlib\n", - "import subprocess\n", - "import sys\n", - "\n", - "REQUIRED_PACKAGES = [\n", - " \"numpy\", \"pandas\", \"scikit-learn\", \"matplotlib\", \"seaborn\",\n", - " \"pyyaml\", \"openpyxl\", \"requests\", \"scipy\"\n", - "]\n", - "OPTIONAL_PACKAGES = [\"shap\"]\n", - "AUTO_INSTALL_MISSING = False # set True if you want notebook to install missing packages\n", - "\n", - "missing_required = []\n", - "missing_optional = []\n", - "\n", - "for pkg in REQUIRED_PACKAGES:\n", - " mod = pkg.replace(\"-\", \"_\")\n", - " try:\n", - " importlib.import_module(mod)\n", - " except Exception:\n", - " missing_required.append(pkg)\n", - "\n", - "for pkg in OPTIONAL_PACKAGES:\n", - " try:\n", - " importlib.import_module(pkg)\n", - " except Exception:\n", - " missing_optional.append(pkg)\n", - "\n", - "print(\"Missing required:\", missing_required)\n", - "print(\"Missing optional:\", missing_optional)\n", - "\n", - "if missing_required and AUTO_INSTALL_MISSING:\n", - " cmd = [sys.executable, \"-m\", \"pip\", \"install\", *missing_required]\n", - " print(\"Installing:\", \" \".join(missing_required))\n", - " subprocess.check_call(cmd)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "32c77bb2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Project root: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\n" - ] - } - ], - "source": [ - "import logging\n", - "import json\n", - "from pathlib import Path\n", - "import sys\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "# Ensure project root is importable when notebook is inside segplus/\n", - "cwd = Path.cwd()\n", - "project_root = cwd.parent if cwd.name.lower() == \"segplus\" else cwd\n", - "if str(project_root) not in sys.path:\n", - " sys.path.insert(0, str(project_root))\n", - "\n", - "from segplus.config import PipelineConfig, load_domain_config\n", - "from segplus.data_input import import_and_validate\n", - "from segplus.feature_engineering import FeatureEngineer\n", - "from segplus.modeling_loop import modeling_loop\n", - "from segplus.evaluation import run_stability_test\n", - "from segplus.experiment_log import ExperimentLog\n", - "from segplus.explainability import build_explainability_report\n", - "from segplus.ollama_client import OllamaClient\n", - "from segplus.persona_generation import PersonaGenerator\n", - "from segplus.visualization import (\n", - " plot_cluster_scatter_2d,\n", - " plot_shap_importance,\n", - " plot_shap_summary,\n", - " plot_pca_loadings_heatmap,\n", - " plot_cluster_profiles_heatmap,\n", - " plot_cluster_sizes,\n", - " plot_radar_charts,\n", - " plot_experiment_history,\n", - " plot_elbow_curve,\n", - ")\n", - "\n", - "logging.basicConfig(\n", - " level=logging.INFO,\n", - " format=\"%(asctime)s | %(levelname)-8s | %(name)-30s | %(message)s\",\n", - ")\n", - "\n", - "print(\"Project root:\", project_root)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "e0196175", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Domain: Financial Services\n", - "Data: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\final_enterprise_clustering_dataset_single_sheet.xlsx\n", - "Output: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n", - "Ollama host: http://localhost:11434\n", - "Primary LLM: qwen2.5:7b\n" - ] - } - ], - "source": [ - "# Configuration (edit these as needed)\n", - "default_data_path = project_root / \"final_enterprise_clustering_dataset_single_sheet.xlsx\"\n", - "default_output_dir = project_root / \"segplus_output\"\n", - "\n", - "config = PipelineConfig(\n", - " data_path=str(default_data_path),\n", - " domain_key=\"financial_services\", # or \"retail\"\n", - " sheet_name=None,\n", - " k_range=(2, 8),\n", - " max_iterations=5,\n", - " pca_variance_threshold=0.85,\n", - " output_dir=str(default_output_dir),\n", - " ollama_host=\"http://localhost:11434\", # local Ollama endpoint\n", - " ollama_model=\"qwen2.5:7b\", # primary local model`n ollama_timeout=240,\n", - " business_objective=(\n", - " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", - " \"improve retention for high-value customers, and convert mid-tier customers \"\n", - " \"to premium products.\"\n", - " ),\n", - ")\n", - "\n", - "# Preferred model order for local Ollama auto-selection\n", - "PREFERRED_OLLAMA_MODELS = [\n", - " \"qwen2.5\",\n", - " \"qwen2\",\n", - " \"llama3.2\",\n", - " \"llama3.1\",\n", - " \"llama3\",\n", - " \"mistral\",\n", - "]\n", - "\n", - "output_dir = Path(config.output_dir)\n", - "output_dir.mkdir(parents=True, exist_ok=True)\n", - "\n", - "domain_config = load_domain_config(config.domain_key, domains_dir=project_root / \"domains\")\n", - "print(\"Domain:\", domain_config.display_name)\n", - "print(\"Data:\", config.data_path)\n", - "print(\"Output:\", output_dir)\n", - "print(\"Ollama host:\", config.ollama_host)\n", - "print(\"Primary LLM:\", config.ollama_model)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "85b24976", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:49:51,635 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n", - "2026-03-06 22:49:51,833 | INFO | segplus.data_input | Data quality: PASSED\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Data Quality Report\n", - " Rows: 120,000 | Columns: 27\n", - " Duplicates: 0\n", - " Status: PASSED\n", - "Raw shape: (120000, 27)\n" - ] - } - ], - "source": [ - "# 1) Data Input + Validation\n", - "df_raw, quality_report, schema = import_and_validate(\n", - " file_path=config.data_path,\n", - " domain_config=domain_config,\n", - " auto_map=True,\n", - " sheet_name=config.sheet_name,\n", - ")\n", - "\n", - "print(quality_report.summary())\n", - "if not quality_report.passed:\n", - " raise ValueError(\"Data quality checks failed. Fix input data and rerun.\")\n", - "\n", - "print(\"Raw shape:\", df_raw.shape)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "7e4bf552", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:49:51,888 | WARNING | segplus.feature_engineering | FE rule 'wealth_tier' failed: name 'investment_portfolio_value' is not defined\n", - "2026-03-06 22:49:51,902 | WARNING | segplus.feature_engineering | FE rule 'digital_vs_branch_ratio' failed: name 'digital_engagement_score' is not defined\n", - "2026-03-06 22:49:51,918 | WARNING | segplus.feature_engineering | FE rule 'product_depth' failed: name 'has_credit_card' is not defined\n", - "2026-03-06 22:49:51,926 | WARNING | segplus.feature_engineering | FE rule 'spending_to_income_ratio' failed: name 'monthly_spending' is not defined\n", - "2026-03-06 22:49:51,942 | WARNING | segplus.feature_engineering | FE rule 'risk_category' failed: name 'debt_to_income_ratio' is not defined\n", - "2026-03-06 22:49:52,618 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", - "2026-03-06 22:49:52,619 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Engineered dataframe shape: (120000, 26)\n", - "Model matrix shape used for clustering: (120000, 7)\n", - "Feature count used for clustering: 7\n", - "SHAP source feature count (original vars): 26\n", - "First SHAP source vars: ['month', 'monthly_spend_x', 'utilization_ratio_x', 'delinquency_flag_x', 'age', 'annual_income', 'risk_score', 'credit_score', 'digital_affinity', 'tenure_months']\n" - ] - } - ], - "source": [ - "# 2) Feature Engineering\n", - "from sklearn.preprocessing import StandardScaler\n", - "\n", - "feature_engineer = FeatureEngineer(domain_config, config)\n", - "fe_result = feature_engineer.run(df_raw)\n", - "\n", - "# Original-variable matrix for SHAP (never PCA names)\n", - "original_feature_names_for_shap = fe_result.df_engineered.columns.tolist()\n", - "X_original_for_shap = StandardScaler().fit_transform(fe_result.df_engineered.values)\n", - "\n", - "# Optional latent representation via local autoencoder (if tensorflow is installed)\n", - "USE_AUTOENCODER_REPRESENTATION = False\n", - "AE_LATENT_DIM = 8\n", - "AE_EPOCHS = 40\n", - "AE_BATCH_SIZE = 256\n", - "\n", - "X = fe_result.X_scaled\n", - "feature_names = fe_result.feature_names\n", - "pca_for_explainability = fe_result.pca\n", - "\n", - "if USE_AUTOENCODER_REPRESENTATION:\n", - " try:\n", - " import tensorflow as tf\n", - " from tensorflow.keras import Model\n", - " from tensorflow.keras.layers import Dense, Input\n", - " from tensorflow.keras.callbacks import EarlyStopping\n", - "\n", - " tf.random.set_seed(config.random_state)\n", - " input_dim = X.shape[1]\n", - " latent_dim = max(2, min(AE_LATENT_DIM, input_dim - 1))\n", - "\n", - " inp = Input(shape=(input_dim,))\n", - " x = Dense(max(16, input_dim // 2), activation=\"relu\")(inp)\n", - " latent = Dense(latent_dim, activation=\"linear\", name=\"latent\")(x)\n", - " x = Dense(max(16, input_dim // 2), activation=\"relu\")(latent)\n", - " out = Dense(input_dim, activation=\"linear\")(x)\n", - "\n", - " autoencoder = Model(inp, out)\n", - " encoder = Model(inp, latent)\n", - " autoencoder.compile(optimizer=\"adam\", loss=\"mse\")\n", - " autoencoder.fit(\n", - " X,\n", - " X,\n", - " epochs=AE_EPOCHS,\n", - " batch_size=min(AE_BATCH_SIZE, len(X)),\n", - " verbose=0,\n", - " callbacks=[EarlyStopping(monitor=\"loss\", patience=5, restore_best_weights=True)],\n", - " )\n", - "\n", - " X = encoder.predict(X, verbose=0)\n", - " feature_names = [f\"AE{i+1}\" for i in range(X.shape[1])]\n", - " pca_for_explainability = None # PCA loadings no longer match AE latent space\n", - " print(f\"Autoencoder latent representation enabled: {X.shape}\")\n", - " except Exception as e:\n", - " print(f\"Autoencoder path unavailable ({e}); continuing with FE output.\")\n", - "\n", - "print(\"Engineered dataframe shape:\", fe_result.df_engineered.shape)\n", - "print(\"Model matrix shape used for clustering:\", X.shape)\n", - "print(\"Feature count used for clustering:\", len(feature_names))\n", - "print(\"SHAP source feature count (original vars):\", len(original_feature_names_for_shap))\n", - "print(\"First SHAP source vars:\", original_feature_names_for_shap[:10])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ca7f19aa", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:\n", - "[WinError 2] The system cannot find the file specified\n", - "Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.\n", - " warnings.warn(\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", - " cpu_info = subprocess.run(\n", - " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", - " capture_output=True,\n", - " text=True,\n", - " )\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", - " with Popen(*popenargs, **kwargs) as process:\n", - " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", - " self._execute_child(args, executable, preexec_fn, close_fds,\n", - " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " pass_fds, cwd, env,\n", - " ^^^^^^^^^^^^^^^^^^^\n", - " ...<5 lines>...\n", - " gid, gids, uid, umask,\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " start_new_session, process_group)\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", - " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", - " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", - " # no special security\n", - " ^^^^^^^^^^^^^^^^^^^^^\n", - " ...<4 lines>...\n", - " cwd,\n", - " ^^^^\n", - " startupinfo)\n", - " ^^^^^^^^^^^^\n", - "2026-03-06 22:49:58,214 | INFO | segplus.clustering | K search: scores={2: np.float64(0.202), 3: np.float64(0.2145), 4: np.float64(0.1609), 5: np.float64(0.1639), 6: np.float64(0.1444), 7: np.float64(0.1399), 8: np.float64(0.141)} | best k=3 (sil=0.2145)\n", - "2026-03-06 22:50:00,159 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", - "2026-03-06 22:50:00,161 | INFO | segplus.modeling_loop | ============================================================\n", - "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", - "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | ============================================================\n", - "2026-03-06 22:50:00,815 | INFO | segplus.clustering | [kmeans] clusters=3\n", - "2026-03-06 22:50:25,748 | INFO | segplus.clustering | [dbscan] clusters=178\n", - "2026-03-06 22:50:44,501 | INFO | segplus.clustering | [gmm] clusters=3\n", - "2026-03-06 22:50:44,663 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2115 | DB=1.5251 | CH=31125.2 | cov=1.00\n", - "2026-03-06 22:50:44,946 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.2252 | DB=0.8652 | CH=142.0 | cov=1.00\n", - "2026-03-06 22:50:45,068 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0667 | DB=3.5552 | CH=13484.7 | cov=1.00\n", - "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", - "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", - "2026-03-06 22:50:45,072 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2115 pass=True\n", - "2026-03-06 22:50:45,073 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2115 | DB=1.5251 | PASS=True\n", - "2026-03-06 22:50:45,074 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Best algorithm: kmeans\n", - "Clusters: 3\n", - "Silhouette: 0.2115\n", - "Davies-Bouldin: 1.5251\n", - "Passes gate: True\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    iterationtimestampkepsgmm_covbest_algorithmn_clusterssilhouettedavies_bouldincalinski_harabaszpassedreconfig_strategy
    012026-03-06T22:50:45.07245831.661fullkmeans30.21151.525131125.2TrueNone
    \n", - "
    " - ], - "text/plain": [ - " iteration timestamp k eps gmm_cov best_algorithm \\\n", - "0 1 2026-03-06T22:50:45.072458 3 1.661 full kmeans \n", - "\n", - " n_clusters silhouette davies_bouldin calinski_harabasz passed \\\n", - "0 3 0.2115 1.5251 31125.2 True \n", - "\n", - " reconfig_strategy \n", - "0 None " - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 3) Modeling Loop (KMeans + DBSCAN + GMM with reconfiguration)\n", - "experiment_log = ExperimentLog()\n", - "\n", - "best_eval, best_cfg = modeling_loop(\n", - " X=X,\n", - " feature_names=feature_names,\n", - " config=config,\n", - " experiment_log=experiment_log,\n", - ")\n", - "\n", - "print(\"Best algorithm:\", best_eval.algorithm)\n", - "print(\"Clusters:\", best_eval.n_clusters)\n", - "print(\"Silhouette:\", best_eval.silhouette)\n", - "print(\"Davies-Bouldin:\", best_eval.davies_bouldin)\n", - "print(\"Passes gate:\", best_eval.passes)\n", - "\n", - "exp_df = experiment_log.to_dataframe()\n", - "exp_df\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "7e9bafbb", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:50:57,856 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", - "2026-03-06 22:50:57,859 | INFO | segplus.explainability | Computing feature importances...\n", - "2026-03-06 22:51:08,907 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", - "2026-03-06 22:51:08,940 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", - "2026-03-06 22:51:08,944 | INFO | segplus.explainability | Computing PCA loadings...\n", - "2026-03-06 22:51:08,945 | INFO | segplus.explainability | Computing inertia curve...\n", - "2026-03-06 22:51:12,627 | INFO | segplus.explainability | Computing cluster profiles...\n", - "2026-03-06 22:51:12,729 | INFO | segplus.explainability | Building ordered convergence drivers...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stability ARI mean: 0.988\n", - "Stability algorithm used: kmeans\n", - "Ordered top drivers: ['risk_score', 'risk_score_cluster', 'risk_behavior_score', 'delinquency_flag_y', 'credit_score', 'credit_score_cluster', 'monthly_spend_y', 'value_score', 'annual_income', 'log_income']\n", - "Top SHAP % (original variables):\n", - " credit_score: 19.58%\n", - " credit_score_cluster: 19.05%\n", - " risk_score: 9.32%\n", - " risk_score_cluster: 7.35%\n", - " risk_behavior_score: 6.92%\n", - " monthly_spend_y: 5.59%\n", - " delinquency_flag_y: 5.43%\n", - " value_score: 5.40%\n", - " monthly_spend_x: 3.53%\n", - " annual_income: 3.00%\n", - "PC to original feature map (top 5):\n", - " PC1: ['credit_score', 'credit_score_cluster', 'risk_score', 'risk_score_cluster', 'log_income']\n", - " PC2: ['value_score', 'monthly_spend_y', 'monthly_spend_x', 'lifetime_value_proxy', 'utilization_ratio_x']\n", - " PC3: ['age', 'age_cluster', 'digital_affinity_cluster', 'digital_affinity', 'delinquency_flag_y']\n", - " PC4: ['tenure_months', 'tenure_months_cluster', 'lifetime_value_proxy', 'utilization_ratio_x', 'utilization_ratio_y']\n", - " PC5: ['annual_income', 'annual_income_cluster', 'log_income', 'delinquency_flag_y', 'risk_behavior_score']\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    featureshap_importancepca_weighted_loadingshap_rankpca_rankshap_rank_normpca_rank_norminertia_elbow_strengthconvergence_score
    0risk_score0.093210.1696243.03.50.920.90158504.1408420.912
    1risk_score_cluster0.073450.1696244.03.50.880.90158504.1408420.888
    2risk_behavior_score0.069180.1701175.02.00.840.96158504.1408420.888
    3delinquency_flag_y0.054290.1702847.01.00.761.00158504.1408420.856
    4credit_score0.195770.1500411.012.51.000.54158504.1408420.816
    5credit_score_cluster0.190510.1500412.012.50.960.54158504.1408420.792
    6monthly_spend_y0.055910.1504126.010.50.800.62158504.1408420.728
    7value_score0.053970.1504128.010.50.720.62158504.1408420.680
    8annual_income0.030040.15700110.08.00.640.72158504.1408420.672
    9log_income0.029880.15923811.07.00.600.76158504.1408420.664
    10utilization_ratio_y0.028070.16146912.06.00.560.80158504.1408420.656
    11monthly_spend_x0.035330.1490169.014.00.680.48158504.1408420.600
    12utilization_ratio_x0.020780.16152515.05.00.440.84158504.1408420.600
    13annual_income_cluster0.027650.15700113.09.00.520.68158504.1408420.584
    14lifetime_value_proxy0.024850.14514214.015.00.480.44158504.1408420.464
    \n", - "
    " - ], - "text/plain": [ - " feature shap_importance pca_weighted_loading shap_rank \\\n", - "0 risk_score 0.09321 0.169624 3.0 \n", - "1 risk_score_cluster 0.07345 0.169624 4.0 \n", - "2 risk_behavior_score 0.06918 0.170117 5.0 \n", - "3 delinquency_flag_y 0.05429 0.170284 7.0 \n", - "4 credit_score 0.19577 0.150041 1.0 \n", - "5 credit_score_cluster 0.19051 0.150041 2.0 \n", - "6 monthly_spend_y 0.05591 0.150412 6.0 \n", - "7 value_score 0.05397 0.150412 8.0 \n", - "8 annual_income 0.03004 0.157001 10.0 \n", - "9 log_income 0.02988 0.159238 11.0 \n", - "10 utilization_ratio_y 0.02807 0.161469 12.0 \n", - "11 monthly_spend_x 0.03533 0.149016 9.0 \n", - "12 utilization_ratio_x 0.02078 0.161525 15.0 \n", - "13 annual_income_cluster 0.02765 0.157001 13.0 \n", - "14 lifetime_value_proxy 0.02485 0.145142 14.0 \n", - "\n", - " pca_rank shap_rank_norm pca_rank_norm inertia_elbow_strength \\\n", - "0 3.5 0.92 0.90 158504.140842 \n", - "1 3.5 0.88 0.90 158504.140842 \n", - "2 2.0 0.84 0.96 158504.140842 \n", - "3 1.0 0.76 1.00 158504.140842 \n", - "4 12.5 1.00 0.54 158504.140842 \n", - "5 12.5 0.96 0.54 158504.140842 \n", - "6 10.5 0.80 0.62 158504.140842 \n", - "7 10.5 0.72 0.62 158504.140842 \n", - "8 8.0 0.64 0.72 158504.140842 \n", - "9 7.0 0.60 0.76 158504.140842 \n", - "10 6.0 0.56 0.80 158504.140842 \n", - "11 14.0 0.68 0.48 158504.140842 \n", - "12 5.0 0.44 0.84 158504.140842 \n", - "13 9.0 0.52 0.68 158504.140842 \n", - "14 15.0 0.48 0.44 158504.140842 \n", - "\n", - " convergence_score \n", - "0 0.912 \n", - "1 0.888 \n", - "2 0.888 \n", - "3 0.856 \n", - "4 0.816 \n", - "5 0.792 \n", - "6 0.728 \n", - "7 0.680 \n", - "8 0.672 \n", - "9 0.664 \n", - "10 0.656 \n", - "11 0.600 \n", - "12 0.600 \n", - "13 0.584 \n", - "14 0.464 " - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 4) Stability + Explainability\n", - "stability = run_stability_test(\n", - " X=X,\n", - " labels=best_eval.labels,\n", - " n_clusters=best_eval.n_clusters,\n", - " config=config,\n", - " algorithm=best_eval.algorithm,\n", - " model=best_eval.model,\n", - ")\n", - "\n", - "explainability = build_explainability_report(\n", - " X=X,\n", - " labels=best_eval.labels,\n", - " feature_names=feature_names,\n", - " df_raw=fe_result.df_engineered,\n", - " pca=pca_for_explainability,\n", - " k_range=config.k_range,\n", - " random_state=config.random_state,\n", - " n_top=config.n_top_features,\n", - " X_original=X_original_for_shap,\n", - " original_feature_names=original_feature_names_for_shap,\n", - ")\n", - "\n", - "print(\"Stability ARI mean:\", stability.ari_mean)\n", - "print(\"Stability algorithm used:\", best_eval.algorithm)\n", - "print(\"Ordered top drivers:\", explainability.top_features[:10])\n", - "print(\"Top SHAP % (original variables):\")\n", - "for k, v in list(explainability.feature_importance_pct.items())[:10]:\n", - " print(f\" {k}: {v:.2f}%\")\n", - "\n", - "print(\"PC to original feature map (top 5):\")\n", - "for pc, cols in list(explainability.pc_feature_map.items())[:5]:\n", - " print(f\" {pc}: {cols}\")\n", - "\n", - "explainability.ordered_feature_drivers.head(15)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "000fb2d4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Installed Ollama models: ['qwen2.5:7b']\n", - "Selected model tag: qwen2.5:7b\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:51:17,003 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", - "2026-03-06 22:53:19,121 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 22:54:37,832 | INFO | segplus.ollama_client | Ollama response received (534 chars)\n", - "2026-03-06 22:55:12,181 | INFO | segplus.ollama_client | Ollama response received (14 chars)\n", - "2026-03-06 22:55:12,184 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'Elite Spenders'\n", - "2026-03-06 22:55:12,202 | INFO | segplus.persona_generation | Persona generated: Cluster A -> Elite Spenders\n", - "2026-03-06 22:57:14,441 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 22:57:55,579 | INFO | segplus.ollama_client | Ollama response received (551 chars)\n", - "2026-03-06 22:58:37,127 | INFO | segplus.ollama_client | Ollama response received (17 chars)\n", - "2026-03-06 22:58:37,130 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", - "2026-03-06 23:00:39,228 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 23:02:14,255 | INFO | segplus.ollama_client | Ollama response received (839 chars)\n", - "2026-03-06 23:02:50,674 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", - "2026-03-06 23:02:50,678 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", - "2026-03-06 23:02:50,721 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", - "2026-03-06 23:04:52,791 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 23:06:56,881 | WARNING | segplus.ollama_client | Ollama attempt 2 failed (Timeout after 120s). Retrying in 4s...\n", - "2026-03-06 23:09:02,941 | WARNING | segplus.persona_generation | Business grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Generated personas: 3\n", - "Executive summary: LLM grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n", - "persona_df columns: ['cluster', 'genai_persona_name', 'profile_descriptor', 'description', 'cluster_size', 'cluster_pct', 'ordered_top_features', 'genai_recommendations', 'categorization_basis', 'naming_rationale']\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    clustergenai_persona_nameprofile_descriptordescriptioncluster_sizecluster_pctordered_top_featuresgenai_recommendationscategorization_basisnaming_rationale
    0Cluster AElite SpendersHigh Value Score & High Monthly Spend YHigh-Value Premium Spenders are among the most...87740.0731value_score:0.1, monthly_spend_y:25414.84, mon...Targeted Upselling of Premium Products | Perso...value_score, monthly_spend_y, monthly_spend_x,...Second-pass focused LLM naming from profile: H...
    1Cluster BCredit Risk Strategists – Higher Credit Score ...High Credit Score & Low Risk ScoreThese customers are highly creditworthy and lo...567820.4732credit_score:827.07, credit_score_cluster:827....Target with premium product promotions | Enhan...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    2Cluster CCredit Risk Strategists – Lower Credit Score C...Low Credit Score & High Risk ScoreBudget-conscious Credit Risk Takers are custom...544440.4537credit_score:692.54, credit_score_cluster:692....Offer tailored credit products with flexible t...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    \n", - "
    " - ], - "text/plain": [ - " cluster genai_persona_name \\\n", - "0 Cluster A Elite Spenders \n", - "1 Cluster B Credit Risk Strategists – Higher Credit Score ... \n", - "2 Cluster C Credit Risk Strategists – Lower Credit Score C... \n", - "\n", - " profile_descriptor \\\n", - "0 High Value Score & High Monthly Spend Y \n", - "1 High Credit Score & Low Risk Score \n", - "2 Low Credit Score & High Risk Score \n", - "\n", - " description cluster_size \\\n", - "0 High-Value Premium Spenders are among the most... 8774 \n", - "1 These customers are highly creditworthy and lo... 56782 \n", - "2 Budget-conscious Credit Risk Takers are custom... 54444 \n", - "\n", - " cluster_pct ordered_top_features \\\n", - "0 0.0731 value_score:0.1, monthly_spend_y:25414.84, mon... \n", - "1 0.4732 credit_score:827.07, credit_score_cluster:827.... \n", - "2 0.4537 credit_score:692.54, credit_score_cluster:692.... \n", - "\n", - " genai_recommendations \\\n", - "0 Targeted Upselling of Premium Products | Perso... \n", - "1 Target with premium product promotions | Enhan... \n", - "2 Offer tailored credit products with flexible t... \n", - "\n", - " categorization_basis \\\n", - "0 value_score, monthly_spend_y, monthly_spend_x,... \n", - "1 credit_score, credit_score_cluster, risk_score... \n", - "2 credit_score, credit_score_cluster, risk_score... \n", - "\n", - " naming_rationale \n", - "0 Second-pass focused LLM naming from profile: H... \n", - "1 LLM returned generic name; using business-styl... \n", - "2 LLM returned generic name; using business-styl... " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 5) Persona Generation + Business Grounding (Ollama local, with fallback)\n", - "import requests\n", - "\n", - "\n", - "def _list_local_ollama_models(host: str) -> list[str]:\n", - " try:\n", - " r = requests.get(f\"{host.rstrip('/')}/api/tags\", timeout=8)\n", - " r.raise_for_status()\n", - " return [m.get(\"name\", \"\") for m in r.json().get(\"models\", []) if m.get(\"name\")]\n", - " except Exception as e:\n", - " print(f\"Ollama model discovery failed: {e}\")\n", - " return []\n", - "\n", - "\n", - "def _choose_ollama_model(installed: list[str], preferred: list[str], configured: str) -> str:\n", - " if configured and configured in installed:\n", - " return configured\n", - " if configured:\n", - " matches = [m for m in installed if configured in m]\n", - " if matches:\n", - " return matches[0]\n", - " for pref in preferred:\n", - " matches = [m for m in installed if m.startswith(pref) or pref in m]\n", - " if matches:\n", - " return matches[0]\n", - " return installed[0] if installed else (configured or \"qwen2.5:7b\")\n", - "\n", - "\n", - "installed_models = _list_local_ollama_models(config.ollama_host)\n", - "selected_model = _choose_ollama_model(installed_models, PREFERRED_OLLAMA_MODELS, config.ollama_model)\n", - "config.ollama_model = selected_model\n", - "\n", - "print(\"Installed Ollama models:\", installed_models if installed_models else \"None found / Ollama offline\")\n", - "print(\"Selected model tag:\", config.ollama_model)\n", - "\n", - "ollama_client = OllamaClient(\n", - " host=config.ollama_host,\n", - " model=config.ollama_model,\n", - " timeout=config.ollama_timeout,\n", - ")\n", - "persona_generator = PersonaGenerator(ollama_client, config)\n", - "\n", - "# Step A: Cluster personas\n", - "personas = persona_generator.generate_personas(\n", - " evaluation=best_eval,\n", - " explainability=explainability,\n", - " raw_df=fe_result.df_original,\n", - " schema=schema,\n", - ")\n", - "\n", - "# Step B: Business grounding + GenAI per-cluster naming/actions\n", - "grounding = persona_generator.ground_in_business_objective(personas)\n", - "personas = persona_generator.apply_grounding_to_personas(personas, grounding)\n", - "\n", - "persona_df = pd.DataFrame([\n", - " {\n", - " \"cluster\": p.persona_name,\n", - " \"genai_persona_name\": p.archetype,\n", - " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", - " \"description\": getattr(p, \"description\", \"\"),\n", - " \"cluster_size\": p.cluster_size,\n", - " \"cluster_pct\": round(p.cluster_pct, 4),\n", - " \"ordered_top_features\": \", \".join([f\"{k}:{v}\" for k, v in p.top_features.items()]),\n", - " \"genai_recommendations\": \" | \".join(p.business_recommendations),\n", - " \"categorization_basis\": \", \".join(getattr(p, \"categorization_basis\", [])),\n", - " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", - " }\n", - " for p in personas\n", - "])\n", - "\n", - "# Exact output schema check\n", - "required_persona_cols = [\n", - " \"cluster\", \"genai_persona_name\", \"profile_descriptor\", \"description\",\n", - " \"cluster_size\", \"cluster_pct\", \"ordered_top_features\",\n", - " \"genai_recommendations\", \"categorization_basis\", \"naming_rationale\",\n", - "]\n", - "missing_cols = [c for c in required_persona_cols if c not in persona_df.columns]\n", - "if missing_cols:\n", - " raise ValueError(f\"persona_df missing required columns: {missing_cols}\")\n", - "\n", - "print(\"Generated personas:\", len(personas))\n", - "print(\"Executive summary:\", grounding.executive_summary)\n", - "print(\"persona_df columns:\", list(persona_df.columns))\n", - "persona_df\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "707cdc91", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 23:09:06,354 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", - "2026-03-06 23:09:06,629 | INFO | segplus.visualization | Saved: feature_importance.png\n", - "2026-03-06 23:09:38,632 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", - "2026-03-06 23:09:39,175 | INFO | segplus.visualization | Saved: pca_loadings.png\n", - "2026-03-06 23:09:39,422 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", - "2026-03-06 23:09:39,526 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", - "2026-03-06 23:09:40,057 | INFO | segplus.visualization | Saved: persona_radar.png\n", - "2026-03-06 23:09:40,212 | INFO | segplus.visualization | Saved: experiment_history.png\n", - "2026-03-06 23:09:40,356 | INFO | segplus.visualization | Saved: elbow_curve.png\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saved charts to: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n" - ] - } - ], - "source": [ - "# 6) Visualizations\n", - "plot_cluster_scatter_2d(X, best_eval.labels, output_dir, best_eval)\n", - "plot_shap_importance(\n", - " explainability.feature_importances, output_dir, top_n=15,\n", - " importance_pct=explainability.feature_importance_pct,\n", - ")\n", - "plot_shap_summary(\n", - " X_original_for_shap,\n", - " best_eval.labels,\n", - " original_feature_names_for_shap,\n", - " output_dir,\n", - " random_state=config.random_state,\n", - " max_display=15,\n", - ")\n", - "plot_pca_loadings_heatmap(explainability.pca_loadings, output_dir)\n", - "plot_cluster_profiles_heatmap(explainability.cluster_profiles, explainability.top_features, output_dir)\n", - "plot_cluster_sizes(best_eval.labels, personas, output_dir)\n", - "plot_radar_charts(fe_result.df_original, best_eval.labels, personas, explainability.top_features, output_dir)\n", - "plot_experiment_history(experiment_log, output_dir)\n", - "plot_elbow_curve(explainability.inertia_curve, output_dir)\n", - "\n", - "print(\"Saved charts to:\", output_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "969da7d8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 23:09:42,767 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Exported:\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\clustered_customers.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\cluster_profiles.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\ordered_feature_drivers.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\shap_feature_importance_pct.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\pc_feature_map.json\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.json\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\business_grounding.json\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" - ] - } - ], - "source": [ - "# 7) Export Outputs\n", - "clustered_df = fe_result.df_original.copy()\n", - "clustered_df[\"cluster\"] = best_eval.labels\n", - "\n", - "clustered_path = output_dir / \"clustered_customers.csv\"\n", - "profiles_path = output_dir / \"cluster_profiles.csv\"\n", - "ordered_drivers_path = output_dir / \"ordered_feature_drivers.csv\"\n", - "shap_pct_path = output_dir / \"shap_feature_importance_pct.csv\"\n", - "pc_feature_map_path = output_dir / \"pc_feature_map.json\"\n", - "personas_path = output_dir / \"personas.csv\"\n", - "personas_json_path = output_dir / \"personas.json\"\n", - "grounding_path = output_dir / \"business_grounding.json\"\n", - "exp_log_path = output_dir / \"experiment_log.json\"\n", - "\n", - "clustered_df.to_csv(clustered_path, index=False)\n", - "explainability.cluster_profiles.to_csv(profiles_path)\n", - "if explainability.ordered_feature_drivers is not None:\n", - " explainability.ordered_feature_drivers.to_csv(ordered_drivers_path, index=False)\n", - "\n", - "shap_pct_df = pd.DataFrame([\n", - " {\"feature\": k, \"importance_pct\": v}\n", - " for k, v in explainability.feature_importance_pct.items()\n", - "]).sort_values(\"importance_pct\", ascending=False)\n", - "shap_pct_df.to_csv(shap_pct_path, index=False)\n", - "\n", - "with open(pc_feature_map_path, \"w\", encoding=\"utf-8\") as f:\n", - " json.dump(explainability.pc_feature_map, f, indent=2)\n", - "\n", - "# Export exact persona schema\n", - "persona_df.to_csv(personas_path, index=False)\n", - "\n", - "personas_payload = [\n", - " {\n", - " \"cluster\": p.persona_name,\n", - " \"genai_persona_name\": p.archetype,\n", - " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", - " \"description\": getattr(p, \"description\", \"\"),\n", - " \"key_traits\": p.key_traits,\n", - " \"genai_recommendations\": p.business_recommendations,\n", - " \"cluster_size\": p.cluster_size,\n", - " \"cluster_pct\": p.cluster_pct,\n", - " \"top_features\": p.top_features,\n", - " \"categorization_basis\": getattr(p, \"categorization_basis\", []),\n", - " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", - " }\n", - " for p in personas\n", - "]\n", - "with open(personas_json_path, \"w\", encoding=\"utf-8\") as f:\n", - " json.dump(personas_payload, f, indent=2)\n", - "\n", - "experiment_log.to_json(exp_log_path)\n", - "\n", - "with open(grounding_path, \"w\", encoding=\"utf-8\") as f:\n", - " json.dump(\n", - " {\n", - " \"executive_summary\": grounding.executive_summary,\n", - " \"cluster_priorities\": grounding.cluster_priorities,\n", - " \"cluster_actions\": grounding.cluster_actions,\n", - " \"quick_wins\": grounding.quick_wins,\n", - " },\n", - " f,\n", - " indent=2,\n", - " )\n", - "\n", - "print(\"Exported:\")\n", - "print(\" -\", clustered_path)\n", - "print(\" -\", profiles_path)\n", - "print(\" -\", ordered_drivers_path)\n", - "print(\" -\", shap_pct_path)\n", - "print(\" -\", pc_feature_map_path)\n", - "print(\" -\", personas_path)\n", - "print(\" -\", personas_json_path)\n", - "print(\" -\", grounding_path)\n", - "print(\" -\", exp_log_path)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notes\n", - "\n", - "- Architecture implemented: data input -> FE -> KMeans/DBSCAN/GMM -> eval gate loop -> explainability -> ordered drivers -> persona generation -> business grounding -> per-cluster rationale outputs.\n", - "- Local Ollama is first-class. `qwen2.5` is primary model and auto-selected when installed.\n", - "- Ordered feature driver list combines SHAP importance + weighted PCA loadings, with inertia elbow context.\n", - "- `pc_feature_map.json` provides exact mapping from each PC to top original variables.\n", - "- SHAP summary plot is saved as `shap_summary.png` when `shap` is installed.\n", - "- Optional autoencoder latent representation is available via `USE_AUTOENCODER_REPRESENTATION=True`.\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python", - "version": "3.x" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From f813a60f1d0cb4f9c6534c8c0c13f6ef291300fd Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:21:01 +0530 Subject: [PATCH 08/13] Delete .gitignore --- .gitignore | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index bc15621..0000000 --- a/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# Data and binaries -*.xlsx -*.xls -*.parquet -*.csv -*.exe - -# Outputs -output/ -persona_output/ -segplus_output/ - -# Python cache -__pycache__/ -*.pyc - -# Env -.venv/ -venv/ - -# OS -.DS_Store -Thumbs.db - -Claude code/ -data/* -!data/.gitkeep From 07ed95768eba51832be6e7b15c3b1b6812aa70eb Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:24:46 +0530 Subject: [PATCH 09/13] Remove Data_generator notebook --- Data_generator.ipynb | 272 ------------------------------------------- 1 file changed, 272 deletions(-) delete mode 100644 Data_generator.ipynb diff --git a/Data_generator.ipynb b/Data_generator.ipynb deleted file mode 100644 index f5dd20f..0000000 --- a/Data_generator.ipynb +++ /dev/null @@ -1,272 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cf9ddabf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Customer Master: (150000, 8)\n", - "Transactions: (3001170, 5)\n", - "Digital: (150000, 4)\n", - "Churn: (150000, 2)\n", - "MMM Weekly: (120, 8)\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "from scipy.special import expit\n", - "from scipy.stats import multivariate_normal\n", - "from datetime import timedelta\n", - "\n", - "np.random.seed(42)\n", - "\n", - "# ============================================================\n", - "# CONFIG\n", - "# ============================================================\n", - "\n", - "N_CUSTOMERS = 150_000\n", - "WEEKS = 120\n", - "START_DATE = pd.to_datetime(\"2023-01-01\")\n", - "\n", - "# ============================================================\n", - "# 1️⃣ CUSTOMER MASTER (Correlated Structure)\n", - "# ============================================================\n", - "\n", - "def generate_customer_master(n):\n", - "\n", - " # Correlated latent variables: income, age, risk_factor\n", - " mean = [12, 40, 0] # log-income, age, latent risk\n", - " cov = [\n", - " [1.2, -0.3, -0.5],\n", - " [-0.3, 25, 0.2],\n", - " [-0.5, 0.2, 1]\n", - " ]\n", - "\n", - " latent = multivariate_normal(mean, cov).rvs(n)\n", - "\n", - " log_income = latent[:,0]\n", - " age = np.clip(latent[:,1], 21, 75)\n", - " latent_risk = latent[:,2]\n", - "\n", - " income = np.exp(log_income) * 1000\n", - " credit_score = np.clip(750 + 40*(log_income - log_income.mean()) - 60*latent_risk, 300, 900)\n", - " risk_score = expit(latent_risk)\n", - "\n", - " digital_affinity = np.clip(1 - (age - 21)/60 + np.random.normal(0,0.1,n), 0,1)\n", - " tenure = np.random.randint(6, 180, n)\n", - "\n", - " credit_limit = income * np.random.uniform(0.2, 0.5, n)\n", - "\n", - " df = pd.DataFrame({\n", - " \"customer_id\": [f\"CUST_{i}\" for i in range(n)],\n", - " \"age\": age,\n", - " \"annual_income\": income,\n", - " \"credit_score\": credit_score,\n", - " \"risk_score\": risk_score,\n", - " \"digital_affinity\": digital_affinity,\n", - " \"tenure_months\": tenure,\n", - " \"credit_limit\": credit_limit\n", - " })\n", - "\n", - " return df\n", - "\n", - "# ============================================================\n", - "# 2️⃣ TRANSACTION ENGINE (Heavy-Tailed + Utilization)\n", - "# ============================================================\n", - "\n", - "def generate_transactions(customers):\n", - "\n", - " txn_rows = []\n", - "\n", - " for _, row in customers.iterrows():\n", - "\n", - " base_spend = np.random.lognormal(mean=10, sigma=1.0)\n", - " utilization = base_spend / row.credit_limit\n", - "\n", - " delinquency_prob = expit(4*utilization + 3*row.risk_score - 3)\n", - " delinquency_flag = np.random.binomial(1, delinquency_prob)\n", - "\n", - " n_txn = np.random.poisson(20)\n", - "\n", - " for _ in range(n_txn):\n", - " txn_rows.append([\n", - " row.customer_id,\n", - " START_DATE + timedelta(days=int(np.random.uniform(0,365))),\n", - " np.random.lognormal(mean=8, sigma=1.2),\n", - " utilization,\n", - " delinquency_flag\n", - " ])\n", - "\n", - " txn_df = pd.DataFrame(txn_rows, columns=[\n", - " \"customer_id\",\n", - " \"txn_date\",\n", - " \"txn_amount\",\n", - " \"utilization_ratio\",\n", - " \"delinquency_flag\"\n", - " ])\n", - "\n", - " return txn_df\n", - "\n", - "# ============================================================\n", - "# 3️⃣ DIGITAL ENGAGEMENT\n", - "# ============================================================\n", - "\n", - "def generate_digital(customers):\n", - "\n", - " df = customers.copy()\n", - "\n", - " df[\"app_sessions_30d\"] = (\n", - " df.digital_affinity * 35 + np.random.normal(0,5,len(df))\n", - " ).astype(int)\n", - "\n", - " df[\"email_open_rate\"] = np.clip(\n", - " df.digital_affinity + np.random.normal(0,0.1,len(df)),0,1\n", - " )\n", - "\n", - " df[\"complaints\"] = np.random.poisson(df.risk_score * 3)\n", - "\n", - " return df[[\n", - " \"customer_id\",\n", - " \"app_sessions_30d\",\n", - " \"email_open_rate\",\n", - " \"complaints\"\n", - " ]]\n", - "\n", - "# ============================================================\n", - "# 4️⃣ CHURN SIMULATION\n", - "# ============================================================\n", - "\n", - "def generate_churn(customers, digital):\n", - "\n", - " merged = customers.merge(digital, on=\"customer_id\")\n", - "\n", - " logit = (\n", - " -2.5\n", - " + 3*merged.risk_score\n", - " + 2*(merged.complaints > 2)\n", - " - 0.02*merged.tenure_months\n", - " - 1.5*merged.digital_affinity\n", - " )\n", - "\n", - " churn_prob = expit(logit)\n", - " merged[\"churn_flag\"] = np.random.binomial(1, churn_prob)\n", - "\n", - " return merged[[\"customer_id\", \"churn_flag\"]]\n", - "\n", - "# ============================================================\n", - "# 5️⃣ MMM ENGINE (Correlated + Adstock + Saturation + Shock)\n", - "# ============================================================\n", - "\n", - "def adstock(x, decay=0.6):\n", - " result = np.zeros_like(x)\n", - " for t in range(len(x)):\n", - " result[t] = x[t] + (decay * result[t-1] if t > 0 else 0)\n", - " return result\n", - "\n", - "def hill(x, alpha=1.5):\n", - " return x**alpha / (x**alpha + 1)\n", - "\n", - "def generate_mmm(weeks):\n", - "\n", - " mean = [10, 8, 7]\n", - " cov = [\n", - " [1, 0.6, 0.4],\n", - " [0.6, 1, 0.5],\n", - " [0.4, 0.5, 1]\n", - " ]\n", - "\n", - " latent_spend = multivariate_normal(mean, cov).rvs(weeks)\n", - " tv = np.exp(latent_spend[:,0]) * 1e5\n", - " meta = np.exp(latent_spend[:,1]) * 8e4\n", - " search = np.exp(latent_spend[:,2]) * 5e4\n", - "\n", - " seasonality = 1 + 0.2*np.sin(np.linspace(0, 4*np.pi, weeks))\n", - "\n", - " macro = np.ones(weeks)\n", - " macro[50:60] *= 0.85 # recession shock\n", - "\n", - " competitor = np.ones(weeks)\n", - " competitor[70:80] *= 1.2\n", - "\n", - " tv_ad = adstock(tv)\n", - " meta_ad = hill(adstock(meta))\n", - " search_ad = search\n", - "\n", - " sales = (\n", - " 0.00002 * tv_ad\n", - " + 0.00004 * meta_ad\n", - " + 0.00005 * search_ad\n", - " + 2000 * seasonality\n", - " + 1500 * macro\n", - " - 1000 * (competitor - 1)\n", - " + np.random.normal(0, 800, weeks)\n", - " )\n", - "\n", - " df = pd.DataFrame({\n", - " \"week\": np.arange(weeks),\n", - " \"tv_spend\": tv,\n", - " \"meta_spend\": meta,\n", - " \"search_spend\": search,\n", - " \"seasonality\": seasonality,\n", - " \"macro_index\": macro,\n", - " \"competitor_index\": competitor,\n", - " \"sales\": sales\n", - " })\n", - "\n", - " return df\n", - "\n", - "# ============================================================\n", - "# RUN FULL PIPELINE\n", - "# ============================================================\n", - "\n", - "customers = generate_customer_master(N_CUSTOMERS)\n", - "transactions = generate_transactions(customers)\n", - "digital = generate_digital(customers)\n", - "churn = generate_churn(customers, digital)\n", - "mmm_weekly = generate_mmm(WEEKS)\n", - "\n", - "print(\"Customer Master:\", customers.shape)\n", - "print(\"Transactions:\", transactions.shape)\n", - "print(\"Digital:\", digital.shape)\n", - "print(\"Churn:\", churn.shape)\n", - "print(\"MMM Weekly:\", mmm_weekly.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "56531166", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "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.13.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From f000257bcc09cb9a758a40b762fb23e0bbf3c507 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:27:58 +0530 Subject: [PATCH 10/13] Remove unnecessary project files --- architecture.md.resolved | 238 ------ architecture_detailed.html | 952 ----------------------- architecture_presentation.html | 988 ----------------------- cluster_evaluation.py | 381 --------- clustering.py | 311 -------- config.py | 181 ----- dashboard.py | 317 -------- data_import.py | 275 ------- eda_preprocessing.py | 412 ---------- implementation_plan.md.resolved | 131 ---- main.py | 275 ------- notebook.ipynb | 1295 ------------------------------- 12 files changed, 5756 deletions(-) delete mode 100644 architecture.md.resolved delete mode 100644 architecture_detailed.html delete mode 100644 architecture_presentation.html delete mode 100644 cluster_evaluation.py delete mode 100644 clustering.py delete mode 100644 config.py delete mode 100644 dashboard.py delete mode 100644 data_import.py delete mode 100644 eda_preprocessing.py delete mode 100644 implementation_plan.md.resolved delete mode 100644 main.py delete mode 100644 notebook.ipynb diff --git a/architecture.md.resolved b/architecture.md.resolved deleted file mode 100644 index 5e94516..0000000 --- a/architecture.md.resolved +++ /dev/null @@ -1,238 +0,0 @@ -# Architecture: Financial Services Client Segmentation & GenAI Persona Generation - -## High-Level System Architecture - -```mermaid -graph TB - subgraph "1. DATA LAYER" - A["🏗️ Synthetic Data Generator
    generate_data.py"] --> B[("📊 Raw Client Data
    data/synthetic_clients.csv
    2,000 records × 25 features")] - end - - subgraph "2. PROCESSING LAYER" - B --> C["🔍 EDA & Preprocessing
    eda_preprocessing.py"] - C --> D[("🧹 Processed Data
    data/processed_clients.csv
    Scaled + PCA")] - C --> E["📈 EDA Charts
    output/eda/"] - end - - subgraph "3. ANALYTICS LAYER" - D --> F["🎯 Clustering Engine
    clustering.py"] - F --> G["K-Means"] - F --> H["DBSCAN"] - F --> I["Hierarchical"] - G --> J[("📋 Clustered Data
    data/clustered_clients.csv")] - H --> J - I --> J - end - - subgraph "4. GenAI LAYER" - J --> K["🤖 Persona Generator
    persona_generation.py"] - K <--> L["☁️ Google Gemini API"] - K --> M["📝 Persona Profiles
    output/personas.md
    output/personas.json"] - end - - subgraph "5. PRESENTATION LAYER" - J --> N["📊 Dashboard Builder
    dashboard.py"] - M --> N - N --> O["🌐 Interactive Dashboard
    output/dashboard.html"] - end - - subgraph "6. ORCHESTRATION" - P["🚀 main.py"] -.-> A - P -.-> C - P -.-> F - P -.-> K - P -.-> N - end - - style A fill:#4CAF50,color:#fff - style C fill:#2196F3,color:#fff - style F fill:#FF9800,color:#fff - style K fill:#9C27B0,color:#fff - style N fill:#E91E63,color:#fff - style P fill:#607D8B,color:#fff -``` - ---- - -## Data Flow Pipeline - -```mermaid -flowchart LR - A["Generate
    2,000 Clients"] -->|raw CSV| B["Clean &
    Scale"] -->|processed CSV| C["Cluster
    Clients"] -->|labeled CSV| D["GenAI
    Personas"] -->|JSON + MD| E["Dashboard"] - - style A fill:#4CAF50,color:#fff - style B fill:#2196F3,color:#fff - style C fill:#FF9800,color:#fff - style D fill:#9C27B0,color:#fff - style E fill:#E91E63,color:#fff -``` - ---- - -## Synthetic Data Schema - -```mermaid -erDiagram - CLIENT { - string client_id PK - int age - string gender - float income - string education - string marital_status - int dependents - string occupation - } - - FINANCIAL_PROFILE { - string client_id FK - float account_balance - int credit_score - float monthly_spending - float savings_rate - float debt_to_income_ratio - float investment_portfolio_value - } - - PRODUCT_HOLDINGS { - string client_id FK - bool has_credit_card - bool has_mortgage - bool has_personal_loan - bool has_investment_account - bool has_insurance - int num_products - } - - BEHAVIORAL { - string client_id FK - float digital_engagement_score - int branch_visits_monthly - float customer_tenure_years - int transaction_frequency_monthly - float avg_transaction_amount - } - - SATISFACTION { - string client_id FK - int nps_score - int complaint_count_yearly - float churn_risk_score - } - - CLIENT ||--|| FINANCIAL_PROFILE : has - CLIENT ||--|| PRODUCT_HOLDINGS : holds - CLIENT ||--|| BEHAVIORAL : exhibits - CLIENT ||--|| SATISFACTION : rates -``` - -> All entities are stored as columns in a **single flat CSV** for ML simplicity. - ---- - -## Clustering Strategy - -```mermaid -graph TD - A["Preprocessed Features
    (StandardScaler + PCA)"] --> B{"Method Selection"} - - B --> C["K-Means"] - B --> D["DBSCAN"] - B --> E["Agglomerative"] - - C --> C1["Elbow Method
    ↳ Optimal K"] - C --> C2["Silhouette Score
    ↳ Cluster Quality"] - C1 --> F["Final Segments"] - C2 --> F - - D --> D1["Epsilon Tuning
    ↳ k-distance plot"] - D1 --> F - - E --> E1["Dendrogram
    ↳ Cut Height"] - E1 --> F - - F --> G["Cluster Profiling
    Mean/Median per feature"] - G --> H["Radar Charts +
    Box Plots"] - - style C fill:#FF9800,color:#fff - style D fill:#FF5722,color:#fff - style E fill:#795548,color:#fff - style F fill:#4CAF50,color:#fff -``` - ---- - -## GenAI Persona Generation Flow - -```mermaid -sequenceDiagram - participant P as persona_generation.py - participant D as Clustered Data - participant G as Google Gemini API - - P->>D: Load cluster profiles - loop For each cluster - P->>P: Aggregate cluster stats
    (mean age, income, products, etc.) - P->>P: Build structured prompt - P->>G: Send prompt with cluster profile - G-->>P: Return persona (name, goals,
    pain points, strategy) - P->>P: Parse & format response - end - P->>P: Save personas.json + personas.md -``` - -### Example Prompt Structure -``` -You are a financial services marketing strategist. - -Cluster 3 Profile: -- Avg Age: 42, Income: $125K, Credit Score: 780 -- Products: Mortgage (80%), Investment Account (90%) -- Digital Engagement: High, Tenure: 12 years -- NPS: 8.5, Churn Risk: Low - -Generate a detailed customer persona including: -1. Persona name and one-line description -2. Demographics and lifestyle -3. Financial goals and pain points -4. Product recommendations -5. Preferred communication channels -6. Marketing strategy (tone, offers, timing) -``` - ---- - -## Directory Structure - -``` -Segmentation_Plus/ -├── main.py # 🚀 Pipeline orchestrator -├── generate_data.py # 🏗️ Synthetic data generator -├── eda_preprocessing.py # 🔍 EDA + feature engineering -├── clustering.py # 🎯 Segmentation algorithms -├── persona_generation.py # 🤖 GenAI persona builder -├── dashboard.py # 📊 Interactive visualizations -├── requirements.txt # 📦 Dependencies -├── data/ -│ ├── synthetic_clients.csv # Raw generated data -│ ├── processed_clients.csv # Scaled/transformed data -│ └── clustered_clients.csv # Data with cluster labels -└── output/ - ├── eda/ # EDA charts (PNG) - ├── clusters/ # Clustering charts (PNG) - ├── personas.md # AI-generated personas (readable) - ├── personas.json # AI-generated personas (structured) - └── dashboard.html # Interactive Plotly dashboard -``` - ---- - -## Technology Stack - -| Layer | Technology | Purpose | -|---|---|---| -| **Data Generation** | `numpy`, `pandas` | Correlated synthetic data | -| **Visualization** | `matplotlib`, `seaborn`, `plotly` | Static + interactive charts | -| **ML / Clustering** | `scikit-learn` | K-Means, DBSCAN, Hierarchical, PCA | -| **GenAI** | `google-generativeai` (Gemini) | Persona narrative generation | -| **Orchestration** | `main.py` | End-to-end pipeline runner | diff --git a/architecture_detailed.html b/architecture_detailed.html deleted file mode 100644 index f2e52c9..0000000 --- a/architecture_detailed.html +++ /dev/null @@ -1,952 +0,0 @@ - - - - - - - Segmentation Plus — Detailed Technical Guide - - - - - - - -
    -
    Detailed Technical Guide
    -

    Segmentation Plus — Step-by-Step

    -

    Deep-dive into each pipeline step: the conceptual "why" and the technical "how" behind domain configuration, - EDA, clustering, evaluation, and GenAI persona generation.

    -
    - -
    - - -
    -
    -
    1
    -

    Domain Configuration Foundation Layer

    -
    - -
    -
    -

    💡 Conceptual — Why?

    -

    Different industries have fundamentally different customer attributes and business questions. A - bank cares about credit risk and product cross-sell; a retailer about purchase frequency and - basket size. Rather than building separate systems, we use a configuration-driven - architecture — one engine, many domains.

    -
      -
    • Eliminates code duplication across client engagements
    • -
    • New domains added by creating a YAML file, not writing new code
    • -
    • Ensures consistency in methodology across all domains
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -

    Each domain is defined in a domains/*.yaml file containing:

    -
      -
    • Feature schema — required columns, data types, valid ranges
    • -
    • EDA rules — which domain-specific analyses to run
    • -
    • Feature engineering recipes — computed columns, ratios, derived scores
    • -
    • Persona prompt template — domain-specific GenAI instructions
    • -
    • Synthetic data distributions — realistic parameter ranges for demo - generation
    • -
    -

    config.py loads the YAML at pipeline start and injects the domain context into every - downstream module via a DomainConfig dataclass.

    -
    -
    - -
    -
    # domains/financial_services.yaml (simplified)
    -domain: financial_services
    -display_name: "Financial Services"
    -
    -features:
    -  demographics: [age, gender, annual_income, education, occupation]
    -  financial: [credit_score, account_balance, portfolio_value, debt_to_income]
    -  products: [has_mortgage, has_credit_card, has_investment_account]
    -  behavioral: [digital_engagement, branch_visits, transaction_frequency]
    -  satisfaction: [nps_score, churn_risk_score]
    -
    -feature_engineering:
    -  - name: wealth_tier
    -    formula: "annual_income * portfolio_value"
    -    bins: [low, medium, high, ultra_high]
    -  - name: digital_ratio
    -    formula: "digital_engagement / (digital_engagement + branch_visits)"
    -
    -eda:
    -  domain_analyses:
    -    - income_vs_credit_risk
    -    - product_cross_holdings_matrix
    -    - high_value_customer_identification
    -
    -persona_prompt_template: |
    -  You are advising a {institution_type} on their customer segments...
    -
    -
    - -
    - - -
    -
    -
    2
    -

    Data Input Layer Synthetic Generation + Real Data Import

    -
    - -
    -
    -

    💡 Conceptual — Why?

    -
      -
    • Synthetic data enables POC/demo without waiting for real client data — - critical for fast sales cycles and internal showcases
    • -
    • Real data import is the production path — when a client provides their - actual customer data, the same pipeline processes it without code changes
    • -
    • Synthetic data is generated with realistic correlations (e.g., higher - income → higher portfolio value → higher credit score) so the downstream clustering produces - meaningful segments even in demo mode
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -

    Synthetic generation (generate_data.py):

    -
      -
    • Uses numpy.random with multivariate normal distributions to create correlated - features
    • -
    • Categorical features sampled via weighted np.random.choice
    • -
    • Domain config defines realistic ranges (e.g., credit_score: 300–850, age: 18–80)
    • -
    -

    Real data import (data_import.py):

    -
      -
    • Schema validation against domain YAML — checks required columns, types, ranges
    • -
    • Automatic column mapping (fuzzy matching for similar column names)
    • -
    • Outputs standardized DataFrame regardless of input source (CSV, SQL, API)
    • -
    -
    -
    - -
    Synthetic correlation: X ~ 𝒩(μ, Σ) where Σ encodes realistic inter-feature correlations -
    - -
    Key design principle: The pipeline is data-source agnostic - — once data passes the schema validator, every downstream step works identically whether the data is - synthetic or real.
    -
    - -
    - - -
    -
    -
    3
    -

    Domain-Aware EDA & Feature Engineering Understanding + Transforming the Data

    -
    - -
    -
    -

    💡 Conceptual — Why?

    -

    EDA tells us what patterns exist in the data before we cluster. Without EDA, - we're clustering blindly — and bad features produce bad segments.

    -
      -
    • Generic EDA — distributions, correlations, outliers, missing values. - Applied to every domain uniformly.
    • -
    • Domain-specific EDA — analyses that only make sense in context. Example: - RFM analysis is meaningless for healthcare but critical for retail.
    • -
    • Feature engineering creates new variables that capture business logic - (e.g., wealth_tier = income × portfolio) and improve clustering quality.
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -

    Generic EDA (always runs):

    -
      -
    • Distribution histograms + KDE plots (seaborn.histplot)
    • -
    • Pearson correlation matrix heatmap
    • -
    • Box plots for outlier detection (IQR method)
    • -
    • Missing value matrix (missingno pattern)
    • -
    -

    Domain-specific EDA (from YAML config):

    -
      -
    • FS: Income decile analysis, credit score vs. product count scatter
    • -
    • Retail: Recency-Frequency-Monetary (RFM) scoring matrix
    • -
    • Healthcare: Risk stratification pyramid, utilization heatmap
    • -
    -
    -
    - -
    -

    Feature Engineering Pipeline

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StageWhat It DoesMethod
    1. Domain featuresCreate business-meaningful derived columnsFormulas from YAML config (ratios, tiers, scores)
    2. EncodingConvert categorical to numericalOne-hot encoding (pd.get_dummies) or Label encoding
    3. Outlier handlingCap extreme valuesWinsorization at 1st/99th percentile
    4. ScalingNormalize all features to same scaleStandardScaler → mean=0, std=1 (critical for distance-based algorithms) -
    5. Dimensionality reductionReduce feature space for visualizationPCA — retain components explaining ≥85% variance
    -
    - -
    Why StandardScaler matters: K-Means and DBSCAN use Euclidean - distance. Without scaling, a feature like income (range: $20K–$500K) would dominate over credit_score - (range: 300–850) simply due to magnitude, not importance.
    -
    - -
    - - -
    -
    -
    4
    -

    Clustering Algorithms Segmenting the Customer Base

    -
    - -
    -
    -

    💡 Conceptual — Why 3 algorithms?

    -

    No single clustering algorithm works best for all data shapes. We run three complementary - approaches and compare:

    -
      -
    • K-Means — fast, interpretable, assumes spherical clusters. Good baseline. -
    • -
    • DBSCAN — finds arbitrarily-shaped clusters and detects noise/outliers. - Great when some customers don't fit any group.
    • -
    • GMM — probabilistic (soft) assignment. Each customer gets a probability of - belonging to each cluster. Handles elliptical shapes and correlated features.
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -

    All algorithms operate on the scaled, engineered feature matrix from Step 3.

    -
      -
    • Algorithms from scikit-learn: KMeans, DBSCAN, - GaussianMixture
    • -
    • We vary hyperparameters and pick the best model via evaluation metrics (Step 5)
    • -
    • GMM additionally outputs predict_proba() — a probability matrix showing each - customer's likelihood per segment
    • -
    -
    -
    - -
    -

    Algorithm Deep-Dive

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AlgorithmHow It WorksKey HyperparameterBest For
    K-Means1. Place K random centroids
    2. Assign each point to nearest centroid
    3. Recompute - centroids as cluster means
    4. Repeat until convergence
    n_clusters (K) — found via Elbow/SilhouetteWell-separated, roughly equal-size, spherical clusters
    DBSCAN1. For each point, count neighbors within radius ε
    2. Points with ≥ min_samples - neighbors are "core points"
    3. Expand clusters from core points
    4. Unlabeled - points become noise (-1)
    eps (radius) + min_samples — found via k-distance plotIrregular shapes, noisy data, unknown number of clusters
    GMM1. Assume data comes from K Gaussian distributions
    2. EM algorithm: E-step assigns - soft probabilities, M-step updates Gaussian parameters
    3. Iterate until - log-likelihood converges
    4. Each point gets probability per cluster
    n_components — found via BIC/AICCorrelated features, overlapping clusters, soft assignment needed
    -
    - -
    K-Means objective: minimize J = Σᵢ Σₓ∈Cᵢ ||x - μᵢ||² (within-cluster sum of squares = - Inertia)
    -
    GMM: P(x) = Σₖ πₖ · 𝒩(x | μₖ, Σₖ) — mixture of K Gaussians with weights πₖ
    - -
    Why GMM over Hierarchical? GMM gives soft assignments - (e.g., "Customer X is 70% Segment A, 30% Segment B") — ideal for marketing where customers often sit - between segments. GMM also handles correlated features via full covariance matrices, and BIC/AIC provide - principled model selection vs. subjective dendrogram cutting.
    -
    - -
    - - -
    -
    -
    5
    -

    Cluster Evaluation Framework Validating Segment Quality

    -
    - -
    -
    -

    💡 Conceptual — Why?

    -

    Clustering is unsupervised — there's no ground truth to check against. - Evaluation ensures our segments are:

    -
      -
    • Optimal K — not too few (overgeneralized) or too many (noise)
    • -
    • Well-separated — customers within a cluster are similar; customers across - clusters are different
    • -
    • Interpretable — we can explain what drives each segment
    • -
    • Stable — segments persist if we resample the data
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -

    Four-step evaluation pipeline, each step uses different techniques:

    -
      -
    • Step 5a: Inertia elbow + BIC/AIC + Silhouette sweeps
    • -
    • Step 5b: Quality scores (Silhouette, Davies-Bouldin, Calinski-Harabasz) -
    • -
    • Step 5c: PCA loadings + SHAP + cluster profiles
    • -
    • Step 5d: Bootstrap resampling + GMM probability confidence
    • -
    -

    All implemented in cluster_evaluation.py using scikit-learn metrics and - shap library.

    -
    -
    - -
    -

    5a · Finding Optimal K

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    MethodWhat It DoesHow to Read
    Inertia / ElbowPlots within-cluster sum of squares (WCSS) vs. K. As K increases, inertia decreases — - but at diminishing returns.Look for the "elbow" — the K where the curve bends sharply. Beyond that, adding clusters - gives little improvement.
    BIC / AICBayesian/Akaike Information Criterion — penalizes model complexity. Used for GMM - specifically.Pick the K where BIC/AIC is minimized. BIC penalizes complexity more than AIC, - so it tends to prefer fewer clusters.
    Silhouette vs KComputes silhouette score for each K. Measures how similar each point is to its own - cluster vs. nearest neighbor cluster.Pick K with the highest average silhouette. Range: -1 (wrong cluster) to +1 - (perfect fit).
    -
    - -
    Silhouette(i) = (b(i) - a(i)) / max(a(i), b(i))
    where a(i) = avg distance to - same-cluster points, b(i) = avg distance to nearest-other-cluster points
    - -
    -

    5b · Cluster Quality Metrics

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    MetricFormula IntuitionIdeal Value
    Silhouette ScoreHow well each point fits its cluster vs. the next-best clusterCloser to +1 (≥0.5 is good, ≥0.7 is strong)
    Davies-Bouldin IndexRatio of within-cluster scatter to between-cluster separation. Lower = tighter, more - separated clusters.Closer to 0
    Calinski-HarabaszRatio of between-cluster variance to within-cluster variance (like an F-statistic for - clusters)Higher = better defined clusters
    -
    - -
    -

    5c · Interpretability: PCA Loadings + SHAP

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    MethodWhat It AnswersTechnical Detail
    PCA LoadingsWhich original features drive each principal component?The loading matrix shows how much each original feature contributes to each PC. A - heatmap of loadings reveals feature groupings. E.g., if PC1 has high loadings for - income, portfolio_value, and credit_score — PC1 represents "wealth". Clusters separated - along PC1 are primarily differentiated by wealth.
    SHAP SummaryWhich features are most important for distinguishing clusters? Why is a specific - customer in a specific cluster?Train a RandomForestClassifier on cluster_label as target. Use - shap.TreeExplainer to compute SHAP values. Summary beeswarm plot shows - global feature importance. Per-cluster bar plots show what defines each segment. Force - plots explain individual customer assignments.
    Cluster ProfilesWhat does each cluster "look like" statistically?Compute mean/median of every feature per cluster. Visualize as radar charts (comparing - clusters on key dimensions) and violin/box plots (distribution of each feature per - cluster).
    -
    - -
    PCA Loadings vs. SHAP — when to use which?
    - • PCA Loadings answer: "What features vary together in the data?" — useful for - understanding data structure before clustering.
    - • SHAP answers: "What features distinguish the clusters we found?" — useful for - explaining cluster assignments after clustering.
    - Both are needed: PCA loadings validate that clustering operates on meaningful dimensions; SHAP validates - that the resulting segments are interpretable.
    - -
    -

    5d · Stability Testing

    - - - - - - - - - - - - - - - - - - - - -
    MethodHow It WorksWhat It Proves
    Bootstrap ResamplingResample the dataset with replacement N times (e.g., 100), re-cluster each time, and - measure agreement using the Adjusted Rand Index (ARI) between the original and resampled - clusters.If ARI is consistently high (≥0.8), the segments are robust — they aren't just artifacts - of the specific data sample.
    GMM Probability DistributionPlot a histogram of each customer's max assignment probability from GMM.If most customers have max-prob ≥0.8, the segments are clearly defined. A flat - distribution means ambiguous assignments — clusters may be overlapping or poorly - separated.
    -
    -
    - -
    - - -
    -
    -
    6
    -

    GenAI Persona Generation Turning Segments into Narratives

    -
    - -
    -
    -

    💡 Conceptual — Why?

    -

    Cluster labels ("Segment 1, 2, 3…") are meaningless to business stakeholders. Marketing teams - need personas — named, narrative profiles that bring segments to life.

    -
      -
    • A persona bridges the gap between statistical output and actionable - strategy
    • -
    • GenAI (Gemini) transforms cluster statistics + SHAP drivers into natural-language personas - with goals, pain points, and recommendations
    • -
    • Domain-aware prompts ensure personas are contextually relevant (banking language for FS, - shopping language for retail)
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -
      -
    1. Aggregate cluster statistics: mean of every feature per cluster
    2. -
    3. Extract top 5 SHAP drivers per cluster (features that most define the segment)
    4. -
    5. Load domain-specific prompt template from YAML config
    6. -
    7. Inject cluster stats + SHAP drivers into the template
    8. -
    9. Call google.generativeai.GenerativeModel('gemini-pro')
    10. -
    11. Parse the structured response (name, goals, pain points, strategy)
    12. -
    13. Save to personas.json (machine-readable) and personas.md - (human-readable)
    14. -
    -

    Uses google-generativeai SDK. API key read from - GOOGLE_API_KEY env var.

    -
    -
    - -
    Why SHAP drivers in the prompt? Without SHAP, the GenAI model only - sees averages (e.g., "Avg Income: $125K"). With SHAP, it also knows what makes this segment - unique — e.g., "income is the #1 differentiator with SHAP value +0.8". This produces much more - targeted and insightful personas.
    -
    - -
    - - -
    -
    -
    7
    -

    Interactive Dashboard Unified Visualization Layer

    -
    - -
    -
    -

    💡 Conceptual — Why?

    -
      -
    • Stakeholders need a single place to explore segments, not scattered PNG files
    • -
    • Interactivity (hover, filter, zoom) enables self-service exploration without data science - involvement
    • -
    • Combining cluster visualizations + persona cards in one view tells the complete story: "Who - are these customers, and what should we do about them?"
    • -
    -
    -
    -

    ⚙️ Technical — How?

    -
      -
    • Built with plotly for interactive charts, output as self-contained HTML
    • -
    • PCA scatter — 2D/3D projection colored by cluster
    • -
    • Cluster size bar chart — segment distribution
    • -
    • Violin plots — feature distributions per cluster
    • -
    • Radar charts — comparative cluster profiles
    • -
    • Persona cards — rendered as styled HTML cards with GenAI output
    • -
    • Single dashboard.html file — no server needed, opens in any browser
    • -
    -
    -
    -
    - -
    - - - - - - - \ No newline at end of file diff --git a/architecture_presentation.html b/architecture_presentation.html deleted file mode 100644 index b6b1a60..0000000 --- a/architecture_presentation.html +++ /dev/null @@ -1,988 +0,0 @@ - - - - - - - Segmentation Plus — Architecture - - - - - - - - -
    -
    Architecture Document
    -

    Segmentation Plus

    -

    Multi-domain customer segmentation & GenAI persona generation platform. Works across Financial Services, - Retail, Healthcare, Telecom — or any custom domain. Supports synthetic demo data and real client data - import.

    -
    -
    📅 March 2026
    -
    🏦🛒🏥📡 Multi-Domain
    -
    📊 Synthetic + Real Data
    -
    🤖 GenAI Personas
    -
    -
    - -
    - - -
    -
    -
    ⚙️
    -

    Supported Domains

    -
    -

    Configurable via YAML files — all downstream modules (data generation, EDA, feature - engineering, persona prompts) adapt automatically per domain.

    -
    -
    -
    🏦
    -
    Financial Services
    -
    Banks · Insurers · Wealth Mgmt
    -
    -
    -
    🛒
    -
    Retail
    -
    E-commerce · Brick & Mortar · D2C
    -
    -
    -
    🏥
    -
    Healthcare
    -
    Payers · Providers · Pharma
    -
    -
    -
    📡
    -
    Telecom
    -
    Mobile · Broadband · OTT
    -
    -
    -
    - -
    - - -
    -
    -
    🔄
    -

    Data Flow Pipeline

    -
    -
    -
    ⚙️ Domain Config
    -
    -
    📥 Data Input
    -
    -
    🔍 Domain EDA
    -
    -
    🎯 Cluster
    -
    -
    🔬 Evaluate
    -
    -
    🤖 GenAI Personas
    -
    -
    📊 Dashboard
    -
    -
    - -
    - - -
    -
    -
    🏛️
    -

    High-Level System Architecture

    -
    -
    -
    -graph TB
    -    subgraph "CONFIGURATION"
    -        CFG["⚙️ Domain Config\ndomains/*.yaml"]
    -    end
    -
    -    subgraph "1 · DATA INPUT"
    -        A1["🏗️ Synthetic Generator\n(Demo Mode)"] --> DATA
    -        A2["📥 Real Data Import\n(CSV / DB / API)"] --> DATA
    -        DATA[("📊 Customer Data")]
    -    end
    -
    -    subgraph "2 · DOMAIN-AWARE PROCESSING"
    -        DATA --> EDA["🔍 EDA Engine\nDomain-specific analysis\n+ Feature engineering"]
    -        EDA --> PROC[("🧹 Processed Data")]
    -    end
    -
    -    subgraph "3 · CLUSTERING & EVALUATION"
    -        PROC --> CL["🎯 Clustering\nK-Means · DBSCAN · GMM"]
    -        CL --> EVAL["🔬 Evaluation\nInertia · BIC/AIC · Silhouette\nPCA Loadings · SHAP"]
    -        EVAL --> SEG[("📋 Segmented\nCustomers")]
    -    end
    -
    -    subgraph "4 · GenAI"
    -        SEG --> PERS["🤖 Persona Generator\nDomain-aware prompts"]
    -        EVAL --> PERS
    -        PERS <--> LLM["☁️ Gemini API"]
    -        PERS --> OUT["📝 Personas"]
    -    end
    -
    -    subgraph "5 · OUTPUT"
    -        SEG --> DASH["📊 Dashboard"]
    -        OUT --> DASH
    -        DASH --> HTML["🌐 dashboard.html"]
    -    end
    -
    -    CFG -.-> A1
    -    CFG -.-> EDA
    -    CFG -.-> PERS
    -
    -    style CFG fill:#607D8B,color:#fff
    -    style A1 fill:#4CAF50,color:#fff
    -    style A2 fill:#8BC34A,color:#fff
    -    style EDA fill:#2196F3,color:#fff
    -    style CL fill:#FF9800,color:#fff
    -    style EVAL fill:#F44336,color:#fff
    -    style PERS fill:#9C27B0,color:#fff
    -    style DASH fill:#E91E63,color:#fff
    -            
    -
    -
    - -
    - - -
    -
    -
    📥
    -

    Data Input: Synthetic vs. Real

    -
    -

    Start with synthetic data for POC/demos. When a client provides their real data, the - system validates it against the domain schema and runs the same pipeline — no code changes needed.

    -
    -
    -flowchart TB
    -    subgraph "Demo / POC Mode"
    -        S1["Synthetic Generator"] --> S2["Domain-specific\nrealistic records"]
    -        S2 --> PIPE
    -    end
    -
    -    subgraph "Production Mode"
    -        R1["CSV Upload"] --> VAL
    -        R2["Database"] --> VAL
    -        R3["API"] --> VAL
    -        VAL["🔍 Schema Validator\n• Column mapping\n• Type checks\n• Domain validation"] --> PIPE
    -    end
    -
    -    PIPE["→ Same Pipeline"]
    -
    -    style S1 fill:#4CAF50,color:#fff
    -    style R1 fill:#2196F3,color:#fff
    -    style R2 fill:#1976D2,color:#fff
    -    style R3 fill:#1565C0,color:#fff
    -    style VAL fill:#FF9800,color:#fff
    -            
    -
    -
    - -
    - - -
    -
    -
    📋
    -

    Domain Configuration

    -
    -

    Each domain defines its own features, EDA focus, and persona angles. A single YAML - file controls the entire pipeline behavior.

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Config Key🏦 Financial Services🛒 Retail🏥 Healthcare
    Key Featurescredit_score, portfolio_value, debt_to_incomepurchase_frequency, avg_basket_size, return_ratevisit_frequency, chronic_conditions, insurance_type
    ProductsMortgage, credit card, investment accountLoyalty card, subscription, premium tierHealth plan, dental, vision, wellness
    BehavioralDigital engagement, branch visitsOnline vs. in-store, coupon usagePortal usage, appointment adherence
    EDA FocusIncome vs. credit risk, cross-holdingsRFM analysis, seasonal patternsRisk stratification, cost drivers
    Feature Eng.wealth_tier, risk_category, digital_ratiorfm_score, discount_sensitivityacuity_score, care_gap_count
    Persona AngleFinancial goals, product upsellShopping behavior, brand loyaltyCare journey, health goals
    -
    -
    - -
    - - -
    -
    -
    🔍
    -

    Domain-Aware EDA & Feature Engineering

    -
    -
    -
    -graph TD
    -    INPUT["Raw Customer Data"] --> DETECT["Domain Detection\n(from config)"]
    -
    -    DETECT --> GEN["📊 Generic EDA\nDistributions · Correlations · Outliers"]
    -
    -    DETECT --> DOM["🎯 Domain-Specific EDA"]
    -
    -    DOM --> FS["🏦 Financial Services\nIncome distributions\nCredit vs. products\nDebt-to-income analysis"]
    -
    -    DOM --> RT["🛒 Retail\nRFM scoring\nBasket analysis\nSeasonal patterns"]
    -
    -    DOM --> HC["🏥 Healthcare\nRisk stratification\nCare utilization\nChronic clustering"]
    -
    -    GEN --> FE["🛠️ Feature Engineering"]
    -    FS --> FE
    -    RT --> FE
    -    HC --> FE
    -
    -    FE --> OUT[("Processed Data")]
    -
    -    style GEN fill:#2196F3,color:#fff
    -    style DOM fill:#FF9800,color:#fff
    -    style FS fill:#1565C0,color:#fff
    -    style RT fill:#E65100,color:#fff
    -    style HC fill:#2E7D32,color:#fff
    -    style FE fill:#9C27B0,color:#fff
    -            
    -
    -
    - -
    - - -
    -
    -
    🎯
    -

    Clustering & Evaluation

    -
    -
    -
    -graph TD
    -    A["Engineered Features"] --> B{"Algorithm Suite"}
    -
    -    B --> C["K-Means\nHard, spherical"]
    -    B --> D["DBSCAN\nDensity, noise"]
    -    B --> E["GMM\nSoft, elliptical"]
    -
    -    C --> C1["Inertia / Elbow\nSilhouette"]
    -    D --> D1["k-distance plot\nNoise ratio"]
    -    E --> E1["BIC / AIC\nLog-Likelihood"]
    -
    -    C1 --> F["🏆 Best Model"]
    -    D1 --> F
    -    E1 --> F
    -
    -    F --> G["🔬 Deep Evaluation"]
    -
    -    style C fill:#FF9800,color:#fff
    -    style D fill:#FF5722,color:#fff
    -    style E fill:#3F51B5,color:#fff
    -    style F fill:#4CAF50,color:#fff
    -            
    -
    - -
    -

    4-Step Evaluation Pipeline

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StepMethodsPurpose
    1 · Optimal KInertia Elbow, BIC/AIC, Silhouette vs KFind the right number of segments
    2 · QualitySilhouette, Davies-Bouldin, Calinski-HarabaszValidate compactness & separation
    3 · InterpretabilityPCA Loadings Heatmap, SHAP Summary, Cluster Radar ChartsUnderstand what defines each segment
    4 · StabilityBootstrap Resampling, GMM Probability DistributionConfirm robustness across resamples
    -
    -
    - -
    - - -
    -
    -
    🎯
    -

    SHAP for Cluster Interpretability

    -
    -

    Train a Random Forest on cluster labels, then use SHAP to explain why each - customer belongs to its segment — making results explainable to business stakeholders across any domain. -

    -
    -
    -sequenceDiagram
    -    participant D as Segmented Data
    -    participant RF as Random Forest (cluster target)
    -    participant S as SHAP Explainer
    -    participant V as Visualizations
    -
    -    D->>RF: Train features → cluster_label
    -    RF->>S: Generate SHAP values
    -    S->>V: Summary Plot (global importance)
    -    S->>V: Per-Cluster Bar Plot (segment drivers)
    -    S->>V: Dependence Plots (interactions)
    -    S->>V: Force Plots (individual explanations)
    -            
    -
    -
    - 💡 Example Insight:
    - "Customer X is in Segment 2 because of high income (+0.8), low digital - engagement (−0.5), and high portfolio value (+0.7)" — actionable for the - client's marketing team. -
    -
    - -
    - - -
    -
    -
    🤖
    -

    GenAI Persona Generation

    -
    -

    Personas adapt to the domain context automatically — prompts pull domain-specific - language, product catalogs, and strategy angles from the config.

    -
    -
    -sequenceDiagram
    -    participant P as Persona Generator
    -    participant C as Domain Config
    -    participant D as Cluster Profiles + SHAP
    -    participant G as Gemini API
    -
    -    P->>C: Load domain context
    -    P->>D: Load cluster stats + SHAP drivers
    -    loop For each segment
    -        P->>P: Build domain-aware prompt
    -        P->>G: Send prompt
    -        G-->>P: Persona response
    -        P->>P: Parse & format
    -    end
    -    P->>P: Save personas.json + personas.md
    -            
    -
    - -

    Example Prompts by Domain

    -
    -

    🏦 Financial Services

    -
    -
    You are a marketing strategist advising a bank on their customers.
    -
    -Segment 3: Avg Age 42, Income $125K, Credit Score 780
    -Products: Mortgage (80%), Investment Account (90%)
    -SHAP Drivers: income (+0.8), portfolio_value (+0.7)
    -
    -Generate persona: name, financial goals, pain points,
    -cross-sell recommendations, channel preferences, campaign strategy.
    -
    -
    -
    -

    🛒 Retail

    -
    -
    You are a retail marketing strategist advising a brand.
    -
    -Segment 2: Avg Age 28, AOV $75, Purchase Freq 3x/month
    -Categories: Apparel (90%), Accessories (60%), Footwear (40%)
    -SHAP Drivers: purchase_frequency (+0.9), discount_sensitivity (+0.6)
    -
    -Generate persona: name, shopping habits, brand affinities,
    -product recommendations, channel mix, retention strategy.
    -
    -
    -
    - -
    - - -
    -
    -
    📁
    -

    Directory Structure

    -
    -
    -
    Segmentation_Plus/
    -├── main.py                         # Pipeline orchestrator
    -├── config.py                       # Domain config loader
    -├── generate_data.py                # Synthetic data generator (per domain)
    -├── data_import.py                  # Real data ingestion + validation
    -├── eda_preprocessing.py            # Domain-aware EDA + feature engineering
    -├── clustering.py                   # K-Means, DBSCAN, GMM
    -├── cluster_evaluation.py           # Metrics + SHAP + PCA loadings
    -├── persona_generation.py           # GenAI persona builder
    -├── dashboard.py                    # Interactive Plotly dashboard
    -├── requirements.txt
    -├── domains/
    -│   ├── financial_services.yaml     # Financial Services config
    -│   ├── retail.yaml                 # Retail config
    -│   ├── healthcare.yaml             # Healthcare config
    -│   └── _template.yaml              # Template for new domains
    -├── data/
    -│   ├── synthetic_customers.csv     # Demo data
    -│   ├── imported_data.csv           # Real client data
    -│   ├── processed_customers.csv     # Scaled + engineered
    -│   └── clustered_customers.csv     # With labels + probabilities
    -└── output/
    -    ├── eda/                        # EDA charts
    -    ├── evaluation/                 # PCA, SHAP, metrics
    -    ├── personas.md / .json         # GenAI personas
    -    └── dashboard.html              # Interactive dashboard
    -
    -
    - -
    - - -
    -
    -
    ⚙️
    -

    Technology Stack

    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    LayerTechnologyPurpose
    ConfigurationpyyamlDomain configs
    Datanumpy, pandasGeneration + processing
    Visualizationmatplotlib, seaborn, plotlyCharts + dashboard
    Clusteringscikit-learnK-Means, DBSCAN, GMM, PCA
    Evaluationscikit-learn, shapMetrics + SHAP interpretability
    GenAIgoogle-generativeaiPersona generation via Gemini
    -
    -
    - -
    - - - - - - - - \ No newline at end of file diff --git a/cluster_evaluation.py b/cluster_evaluation.py deleted file mode 100644 index a50bc77..0000000 --- a/cluster_evaluation.py +++ /dev/null @@ -1,381 +0,0 @@ -""" -Segmentation Plus — Cluster Evaluation Framework -================================================= -4-step evaluation: Optimal K, Quality Metrics, Interpretability -(PCA loadings + SHAP), and Stability testing. -""" - -from __future__ import annotations - -import json -import logging -from pathlib import Path -from typing import Dict, List, Optional, Tuple - -import matplotlib -matplotlib.use("Agg") -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import seaborn as sns -from sklearn.decomposition import PCA -from sklearn.ensemble import RandomForestClassifier -from sklearn.cluster import KMeans -from sklearn.metrics import silhouette_score, adjusted_rand_score -from sklearn.mixture import GaussianMixture - -from clustering import ClusteringResult - -logger = logging.getLogger(__name__) - - -class ClusterEvaluator: - """ - Comprehensive cluster evaluation framework. - - Parameters - ---------- - X : np.ndarray - Feature matrix used for clustering. - labels : np.ndarray - Cluster assignments. - feature_names : list[str] - Names of the features (columns). - output_dir : Path - Directory to save evaluation plots and reports. - """ - - def __init__( - self, - X: np.ndarray, - labels: np.ndarray, - feature_names: List[str], - output_dir: Path, - ) -> None: - self.X = X - self.labels = labels - self.feature_names = feature_names - self.output_dir = Path(output_dir) - self.output_dir.mkdir(parents=True, exist_ok=True) - self.report: Dict = {} - - def run_full_evaluation( - self, - pca: Optional[PCA] = None, - k_range: Tuple[int, int] = (2, 10), - random_state: int = 42, - ) -> Dict: - """ - Run the complete 4-step evaluation pipeline. - - Returns - ------- - dict - Full evaluation report. - """ - logger.info("Starting cluster evaluation (4 steps)...") - - # Step 1: Optimal K analysis - self.report["optimal_k"] = self._step1_optimal_k(k_range, random_state) - - # Step 2: Quality metrics - self.report["quality_metrics"] = self._step2_quality_metrics() - - # Step 3: Interpretability - self.report["pca_loadings"] = self._step3a_pca_loadings(pca) - self.report["shap_importance"] = self._step3b_shap_analysis(random_state) - self._step3c_cluster_profiles() - - # Step 4: Stability - self.report["stability"] = self._step4_stability(random_state) - - # Save report - report_path = self.output_dir / "evaluation_report.json" - with open(report_path, "w") as f: - json.dump(self._serialize_report(self.report), f, indent=2) - logger.info("Evaluation report saved to %s", report_path) - - return self.report - - # ── Step 1: Optimal K ── - - def _step1_optimal_k(self, k_range: Tuple[int, int], random_state: int) -> Dict: - """Elbow plot (inertia), Silhouette vs K, BIC/AIC curves.""" - k_min, k_max = k_range - ks = list(range(k_min, k_max + 1)) - inertias, silhouettes, bics, aics = [], [], [], [] - - for k in ks: - # K-Means - km = KMeans(n_clusters=k, n_init=10, random_state=random_state) - labs = km.fit_predict(self.X) - inertias.append(float(km.inertia_)) - silhouettes.append(float(silhouette_score(self.X, labs))) - - # GMM - gm = GaussianMixture(n_components=k, n_init=3, random_state=random_state) - gm.fit(self.X) - bics.append(float(gm.bic(self.X))) - aics.append(float(gm.aic(self.X))) - - # Plot - fig, axes = plt.subplots(1, 3, figsize=(18, 5)) - - axes[0].plot(ks, inertias, "bo-", linewidth=2) - axes[0].set_title("Elbow Method (Inertia)", fontweight="bold") - axes[0].set_xlabel("K"); axes[0].set_ylabel("Inertia") - - axes[1].plot(ks, silhouettes, "go-", linewidth=2) - axes[1].set_title("Silhouette Score vs K", fontweight="bold") - axes[1].set_xlabel("K"); axes[1].set_ylabel("Silhouette") - - axes[2].plot(ks, bics, "ro-", linewidth=2, label="BIC") - axes[2].plot(ks, aics, "mo-", linewidth=2, label="AIC") - axes[2].set_title("GMM: BIC / AIC", fontweight="bold") - axes[2].set_xlabel("K"); axes[2].legend() - - plt.tight_layout() - fig.savefig(self.output_dir / "optimal_k_analysis.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - return {"k_range": ks, "inertias": inertias, "silhouettes": silhouettes, "bics": bics, "aics": aics} - - # ── Step 2: Quality Metrics ── - - def _step2_quality_metrics(self) -> Dict[str, float]: - """Compute silhouette, Davies-Bouldin, Calinski-Harabasz.""" - from sklearn.metrics import davies_bouldin_score, calinski_harabasz_score - - mask = self.labels != -1 - X, labels = self.X[mask], self.labels[mask] - - if len(set(labels)) < 2: - logger.warning("Cannot compute quality metrics: < 2 clusters") - return {} - - metrics = { - "silhouette": float(silhouette_score(X, labels)), - "davies_bouldin": float(davies_bouldin_score(X, labels)), - "calinski_harabasz": float(calinski_harabasz_score(X, labels)), - "n_clusters": int(len(set(labels))), - } - - logger.info( - "Quality: Silhouette=%.3f, DB=%.3f, CH=%.1f", - metrics["silhouette"], metrics["davies_bouldin"], metrics["calinski_harabasz"], - ) - return metrics - - # ── Step 3a: PCA Loadings ── - - def _step3a_pca_loadings(self, pca: Optional[PCA]) -> Optional[Dict]: - """Generate PCA loadings heatmap.""" - if pca is None: - logger.info("No PCA object provided — fitting new PCA for loadings analysis") - pca = PCA(n_components=min(5, self.X.shape[1])).fit(self.X) - - n_components = pca.n_components_ - feature_names = self.feature_names[:pca.components_.shape[1]] - - loadings = pd.DataFrame( - pca.components_.T, - columns=[f"PC{i+1}" for i in range(n_components)], - index=feature_names, - ) - - # Heatmap - fig, ax = plt.subplots(figsize=(max(8, n_components * 1.5), max(6, len(feature_names) * 0.4))) - sns.heatmap( - loadings, annot=True, fmt=".2f", cmap="RdBu_r", - center=0, ax=ax, linewidths=0.5 - ) - ax.set_title("PCA Loadings Heatmap", fontsize=14, fontweight="bold") - plt.tight_layout() - fig.savefig(self.output_dir / "pca_loadings_heatmap.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - logger.info("PCA loadings heatmap saved (%d components × %d features)", n_components, len(feature_names)) - - return { - "explained_variance": pca.explained_variance_ratio_.tolist(), - "top_features_per_pc": { - f"PC{i+1}": loadings.iloc[:, i].abs().nlargest(5).index.tolist() - for i in range(n_components) - } - } - - # ── Step 3b: SHAP Analysis ── - - def _step3b_shap_analysis(self, random_state: int) -> Optional[Dict]: - """Train RF on cluster labels → SHAP feature importance.""" - mask = self.labels != -1 - X, labels = self.X[mask], self.labels[mask] - - if len(set(labels)) < 2: - return None - - # Train Random Forest - rf = RandomForestClassifier( - n_estimators=100, max_depth=10, random_state=random_state, n_jobs=-1, - ) - rf.fit(X, labels) - accuracy = rf.score(X, labels) - logger.info("RF classifier accuracy on cluster labels: %.3f", accuracy) - - try: - import shap - explainer = shap.TreeExplainer(rf) - shap_values = explainer.shap_values(X) - - # Summary plot - fig, ax = plt.subplots(figsize=(10, max(6, len(self.feature_names) * 0.35))) - plt.sca(ax) - shap.summary_plot( - shap_values, X, - feature_names=self.feature_names[:X.shape[1]], - show=False, max_display=15, - ) - plt.tight_layout() - fig.savefig(self.output_dir / "shap_summary.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - # Feature importance bar plot - fig, ax = plt.subplots(figsize=(10, max(6, len(self.feature_names) * 0.35))) - plt.sca(ax) - shap.summary_plot( - shap_values, X, - feature_names=self.feature_names[:X.shape[1]], - plot_type="bar", show=False, max_display=15, - ) - plt.tight_layout() - fig.savefig(self.output_dir / "shap_feature_importance.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - logger.info("SHAP plots saved") - - # Extract top features - if isinstance(shap_values, list): - mean_abs = np.mean([np.abs(sv).mean(axis=0) for sv in shap_values], axis=0) - else: - mean_abs = np.abs(shap_values).mean(axis=0) - - feature_importance = dict(zip( - self.feature_names[:X.shape[1]], - mean_abs.tolist() if hasattr(mean_abs, 'tolist') else mean_abs, - )) - - return { - "rf_accuracy": accuracy, - "feature_importance": feature_importance, - } - - except ImportError: - logger.warning("shap not installed — using RF feature_importances_ as fallback") - importance = dict(zip( - self.feature_names[:X.shape[1]], - rf.feature_importances_.tolist(), - )) - # Fallback bar plot - sorted_imp = sorted(importance.items(), key=lambda x: x[1], reverse=True)[:15] - fig, ax = plt.subplots(figsize=(10, 6)) - ax.barh([x[0] for x in sorted_imp], [x[1] for x in sorted_imp], color="#5b8def") - ax.set_title("Feature Importance (RF)", fontweight="bold") - ax.invert_yaxis() - plt.tight_layout() - fig.savefig(self.output_dir / "rf_feature_importance.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - return {"rf_accuracy": accuracy, "feature_importance": importance} - - # ── Step 3c: Cluster Profiles ── - - def _step3c_cluster_profiles(self) -> None: - """Generate radar charts and box plots per cluster.""" - mask = self.labels != -1 - n_features = min(len(self.feature_names), self.X.shape[1]) - df = pd.DataFrame(self.X[mask, :n_features], columns=self.feature_names[:n_features]) - df["cluster"] = self.labels[mask] - - n_clusters = df["cluster"].nunique() - - # Box plots for top features - top_features = self.feature_names[:min(8, n_features)] - if top_features: - fig, axes = plt.subplots(2, 4, figsize=(20, 10)) - axes = axes.flatten() - for idx, feat in enumerate(top_features): - if idx >= len(axes): - break - df.boxplot(column=feat, by="cluster", ax=axes[idx]) - axes[idx].set_title(feat, fontweight="bold") - for idx in range(len(top_features), len(axes)): - axes[idx].set_visible(False) - plt.suptitle("Feature Distributions by Cluster", fontsize=14, fontweight="bold", y=1.02) - plt.tight_layout() - fig.savefig(self.output_dir / "cluster_boxplots.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - # Cluster size distribution - fig, ax = plt.subplots(figsize=(8, 5)) - cluster_sizes = df["cluster"].value_counts().sort_index() - cluster_sizes.plot(kind="bar", ax=ax, color="#5b8def", edgecolor="white") - ax.set_title("Cluster Size Distribution", fontweight="bold") - ax.set_xlabel("Cluster"); ax.set_ylabel("Count") - for i, v in enumerate(cluster_sizes): - ax.text(i, v + 5, str(v), ha="center", fontweight="bold") - plt.tight_layout() - fig.savefig(self.output_dir / "cluster_sizes.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - logger.info("Cluster profile plots saved") - - # ── Step 4: Stability ── - - def _step4_stability(self, random_state: int, n_bootstraps: int = 30) -> Dict: - """Bootstrap stability test using Adjusted Rand Index.""" - ari_scores = [] - n_samples = len(self.X) - n_clusters = len(set(self.labels) - {-1}) - - if n_clusters < 2: - return {"ari_mean": 0, "ari_std": 0, "n_bootstraps": 0} - - for i in range(n_bootstraps): - rng = np.random.RandomState(random_state + i) - idx = rng.choice(n_samples, size=n_samples, replace=True) - - km = KMeans(n_clusters=n_clusters, n_init=5, random_state=random_state + i) - boot_labels = km.fit_predict(self.X[idx]) - - # Compare with original labels (reindexed) - ari = adjusted_rand_score(self.labels[idx], boot_labels) - ari_scores.append(float(ari)) - - result = { - "ari_mean": float(np.mean(ari_scores)), - "ari_std": float(np.std(ari_scores)), - "n_bootstraps": n_bootstraps, - "stable": float(np.mean(ari_scores)) >= 0.7, - } - - logger.info("Bootstrap stability: ARI=%.3f ± %.3f (stable=%s)", result["ari_mean"], result["ari_std"], result["stable"]) - return result - - # ── Utility ── - - @staticmethod - def _serialize_report(report: Dict) -> Dict: - """Make report JSON-serializable.""" - def _convert(obj): - if isinstance(obj, (np.integer,)): - return int(obj) - if isinstance(obj, (np.floating,)): - return float(obj) - if isinstance(obj, np.ndarray): - return obj.tolist() - if isinstance(obj, dict): - return {k: _convert(v) for k, v in obj.items()} - if isinstance(obj, list): - return [_convert(v) for v in obj] - return obj - return _convert(report) diff --git a/clustering.py b/clustering.py deleted file mode 100644 index 4ea046b..0000000 --- a/clustering.py +++ /dev/null @@ -1,311 +0,0 @@ -""" -Segmentation Plus — Clustering Engine -====================================== -K-Means, DBSCAN, and GMM clustering with hyperparameter search -and model comparison. -""" - -from __future__ import annotations - -import logging -from dataclasses import dataclass, field -from typing import Dict, List, Optional, Tuple - -import numpy as np -import pandas as pd -from sklearn.cluster import DBSCAN, KMeans -from sklearn.metrics import ( - calinski_harabasz_score, - davies_bouldin_score, - silhouette_score, -) -from sklearn.mixture import GaussianMixture - -logger = logging.getLogger(__name__) - - -# ────────────────────────────────────────────── -# Clustering Result -# ────────────────────────────────────────────── - -@dataclass -class ClusteringResult: - """Container for a single clustering run's outputs.""" - - algorithm: str - labels: np.ndarray - n_clusters: int - metrics: Dict[str, float] = field(default_factory=dict) - model: object = None # The fitted model object - probabilities: Optional[np.ndarray] = None # GMM soft assignments - extra: Dict = field(default_factory=dict) - - @property - def is_valid(self) -> bool: - """Check if clustering produced at least 2 distinct clusters.""" - unique = len(set(self.labels) - {-1}) # Exclude DBSCAN noise - return unique >= 2 - - -# ────────────────────────────────────────────── -# Clustering Engine -# ────────────────────────────────────────────── - -class ClusteringEngine: - """ - Runs multiple clustering algorithms, evaluates them, - and selects the best model. - - Parameters - ---------- - X : np.ndarray - Scaled/PCA-transformed feature matrix (n_samples, n_features). - k_range : tuple - Min and max K to evaluate (default: 2 to 10). - random_state : int - Random seed for reproducibility. - """ - - def __init__( - self, - X: np.ndarray, - k_range: Tuple[int, int] = (2, 10), - random_state: int = 42, - ) -> None: - self.X = X - self.k_min, self.k_max = k_range - self.random_state = random_state - self.results: Dict[str, ClusteringResult] = {} - - # ── K-Means ── - - def run_kmeans(self, n_clusters: Optional[int] = None) -> ClusteringResult: - """ - Run K-Means clustering. - - If n_clusters is None, runs elbow analysis and picks the optimal K. - """ - logger.info("Running K-Means clustering...") - - if n_clusters is None: - n_clusters = self._find_optimal_k_kmeans() - - model = KMeans( - n_clusters=n_clusters, - n_init=10, - max_iter=300, - random_state=self.random_state, - ) - labels = model.fit_predict(self.X) - - result = ClusteringResult( - algorithm="kmeans", - labels=labels, - n_clusters=n_clusters, - model=model, - extra={"inertia": model.inertia_}, - ) - result.metrics = self._compute_metrics(labels) - - self.results["kmeans"] = result - logger.info( - "K-Means: K=%d, Silhouette=%.3f, Inertia=%.1f", - n_clusters, result.metrics.get("silhouette", 0), model.inertia_, - ) - return result - - def _find_optimal_k_kmeans(self) -> int: - """Find optimal K using silhouette score sweep.""" - best_k, best_score = 2, -1 - scores = {} - - for k in range(self.k_min, self.k_max + 1): - km = KMeans(n_clusters=k, n_init=10, random_state=self.random_state) - labs = km.fit_predict(self.X) - score = silhouette_score(self.X, labs) - scores[k] = score - if score > best_score: - best_k, best_score = k, score - - logger.info("K-Means silhouette sweep: %s → optimal K=%d (%.3f)", scores, best_k, best_score) - return best_k - - # ── DBSCAN ── - - def run_dbscan( - self, - eps: Optional[float] = None, - min_samples: int = 5, - ) -> ClusteringResult: - """ - Run DBSCAN clustering. - - If eps is None, auto-selects using k-distance heuristic. - """ - logger.info("Running DBSCAN clustering...") - - if eps is None: - eps = self._estimate_eps(min_samples) - - model = DBSCAN(eps=eps, min_samples=min_samples) - labels = model.fit_predict(self.X) - - n_clusters = len(set(labels) - {-1}) - n_noise = int((labels == -1).sum()) - - result = ClusteringResult( - algorithm="dbscan", - labels=labels, - n_clusters=n_clusters, - model=model, - extra={"eps": eps, "min_samples": min_samples, "n_noise": n_noise}, - ) - - if result.is_valid: - result.metrics = self._compute_metrics(labels[labels != -1], exclude_noise=True) - else: - logger.warning("DBSCAN found < 2 clusters (n_clusters=%d, noise=%d)", n_clusters, n_noise) - - self.results["dbscan"] = result - logger.info("DBSCAN: clusters=%d, noise=%d, eps=%.3f", n_clusters, n_noise, eps) - return result - - def _estimate_eps(self, min_samples: int) -> float: - """Estimate eps using k-distance plot knee detection.""" - from sklearn.neighbors import NearestNeighbors - - nn = NearestNeighbors(n_neighbors=min_samples) - nn.fit(self.X) - distances, _ = nn.kneighbors(self.X) - k_distances = np.sort(distances[:, -1]) - - # Simple knee detection: point of max curvature - diffs = np.diff(k_distances) - knee_idx = np.argmax(diffs) + 1 - eps = float(k_distances[knee_idx]) - - logger.info("Auto-estimated DBSCAN eps=%.3f (knee at index %d)", eps, knee_idx) - return eps - - # ── GMM ── - - def run_gmm(self, n_components: Optional[int] = None) -> ClusteringResult: - """ - Run Gaussian Mixture Model clustering. - - If n_components is None, selects using BIC minimization. - """ - logger.info("Running GMM clustering...") - - if n_components is None: - n_components = self._find_optimal_k_gmm() - - model = GaussianMixture( - n_components=n_components, - covariance_type="full", - n_init=3, - random_state=self.random_state, - ) - labels = model.fit_predict(self.X) - probabilities = model.predict_proba(self.X) - - result = ClusteringResult( - algorithm="gmm", - labels=labels, - n_clusters=n_components, - model=model, - probabilities=probabilities, - extra={ - "bic": model.bic(self.X), - "aic": model.aic(self.X), - "converged": model.converged_, - }, - ) - result.metrics = self._compute_metrics(labels) - - self.results["gmm"] = result - logger.info( - "GMM: K=%d, Silhouette=%.3f, BIC=%.1f, AIC=%.1f", - n_components, result.metrics.get("silhouette", 0), - result.extra["bic"], result.extra["aic"], - ) - return result - - def _find_optimal_k_gmm(self) -> int: - """Find optimal K for GMM using BIC minimization.""" - best_k, best_bic = 2, np.inf - - for k in range(self.k_min, self.k_max + 1): - gm = GaussianMixture( - n_components=k, covariance_type="full", - n_init=3, random_state=self.random_state, - ) - gm.fit(self.X) - bic = gm.bic(self.X) - if bic < best_bic: - best_k, best_bic = k, bic - - logger.info("GMM BIC sweep → optimal K=%d (BIC=%.1f)", best_k, best_bic) - return best_k - - # ── Metrics ── - - def _compute_metrics( - self, labels: np.ndarray, exclude_noise: bool = False, - ) -> Dict[str, float]: - """Compute clustering quality metrics.""" - X = self.X - if exclude_noise: - mask = labels != -1 - X = self.X[mask] - labels = labels[mask] - - if len(set(labels)) < 2: - return {} - - return { - "silhouette": float(silhouette_score(X, labels)), - "davies_bouldin": float(davies_bouldin_score(X, labels)), - "calinski_harabasz": float(calinski_harabasz_score(X, labels)), - } - - # ── Run All & Compare ── - - def run_all(self) -> Dict[str, ClusteringResult]: - """Run all three algorithms and return results.""" - self.run_kmeans() - self.run_dbscan() - self.run_gmm() - return self.results - - def get_best_model(self, metric: str = "silhouette") -> ClusteringResult: - """ - Select best model by a given metric. - - Parameters - ---------- - metric : str - Metric to compare (default: 'silhouette', higher is better). - - Returns - ------- - ClusteringResult - Best performing clustering result. - """ - valid = { - name: r for name, r in self.results.items() - if r.is_valid and metric in r.metrics - } - - if not valid: - raise ValueError("No valid clustering results found.") - - # Higher is better for silhouette & calinski_harabasz; lower for davies_bouldin - reverse = metric != "davies_bouldin" - best_name = max(valid, key=lambda n: valid[n].metrics[metric] * (1 if reverse else -1)) - - logger.info( - "Best model by %s: %s (%.4f)", - metric, best_name, valid[best_name].metrics[metric], - ) - return valid[best_name] diff --git a/config.py b/config.py deleted file mode 100644 index 3a8450c..0000000 --- a/config.py +++ /dev/null @@ -1,181 +0,0 @@ -""" -Segmentation Plus — Domain Configuration System -================================================= -Loads domain-specific YAML configs that drive the entire pipeline: -EDA, feature engineering, clustering, and persona generation. -""" - -from __future__ import annotations - -import logging -from dataclasses import dataclass, field -from pathlib import Path -from typing import Any, Dict, List, Optional - -import yaml - -logger = logging.getLogger(__name__) - -# ────────────────────────────────────────────── -# Domain Config Dataclass -# ────────────────────────────────────────────── - -@dataclass -class FeatureEngineeringRule: - """Single feature engineering rule from the domain config.""" - name: str - formula: str - bins: Optional[List[str]] = None - description: str = "" - - -@dataclass -class DomainConfig: - """ - Complete configuration for a single domain. - - Attributes - ---------- - domain_key : str - Machine-readable domain identifier (e.g., 'financial_services'). - display_name : str - Human-readable name (e.g., 'Financial Services'). - features : dict - Feature groups → list of column names. - required_columns : list - Columns that MUST exist in any input dataset for this domain. - feature_engineering : list - Derived feature rules (formulas, bins, etc.). - eda_analyses : list - Domain-specific EDA analyses to run. - persona_prompt_template : str - Jinja-style prompt template for GenAI persona generation. - scaling_exclude : list - Columns to exclude from StandardScaler (e.g., IDs, booleans). - categorical_columns : list - Columns to one-hot encode. - target_column : str | None - Optional target column (not used in unsupervised, but kept for flexibility). - metadata : dict - Any extra domain-specific metadata. - """ - - domain_key: str - display_name: str - features: Dict[str, List[str]] = field(default_factory=dict) - required_columns: List[str] = field(default_factory=list) - feature_engineering: List[FeatureEngineeringRule] = field(default_factory=list) - eda_analyses: List[str] = field(default_factory=list) - persona_prompt_template: str = "" - scaling_exclude: List[str] = field(default_factory=list) - categorical_columns: List[str] = field(default_factory=list) - target_column: Optional[str] = None - metadata: Dict[str, Any] = field(default_factory=dict) - - # ── Computed properties ── - - @property - def all_feature_columns(self) -> List[str]: - """Flatten all feature groups into a single list.""" - cols = [] - for group_cols in self.features.values(): - cols.extend(group_cols) - return cols - - @property - def numerical_columns(self) -> List[str]: - """All feature columns minus categorical ones.""" - return [c for c in self.all_feature_columns if c not in self.categorical_columns] - - -# ────────────────────────────────────────────── -# Config Loader -# ────────────────────────────────────────────── - -_DOMAINS_DIR = Path(__file__).parent / "domains" - - -def list_available_domains() -> List[str]: - """Return names of all available domain configs (without .yaml extension).""" - if not _DOMAINS_DIR.exists(): - return [] - return [ - p.stem for p in _DOMAINS_DIR.glob("*.yaml") - if not p.stem.startswith("_") - ] - - -def load_domain_config(domain_key: str, config_path: Optional[Path] = None) -> DomainConfig: - """ - Load and parse a domain YAML config into a DomainConfig dataclass. - - Parameters - ---------- - domain_key : str - Name of the domain (matches the YAML filename without extension). - config_path : Path, optional - Override path. If None, looks in the default `domains/` directory. - - Returns - ------- - DomainConfig - Fully parsed domain configuration. - - Raises - ------ - FileNotFoundError - If the YAML file does not exist. - ValueError - If the YAML is malformed or missing required fields. - """ - if config_path is None: - config_path = _DOMAINS_DIR / f"{domain_key}.yaml" - - if not config_path.exists(): - available = list_available_domains() - raise FileNotFoundError( - f"Domain config '{domain_key}' not found at {config_path}. " - f"Available domains: {available}" - ) - - logger.info("Loading domain config: %s from %s", domain_key, config_path) - - with open(config_path, "r", encoding="utf-8") as f: - raw: Dict[str, Any] = yaml.safe_load(f) - - if not raw or not isinstance(raw, dict): - raise ValueError(f"Domain config '{config_path}' is empty or malformed.") - - # Parse feature engineering rules - fe_rules = [] - for rule_dict in raw.get("feature_engineering", []): - fe_rules.append(FeatureEngineeringRule( - name=rule_dict["name"], - formula=rule_dict.get("formula", ""), - bins=rule_dict.get("bins"), - description=rule_dict.get("description", ""), - )) - - config = DomainConfig( - domain_key=raw.get("domain", domain_key), - display_name=raw.get("display_name", domain_key.replace("_", " ").title()), - features=raw.get("features", {}), - required_columns=raw.get("required_columns", []), - feature_engineering=fe_rules, - eda_analyses=raw.get("eda", {}).get("domain_analyses", []), - persona_prompt_template=raw.get("persona_prompt_template", ""), - scaling_exclude=raw.get("scaling_exclude", []), - categorical_columns=raw.get("categorical_columns", []), - target_column=raw.get("target_column"), - metadata=raw.get("metadata", {}), - ) - - logger.info( - "Loaded domain '%s': %d feature groups, %d FE rules, %d EDA analyses", - config.display_name, - len(config.features), - len(config.feature_engineering), - len(config.eda_analyses), - ) - - return config diff --git a/dashboard.py b/dashboard.py deleted file mode 100644 index 77f8158..0000000 --- a/dashboard.py +++ /dev/null @@ -1,317 +0,0 @@ -""" -Segmentation Plus — Interactive Dashboard -========================================== -Plotly-based interactive dashboard combining cluster visualizations, -evaluation metrics, and persona cards into a single HTML file. -""" - -from __future__ import annotations - -import json -import logging -from pathlib import Path -from typing import Any, Dict, List, Optional - -import numpy as np -import pandas as pd -import plotly.express as px -import plotly.graph_objects as go -from plotly.subplots import make_subplots - -logger = logging.getLogger(__name__) - - -class DashboardBuilder: - """ - Builds an interactive HTML dashboard. - - Parameters - ---------- - output_dir : Path - Directory to save the dashboard HTML. - """ - - def __init__(self, output_dir: Path) -> None: - self.output_dir = Path(output_dir) - self.output_dir.mkdir(parents=True, exist_ok=True) - self.sections: List[str] = [] - - def build( - self, - df: pd.DataFrame, - labels: np.ndarray, - X_for_viz: np.ndarray, - feature_names: List[str], - personas: Optional[List[Dict]] = None, - evaluation_report: Optional[Dict] = None, - ) -> Path: - """ - Build and save the full dashboard. - - Parameters - ---------- - df : pd.DataFrame - Original DataFrame. - labels : np.ndarray - Cluster assignments. - X_for_viz : np.ndarray - 2D or 3D array for scatter plots (PCA-reduced). - feature_names : list[str] - Feature column names. - personas : list[dict], optional - Generated personas. - evaluation_report : dict, optional - Evaluation metrics. - - Returns - ------- - Path - Path to the saved dashboard HTML file. - """ - logger.info("Building interactive dashboard...") - - self.sections = [] - - # Cluster scatter plot - self._add_cluster_scatter(X_for_viz, labels) - - # Cluster size distribution - self._add_cluster_sizes(labels) - - # Feature distributions by cluster - self._add_feature_distributions(df, labels, feature_names) - - # Cluster radar chart - self._add_radar_chart(df, labels, feature_names) - - # Evaluation metrics summary - if evaluation_report: - self._add_metrics_summary(evaluation_report) - - # Persona cards - if personas: - self._add_persona_cards(personas) - - # Combine into HTML - html = self._render_html() - output_path = self.output_dir / "dashboard.html" - with open(output_path, "w", encoding="utf-8") as f: - f.write(html) - - logger.info("Dashboard saved to %s", output_path) - return output_path - - def _add_cluster_scatter(self, X: np.ndarray, labels: np.ndarray) -> None: - """PCA scatter plot colored by cluster.""" - df_plot = pd.DataFrame({ - "PC1": X[:, 0], - "PC2": X[:, 1] if X.shape[1] > 1 else np.zeros(len(X)), - "Cluster": labels.astype(str), - }) - - fig = px.scatter( - df_plot, x="PC1", y="PC2", color="Cluster", - title="Customer Segments (PCA Projection)", - opacity=0.6, width=900, height=500, - color_discrete_sequence=px.colors.qualitative.Set2, - ) - fig.update_layout( - template="plotly_dark", - plot_bgcolor="#1e2233", - paper_bgcolor="#0f1117", - font=dict(family="Inter"), - ) - self.sections.append(("Cluster Scatter Plot", fig.to_html(include_plotlyjs=False, full_html=False))) - - def _add_cluster_sizes(self, labels: np.ndarray) -> None: - """Cluster size bar chart.""" - unique, counts = np.unique(labels[labels != -1], return_counts=True) - - fig = go.Figure(data=[go.Bar( - x=[f"Segment {c}" for c in unique], - y=counts, - marker_color=px.colors.qualitative.Set2[:len(unique)], - text=counts, textposition="auto", - )]) - fig.update_layout( - title="Segment Size Distribution", - template="plotly_dark", - plot_bgcolor="#1e2233", - paper_bgcolor="#0f1117", - width=900, height=400, - font=dict(family="Inter"), - ) - self.sections.append(("Segment Sizes", fig.to_html(include_plotlyjs=False, full_html=False))) - - def _add_feature_distributions( - self, df: pd.DataFrame, labels: np.ndarray, feature_names: List[str], - ) -> None: - """Violin plots for key features per cluster.""" - plot_df = df.copy() - plot_df["Cluster"] = labels.astype(str) - - numeric_features = [ - c for c in feature_names - if c in plot_df.columns and plot_df[c].dtype in [np.float64, np.int64] - ][:6] # Top 6 features - - if not numeric_features: - return - - fig = make_subplots(rows=2, cols=3, subplot_titles=numeric_features) - for idx, feat in enumerate(numeric_features): - row, col = idx // 3 + 1, idx % 3 + 1 - for cluster_val in sorted(plot_df["Cluster"].unique()): - subset = plot_df[plot_df["Cluster"] == cluster_val] - fig.add_trace( - go.Violin(y=subset[feat], name=f"Seg {cluster_val}", legendgroup=cluster_val, - scalemode="count", showlegend=(idx == 0)), - row=row, col=col, - ) - - fig.update_layout( - title="Feature Distributions by Segment", - template="plotly_dark", plot_bgcolor="#1e2233", paper_bgcolor="#0f1117", - width=1000, height=600, font=dict(family="Inter"), - ) - self.sections.append(("Feature Distributions", fig.to_html(include_plotlyjs=False, full_html=False))) - - def _add_radar_chart( - self, df: pd.DataFrame, labels: np.ndarray, feature_names: List[str], - ) -> None: - """Radar chart comparing cluster profiles.""" - plot_df = df.copy() - plot_df["cluster"] = labels - - numeric_features = [ - c for c in feature_names - if c in plot_df.columns and plot_df[c].dtype in [np.float64, np.int64] - ][:8] - - if len(numeric_features) < 3: - return - - # Normalize to 0-1 for radar - means = plot_df.groupby("cluster")[numeric_features].mean() - for col in numeric_features: - col_range = means[col].max() - means[col].min() - if col_range > 0: - means[col] = (means[col] - means[col].min()) / col_range - - fig = go.Figure() - colors = px.colors.qualitative.Set2 - for idx, (cluster_id, row) in enumerate(means.iterrows()): - if cluster_id == -1: - continue - fig.add_trace(go.Scatterpolar( - r=row.values.tolist() + [row.values[0]], - theta=numeric_features + [numeric_features[0]], - fill="toself", name=f"Segment {cluster_id}", - opacity=0.6, line=dict(color=colors[idx % len(colors)]), - )) - - fig.update_layout( - title="Segment Profile Comparison", - template="plotly_dark", paper_bgcolor="#0f1117", - width=800, height=500, font=dict(family="Inter"), - polar=dict(bgcolor="#1e2233"), - ) - self.sections.append(("Radar Comparison", fig.to_html(include_plotlyjs=False, full_html=False))) - - def _add_metrics_summary(self, report: Dict) -> None: - """Render evaluation metrics as an HTML card.""" - quality = report.get("quality_metrics", {}) - stability = report.get("stability", {}) - - html = '
    ' - metrics = [ - ("Silhouette", f"{quality.get('silhouette', 0):.3f}", "#5b8def"), - ("Davies-Bouldin", f"{quality.get('davies_bouldin', 0):.3f}", "#fb923c"), - ("Calinski-Harabasz", f"{quality.get('calinski_harabasz', 0):.0f}", "#34d399"), - ("Stability (ARI)", f"{stability.get('ari_mean', 0):.3f}", "#a78bfa"), - ] - for name, val, color in metrics: - html += f''' -
    -
    {name}
    -
    {val}
    -
    ''' - html += '
    ' - self.sections.append(("Evaluation Metrics", html)) - - def _add_persona_cards(self, personas: List[Dict]) -> None: - """Render persona cards as styled HTML.""" - cards_html = '
    ' - - for p in personas: - name = p.get("name", f"Segment {p.get('segment_id', '?')}") - tagline = p.get("tagline", "") - size = p.get("segment_size", "?") - pct = p.get("segment_pct", "?") - - goals = p.get("goals", []) - if isinstance(goals, str): - goals = [goals] - goals_html = "".join(f"
  • {g}
  • " for g in goals[:4]) - - pain_points = p.get("pain_points", []) - if isinstance(pain_points, str): - pain_points = [pain_points] - pp_html = "".join(f"
  • {pp}
  • " for pp in pain_points[:4]) - - cards_html += f''' -
    -
    - 🧑 {name} -
    -
    - {tagline} -
    -
    - {size} customers ({pct}% of total) -
    -
    - Goals: -
      {goals_html}
    - Pain Points: -
      {pp_html}
    -
    -
    ''' - cards_html += '
    ' - self.sections.append(("Customer Personas", cards_html)) - - def _render_html(self) -> str: - """Combine all sections into a final HTML page.""" - sections_html = "" - for title, content in self.sections: - sections_html += f''' -
    -

    {title}

    - {content} -
    ''' - - return f''' - - -Segmentation Plus — Dashboard - - - -
    -

    Segmentation Plus — Dashboard

    -

    Interactive customer segmentation results and AI-generated personas

    -
    -
    {sections_html}
    -''' diff --git a/data_import.py b/data_import.py deleted file mode 100644 index 800e51b..0000000 --- a/data_import.py +++ /dev/null @@ -1,275 +0,0 @@ -""" -Segmentation Plus — Data Import & Validation -============================================= -Production-grade data ingestion with schema validation, -column mapping, and data quality checks. -""" - -from __future__ import annotations - -import logging -from pathlib import Path -from typing import Optional, Tuple - -import numpy as np -import pandas as pd - -from config import DomainConfig - -logger = logging.getLogger(__name__) - - -# ────────────────────────────────────────────── -# Data Quality Report -# ────────────────────────────────────────────── - -class DataQualityReport: - """Stores data quality check results.""" - - def __init__(self) -> None: - self.total_rows: int = 0 - self.total_columns: int = 0 - self.missing_values: dict[str, int] = {} - self.missing_pct: dict[str, float] = {} - self.duplicate_rows: int = 0 - self.column_types: dict[str, str] = {} - self.warnings: list[str] = [] - self.errors: list[str] = [] - self.passed: bool = True - - def summary(self) -> str: - status = "✅ PASSED" if self.passed else "❌ FAILED" - lines = [ - f"Data Quality Report — {status}", - f" Rows: {self.total_rows:,} | Columns: {self.total_columns}", - f" Duplicates: {self.duplicate_rows}", - ] - if self.warnings: - lines.append(f" Warnings ({len(self.warnings)}):") - for w in self.warnings: - lines.append(f" ⚠ {w}") - if self.errors: - lines.append(f" Errors ({len(self.errors)}):") - for e in self.errors: - lines.append(f" ✗ {e}") - return "\n".join(lines) - - -# ────────────────────────────────────────────── -# Data Loader -# ────────────────────────────────────────────── - -def load_data( - file_path: str | Path, - sheet_name: Optional[str] = None, -) -> pd.DataFrame: - """ - Load data from CSV or Excel file. - - Parameters - ---------- - file_path : str or Path - Path to the data file (.csv, .xlsx, .xls). - sheet_name : str, optional - Sheet name for Excel files. - - Returns - ------- - pd.DataFrame - Raw loaded DataFrame. - - Raises - ------ - FileNotFoundError - If the file does not exist. - ValueError - If the file format is not supported. - """ - path = Path(file_path) - - if not path.exists(): - raise FileNotFoundError(f"Data file not found: {path}") - - suffix = path.suffix.lower() - logger.info("Loading data from %s (%s)", path.name, suffix) - - if suffix == ".csv": - df = pd.read_csv(path) - elif suffix in (".xlsx", ".xls"): - df = pd.read_excel(path, sheet_name=sheet_name) - elif suffix == ".parquet": - df = pd.read_parquet(path) - else: - raise ValueError( - f"Unsupported file format: '{suffix}'. " - f"Supported: .csv, .xlsx, .xls, .parquet" - ) - - logger.info("Loaded %d rows × %d columns", len(df), len(df.columns)) - return df - - -# ────────────────────────────────────────────── -# Schema Validation -# ────────────────────────────────────────────── - -def validate_schema( - df: pd.DataFrame, - domain_config: DomainConfig, - strict: bool = False, -) -> DataQualityReport: - """ - Validate a DataFrame against the domain schema. - - Parameters - ---------- - df : pd.DataFrame - Input data to validate. - domain_config : DomainConfig - Domain configuration with required columns and feature schema. - strict : bool - If True, fail on warnings (missing optional columns). Default False. - - Returns - ------- - DataQualityReport - Detailed quality report with pass/fail status. - """ - report = DataQualityReport() - report.total_rows = len(df) - report.total_columns = len(df.columns) - report.column_types = {col: str(df[col].dtype) for col in df.columns} - - # 1. Check required columns - df_cols_lower = {c.lower(): c for c in df.columns} - for req_col in domain_config.required_columns: - if req_col.lower() not in df_cols_lower: - report.errors.append(f"Required column missing: '{req_col}'") - report.passed = False - - # 2. Check optional domain feature columns - all_domain_cols = domain_config.all_feature_columns - for col in all_domain_cols: - if col.lower() not in df_cols_lower and col not in df.columns: - report.warnings.append(f"Domain feature column missing: '{col}'") - if strict: - report.passed = False - - # 3. Missing values - missing = df.isnull().sum() - for col in df.columns: - if missing[col] > 0: - report.missing_values[col] = int(missing[col]) - report.missing_pct[col] = round(missing[col] / len(df) * 100, 2) - if report.missing_pct[col] > 50: - report.warnings.append( - f"Column '{col}' has {report.missing_pct[col]:.1f}% missing values" - ) - - # 4. Duplicate rows - report.duplicate_rows = int(df.duplicated().sum()) - if report.duplicate_rows > 0: - report.warnings.append( - f"{report.duplicate_rows} duplicate rows found ({report.duplicate_rows/len(df)*100:.1f}%)" - ) - - # 5. Row count check - if len(df) < 50: - report.warnings.append( - f"Very small dataset ({len(df)} rows) — clustering may not be reliable" - ) - - logger.info("Schema validation: %s", "PASSED" if report.passed else "FAILED") - return report - - -# ────────────────────────────────────────────── -# Column Mapping (fuzzy matching) -# ────────────────────────────────────────────── - -def auto_map_columns( - df: pd.DataFrame, - domain_config: DomainConfig, -) -> Tuple[pd.DataFrame, dict[str, str]]: - """ - Attempt to auto-map DataFrame columns to domain schema columns - using case-insensitive and partial matching. - - Parameters - ---------- - df : pd.DataFrame - Input DataFrame with potentially different column names. - domain_config : DomainConfig - Domain config with expected column names. - - Returns - ------- - tuple[pd.DataFrame, dict] - Renamed DataFrame and the mapping used (original → domain). - """ - mapping: dict[str, str] = {} - domain_cols = ( - domain_config.required_columns + domain_config.all_feature_columns - ) - - df_cols_lower = {c.lower().replace(" ", "_").replace("-", "_"): c for c in df.columns} - - for domain_col in domain_cols: - normalized = domain_col.lower().replace(" ", "_").replace("-", "_") - - # Exact match (case-insensitive) - if normalized in df_cols_lower: - original = df_cols_lower[normalized] - if original != domain_col: - mapping[original] = domain_col - - if mapping: - logger.info("Auto-mapped %d columns: %s", len(mapping), mapping) - df = df.rename(columns=mapping) - - return df, mapping - - -# ────────────────────────────────────────────── -# Public API -# ────────────────────────────────────────────── - -def import_and_validate( - file_path: str | Path, - domain_config: DomainConfig, - auto_map: bool = True, - sheet_name: Optional[str] = None, -) -> Tuple[pd.DataFrame, DataQualityReport]: - """ - Full import pipeline: load → auto-map → validate → report. - - Parameters - ---------- - file_path : str or Path - Path to data file. - domain_config : DomainConfig - Domain configuration to validate against. - auto_map : bool - Whether to attempt automatic column name mapping. - sheet_name : str, optional - Sheet name for Excel files. - - Returns - ------- - tuple[pd.DataFrame, DataQualityReport] - Processed DataFrame and its quality report. - """ - # Load - df = load_data(file_path, sheet_name=sheet_name) - - # Auto-map columns - if auto_map: - df, col_mapping = auto_map_columns(df, domain_config) - - # Validate - report = validate_schema(df, domain_config) - - # Log summary - logger.info("\n%s", report.summary()) - - return df, report diff --git a/eda_preprocessing.py b/eda_preprocessing.py deleted file mode 100644 index 0839626..0000000 --- a/eda_preprocessing.py +++ /dev/null @@ -1,412 +0,0 @@ -""" -Segmentation Plus — Domain-Aware EDA & Feature Engineering -========================================================== -Generic + domain-specific exploratory analysis, data cleaning, -feature engineering, and preprocessing for clustering. -""" - -from __future__ import annotations - -import logging -from pathlib import Path -from typing import Optional, Tuple - -import matplotlib -matplotlib.use("Agg") # Non-interactive backend -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import seaborn as sns -from sklearn.decomposition import PCA -from sklearn.preprocessing import StandardScaler, LabelEncoder - -from config import DomainConfig - -logger = logging.getLogger(__name__) - - -# ────────────────────────────────────────────── -# EDA Engine -# ────────────────────────────────────────────── - -class EDAEngine: - """ - Runs generic and domain-specific exploratory data analysis. - - Parameters - ---------- - df : pd.DataFrame - Input data (raw or lightly cleaned). - domain_config : DomainConfig - Domain configuration driving domain-specific analyses. - output_dir : Path - Directory to save EDA charts. - """ - - def __init__( - self, - df: pd.DataFrame, - domain_config: DomainConfig, - output_dir: Path, - ) -> None: - self.df = df.copy() - self.config = domain_config - self.output_dir = Path(output_dir) - self.output_dir.mkdir(parents=True, exist_ok=True) - - def run_all(self) -> dict: - """Run all EDA analyses and return summary statistics.""" - logger.info("Running EDA for domain: %s", self.config.display_name) - results = {} - - results["summary_stats"] = self._summary_statistics() - results["missing_analysis"] = self._missing_value_analysis() - self._distribution_plots() - self._correlation_heatmap() - self._outlier_detection() - self._run_domain_analyses() - - logger.info("EDA complete. Charts saved to %s", self.output_dir) - return results - - def _summary_statistics(self) -> dict: - """Compute and log summary statistics.""" - numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() - stats = self.df[numeric_cols].describe().to_dict() - logger.info("Summary stats computed for %d numeric columns", len(numeric_cols)) - return stats - - def _missing_value_analysis(self) -> dict: - """Analyze missing values.""" - missing = self.df.isnull().sum() - missing_pct = (missing / len(self.df) * 100).round(2) - missing_report = { - col: {"count": int(missing[col]), "pct": float(missing_pct[col])} - for col in self.df.columns if missing[col] > 0 - } - if missing_report: - logger.warning("Missing values found in %d columns", len(missing_report)) - else: - logger.info("No missing values detected") - return missing_report - - def _distribution_plots(self) -> None: - """Plot distributions for all numeric features.""" - numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() - # Exclude ID-like columns - plot_cols = [c for c in numeric_cols if "id" not in c.lower()] - - if not plot_cols: - return - - n_cols = min(4, len(plot_cols)) - n_rows = (len(plot_cols) + n_cols - 1) // n_cols - - fig, axes = plt.subplots(n_rows, n_cols, figsize=(5 * n_cols, 4 * n_rows)) - axes = np.atleast_2d(axes) - - for idx, col in enumerate(plot_cols): - ax = axes[idx // n_cols, idx % n_cols] - self.df[col].hist(bins=30, ax=ax, color="#5b8def", edgecolor="white", alpha=0.8) - ax.set_title(col, fontsize=10, fontweight="bold") - ax.tick_params(labelsize=8) - - # Hide unused axes - for idx in range(len(plot_cols), n_rows * n_cols): - axes[idx // n_cols, idx % n_cols].set_visible(False) - - plt.tight_layout() - fig.savefig(self.output_dir / "distributions.png", dpi=150, bbox_inches="tight") - plt.close(fig) - logger.info("Distribution plots saved") - - def _correlation_heatmap(self) -> None: - """Plot correlation heatmap for numeric features.""" - numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() - numeric_cols = [c for c in numeric_cols if "id" not in c.lower()] - - if len(numeric_cols) < 2: - return - - corr = self.df[numeric_cols].corr() - fig, ax = plt.subplots(figsize=(max(10, len(numeric_cols) * 0.6), max(8, len(numeric_cols) * 0.5))) - mask = np.triu(np.ones_like(corr, dtype=bool)) - sns.heatmap( - corr, mask=mask, annot=len(numeric_cols) <= 15, fmt=".2f", - cmap="RdBu_r", center=0, vmin=-1, vmax=1, - square=True, linewidths=0.5, ax=ax, - cbar_kws={"shrink": 0.8} - ) - ax.set_title("Feature Correlation Matrix", fontsize=14, fontweight="bold", pad=15) - plt.tight_layout() - fig.savefig(self.output_dir / "correlation_heatmap.png", dpi=150, bbox_inches="tight") - plt.close(fig) - logger.info("Correlation heatmap saved") - - def _outlier_detection(self) -> None: - """Box plots for outlier detection.""" - numeric_cols = self.df.select_dtypes(include=[np.number]).columns.tolist() - plot_cols = [c for c in numeric_cols if "id" not in c.lower()] - - if not plot_cols: - return - - n_cols = min(4, len(plot_cols)) - n_rows = (len(plot_cols) + n_cols - 1) // n_cols - - fig, axes = plt.subplots(n_rows, n_cols, figsize=(5 * n_cols, 3 * n_rows)) - axes = np.atleast_2d(axes) - - for idx, col in enumerate(plot_cols): - ax = axes[idx // n_cols, idx % n_cols] - self.df.boxplot(column=col, ax=ax) - ax.set_title(col, fontsize=10, fontweight="bold") - ax.tick_params(labelsize=8) - - for idx in range(len(plot_cols), n_rows * n_cols): - axes[idx // n_cols, idx % n_cols].set_visible(False) - - plt.tight_layout() - fig.savefig(self.output_dir / "outlier_boxplots.png", dpi=150, bbox_inches="tight") - plt.close(fig) - logger.info("Outlier box plots saved") - - def _run_domain_analyses(self) -> None: - """Run domain-specific EDA analyses defined in config.""" - for analysis_name in self.config.eda_analyses: - method_name = f"_eda_{analysis_name}" - if hasattr(self, method_name): - logger.info("Running domain analysis: %s", analysis_name) - getattr(self, method_name)() - else: - logger.debug( - "Domain analysis '%s' not implemented — skipping. " - "Implement as method '%s' in EDAEngine.", - analysis_name, method_name, - ) - - # ── Domain-specific EDA methods (add more as needed) ── - - def _eda_product_cross_holding_matrix(self) -> None: - """Cross-holding heatmap for product columns.""" - product_cols = self.config.features.get("products", []) - bool_cols = [c for c in product_cols if c in self.df.columns and self.df[c].dtype in ["bool", "int64", "float64"]] - if len(bool_cols) < 2: - return - - cross = self.df[bool_cols].corr() - fig, ax = plt.subplots(figsize=(8, 6)) - sns.heatmap(cross, annot=True, fmt=".2f", cmap="YlOrRd", ax=ax, square=True) - ax.set_title("Product Cross-Holding Matrix", fontsize=13, fontweight="bold") - plt.tight_layout() - fig.savefig(self.output_dir / "product_cross_holdings.png", dpi=150, bbox_inches="tight") - plt.close(fig) - - -# ────────────────────────────────────────────── -# Feature Engineering -# ────────────────────────────────────────────── - -class FeatureEngineer: - """ - Applies domain-specific and generic feature engineering. - - Parameters - ---------- - domain_config : DomainConfig - Domain configuration with FE rules. - """ - - def __init__(self, domain_config: DomainConfig) -> None: - self.config = domain_config - - def engineer_features(self, df: pd.DataFrame) -> pd.DataFrame: - """ - Apply all feature engineering rules from domain config. - - Parameters - ---------- - df : pd.DataFrame - Cleaned DataFrame. - - Returns - ------- - pd.DataFrame - DataFrame with new engineered columns added. - """ - df = df.copy() - - for rule in self.config.feature_engineering: - try: - # Evaluate the formula safely using DataFrame columns - df[rule.name] = df.eval(rule.formula) - logger.info("Engineered feature: '%s'", rule.name) - - # Apply binning if specified - if rule.bins: - df[f"{rule.name}_bin"] = pd.qcut( - df[rule.name], q=len(rule.bins), labels=rule.bins, duplicates="drop" - ) - logger.info(" → Binned into %d categories", len(rule.bins)) - - except Exception as e: - logger.warning( - "Failed to engineer feature '%s': %s. " - "Check that all columns in formula '%s' exist.", - rule.name, e, rule.formula, - ) - - return df - - -# ────────────────────────────────────────────── -# Preprocessor -# ────────────────────────────────────────────── - -class Preprocessor: - """ - Data cleaning, encoding, scaling, and PCA. - - Parameters - ---------- - domain_config : DomainConfig - Domain configuration. - """ - - def __init__(self, domain_config: DomainConfig) -> None: - self.config = domain_config - self.scaler: Optional[StandardScaler] = None - self.pca: Optional[PCA] = None - self.label_encoders: dict[str, LabelEncoder] = {} - self.feature_columns: list[str] = [] - - def fit_transform( - self, - df: pd.DataFrame, - n_pca_components: Optional[int] = None, - pca_variance_threshold: float = 0.85, - ) -> Tuple[pd.DataFrame, np.ndarray, Optional[PCA]]: - """ - Full preprocessing pipeline: clean → encode → scale → PCA. - - Parameters - ---------- - df : pd.DataFrame - Input DataFrame (after feature engineering). - n_pca_components : int, optional - Fixed number of PCA components. If None, auto-selects based on - variance threshold. - pca_variance_threshold : float - Minimum cumulative variance to retain (default 85%). - - Returns - ------- - tuple[pd.DataFrame, np.ndarray, PCA | None] - - Processed DataFrame (with encodings, scaled features) - - Feature matrix for clustering (scaled, optionally PCA-reduced) - - Fitted PCA object (or None if not applied) - """ - df = df.copy() - - # 1. Handle missing values - df = self._handle_missing(df) - - # 2. Encode categoricals - df = self._encode_categoricals(df) - - # 3. Select numeric features for clustering - exclude = set(self.config.scaling_exclude) - numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist() - self.feature_columns = [c for c in numeric_cols if c not in exclude] - - if not self.feature_columns: - raise ValueError("No numeric feature columns found for clustering after exclusions.") - - logger.info("Features for clustering: %d columns", len(self.feature_columns)) - - # 4. Handle outliers (winsorize) - df = self._winsorize(df) - - # 5. Scale - self.scaler = StandardScaler() - X_scaled = self.scaler.fit_transform(df[self.feature_columns]) - - logger.info("Scaling applied: StandardScaler (mean=0, std=1)") - - # 6. PCA (optional) - if n_pca_components is not None or pca_variance_threshold < 1.0: - X_scaled, self.pca = self._apply_pca( - X_scaled, n_pca_components, pca_variance_threshold - ) - - return df, X_scaled, self.pca - - def _handle_missing(self, df: pd.DataFrame) -> pd.DataFrame: - """Impute missing values: median for numeric, mode for categorical.""" - for col in df.columns: - if df[col].isnull().sum() == 0: - continue - if df[col].dtype in [np.float64, np.int64, float, int]: - median_val = df[col].median() - df[col] = df[col].fillna(median_val) - logger.info("Imputed '%s' with median: %.2f", col, median_val) - else: - mode_val = df[col].mode() - if len(mode_val) > 0: - df[col] = df[col].fillna(mode_val.iloc[0]) - logger.info("Imputed '%s' with mode: %s", col, mode_val.iloc[0]) - return df - - def _encode_categoricals(self, df: pd.DataFrame) -> pd.DataFrame: - """Label-encode categorical columns.""" - cat_cols = [ - c for c in self.config.categorical_columns - if c in df.columns and df[c].dtype == "object" - ] - for col in cat_cols: - le = LabelEncoder() - df[col] = le.fit_transform(df[col].astype(str)) - self.label_encoders[col] = le - logger.info("Label-encoded '%s' (%d classes)", col, len(le.classes_)) - return df - - def _winsorize(self, df: pd.DataFrame, lower: float = 0.01, upper: float = 0.99) -> pd.DataFrame: - """Winsorize numeric features at given percentiles.""" - for col in self.feature_columns: - lo = df[col].quantile(lower) - hi = df[col].quantile(upper) - clipped = df[col].clip(lo, hi) - n_clipped = (df[col] != clipped).sum() - if n_clipped > 0: - df[col] = clipped - logger.debug("Winsorized '%s': %d values clipped", col, n_clipped) - return df - - def _apply_pca( - self, - X: np.ndarray, - n_components: Optional[int], - variance_threshold: float, - ) -> Tuple[np.ndarray, PCA]: - """Apply PCA for dimensionality reduction.""" - if n_components is None: - # Auto-select: find n_components that explain ≥ threshold variance - pca_full = PCA().fit(X) - cumvar = np.cumsum(pca_full.explained_variance_ratio_) - n_components = int(np.searchsorted(cumvar, variance_threshold) + 1) - n_components = max(2, min(n_components, X.shape[1])) - logger.info( - "Auto-selected %d PCA components (%.1f%% variance)", - n_components, cumvar[n_components - 1] * 100, - ) - - pca = PCA(n_components=n_components) - X_pca = pca.fit_transform(X) - - logger.info( - "PCA: %d → %d components (%.1f%% variance explained)", - X.shape[1], n_components, - sum(pca.explained_variance_ratio_) * 100, - ) - - return X_pca, pca diff --git a/implementation_plan.md.resolved b/implementation_plan.md.resolved deleted file mode 100644 index b1bad1b..0000000 --- a/implementation_plan.md.resolved +++ /dev/null @@ -1,131 +0,0 @@ -# Financial Services Client Segmentation & GenAI Persona Generation - -Build a complete pipeline that generates synthetic financial client data, segments clients using clustering algorithms, and generates rich customer personas using Generative AI (Google Gemini). - -## Proposed Changes - -### 1. Synthetic Data Generation - -#### [NEW] [generate_data.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/generate_data.py) - -Generate **2,000 synthetic client records** with realistic financial services attributes: - -| Category | Fields | -|---|---| -| **Demographics** | `client_id`, `age`, `gender`, `income`, `education`, `marital_status`, `dependents`, `occupation` | -| **Financial Profile** | `account_balance`, `credit_score`, `monthly_spending`, `savings_rate`, `debt_to_income_ratio`, `investment_portfolio_value` | -| **Product Holdings** | `has_credit_card`, `has_mortgage`, `has_personal_loan`, `has_investment_account`, `has_insurance`, `num_products` | -| **Behavioral** | `digital_engagement_score`, `branch_visits_monthly`, `customer_tenure_years`, `transaction_frequency_monthly`, `avg_transaction_amount` | -| **Satisfaction** | `nps_score`, `complaint_count_yearly`, `churn_risk_score` | - -Data will be generated using `numpy` and `pandas` with correlated distributions (e.g., higher income → higher portfolio value, younger age → higher digital engagement). - ---- - -### 2. EDA & Preprocessing - -#### [NEW] [eda_preprocessing.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/eda_preprocessing.py) - -- Summary statistics and distribution plots for each feature -- Correlation heatmap across all numerical features -- Missing value analysis (none expected, but included for robustness) -- Feature scaling using `StandardScaler` -- Dimensionality reduction with PCA for visualization -- Export preprocessed data to `data/processed_clients.csv` - ---- - -### 3. Clustering & Segmentation - -#### [NEW] [clustering.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/clustering.py) - -- **K-Means Clustering** with Elbow Method and Silhouette Score to find optimal K -- **DBSCAN** as alternative density-based method -- **Hierarchical Clustering** with dendrogram visualization -- Cluster profiling: aggregate statistics per cluster (mean income, avg products, etc.) -- Radar charts and box plots per cluster -- Export cluster assignments back to the dataset - ---- - -### 4. GenAI Persona Generation - -#### [NEW] [persona_generation.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/persona_generation.py) - -Uses **Google Gemini API** to generate rich marketing personas for each cluster: - -- Summarize each cluster's statistical profile into a prompt -- Send structured prompts to Gemini asking for: - - Persona name and demographic snapshot - - Financial goals and pain points - - Preferred products and services - - Communication channel preferences - - Marketing strategy recommendations -- Parse and format the AI-generated personas -- Save output as `output/personas.md` and `output/personas.json` - -> [!IMPORTANT] -> **API Key required**: You'll need a Google Gemini API key. The script will read it from the environment variable `GOOGLE_API_KEY`. Please have your key ready, or let me know if you'd prefer a different GenAI provider (OpenAI, Azure, etc.). - ---- - -### 5. Visualization Dashboard - -#### [NEW] [dashboard.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/dashboard.py) - -An interactive **Plotly** dashboard (HTML output) combining: - -- PCA scatter plot colored by cluster -- Cluster size distribution (bar chart) -- Feature distributions per cluster (violin plots) -- Radar chart of cluster profiles -- Persona cards rendered as styled HTML - ---- - -### 6. Project Configuration - -#### [NEW] [requirements.txt](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/requirements.txt) - -``` -pandas -numpy -scikit-learn -matplotlib -seaborn -plotly -google-generativeai -``` - -#### [NEW] [main.py](file:///c:/Users/UmairAhmed/OneDrive%20-%20Blend%20360/Documents/Segmentation_Plus/main.py) - -Orchestrator script that runs the full pipeline end-to-end: -1. Generate data → 2. EDA & preprocess → 3. Cluster → 4. Generate personas → 5. Build dashboard - ---- - -## Verification Plan - -### Automated Tests - -1. **Data generation validity**: - ``` - python -c "import pandas as pd; df=pd.read_csv('data/synthetic_clients.csv'); assert len(df)==2000; assert df.isnull().sum().sum()==0; print('✓ Data OK')" - ``` - -2. **Clustering output check**: - ``` - python -c "import pandas as pd; df=pd.read_csv('data/clustered_clients.csv'); assert 'cluster' in df.columns; print(f'✓ {df.cluster.nunique()} clusters found')" - ``` - -3. **Full pipeline run**: - ``` - python main.py - ``` - Expected: All output files generated in `data/` and `output/` directories without errors. - -### Manual Verification - -- Review generated charts in `output/` folder for visual correctness -- Read persona output in `output/personas.md` for quality and relevance -- Open `output/dashboard.html` in a browser to verify interactivity diff --git a/main.py b/main.py deleted file mode 100644 index d5c10e7..0000000 --- a/main.py +++ /dev/null @@ -1,275 +0,0 @@ -""" -Segmentation Plus — Pipeline Orchestrator -========================================== -End-to-end pipeline: Data Import → EDA → Cluster → Evaluate → Personas → Dashboard. - -Usage: - python main.py --data path/to/data.csv --domain financial_services - python main.py --data path/to/data.csv --domain retail --skip-personas -""" - -from __future__ import annotations - -import argparse -import logging -import sys -from pathlib import Path -from typing import Optional - -import numpy as np -import pandas as pd - -# ────────────────────────────────────────────── -# Logging Setup -# ────────────────────────────────────────────── - -def setup_logging(verbose: bool = False) -> None: - """Configure logging for the pipeline.""" - level = logging.DEBUG if verbose else logging.INFO - fmt = "%(asctime)s | %(levelname)-8s | %(name)-25s | %(message)s" - logging.basicConfig(level=level, format=fmt, datefmt="%H:%M:%S") - # Suppress noisy libraries - logging.getLogger("matplotlib").setLevel(logging.WARNING) - logging.getLogger("PIL").setLevel(logging.WARNING) - -logger = logging.getLogger("segmentation_plus") - - -# ────────────────────────────────────────────── -# Pipeline -# ────────────────────────────────────────────── - -def run_pipeline( - data_path: str, - domain_key: str, - output_base: str = "output", - skip_personas: bool = False, - k_range: tuple = (2, 10), - pca_variance: float = 0.85, - verbose: bool = False, -) -> dict: - """ - Run the full segmentation pipeline. - - Parameters - ---------- - data_path : str - Path to the input data file (CSV/Excel/Parquet). - domain_key : str - Domain config to use (e.g., 'financial_services', 'retail'). - output_base : str - Base output directory (default: 'output'). - skip_personas : bool - If True, skip GenAI persona generation (useful if no API key). - k_range : tuple - Min and max K for clustering (default: 2 to 10). - pca_variance : float - Cumulative variance threshold for PCA (default: 0.85). - verbose : bool - Enable debug logging. - - Returns - ------- - dict - Pipeline results including cluster labels, evaluation, and personas. - """ - setup_logging(verbose) - results = {} - - # ── Setup directories ── - output_dir = Path(output_base) - eda_dir = output_dir / "eda" - eval_dir = output_dir / "evaluation" - data_dir = Path("data") - data_dir.mkdir(exist_ok=True) - - logger.info("=" * 60) - logger.info("SEGMENTATION PLUS — Pipeline Start") - logger.info(" Data: %s", data_path) - logger.info(" Domain: %s", domain_key) - logger.info(" Output: %s", output_dir) - logger.info("=" * 60) - - # ──────────────────────────────────────── - # STEP 1: Load Domain Config - # ──────────────────────────────────────── - logger.info("\n📋 Step 1: Loading domain configuration...") - from config import load_domain_config - domain_config = load_domain_config(domain_key) - logger.info(" Domain: %s", domain_config.display_name) - - # ──────────────────────────────────────── - # STEP 2: Import & Validate Data - # ──────────────────────────────────────── - logger.info("\n📥 Step 2: Importing and validating data...") - from data_import import import_and_validate - df, quality_report = import_and_validate(data_path, domain_config) - logger.info("\n%s", quality_report.summary()) - - if not quality_report.passed: - logger.error("Data validation FAILED. Fix the errors above and retry.") - sys.exit(1) - - results["data_shape"] = df.shape - results["quality_report"] = quality_report - - # ──────────────────────────────────────── - # STEP 3: EDA & Feature Engineering - # ──────────────────────────────────────── - logger.info("\n🔍 Step 3: Running EDA & feature engineering...") - from eda_preprocessing import EDAEngine, FeatureEngineer, Preprocessor - - # EDA - eda = EDAEngine(df, domain_config, eda_dir) - eda_results = eda.run_all() - - # Feature Engineering - fe = FeatureEngineer(domain_config) - df_engineered = fe.engineer_features(df) - - # Preprocessing - preprocessor = Preprocessor(domain_config) - df_processed, X_scaled, pca = preprocessor.fit_transform( - df_engineered, - pca_variance_threshold=pca_variance, - ) - - feature_names = preprocessor.feature_columns - results["n_features"] = len(feature_names) - results["pca_components"] = pca.n_components_ if pca else None - - # Save processed data - df_processed.to_csv(data_dir / "processed_customers.csv", index=False) - logger.info(" Processed data saved: %d rows × %d features", len(df_processed), len(feature_names)) - - # ──────────────────────────────────────── - # STEP 4: Clustering - # ──────────────────────────────────────── - logger.info("\n🎯 Step 4: Running clustering algorithms...") - from clustering import ClusteringEngine - - engine = ClusteringEngine(X_scaled, k_range=k_range) - all_results = engine.run_all() - - # Select best model - best = engine.get_best_model(metric="silhouette") - labels = best.labels - logger.info(" Best model: %s (K=%d, Silhouette=%.3f)", - best.algorithm, best.n_clusters, best.metrics.get("silhouette", 0)) - - results["best_algorithm"] = best.algorithm - results["n_clusters"] = best.n_clusters - results["cluster_metrics"] = best.metrics - - # Save clustered data - df_processed["cluster"] = labels - df_processed.to_csv(data_dir / "clustered_customers.csv", index=False) - logger.info(" Clustered data saved") - - # ──────────────────────────────────────── - # STEP 5: Cluster Evaluation - # ──────────────────────────────────────── - logger.info("\n🔬 Step 5: Evaluating clusters...") - from cluster_evaluation import ClusterEvaluator - - evaluator = ClusterEvaluator(X_scaled, labels, feature_names, eval_dir) - eval_report = evaluator.run_full_evaluation(pca=pca, k_range=k_range) - results["evaluation"] = eval_report - - # ──────────────────────────────────────── - # STEP 6: GenAI Persona Generation - # ──────────────────────────────────────── - personas = [] - if not skip_personas: - logger.info("\n🤖 Step 6: Generating personas with GenAI...") - from persona_generation import PersonaGenerator, build_cluster_profiles - - profiles = build_cluster_profiles( - df_processed, labels, feature_names, - shap_importance=eval_report.get("shap_importance", {}).get("feature_importance"), - ) - - try: - generator = PersonaGenerator(domain_config, output_dir) - personas = generator.generate_personas(profiles) - results["personas"] = personas - logger.info(" Generated %d personas", len(personas)) - except Exception as e: - logger.warning("Persona generation failed: %s (continuing without personas)", e) - else: - logger.info("\n⏭️ Step 6: Skipping persona generation (--skip-personas)") - - # ──────────────────────────────────────── - # STEP 7: Dashboard - # ──────────────────────────────────────── - logger.info("\n📊 Step 7: Building dashboard...") - from dashboard import DashboardBuilder - - # Prepare 2D projection for scatter plot - X_viz = X_scaled[:, :2] if X_scaled.shape[1] >= 2 else X_scaled - - builder = DashboardBuilder(output_dir) - dashboard_path = builder.build( - df=df_processed, - labels=labels, - X_for_viz=X_viz, - feature_names=feature_names, - personas=personas, - evaluation_report=eval_report, - ) - results["dashboard_path"] = str(dashboard_path) - - # ──────────────────────────────────────── - # Done - # ──────────────────────────────────────── - logger.info("\n" + "=" * 60) - logger.info("✅ PIPELINE COMPLETE") - logger.info(" Clusters: %d (%s)", best.n_clusters, best.algorithm) - logger.info(" Silhouette: %.3f", best.metrics.get("silhouette", 0)) - logger.info(" Dashboard: %s", dashboard_path) - logger.info("=" * 60) - - return results - - -# ────────────────────────────────────────────── -# CLI -# ────────────────────────────────────────────── - -def main() -> None: - """CLI entry point.""" - parser = argparse.ArgumentParser( - description="Segmentation Plus — Customer Segmentation & Persona Generation", - formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=""" -Examples: - python main.py --data data/customers.csv --domain financial_services - python main.py --data data/sales.xlsx --domain retail --skip-personas - python main.py --data data/patients.csv --domain healthcare --k-min 3 --k-max 8 - """, - ) - - parser.add_argument("--data", required=True, help="Path to input data file (CSV/Excel/Parquet)") - parser.add_argument("--domain", required=True, help="Domain config name (e.g., financial_services, retail)") - parser.add_argument("--output", default="output", help="Output directory (default: output)") - parser.add_argument("--skip-personas", action="store_true", help="Skip GenAI persona generation") - parser.add_argument("--k-min", type=int, default=2, help="Minimum K for clustering (default: 2)") - parser.add_argument("--k-max", type=int, default=10, help="Maximum K for clustering (default: 10)") - parser.add_argument("--pca-variance", type=float, default=0.85, help="PCA variance threshold (default: 0.85)") - parser.add_argument("--verbose", "-v", action="store_true", help="Enable debug logging") - - args = parser.parse_args() - - run_pipeline( - data_path=args.data, - domain_key=args.domain, - output_base=args.output, - skip_personas=args.skip_personas, - k_range=(args.k_min, args.k_max), - pca_variance=args.pca_variance, - verbose=args.verbose, - ) - - -if __name__ == "__main__": - main() diff --git a/notebook.ipynb b/notebook.ipynb deleted file mode 100644 index d2b827e..0000000 --- a/notebook.ipynb +++ /dev/null @@ -1,1295 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# SegPlus Final End-to-End Pipeline\n", - "\n", - "This notebook runs the full architecture:\n", - "- Data input and validation\n", - "- Feature engineering\n", - "- KMeans + DBSCAN + GMM modeling loop\n", - "- Cluster evaluation + stability\n", - "- Explainability (feature drivers, PCA loadings, profiles)\n", - "- Persona generation and business grounding (Ollama with fallback)\n", - "- Visualization and export\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "64579db4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Missing required: ['scikit-learn', 'pyyaml']\n", - "Missing optional: []\n" - ] - } - ], - "source": [ - "# Optional dependency installer/check\n", - "import importlib\n", - "import subprocess\n", - "import sys\n", - "\n", - "REQUIRED_PACKAGES = [\n", - " \"numpy\", \"pandas\", \"scikit-learn\", \"matplotlib\", \"seaborn\",\n", - " \"pyyaml\", \"openpyxl\", \"requests\", \"scipy\"\n", - "]\n", - "OPTIONAL_PACKAGES = [\"shap\"]\n", - "AUTO_INSTALL_MISSING = False # set True if you want notebook to install missing packages\n", - "\n", - "missing_required = []\n", - "missing_optional = []\n", - "\n", - "for pkg in REQUIRED_PACKAGES:\n", - " mod = pkg.replace(\"-\", \"_\")\n", - " try:\n", - " importlib.import_module(mod)\n", - " except Exception:\n", - " missing_required.append(pkg)\n", - "\n", - "for pkg in OPTIONAL_PACKAGES:\n", - " try:\n", - " importlib.import_module(pkg)\n", - " except Exception:\n", - " missing_optional.append(pkg)\n", - "\n", - "print(\"Missing required:\", missing_required)\n", - "print(\"Missing optional:\", missing_optional)\n", - "\n", - "if missing_required and AUTO_INSTALL_MISSING:\n", - " cmd = [sys.executable, \"-m\", \"pip\", \"install\", *missing_required]\n", - " print(\"Installing:\", \" \".join(missing_required))\n", - " subprocess.check_call(cmd)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "32c77bb2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Project root: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\n" - ] - } - ], - "source": [ - "import logging\n", - "import json\n", - "from pathlib import Path\n", - "import sys\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "# Ensure project root is importable when notebook is inside segplus/\n", - "cwd = Path.cwd()\n", - "project_root = cwd.parent if cwd.name.lower() == \"segplus\" else cwd\n", - "if str(project_root) not in sys.path:\n", - " sys.path.insert(0, str(project_root))\n", - "\n", - "from segplus.config import PipelineConfig, load_domain_config\n", - "from segplus.data_input import import_and_validate\n", - "from segplus.feature_engineering import FeatureEngineer\n", - "from segplus.modeling_loop import modeling_loop\n", - "from segplus.evaluation import run_stability_test\n", - "from segplus.experiment_log import ExperimentLog\n", - "from segplus.explainability import build_explainability_report\n", - "from segplus.ollama_client import OllamaClient\n", - "from segplus.persona_generation import PersonaGenerator\n", - "from segplus.visualization import (\n", - " plot_cluster_scatter_2d,\n", - " plot_shap_importance,\n", - " plot_shap_summary,\n", - " plot_pca_loadings_heatmap,\n", - " plot_cluster_profiles_heatmap,\n", - " plot_cluster_sizes,\n", - " plot_radar_charts,\n", - " plot_experiment_history,\n", - " plot_elbow_curve,\n", - ")\n", - "\n", - "logging.basicConfig(\n", - " level=logging.INFO,\n", - " format=\"%(asctime)s | %(levelname)-8s | %(name)-30s | %(message)s\",\n", - ")\n", - "\n", - "print(\"Project root:\", project_root)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "e0196175", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Domain: Financial Services\n", - "Data: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\final_enterprise_clustering_dataset_single_sheet.xlsx\n", - "Output: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n", - "Ollama host: http://localhost:11434\n", - "Primary LLM: qwen2.5:7b\n" - ] - } - ], - "source": [ - "# Configuration (edit these as needed)\n", - "default_data_path = project_root / \"final_enterprise_clustering_dataset_single_sheet.xlsx\"\n", - "default_output_dir = project_root / \"segplus_output\"\n", - "\n", - "config = PipelineConfig(\n", - " data_path=str(default_data_path),\n", - " domain_key=\"financial_services\", # or \"retail\"\n", - " sheet_name=None,\n", - " k_range=(2, 8),\n", - " max_iterations=5,\n", - " pca_variance_threshold=0.85,\n", - " output_dir=str(default_output_dir),\n", - " ollama_host=\"http://localhost:11434\", # local Ollama endpoint\n", - " ollama_model=\"qwen2.5:7b\", # primary local model`n ollama_timeout=240,\n", - " business_objective=(\n", - " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", - " \"improve retention for high-value customers, and convert mid-tier customers \"\n", - " \"to premium products.\"\n", - " ),\n", - ")\n", - "\n", - "# Preferred model order for local Ollama auto-selection\n", - "PREFERRED_OLLAMA_MODELS = [\n", - " \"qwen2.5\",\n", - " \"qwen2\",\n", - " \"llama3.2\",\n", - " \"llama3.1\",\n", - " \"llama3\",\n", - " \"mistral\",\n", - "]\n", - "\n", - "output_dir = Path(config.output_dir)\n", - "output_dir.mkdir(parents=True, exist_ok=True)\n", - "\n", - "domain_config = load_domain_config(config.domain_key, domains_dir=project_root / \"domains\")\n", - "print(\"Domain:\", domain_config.display_name)\n", - "print(\"Data:\", config.data_path)\n", - "print(\"Output:\", output_dir)\n", - "print(\"Ollama host:\", config.ollama_host)\n", - "print(\"Primary LLM:\", config.ollama_model)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "85b24976", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:49:51,635 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n", - "2026-03-06 22:49:51,833 | INFO | segplus.data_input | Data quality: PASSED\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Data Quality Report\n", - " Rows: 120,000 | Columns: 27\n", - " Duplicates: 0\n", - " Status: PASSED\n", - "Raw shape: (120000, 27)\n" - ] - } - ], - "source": [ - "# 1) Data Input + Validation\n", - "df_raw, quality_report, schema = import_and_validate(\n", - " file_path=config.data_path,\n", - " domain_config=domain_config,\n", - " auto_map=True,\n", - " sheet_name=config.sheet_name,\n", - ")\n", - "\n", - "print(quality_report.summary())\n", - "if not quality_report.passed:\n", - " raise ValueError(\"Data quality checks failed. Fix input data and rerun.\")\n", - "\n", - "print(\"Raw shape:\", df_raw.shape)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "7e4bf552", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:49:51,888 | WARNING | segplus.feature_engineering | FE rule 'wealth_tier' failed: name 'investment_portfolio_value' is not defined\n", - "2026-03-06 22:49:51,902 | WARNING | segplus.feature_engineering | FE rule 'digital_vs_branch_ratio' failed: name 'digital_engagement_score' is not defined\n", - "2026-03-06 22:49:51,918 | WARNING | segplus.feature_engineering | FE rule 'product_depth' failed: name 'has_credit_card' is not defined\n", - "2026-03-06 22:49:51,926 | WARNING | segplus.feature_engineering | FE rule 'spending_to_income_ratio' failed: name 'monthly_spending' is not defined\n", - "2026-03-06 22:49:51,942 | WARNING | segplus.feature_engineering | FE rule 'risk_category' failed: name 'debt_to_income_ratio' is not defined\n", - "2026-03-06 22:49:52,618 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", - "2026-03-06 22:49:52,619 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Engineered dataframe shape: (120000, 26)\n", - "Model matrix shape used for clustering: (120000, 7)\n", - "Feature count used for clustering: 7\n", - "SHAP source feature count (original vars): 26\n", - "First SHAP source vars: ['month', 'monthly_spend_x', 'utilization_ratio_x', 'delinquency_flag_x', 'age', 'annual_income', 'risk_score', 'credit_score', 'digital_affinity', 'tenure_months']\n" - ] - } - ], - "source": [ - "# 2) Feature Engineering\n", - "from sklearn.preprocessing import StandardScaler\n", - "\n", - "feature_engineer = FeatureEngineer(domain_config, config)\n", - "fe_result = feature_engineer.run(df_raw)\n", - "\n", - "# Original-variable matrix for SHAP (never PCA names)\n", - "original_feature_names_for_shap = fe_result.df_engineered.columns.tolist()\n", - "X_original_for_shap = StandardScaler().fit_transform(fe_result.df_engineered.values)\n", - "\n", - "# Optional latent representation via local autoencoder (if tensorflow is installed)\n", - "USE_AUTOENCODER_REPRESENTATION = False\n", - "AE_LATENT_DIM = 8\n", - "AE_EPOCHS = 40\n", - "AE_BATCH_SIZE = 256\n", - "\n", - "X = fe_result.X_scaled\n", - "feature_names = fe_result.feature_names\n", - "pca_for_explainability = fe_result.pca\n", - "\n", - "if USE_AUTOENCODER_REPRESENTATION:\n", - " try:\n", - " import tensorflow as tf\n", - " from tensorflow.keras import Model\n", - " from tensorflow.keras.layers import Dense, Input\n", - " from tensorflow.keras.callbacks import EarlyStopping\n", - "\n", - " tf.random.set_seed(config.random_state)\n", - " input_dim = X.shape[1]\n", - " latent_dim = max(2, min(AE_LATENT_DIM, input_dim - 1))\n", - "\n", - " inp = Input(shape=(input_dim,))\n", - " x = Dense(max(16, input_dim // 2), activation=\"relu\")(inp)\n", - " latent = Dense(latent_dim, activation=\"linear\", name=\"latent\")(x)\n", - " x = Dense(max(16, input_dim // 2), activation=\"relu\")(latent)\n", - " out = Dense(input_dim, activation=\"linear\")(x)\n", - "\n", - " autoencoder = Model(inp, out)\n", - " encoder = Model(inp, latent)\n", - " autoencoder.compile(optimizer=\"adam\", loss=\"mse\")\n", - " autoencoder.fit(\n", - " X,\n", - " X,\n", - " epochs=AE_EPOCHS,\n", - " batch_size=min(AE_BATCH_SIZE, len(X)),\n", - " verbose=0,\n", - " callbacks=[EarlyStopping(monitor=\"loss\", patience=5, restore_best_weights=True)],\n", - " )\n", - "\n", - " X = encoder.predict(X, verbose=0)\n", - " feature_names = [f\"AE{i+1}\" for i in range(X.shape[1])]\n", - " pca_for_explainability = None # PCA loadings no longer match AE latent space\n", - " print(f\"Autoencoder latent representation enabled: {X.shape}\")\n", - " except Exception as e:\n", - " print(f\"Autoencoder path unavailable ({e}); continuing with FE output.\")\n", - "\n", - "print(\"Engineered dataframe shape:\", fe_result.df_engineered.shape)\n", - "print(\"Model matrix shape used for clustering:\", X.shape)\n", - "print(\"Feature count used for clustering:\", len(feature_names))\n", - "print(\"SHAP source feature count (original vars):\", len(original_feature_names_for_shap))\n", - "print(\"First SHAP source vars:\", original_feature_names_for_shap[:10])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ca7f19aa", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:\n", - "[WinError 2] The system cannot find the file specified\n", - "Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.\n", - " warnings.warn(\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", - " cpu_info = subprocess.run(\n", - " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", - " capture_output=True,\n", - " text=True,\n", - " )\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", - " with Popen(*popenargs, **kwargs) as process:\n", - " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", - " self._execute_child(args, executable, preexec_fn, close_fds,\n", - " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " pass_fds, cwd, env,\n", - " ^^^^^^^^^^^^^^^^^^^\n", - " ...<5 lines>...\n", - " gid, gids, uid, umask,\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " start_new_session, process_group)\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", - " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", - " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", - " # no special security\n", - " ^^^^^^^^^^^^^^^^^^^^^\n", - " ...<4 lines>...\n", - " cwd,\n", - " ^^^^\n", - " startupinfo)\n", - " ^^^^^^^^^^^^\n", - "2026-03-06 22:49:58,214 | INFO | segplus.clustering | K search: scores={2: np.float64(0.202), 3: np.float64(0.2145), 4: np.float64(0.1609), 5: np.float64(0.1639), 6: np.float64(0.1444), 7: np.float64(0.1399), 8: np.float64(0.141)} | best k=3 (sil=0.2145)\n", - "2026-03-06 22:50:00,159 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", - "2026-03-06 22:50:00,161 | INFO | segplus.modeling_loop | ============================================================\n", - "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", - "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | ============================================================\n", - "2026-03-06 22:50:00,815 | INFO | segplus.clustering | [kmeans] clusters=3\n", - "2026-03-06 22:50:25,748 | INFO | segplus.clustering | [dbscan] clusters=178\n", - "2026-03-06 22:50:44,501 | INFO | segplus.clustering | [gmm] clusters=3\n", - "2026-03-06 22:50:44,663 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2115 | DB=1.5251 | CH=31125.2 | cov=1.00\n", - "2026-03-06 22:50:44,946 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.2252 | DB=0.8652 | CH=142.0 | cov=1.00\n", - "2026-03-06 22:50:45,068 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0667 | DB=3.5552 | CH=13484.7 | cov=1.00\n", - "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", - "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", - "2026-03-06 22:50:45,072 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2115 pass=True\n", - "2026-03-06 22:50:45,073 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2115 | DB=1.5251 | PASS=True\n", - "2026-03-06 22:50:45,074 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Best algorithm: kmeans\n", - "Clusters: 3\n", - "Silhouette: 0.2115\n", - "Davies-Bouldin: 1.5251\n", - "Passes gate: True\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    iterationtimestampkepsgmm_covbest_algorithmn_clusterssilhouettedavies_bouldincalinski_harabaszpassedreconfig_strategy
    012026-03-06T22:50:45.07245831.661fullkmeans30.21151.525131125.2TrueNone
    \n", - "
    " - ], - "text/plain": [ - " iteration timestamp k eps gmm_cov best_algorithm \\\n", - "0 1 2026-03-06T22:50:45.072458 3 1.661 full kmeans \n", - "\n", - " n_clusters silhouette davies_bouldin calinski_harabasz passed \\\n", - "0 3 0.2115 1.5251 31125.2 True \n", - "\n", - " reconfig_strategy \n", - "0 None " - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 3) Modeling Loop (KMeans + DBSCAN + GMM with reconfiguration)\n", - "experiment_log = ExperimentLog()\n", - "\n", - "best_eval, best_cfg = modeling_loop(\n", - " X=X,\n", - " feature_names=feature_names,\n", - " config=config,\n", - " experiment_log=experiment_log,\n", - ")\n", - "\n", - "print(\"Best algorithm:\", best_eval.algorithm)\n", - "print(\"Clusters:\", best_eval.n_clusters)\n", - "print(\"Silhouette:\", best_eval.silhouette)\n", - "print(\"Davies-Bouldin:\", best_eval.davies_bouldin)\n", - "print(\"Passes gate:\", best_eval.passes)\n", - "\n", - "exp_df = experiment_log.to_dataframe()\n", - "exp_df\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "7e9bafbb", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:50:57,856 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", - "2026-03-06 22:50:57,859 | INFO | segplus.explainability | Computing feature importances...\n", - "2026-03-06 22:51:08,907 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", - "2026-03-06 22:51:08,940 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", - "2026-03-06 22:51:08,944 | INFO | segplus.explainability | Computing PCA loadings...\n", - "2026-03-06 22:51:08,945 | INFO | segplus.explainability | Computing inertia curve...\n", - "2026-03-06 22:51:12,627 | INFO | segplus.explainability | Computing cluster profiles...\n", - "2026-03-06 22:51:12,729 | INFO | segplus.explainability | Building ordered convergence drivers...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stability ARI mean: 0.988\n", - "Stability algorithm used: kmeans\n", - "Ordered top drivers: ['risk_score', 'risk_score_cluster', 'risk_behavior_score', 'delinquency_flag_y', 'credit_score', 'credit_score_cluster', 'monthly_spend_y', 'value_score', 'annual_income', 'log_income']\n", - "Top SHAP % (original variables):\n", - " credit_score: 19.58%\n", - " credit_score_cluster: 19.05%\n", - " risk_score: 9.32%\n", - " risk_score_cluster: 7.35%\n", - " risk_behavior_score: 6.92%\n", - " monthly_spend_y: 5.59%\n", - " delinquency_flag_y: 5.43%\n", - " value_score: 5.40%\n", - " monthly_spend_x: 3.53%\n", - " annual_income: 3.00%\n", - "PC to original feature map (top 5):\n", - " PC1: ['credit_score', 'credit_score_cluster', 'risk_score', 'risk_score_cluster', 'log_income']\n", - " PC2: ['value_score', 'monthly_spend_y', 'monthly_spend_x', 'lifetime_value_proxy', 'utilization_ratio_x']\n", - " PC3: ['age', 'age_cluster', 'digital_affinity_cluster', 'digital_affinity', 'delinquency_flag_y']\n", - " PC4: ['tenure_months', 'tenure_months_cluster', 'lifetime_value_proxy', 'utilization_ratio_x', 'utilization_ratio_y']\n", - " PC5: ['annual_income', 'annual_income_cluster', 'log_income', 'delinquency_flag_y', 'risk_behavior_score']\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    featureshap_importancepca_weighted_loadingshap_rankpca_rankshap_rank_normpca_rank_norminertia_elbow_strengthconvergence_score
    0risk_score0.093210.1696243.03.50.920.90158504.1408420.912
    1risk_score_cluster0.073450.1696244.03.50.880.90158504.1408420.888
    2risk_behavior_score0.069180.1701175.02.00.840.96158504.1408420.888
    3delinquency_flag_y0.054290.1702847.01.00.761.00158504.1408420.856
    4credit_score0.195770.1500411.012.51.000.54158504.1408420.816
    5credit_score_cluster0.190510.1500412.012.50.960.54158504.1408420.792
    6monthly_spend_y0.055910.1504126.010.50.800.62158504.1408420.728
    7value_score0.053970.1504128.010.50.720.62158504.1408420.680
    8annual_income0.030040.15700110.08.00.640.72158504.1408420.672
    9log_income0.029880.15923811.07.00.600.76158504.1408420.664
    10utilization_ratio_y0.028070.16146912.06.00.560.80158504.1408420.656
    11monthly_spend_x0.035330.1490169.014.00.680.48158504.1408420.600
    12utilization_ratio_x0.020780.16152515.05.00.440.84158504.1408420.600
    13annual_income_cluster0.027650.15700113.09.00.520.68158504.1408420.584
    14lifetime_value_proxy0.024850.14514214.015.00.480.44158504.1408420.464
    \n", - "
    " - ], - "text/plain": [ - " feature shap_importance pca_weighted_loading shap_rank \\\n", - "0 risk_score 0.09321 0.169624 3.0 \n", - "1 risk_score_cluster 0.07345 0.169624 4.0 \n", - "2 risk_behavior_score 0.06918 0.170117 5.0 \n", - "3 delinquency_flag_y 0.05429 0.170284 7.0 \n", - "4 credit_score 0.19577 0.150041 1.0 \n", - "5 credit_score_cluster 0.19051 0.150041 2.0 \n", - "6 monthly_spend_y 0.05591 0.150412 6.0 \n", - "7 value_score 0.05397 0.150412 8.0 \n", - "8 annual_income 0.03004 0.157001 10.0 \n", - "9 log_income 0.02988 0.159238 11.0 \n", - "10 utilization_ratio_y 0.02807 0.161469 12.0 \n", - "11 monthly_spend_x 0.03533 0.149016 9.0 \n", - "12 utilization_ratio_x 0.02078 0.161525 15.0 \n", - "13 annual_income_cluster 0.02765 0.157001 13.0 \n", - "14 lifetime_value_proxy 0.02485 0.145142 14.0 \n", - "\n", - " pca_rank shap_rank_norm pca_rank_norm inertia_elbow_strength \\\n", - "0 3.5 0.92 0.90 158504.140842 \n", - "1 3.5 0.88 0.90 158504.140842 \n", - "2 2.0 0.84 0.96 158504.140842 \n", - "3 1.0 0.76 1.00 158504.140842 \n", - "4 12.5 1.00 0.54 158504.140842 \n", - "5 12.5 0.96 0.54 158504.140842 \n", - "6 10.5 0.80 0.62 158504.140842 \n", - "7 10.5 0.72 0.62 158504.140842 \n", - "8 8.0 0.64 0.72 158504.140842 \n", - "9 7.0 0.60 0.76 158504.140842 \n", - "10 6.0 0.56 0.80 158504.140842 \n", - "11 14.0 0.68 0.48 158504.140842 \n", - "12 5.0 0.44 0.84 158504.140842 \n", - "13 9.0 0.52 0.68 158504.140842 \n", - "14 15.0 0.48 0.44 158504.140842 \n", - "\n", - " convergence_score \n", - "0 0.912 \n", - "1 0.888 \n", - "2 0.888 \n", - "3 0.856 \n", - "4 0.816 \n", - "5 0.792 \n", - "6 0.728 \n", - "7 0.680 \n", - "8 0.672 \n", - "9 0.664 \n", - "10 0.656 \n", - "11 0.600 \n", - "12 0.600 \n", - "13 0.584 \n", - "14 0.464 " - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 4) Stability + Explainability\n", - "stability = run_stability_test(\n", - " X=X,\n", - " labels=best_eval.labels,\n", - " n_clusters=best_eval.n_clusters,\n", - " config=config,\n", - " algorithm=best_eval.algorithm,\n", - " model=best_eval.model,\n", - ")\n", - "\n", - "explainability = build_explainability_report(\n", - " X=X,\n", - " labels=best_eval.labels,\n", - " feature_names=feature_names,\n", - " df_raw=fe_result.df_engineered,\n", - " pca=pca_for_explainability,\n", - " k_range=config.k_range,\n", - " random_state=config.random_state,\n", - " n_top=config.n_top_features,\n", - " X_original=X_original_for_shap,\n", - " original_feature_names=original_feature_names_for_shap,\n", - ")\n", - "\n", - "print(\"Stability ARI mean:\", stability.ari_mean)\n", - "print(\"Stability algorithm used:\", best_eval.algorithm)\n", - "print(\"Ordered top drivers:\", explainability.top_features[:10])\n", - "print(\"Top SHAP % (original variables):\")\n", - "for k, v in list(explainability.feature_importance_pct.items())[:10]:\n", - " print(f\" {k}: {v:.2f}%\")\n", - "\n", - "print(\"PC to original feature map (top 5):\")\n", - "for pc, cols in list(explainability.pc_feature_map.items())[:5]:\n", - " print(f\" {pc}: {cols}\")\n", - "\n", - "explainability.ordered_feature_drivers.head(15)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "000fb2d4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Installed Ollama models: ['qwen2.5:7b']\n", - "Selected model tag: qwen2.5:7b\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 22:51:17,003 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", - "2026-03-06 22:53:19,121 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 22:54:37,832 | INFO | segplus.ollama_client | Ollama response received (534 chars)\n", - "2026-03-06 22:55:12,181 | INFO | segplus.ollama_client | Ollama response received (14 chars)\n", - "2026-03-06 22:55:12,184 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'Elite Spenders'\n", - "2026-03-06 22:55:12,202 | INFO | segplus.persona_generation | Persona generated: Cluster A -> Elite Spenders\n", - "2026-03-06 22:57:14,441 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 22:57:55,579 | INFO | segplus.ollama_client | Ollama response received (551 chars)\n", - "2026-03-06 22:58:37,127 | INFO | segplus.ollama_client | Ollama response received (17 chars)\n", - "2026-03-06 22:58:37,130 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", - "2026-03-06 23:00:39,228 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 23:02:14,255 | INFO | segplus.ollama_client | Ollama response received (839 chars)\n", - "2026-03-06 23:02:50,674 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", - "2026-03-06 23:02:50,678 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", - "2026-03-06 23:02:50,721 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", - "2026-03-06 23:04:52,791 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 23:06:56,881 | WARNING | segplus.ollama_client | Ollama attempt 2 failed (Timeout after 120s). Retrying in 4s...\n", - "2026-03-06 23:09:02,941 | WARNING | segplus.persona_generation | Business grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Generated personas: 3\n", - "Executive summary: LLM grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n", - "persona_df columns: ['cluster', 'genai_persona_name', 'profile_descriptor', 'description', 'cluster_size', 'cluster_pct', 'ordered_top_features', 'genai_recommendations', 'categorization_basis', 'naming_rationale']\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    clustergenai_persona_nameprofile_descriptordescriptioncluster_sizecluster_pctordered_top_featuresgenai_recommendationscategorization_basisnaming_rationale
    0Cluster AElite SpendersHigh Value Score & High Monthly Spend YHigh-Value Premium Spenders are among the most...87740.0731value_score:0.1, monthly_spend_y:25414.84, mon...Targeted Upselling of Premium Products | Perso...value_score, monthly_spend_y, monthly_spend_x,...Second-pass focused LLM naming from profile: H...
    1Cluster BCredit Risk Strategists – Higher Credit Score ...High Credit Score & Low Risk ScoreThese customers are highly creditworthy and lo...567820.4732credit_score:827.07, credit_score_cluster:827....Target with premium product promotions | Enhan...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    2Cluster CCredit Risk Strategists – Lower Credit Score C...Low Credit Score & High Risk ScoreBudget-conscious Credit Risk Takers are custom...544440.4537credit_score:692.54, credit_score_cluster:692....Offer tailored credit products with flexible t...credit_score, credit_score_cluster, risk_score...LLM returned generic name; using business-styl...
    \n", - "
    " - ], - "text/plain": [ - " cluster genai_persona_name \\\n", - "0 Cluster A Elite Spenders \n", - "1 Cluster B Credit Risk Strategists – Higher Credit Score ... \n", - "2 Cluster C Credit Risk Strategists – Lower Credit Score C... \n", - "\n", - " profile_descriptor \\\n", - "0 High Value Score & High Monthly Spend Y \n", - "1 High Credit Score & Low Risk Score \n", - "2 Low Credit Score & High Risk Score \n", - "\n", - " description cluster_size \\\n", - "0 High-Value Premium Spenders are among the most... 8774 \n", - "1 These customers are highly creditworthy and lo... 56782 \n", - "2 Budget-conscious Credit Risk Takers are custom... 54444 \n", - "\n", - " cluster_pct ordered_top_features \\\n", - "0 0.0731 value_score:0.1, monthly_spend_y:25414.84, mon... \n", - "1 0.4732 credit_score:827.07, credit_score_cluster:827.... \n", - "2 0.4537 credit_score:692.54, credit_score_cluster:692.... \n", - "\n", - " genai_recommendations \\\n", - "0 Targeted Upselling of Premium Products | Perso... \n", - "1 Target with premium product promotions | Enhan... \n", - "2 Offer tailored credit products with flexible t... \n", - "\n", - " categorization_basis \\\n", - "0 value_score, monthly_spend_y, monthly_spend_x,... \n", - "1 credit_score, credit_score_cluster, risk_score... \n", - "2 credit_score, credit_score_cluster, risk_score... \n", - "\n", - " naming_rationale \n", - "0 Second-pass focused LLM naming from profile: H... \n", - "1 LLM returned generic name; using business-styl... \n", - "2 LLM returned generic name; using business-styl... " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 5) Persona Generation + Business Grounding (Ollama local, with fallback)\n", - "import requests\n", - "\n", - "\n", - "def _list_local_ollama_models(host: str) -> list[str]:\n", - " try:\n", - " r = requests.get(f\"{host.rstrip('/')}/api/tags\", timeout=8)\n", - " r.raise_for_status()\n", - " return [m.get(\"name\", \"\") for m in r.json().get(\"models\", []) if m.get(\"name\")]\n", - " except Exception as e:\n", - " print(f\"Ollama model discovery failed: {e}\")\n", - " return []\n", - "\n", - "\n", - "def _choose_ollama_model(installed: list[str], preferred: list[str], configured: str) -> str:\n", - " if configured and configured in installed:\n", - " return configured\n", - " if configured:\n", - " matches = [m for m in installed if configured in m]\n", - " if matches:\n", - " return matches[0]\n", - " for pref in preferred:\n", - " matches = [m for m in installed if m.startswith(pref) or pref in m]\n", - " if matches:\n", - " return matches[0]\n", - " return installed[0] if installed else (configured or \"qwen2.5:7b\")\n", - "\n", - "\n", - "installed_models = _list_local_ollama_models(config.ollama_host)\n", - "selected_model = _choose_ollama_model(installed_models, PREFERRED_OLLAMA_MODELS, config.ollama_model)\n", - "config.ollama_model = selected_model\n", - "\n", - "print(\"Installed Ollama models:\", installed_models if installed_models else \"None found / Ollama offline\")\n", - "print(\"Selected model tag:\", config.ollama_model)\n", - "\n", - "ollama_client = OllamaClient(\n", - " host=config.ollama_host,\n", - " model=config.ollama_model,\n", - " timeout=config.ollama_timeout,\n", - ")\n", - "persona_generator = PersonaGenerator(ollama_client, config)\n", - "\n", - "# Step A: Cluster personas\n", - "personas = persona_generator.generate_personas(\n", - " evaluation=best_eval,\n", - " explainability=explainability,\n", - " raw_df=fe_result.df_original,\n", - " schema=schema,\n", - ")\n", - "\n", - "# Step B: Business grounding + GenAI per-cluster naming/actions\n", - "grounding = persona_generator.ground_in_business_objective(personas)\n", - "personas = persona_generator.apply_grounding_to_personas(personas, grounding)\n", - "\n", - "persona_df = pd.DataFrame([\n", - " {\n", - " \"cluster\": p.persona_name,\n", - " \"genai_persona_name\": p.archetype,\n", - " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", - " \"description\": getattr(p, \"description\", \"\"),\n", - " \"cluster_size\": p.cluster_size,\n", - " \"cluster_pct\": round(p.cluster_pct, 4),\n", - " \"ordered_top_features\": \", \".join([f\"{k}:{v}\" for k, v in p.top_features.items()]),\n", - " \"genai_recommendations\": \" | \".join(p.business_recommendations),\n", - " \"categorization_basis\": \", \".join(getattr(p, \"categorization_basis\", [])),\n", - " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", - " }\n", - " for p in personas\n", - "])\n", - "\n", - "# Exact output schema check\n", - "required_persona_cols = [\n", - " \"cluster\", \"genai_persona_name\", \"profile_descriptor\", \"description\",\n", - " \"cluster_size\", \"cluster_pct\", \"ordered_top_features\",\n", - " \"genai_recommendations\", \"categorization_basis\", \"naming_rationale\",\n", - "]\n", - "missing_cols = [c for c in required_persona_cols if c not in persona_df.columns]\n", - "if missing_cols:\n", - " raise ValueError(f\"persona_df missing required columns: {missing_cols}\")\n", - "\n", - "print(\"Generated personas:\", len(personas))\n", - "print(\"Executive summary:\", grounding.executive_summary)\n", - "print(\"persona_df columns:\", list(persona_df.columns))\n", - "persona_df\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "707cdc91", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 23:09:06,354 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", - "2026-03-06 23:09:06,629 | INFO | segplus.visualization | Saved: feature_importance.png\n", - "2026-03-06 23:09:38,632 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", - "2026-03-06 23:09:39,175 | INFO | segplus.visualization | Saved: pca_loadings.png\n", - "2026-03-06 23:09:39,422 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", - "2026-03-06 23:09:39,526 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", - "2026-03-06 23:09:40,057 | INFO | segplus.visualization | Saved: persona_radar.png\n", - "2026-03-06 23:09:40,212 | INFO | segplus.visualization | Saved: experiment_history.png\n", - "2026-03-06 23:09:40,356 | INFO | segplus.visualization | Saved: elbow_curve.png\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saved charts to: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n" - ] - } - ], - "source": [ - "# 6) Visualizations\n", - "plot_cluster_scatter_2d(X, best_eval.labels, output_dir, best_eval)\n", - "plot_shap_importance(\n", - " explainability.feature_importances, output_dir, top_n=15,\n", - " importance_pct=explainability.feature_importance_pct,\n", - ")\n", - "plot_shap_summary(\n", - " X_original_for_shap,\n", - " best_eval.labels,\n", - " original_feature_names_for_shap,\n", - " output_dir,\n", - " random_state=config.random_state,\n", - " max_display=15,\n", - ")\n", - "plot_pca_loadings_heatmap(explainability.pca_loadings, output_dir)\n", - "plot_cluster_profiles_heatmap(explainability.cluster_profiles, explainability.top_features, output_dir)\n", - "plot_cluster_sizes(best_eval.labels, personas, output_dir)\n", - "plot_radar_charts(fe_result.df_original, best_eval.labels, personas, explainability.top_features, output_dir)\n", - "plot_experiment_history(experiment_log, output_dir)\n", - "plot_elbow_curve(explainability.inertia_curve, output_dir)\n", - "\n", - "print(\"Saved charts to:\", output_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "969da7d8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2026-03-06 23:09:42,767 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Exported:\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\clustered_customers.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\cluster_profiles.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\ordered_feature_drivers.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\shap_feature_importance_pct.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\pc_feature_map.json\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.csv\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\personas.json\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\business_grounding.json\n", - " - c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" - ] - } - ], - "source": [ - "# 7) Export Outputs\n", - "clustered_df = fe_result.df_original.copy()\n", - "clustered_df[\"cluster\"] = best_eval.labels\n", - "\n", - "clustered_path = output_dir / \"clustered_customers.csv\"\n", - "profiles_path = output_dir / \"cluster_profiles.csv\"\n", - "ordered_drivers_path = output_dir / \"ordered_feature_drivers.csv\"\n", - "shap_pct_path = output_dir / \"shap_feature_importance_pct.csv\"\n", - "pc_feature_map_path = output_dir / \"pc_feature_map.json\"\n", - "personas_path = output_dir / \"personas.csv\"\n", - "personas_json_path = output_dir / \"personas.json\"\n", - "grounding_path = output_dir / \"business_grounding.json\"\n", - "exp_log_path = output_dir / \"experiment_log.json\"\n", - "\n", - "clustered_df.to_csv(clustered_path, index=False)\n", - "explainability.cluster_profiles.to_csv(profiles_path)\n", - "if explainability.ordered_feature_drivers is not None:\n", - " explainability.ordered_feature_drivers.to_csv(ordered_drivers_path, index=False)\n", - "\n", - "shap_pct_df = pd.DataFrame([\n", - " {\"feature\": k, \"importance_pct\": v}\n", - " for k, v in explainability.feature_importance_pct.items()\n", - "]).sort_values(\"importance_pct\", ascending=False)\n", - "shap_pct_df.to_csv(shap_pct_path, index=False)\n", - "\n", - "with open(pc_feature_map_path, \"w\", encoding=\"utf-8\") as f:\n", - " json.dump(explainability.pc_feature_map, f, indent=2)\n", - "\n", - "# Export exact persona schema\n", - "persona_df.to_csv(personas_path, index=False)\n", - "\n", - "personas_payload = [\n", - " {\n", - " \"cluster\": p.persona_name,\n", - " \"genai_persona_name\": p.archetype,\n", - " \"profile_descriptor\": getattr(p, \"profile_descriptor\", \"\"),\n", - " \"description\": getattr(p, \"description\", \"\"),\n", - " \"key_traits\": p.key_traits,\n", - " \"genai_recommendations\": p.business_recommendations,\n", - " \"cluster_size\": p.cluster_size,\n", - " \"cluster_pct\": p.cluster_pct,\n", - " \"top_features\": p.top_features,\n", - " \"categorization_basis\": getattr(p, \"categorization_basis\", []),\n", - " \"naming_rationale\": getattr(p, \"naming_rationale\", \"\"),\n", - " }\n", - " for p in personas\n", - "]\n", - "with open(personas_json_path, \"w\", encoding=\"utf-8\") as f:\n", - " json.dump(personas_payload, f, indent=2)\n", - "\n", - "experiment_log.to_json(exp_log_path)\n", - "\n", - "with open(grounding_path, \"w\", encoding=\"utf-8\") as f:\n", - " json.dump(\n", - " {\n", - " \"executive_summary\": grounding.executive_summary,\n", - " \"cluster_priorities\": grounding.cluster_priorities,\n", - " \"cluster_actions\": grounding.cluster_actions,\n", - " \"quick_wins\": grounding.quick_wins,\n", - " },\n", - " f,\n", - " indent=2,\n", - " )\n", - "\n", - "print(\"Exported:\")\n", - "print(\" -\", clustered_path)\n", - "print(\" -\", profiles_path)\n", - "print(\" -\", ordered_drivers_path)\n", - "print(\" -\", shap_pct_path)\n", - "print(\" -\", pc_feature_map_path)\n", - "print(\" -\", personas_path)\n", - "print(\" -\", personas_json_path)\n", - "print(\" -\", grounding_path)\n", - "print(\" -\", exp_log_path)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notes\n", - "\n", - "- Architecture implemented: data input -> FE -> KMeans/DBSCAN/GMM -> eval gate loop -> explainability -> ordered drivers -> persona generation -> business grounding -> per-cluster rationale outputs.\n", - "- Local Ollama is first-class. `qwen2.5` is primary model and auto-selected when installed.\n", - "- Ordered feature driver list combines SHAP importance + weighted PCA loadings, with inertia elbow context.\n", - "- `pc_feature_map.json` provides exact mapping from each PC to top original variables.\n", - "- SHAP summary plot is saved as `shap_summary.png` when `shap` is installed.\n", - "- Optional autoencoder latent representation is available via `USE_AUTOENCODER_REPRESENTATION=True`.\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python", - "version": "3.x" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From a12468724237270787c0667bcb85f047a15848f2 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 12:32:38 +0530 Subject: [PATCH 11/13] Clean repo: remove domains and unnecessary scripts --- domains/retail.yaml | 104 -- persona_generation.py | 318 ---- persona_identification_pipeline.ipynb | 2120 ------------------------- 3 files changed, 2542 deletions(-) delete mode 100644 domains/retail.yaml delete mode 100644 persona_generation.py delete mode 100644 persona_identification_pipeline.ipynb diff --git a/domains/retail.yaml b/domains/retail.yaml deleted file mode 100644 index 01685cc..0000000 --- a/domains/retail.yaml +++ /dev/null @@ -1,104 +0,0 @@ -domain: retail -display_name: "Retail" - -required_columns: - - customer_id - - total_spend - -features: - demographics: - - age - - gender - - annual_income - - location_tier - - marital_status - transactional: - - total_spend - - avg_order_value - - purchase_frequency_monthly - - days_since_last_purchase - - total_orders - - return_rate - product: - - has_loyalty_card - - has_subscription - - is_premium_tier - - top_category - - num_categories_purchased - behavioral: - - online_vs_instore_ratio - - browse_to_buy_ratio - - coupon_usage_rate - - avg_session_duration_min - - app_visits_monthly - satisfaction: - - csat_score - - review_rating - - support_tickets_yearly - -categorical_columns: - - gender - - location_tier - - marital_status - - top_category - -scaling_exclude: - - customer_id - - has_loyalty_card - - has_subscription - - is_premium_tier - -feature_engineering: - - name: rfm_recency - formula: "1 / (days_since_last_purchase + 1)" - description: "Inverse recency — higher = more recent purchase" - - - name: rfm_frequency - formula: "purchase_frequency_monthly" - description: "Direct frequency measure" - - - name: rfm_monetary - formula: "avg_order_value * purchase_frequency_monthly" - description: "Estimated monthly revenue from customer" - - - name: discount_sensitivity - formula: "coupon_usage_rate * (1 - avg_order_value / (total_spend / (total_orders + 1) + 1))" - description: "How responsive customer is to discounts" - - - name: cross_category_shopper - formula: "num_categories_purchased >= 3" - description: "Boolean: shops across 3+ categories" - -eda: - domain_analyses: - - rfm_scoring_matrix - - basket_composition_analysis - - seasonal_purchase_patterns - - channel_preference_mapping - - category_affinity_heatmap - - customer_lifetime_value_distribution - -persona_prompt_template: | - You are a retail marketing strategist advising a brand on their customer segments. - - Segment {segment_id} Profile: - {segment_stats} - - Top SHAP Feature Drivers: - {shap_drivers} - - Based on this data, generate a detailed customer persona including: - 1. Persona Name — a memorable, representative shopper name - 2. One-Line Description — a concise tagline - 3. Demographics & Lifestyle — age range, income, shopping style - 4. Shopping Habits — frequency, channels, categories, timing - 5. Brand Affinities — what they value in a brand - 6. Pain Points — frustrations, barriers to purchase - 7. Product Recommendations — categories, items, bundles - 8. Retention Strategy — loyalty, re-engagement, upsell ideas - - Output as structured JSON with keys: name, tagline, demographics, - shopping_habits, brand_affinities, pain_points, product_recommendations, strategy. - -metadata: - business_types: [ecommerce, brick_and_mortar, d2c, marketplace] diff --git a/persona_generation.py b/persona_generation.py deleted file mode 100644 index b7551be..0000000 --- a/persona_generation.py +++ /dev/null @@ -1,318 +0,0 @@ -""" -Segmentation Plus — GenAI Persona Generation -============================================= -Generates rich marketing personas from cluster profiles -using Google Gemini API, with domain-aware prompt engineering. -""" - -from __future__ import annotations - -import json -import logging -import os -from pathlib import Path -from typing import Any, Dict, List, Optional - -import numpy as np -import pandas as pd - -from config import DomainConfig - -logger = logging.getLogger(__name__) - - -# ────────────────────────────────────────────── -# Cluster Profile Builder -# ────────────────────────────────────────────── - -def build_cluster_profiles( - df: pd.DataFrame, - labels: np.ndarray, - feature_columns: List[str], - shap_importance: Optional[Dict] = None, -) -> List[Dict[str, Any]]: - """ - Build statistical profiles for each cluster. - - Parameters - ---------- - df : pd.DataFrame - Original DataFrame (pre-scaling, for interpretable stats). - labels : np.ndarray - Cluster assignments. - feature_columns : list[str] - Feature columns to compute stats on. - shap_importance : dict, optional - Feature importance from SHAP (feature_name → importance). - - Returns - ------- - list[dict] - Per-cluster profile dictionaries. - """ - df = df.copy() - df["cluster"] = labels - - profiles = [] - available_cols = [c for c in feature_columns if c in df.columns] - - for cluster_id in sorted(df["cluster"].unique()): - if cluster_id == -1: - continue # Skip DBSCAN noise - - cluster_df = df[df["cluster"] == cluster_id] - profile = { - "segment_id": int(cluster_id), - "size": len(cluster_df), - "pct_of_total": round(len(cluster_df) / len(df) * 100, 1), - } - - # Compute mean for numeric columns - stats = {} - for col in available_cols: - if df[col].dtype in [np.float64, np.int64, float, int]: - stats[col] = { - "mean": round(float(cluster_df[col].mean()), 2), - "median": round(float(cluster_df[col].median()), 2), - "std": round(float(cluster_df[col].std()), 2), - } - profile["stats"] = stats - - # Top SHAP drivers for this cluster - if shap_importance: - sorted_feats = sorted( - shap_importance.items(), key=lambda x: abs(x[1]), reverse=True - ) - profile["shap_drivers"] = [ - {"feature": f, "importance": round(v, 4)} - for f, v in sorted_feats[:7] - ] - - profiles.append(profile) - - logger.info("Built profiles for %d clusters", len(profiles)) - return profiles - - -# ────────────────────────────────────────────── -# Prompt Builder -# ────────────────────────────────────────────── - -def build_persona_prompt( - profile: Dict, - domain_config: DomainConfig, -) -> str: - """ - Build the GenAI prompt for a single cluster. - - Parameters - ---------- - profile : dict - Cluster profile from build_cluster_profiles(). - domain_config : DomainConfig - Domain configuration with prompt template. - - Returns - ------- - str - Formatted prompt ready for the LLM. - """ - # Format stats as readable text - stats_lines = [] - for feature, vals in profile.get("stats", {}).items(): - stats_lines.append(f" - {feature}: mean={vals['mean']}, median={vals['median']}") - segment_stats = "\n".join(stats_lines) if stats_lines else " - No stats available" - - # Format SHAP drivers - shap_lines = [] - for driver in profile.get("shap_drivers", []): - shap_lines.append(f" - {driver['feature']}: {driver['importance']}") - shap_drivers = "\n".join(shap_lines) if shap_lines else " - No SHAP data available" - - # Fill template - template = domain_config.persona_prompt_template - if not template: - template = _DEFAULT_PROMPT_TEMPLATE - - prompt = template.format( - segment_id=profile["segment_id"], - segment_stats=segment_stats, - shap_drivers=shap_drivers, - segment_size=profile["size"], - segment_pct=profile["pct_of_total"], - ) - - return prompt - - -_DEFAULT_PROMPT_TEMPLATE = """ -You are a marketing strategist advising a company on their customer segments. - -Segment {segment_id} ({segment_size} customers, {segment_pct}% of total): -{segment_stats} - -Top Feature Drivers (SHAP importance): -{shap_drivers} - -Generate a detailed customer persona as structured JSON with keys: -name, tagline, demographics, goals, pain_points, product_recommendations, -channels, strategy -""" - - -# ────────────────────────────────────────────── -# Persona Generator -# ────────────────────────────────────────────── - -class PersonaGenerator: - """ - Generates marketing personas using Google Gemini API. - - Parameters - ---------- - domain_config : DomainConfig - Domain configuration. - output_dir : Path - Output directory for personas. - api_key : str, optional - Gemini API key. If None, reads from GOOGLE_API_KEY env var. - model_name : str - Gemini model name (default: 'gemini-pro'). - """ - - def __init__( - self, - domain_config: DomainConfig, - output_dir: Path, - api_key: Optional[str] = None, - model_name: str = "gemini-pro", - ) -> None: - self.config = domain_config - self.output_dir = Path(output_dir) - self.output_dir.mkdir(parents=True, exist_ok=True) - self.api_key = api_key or os.environ.get("GOOGLE_API_KEY", "") - self.model_name = model_name - self._model = None - - def _init_model(self): - """Lazily initialize the Gemini model.""" - if self._model is not None: - return - - if not self.api_key: - raise ValueError( - "Google API key not found. Set GOOGLE_API_KEY environment variable " - "or pass api_key parameter." - ) - - try: - import google.generativeai as genai - genai.configure(api_key=self.api_key) - self._model = genai.GenerativeModel(self.model_name) - logger.info("Gemini model '%s' initialized", self.model_name) - except ImportError: - raise ImportError( - "google-generativeai package not installed. " - "Run: pip install google-generativeai" - ) - - def generate_personas( - self, - profiles: List[Dict], - ) -> List[Dict]: - """ - Generate personas for all cluster profiles. - - Parameters - ---------- - profiles : list[dict] - Cluster profiles from build_cluster_profiles(). - - Returns - ------- - list[dict] - Generated persona dictionaries. - """ - self._init_model() - personas = [] - - for profile in profiles: - try: - prompt = build_persona_prompt(profile, self.config) - logger.info("Generating persona for Segment %d...", profile["segment_id"]) - - response = self._model.generate_content(prompt) - persona_text = response.text - - # Try to parse as JSON - persona = self._parse_persona(persona_text, profile["segment_id"]) - persona["segment_id"] = profile["segment_id"] - persona["segment_size"] = profile["size"] - persona["segment_pct"] = profile["pct_of_total"] - personas.append(persona) - - logger.info(" → Generated: %s", persona.get("name", "Unknown")) - - except Exception as e: - logger.error("Failed to generate persona for Segment %d: %s", profile["segment_id"], e) - personas.append({ - "segment_id": profile["segment_id"], - "error": str(e), - "raw_profile": profile, - }) - - # Save outputs - self._save_personas(personas) - return personas - - def _parse_persona(self, text: str, segment_id: int) -> Dict: - """Parse LLM response text into a structured persona dict.""" - # Try JSON extraction - try: - # Look for JSON block in the response - start = text.find("{") - end = text.rfind("}") + 1 - if start != -1 and end > start: - return json.loads(text[start:end]) - except json.JSONDecodeError: - pass - - # Fallback: return as raw text - logger.warning("Could not parse JSON for Segment %d — storing as raw text", segment_id) - return {"raw_text": text} - - def _save_personas(self, personas: List[Dict]) -> None: - """Save personas as JSON and Markdown.""" - # JSON - json_path = self.output_dir / "personas.json" - with open(json_path, "w", encoding="utf-8") as f: - json.dump(personas, f, indent=2, ensure_ascii=False) - logger.info("Personas saved to %s", json_path) - - # Markdown - md_path = self.output_dir / "personas.md" - md_lines = ["# Customer Personas\n"] - for p in personas: - md_lines.append(f"## Segment {p.get('segment_id', '?')}: {p.get('name', 'Unknown')}\n") - md_lines.append(f"**{p.get('tagline', '')}**\n") - md_lines.append(f"- Size: {p.get('segment_size', '?')} customers ({p.get('segment_pct', '?')}%)\n") - - for key in ["demographics", "goals", "pain_points", "product_recommendations", "channels", "strategy"]: - if key in p: - md_lines.append(f"\n### {key.replace('_', ' ').title()}\n") - val = p[key] - if isinstance(val, list): - for item in val: - md_lines.append(f"- {item}") - elif isinstance(val, str): - md_lines.append(val) - md_lines.append("") - - if "raw_text" in p: - md_lines.append(f"\n{p['raw_text']}\n") - - md_lines.append("\n---\n") - - with open(md_path, "w", encoding="utf-8") as f: - f.write("\n".join(md_lines)) - logger.info("Personas markdown saved to %s", md_path) diff --git a/persona_identification_pipeline.ipynb b/persona_identification_pipeline.ipynb deleted file mode 100644 index 30b52e2..0000000 --- a/persona_identification_pipeline.ipynb +++ /dev/null @@ -1,2120 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 🧠 Profiling Plus Modeling Loop — Persona Identification Pipeline\n", - "### Full Architecture: Feature Engineering → Clustering → Evaluation → Explainability → LLM Persona ID (Ollama/llama3)\n", - "\n", - "**Architecture Flow:**\n", - "```\n", - "Start → Data Input → Feature Engineering → Select/Configure Clustering Runs\n", - " → [K-Means | DBSCAN | GMM] → Cluster Evaluation\n", - " → Evaluation Pass?\n", - " No → Reconfigure & Retry (up to N iterations)\n", - " Yes → Explainability (SHAP-style + PCA + Inertia)\n", - " → Feature List Driving Convergence\n", - " → Persona Identification Layer ← LOCAL LLM (Ollama llama3)\n", - " → Ground in Business Objective\n", - " → [Cluster A | Cluster B | Cluster C] → End\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 1 — Requirements\n", - "Install required packages (run once)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ All packages installed.\n", - "⚠️ Make sure Ollama is running: ollama serve\n", - "⚠️ Make sure llama3 is pulled: ollama pull llama3\n" - ] - } - ], - "source": [ - "# ── Requirements ─────────────────────────────────────────────────────────────\n", - "# Run this cell once to install dependencies.\n", - "# Ollama must be separately installed: https://ollama.com/download\n", - "# Then pull the model: ollama pull llama3\n", - "\n", - "import subprocess, sys\n", - "\n", - "PACKAGES = [\n", - " \"scikit-learn\",\n", - " \"pandas\",\n", - " \"numpy\",\n", - " \"matplotlib\",\n", - " \"seaborn\",\n", - " \"openpyxl\", # Excel support\n", - " \"pyarrow\", # Parquet support\n", - " \"requests\", # Ollama HTTP API\n", - "]\n", - "\n", - "for pkg in PACKAGES:\n", - " subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", pkg, \"-q\"])\n", - "\n", - "print(\"✅ All packages installed.\")\n", - "print(\"⚠️ Make sure Ollama is running: ollama serve\")\n", - "print(\"⚠️ Make sure llama3 is pulled: ollama pull llama3\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 2 — Imports & Global Config" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Imports complete.\n" - ] - } - ], - "source": [ - "# ── Imports ──────────────────────────────────────────────────────────────────\n", - "from __future__ import annotations\n", - "\n", - "import json\n", - "import logging\n", - "import math\n", - "import os\n", - "import re\n", - "import time\n", - "import warnings\n", - "from dataclasses import dataclass, field\n", - "from pathlib import Path\n", - "from typing import Literal, Optional\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.patches as mpatches\n", - "import numpy as np\n", - "import pandas as pd\n", - "import requests\n", - "import seaborn as sns\n", - "from sklearn.cluster import KMeans, DBSCAN\n", - "from sklearn.decomposition import PCA\n", - "from sklearn.impute import SimpleImputer\n", - "from sklearn.metrics import (\n", - " silhouette_score,\n", - " davies_bouldin_score,\n", - " calinski_harabasz_score,\n", - ")\n", - "from sklearn.mixture import GaussianMixture\n", - "from sklearn.preprocessing import StandardScaler, LabelEncoder\n", - "\n", - "warnings.filterwarnings(\"ignore\")\n", - "logging.basicConfig(\n", - " level=logging.INFO,\n", - " format=\"%(asctime)s | %(levelname)-8s | %(message)s\",\n", - " datefmt=\"%H:%M:%S\",\n", - ")\n", - "log = logging.getLogger(\"persona_pipeline\")\n", - "\n", - "# ── Global palette ────────────────────────────────────────────────────────────\n", - "PALETTE = [\"#4C72B0\", \"#DD8452\", \"#55A868\", \"#C44E52\", \"#8172B2\"]\n", - "sns.set_theme(style=\"whitegrid\", palette=PALETTE)\n", - "plt.rcParams.update({\"figure.dpi\": 130, \"axes.titlesize\": 13, \"axes.labelsize\": 11})\n", - "\n", - "print(\"✅ Imports complete.\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 3 — Pipeline Configuration\n", - "Edit this cell to configure your run." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Configuration loaded.\n", - " Data source : synthetic\n", - " Ollama model : llama3 @ http://localhost:11434\n", - " Max retries : 5\n", - " Output dir : C:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\persona_output\n" - ] - } - ], - "source": [ - "# ═══════════════════════════════════════════════════════════════════════════\n", - "# PIPELINE CONFIGURATION ← Edit this block\n", - "# ═══════════════════════════════════════════════════════════════════════════\n", - "\n", - "# ── Data source ───────────────────────────────────────────────────────────────\n", - "DATA_SOURCE: Literal[\"csv\", \"parquet\", \"excel\", \"synthetic\"] = \"synthetic\"\n", - "DATA_PATH: str = \"\" # e.g. \"data/customers.csv\" — leave \"\" for synthetic\n", - "\n", - "# ── Target / ID columns to exclude from clustering ───────────────────────────\n", - "EXCLUDE_COLS: list[str] = [\"customer_id\", \"cluster_truth\"]\n", - "\n", - "# ── Clustering ────────────────────────────────────────────────────────────────\n", - "K_RANGE = (2, 6) # min/max k to search over for K-Means & GMM\n", - "DBSCAN_EPS = 0.5\n", - "DBSCAN_MIN_SAMP = 10\n", - "MAX_ITERATIONS = 5 # max modeling loop retries if eval fails\n", - "\n", - "# ── Evaluation thresholds ─────────────────────────────────────────────────────\n", - "SILHOUETTE_THRESHOLD = 0.25 # below this → loop again\n", - "DB_THRESHOLD = 2.0 # Davies-Bouldin: lower is better\n", - "\n", - "# ── Explainability ────────────────────────────────────────────────────────────\n", - "N_TOP_FEATURES = 8 # how many driving features to surface\n", - "\n", - "# ── Ollama / Local LLM ───────────────────────────────────────────────────────\n", - "OLLAMA_HOST = \"http://localhost:11434\"\n", - "OLLAMA_MODEL = \"llama3\"\n", - "OLLAMA_TIMEOUT = 120 # seconds\n", - "\n", - "# ── Business objective (used by LLM for grounding) ───────────────────────────\n", - "BUSINESS_OBJECTIVE = (\n", - " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", - " \"improve retention for high-value customers, and convert mid-tier customers \"\n", - " \"to premium products.\"\n", - ")\n", - "\n", - "# ── Output ────────────────────────────────────────────────────────────────────\n", - "OUTPUT_DIR = Path(\"persona_output\")\n", - "OUTPUT_DIR.mkdir(exist_ok=True)\n", - "\n", - "print(\"✅ Configuration loaded.\")\n", - "print(f\" Data source : {DATA_SOURCE}\")\n", - "print(f\" Ollama model : {OLLAMA_MODEL} @ {OLLAMA_HOST}\")\n", - "print(f\" Max retries : {MAX_ITERATIONS}\")\n", - "print(f\" Output dir : {OUTPUT_DIR.resolve()}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 4 — Data Input Layer\n", - "Supports CSV, Parquet, Excel, and synthetic data generation." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "13:07:49 | INFO | Loaded data: 2000 rows × 12 cols\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "📊 Dataset Overview\n", - " Rows : 2,000\n", - " Columns : 12\n", - " Numeric cols : ['age', 'annual_spend', 'purchase_frequency', 'avg_order_value', 'days_since_last_purchase', 'support_tickets_12m', 'nps_score', 'lifetime_months']\n", - " Categorical cols: ['channel', 'region', 'product_category', 'cluster_truth']\n", - "\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    ageannual_spendpurchase_frequencyavg_order_valuedays_since_last_purchasesupport_tickets_12mnps_scorelifetime_monthschannelregionproduct_categorycluster_truth
    0413762.869240.431226.331mobileNorthpremiumC
    1409836.6029378.04909.029mobileSouthpremiumA
    2484082.7314246.092509.139mobileNorthstandardC
    3271541.50591.205716.749webSouthstandardB
    4271775.54687.414826.141webSouthstandardB
    \n", - "
    " - ], - "text/plain": [ - " age annual_spend purchase_frequency avg_order_value \\\n", - "0 41 3762.86 9 240.43 \n", - "1 40 9836.60 29 378.04 \n", - "2 48 4082.73 14 246.09 \n", - "3 27 1541.50 5 91.20 \n", - "4 27 1775.54 6 87.41 \n", - "\n", - " days_since_last_purchase support_tickets_12m nps_score lifetime_months \\\n", - "0 12 2 6.3 31 \n", - "1 9 0 9.0 29 \n", - "2 25 0 9.1 39 \n", - "3 57 1 6.7 49 \n", - "4 48 2 6.1 41 \n", - "\n", - " channel region product_category cluster_truth \n", - "0 mobile North premium C \n", - "1 mobile South premium A \n", - "2 mobile North standard C \n", - "3 web South standard B \n", - "4 web South standard B " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# ── Data Input Layer ─────────────────────────────────────────────────────────\n", - "\n", - "@dataclass\n", - "class ColumnMeta:\n", - " name: str\n", - " dtype: Literal[\"numeric\", \"categorical\", \"datetime\", \"text\", \"boolean\"]\n", - " null_rate: float\n", - " n_unique: int\n", - "\n", - "@dataclass\n", - "class DataSchema:\n", - " n_rows: int\n", - " n_cols: int\n", - " columns: list[ColumnMeta] = field(default_factory=list)\n", - "\n", - " @property\n", - " def numeric_cols(self) -> list[str]:\n", - " return [c.name for c in self.columns if c.dtype == \"numeric\"]\n", - "\n", - " @property\n", - " def categorical_cols(self) -> list[str]:\n", - " return [c.name for c in self.columns if c.dtype == \"categorical\"]\n", - "\n", - "\n", - "def infer_schema(df: pd.DataFrame) -> DataSchema:\n", - " cols = []\n", - " for col in df.columns:\n", - " s = df[col]\n", - " nu = s.nunique()\n", - " if pd.api.types.is_bool_dtype(s):\n", - " dtype = \"boolean\"\n", - " elif pd.api.types.is_datetime64_any_dtype(s):\n", - " dtype = \"datetime\"\n", - " elif pd.api.types.is_numeric_dtype(s):\n", - " dtype = \"numeric\"\n", - " elif nu / max(len(s), 1) < 0.05 or nu <= 20:\n", - " dtype = \"categorical\"\n", - " else:\n", - " dtype = \"text\"\n", - " cols.append(ColumnMeta(col, dtype, s.isna().mean(), nu))\n", - " return DataSchema(len(df), len(df.columns), cols)\n", - "\n", - "\n", - "def _generate_synthetic() -> pd.DataFrame:\n", - " \"\"\"3-cluster synthetic customer dataset with realistic feature distributions.\"\"\"\n", - " rng = np.random.default_rng(42)\n", - " N = 2000\n", - "\n", - " def make_cluster(n, age_mu, spend_mu, freq_mu, aov_mu, days_mu, nps_mu,\n", - " mobile_p, premium_p, seed_offset=0):\n", - " return pd.DataFrame({\n", - " \"age\": rng.normal(age_mu, 6, n).clip(18, 75).astype(int),\n", - " \"annual_spend\": rng.normal(spend_mu, spend_mu*0.15, n).clip(100, 20000).round(2),\n", - " \"purchase_frequency\": rng.normal(freq_mu, freq_mu*0.2, n).clip(1, 52).astype(int),\n", - " \"avg_order_value\": rng.normal(aov_mu, aov_mu*0.18, n).clip(10, 1000).round(2),\n", - " \"days_since_last_purchase\": rng.normal(days_mu, days_mu*0.3, n).clip(1, 365).astype(int),\n", - " \"support_tickets_12m\": rng.poisson(0.5 + seed_offset*0.8, n),\n", - " \"nps_score\": rng.normal(nps_mu, 0.8, n).clip(1, 10).round(1),\n", - " \"lifetime_months\": rng.normal(24 + seed_offset*12, 8, n).clip(1, 120).astype(int),\n", - " \"channel\": rng.choice([\"mobile\",\"web\",\"in-store\"], n, p=[mobile_p, 1-mobile_p-0.05, 0.05]),\n", - " \"region\": rng.choice([\"North\",\"South\",\"East\",\"West\"], n),\n", - " \"product_category\": rng.choice([\"premium\",\"standard\",\"budget\"], n,\n", - " p=[premium_p, 1-premium_p-0.1, 0.1]),\n", - " })\n", - "\n", - " df_a = make_cluster(N//3, age_mu=36, spend_mu=9000, freq_mu=26, aov_mu=340,\n", - " days_mu=7, nps_mu=9.0, mobile_p=0.65, premium_p=0.80, seed_offset=0)\n", - " df_b = make_cluster(N//3, age_mu=28, spend_mu=1600, freq_mu=5, aov_mu=80,\n", - " days_mu=70, nps_mu=6.0, mobile_p=0.30, premium_p=0.08, seed_offset=2)\n", - " df_c = make_cluster(N-2*(N//3), age_mu=46, spend_mu=4200, freq_mu=13, aov_mu=190,\n", - " days_mu=28, nps_mu=7.5, mobile_p=0.50, premium_p=0.42, seed_offset=1)\n", - "\n", - " df_a[\"cluster_truth\"] = \"A\"\n", - " df_b[\"cluster_truth\"] = \"B\"\n", - " df_c[\"cluster_truth\"] = \"C\"\n", - "\n", - " df = pd.concat([df_a, df_b, df_c], ignore_index=True)\n", - " return df.sample(frac=1, random_state=42).reset_index(drop=True)\n", - "\n", - "\n", - "def load_data(source: str, path: str) -> pd.DataFrame:\n", - " loaders = {\n", - " \"csv\": lambda p: pd.read_csv(p),\n", - " \"parquet\": lambda p: pd.read_parquet(p),\n", - " \"excel\": lambda p: pd.read_excel(p),\n", - " \"synthetic\": lambda p: _generate_synthetic(),\n", - " }\n", - " if source not in loaders:\n", - " raise ValueError(f\"Unknown source {source!r}. Choose from {list(loaders)}\")\n", - " df = loaders[source](path or None)\n", - " log.info(\"Loaded data: %d rows × %d cols\", *df.shape)\n", - " return df\n", - "\n", - "\n", - "# ── Run Data Input ────────────────────────────────────────────────────────────\n", - "raw_df = load_data(DATA_SOURCE, DATA_PATH)\n", - "schema = infer_schema(raw_df)\n", - "\n", - "print(f\"\\n📊 Dataset Overview\")\n", - "print(f\" Rows : {schema.n_rows:,}\")\n", - "print(f\" Columns : {schema.n_cols}\")\n", - "print(f\" Numeric cols : {schema.numeric_cols}\")\n", - "print(f\" Categorical cols: {schema.categorical_cols}\")\n", - "print()\n", - "raw_df.head()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 5 — Feature Engineering\n", - "Imputation → Encoding → Outlier clipping → Scaling → PCA (optional)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "13:08:03 | INFO | Feature engineering complete: 11 features\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Feature matrix shape : (2000, 11)\n", - " Features : ['age', 'annual_spend', 'purchase_frequency', 'avg_order_value', 'days_since_last_purchase', 'support_tickets_12m', 'nps_score', 'lifetime_months', 'channel', 'region', 'product_category']\n" - ] - }, - { - "data": { - "text/html": [ - "
    \n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
    ageannual_spendpurchase_frequencyavg_order_valuedays_since_last_purchasesupport_tickets_12mnps_scorelifetime_monthschannelregionproduct_category
    count2000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.0002000.000
    mean0.0000.000-0.0000.000-0.000-0.0000.000-0.000-0.000-0.0000.000
    std1.0001.0001.0001.0001.0001.0001.0001.0001.0001.0001.000
    min-1.911-1.185-1.222-1.322-1.088-1.001-2.026-2.121-2.494-1.373-2.062
    25%-0.741-1.005-1.000-1.008-0.913-1.001-0.824-0.768-0.756-0.469-0.534
    50%0.003-0.225-0.115-0.093-0.250-0.2230.024-0.052-0.7560.434-0.534
    75%0.7480.9910.7980.8290.7270.5560.8020.7440.9830.4340.994
    max2.2362.0582.3192.2512.5432.8921.7912.1770.9831.3380.994
    \n", - "
    " - ], - "text/plain": [ - " age annual_spend purchase_frequency avg_order_value \\\n", - "count 2000.000 2000.000 2000.000 2000.000 \n", - "mean 0.000 0.000 -0.000 0.000 \n", - "std 1.000 1.000 1.000 1.000 \n", - "min -1.911 -1.185 -1.222 -1.322 \n", - "25% -0.741 -1.005 -1.000 -1.008 \n", - "50% 0.003 -0.225 -0.115 -0.093 \n", - "75% 0.748 0.991 0.798 0.829 \n", - "max 2.236 2.058 2.319 2.251 \n", - "\n", - " days_since_last_purchase support_tickets_12m nps_score \\\n", - "count 2000.000 2000.000 2000.000 \n", - "mean -0.000 -0.000 0.000 \n", - "std 1.000 1.000 1.000 \n", - "min -1.088 -1.001 -2.026 \n", - "25% -0.913 -1.001 -0.824 \n", - "50% -0.250 -0.223 0.024 \n", - "75% 0.727 0.556 0.802 \n", - "max 2.543 2.892 1.791 \n", - "\n", - " lifetime_months channel region product_category \n", - "count 2000.000 2000.000 2000.000 2000.000 \n", - "mean -0.000 -0.000 -0.000 0.000 \n", - "std 1.000 1.000 1.000 1.000 \n", - "min -2.121 -2.494 -1.373 -2.062 \n", - "25% -0.768 -0.756 -0.469 -0.534 \n", - "50% -0.052 -0.756 0.434 -0.534 \n", - "75% 0.744 0.983 0.434 0.994 \n", - "max 2.177 0.983 1.338 0.994 " - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# ── Feature Engineering ──────────────────────────────────────────────────────\n", - "\n", - "class FeatureEngineer:\n", - " \"\"\"\n", - " Stateless-first feature engineering. Call .fit_transform() once;\n", - " subsequent calls to .transform() reuse fitted state for consistency.\n", - " \"\"\"\n", - "\n", - " def __init__(self, exclude_cols: list[str]):\n", - " self.exclude_cols = exclude_cols\n", - " self._imputer: SimpleImputer | None = None\n", - " self._scaler: StandardScaler | None = None\n", - " self._encoders: dict[str, LabelEncoder] = {}\n", - " self._feature_cols: list[str] = []\n", - " self._fitted = False\n", - "\n", - " def fit_transform(self, df: pd.DataFrame, schema: DataSchema) -> pd.DataFrame:\n", - " df = df.copy()\n", - " # Drop excluded\n", - " df.drop(columns=[c for c in self.exclude_cols if c in df.columns], inplace=True)\n", - "\n", - " num_cols = [c for c in schema.numeric_cols if c in df.columns]\n", - " cat_cols = [c for c in schema.categorical_cols if c in df.columns]\n", - "\n", - " # Encode categoricals\n", - " for col in cat_cols:\n", - " le = LabelEncoder()\n", - " df[col] = le.fit_transform(df[col].astype(str))\n", - " self._encoders[col] = le\n", - "\n", - " self._feature_cols = num_cols + cat_cols\n", - " X = df[self._feature_cols].copy()\n", - "\n", - " # Impute\n", - " self._imputer = SimpleImputer(strategy=\"median\")\n", - " X_arr = self._imputer.fit_transform(X)\n", - " X = pd.DataFrame(X_arr, columns=self._feature_cols)\n", - "\n", - " # Clip outliers (1st–99th percentile)\n", - " for col in num_cols:\n", - " lo, hi = X[col].quantile([0.01, 0.99])\n", - " X[col] = X[col].clip(lo, hi)\n", - "\n", - " # Scale\n", - " self._scaler = StandardScaler()\n", - " X_scaled = self._scaler.fit_transform(X)\n", - " X = pd.DataFrame(X_scaled, columns=self._feature_cols)\n", - "\n", - " self._fitted = True\n", - " log.info(\"Feature engineering complete: %s features\", len(self._feature_cols))\n", - " return X\n", - "\n", - " @property\n", - " def feature_names(self) -> list[str]:\n", - " return list(self._feature_cols)\n", - "\n", - "\n", - "fe = FeatureEngineer(exclude_cols=EXCLUDE_COLS)\n", - "features_df = fe.fit_transform(raw_df, schema)\n", - "X = features_df.values\n", - "\n", - "print(f\"✅ Feature matrix shape : {X.shape}\")\n", - "print(f\" Features : {fe.feature_names}\")\n", - "features_df.describe().round(3)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 6 — Clustering Algorithms\n", - "K-Means (distance-based), DBSCAN (density-based), GMM/EM (probabilistic)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Clustering algorithms defined (K-Means, DBSCAN, GMM).\n" - ] - } - ], - "source": [ - "# ── Clustering Configurator & Runners ────────────────────────────────────────\n", - "\n", - "@dataclass\n", - "class ClusteringConfig:\n", - " k: int = 3\n", - " kmeans_init: str = \"k-means++\"\n", - " kmeans_n_init: int = 10\n", - " kmeans_max_iter: int = 300\n", - " dbscan_eps: float = DBSCAN_EPS\n", - " dbscan_min_samples: int = DBSCAN_MIN_SAMP\n", - " gmm_covariance_type: str = \"full\"\n", - " gmm_n_init: int = 5\n", - " random_state: int = 42\n", - "\n", - "\n", - "@dataclass\n", - "class ClusterRunResult:\n", - " algorithm: str\n", - " labels: np.ndarray\n", - " n_clusters: int\n", - " model: object\n", - "\n", - "\n", - "class ClusteringConfigurator:\n", - " \"\"\"\n", - " Selects the optimal k for K-Means / GMM using elbow + silhouette.\n", - " Reconfigures on failed evaluation by nudging k and eps.\n", - " \"\"\"\n", - "\n", - " def __init__(self, k_range: tuple[int, int]):\n", - " self.k_range = k_range\n", - "\n", - " def configure(self, X: np.ndarray) -> ClusteringConfig:\n", - " best_k, best_score = self.k_range[0], -1.0\n", - " scores = {}\n", - " for k in range(self.k_range[0], self.k_range[1] + 1):\n", - " km = KMeans(n_clusters=k, init=\"k-means++\", n_init=5, random_state=42)\n", - " lbl = km.fit_predict(X)\n", - " if len(set(lbl)) < 2:\n", - " continue\n", - " s = silhouette_score(X, lbl, sample_size=min(1000, len(X)))\n", - " scores[k] = round(s, 4)\n", - " if s > best_score:\n", - " best_score, best_k = s, k\n", - " log.info(\" K search → scores: %s | selected k=%d (sil=%.4f)\", scores, best_k, best_score)\n", - " return ClusteringConfig(k=best_k)\n", - "\n", - " def reconfigure(self, X: np.ndarray, cfg: ClusteringConfig, iteration: int) -> ClusteringConfig:\n", - " \"\"\"Nudge parameters when evaluation fails.\"\"\"\n", - " new_k = min(cfg.k + 1, self.k_range[1])\n", - " new_eps = round(cfg.dbscan_eps * 1.2, 3)\n", - " log.info(\" Reconfiguring: k %d→%d, eps %.3f→%.3f\", cfg.k, new_k, cfg.dbscan_eps, new_eps)\n", - " return ClusteringConfig(k=new_k, dbscan_eps=new_eps)\n", - "\n", - "\n", - "def run_kmeans(X: np.ndarray, cfg: ClusteringConfig) -> ClusterRunResult:\n", - " model = KMeans(\n", - " n_clusters=cfg.k,\n", - " init=cfg.kmeans_init,\n", - " n_init=cfg.kmeans_n_init,\n", - " max_iter=cfg.kmeans_max_iter,\n", - " random_state=cfg.random_state,\n", - " )\n", - " labels = model.fit_predict(X)\n", - " return ClusterRunResult(\"kmeans\", labels, len(set(labels)), model)\n", - "\n", - "\n", - "def run_dbscan(X: np.ndarray, cfg: ClusteringConfig) -> ClusterRunResult:\n", - " model = DBSCAN(eps=cfg.dbscan_eps, min_samples=cfg.dbscan_min_samples)\n", - " labels = model.fit_predict(X)\n", - " n = len(set(labels)) - (1 if -1 in labels else 0)\n", - " return ClusterRunResult(\"dbscan\", labels, max(n, 1), model)\n", - "\n", - "\n", - "def run_gmm(X: np.ndarray, cfg: ClusteringConfig) -> ClusterRunResult:\n", - " model = GaussianMixture(\n", - " n_components=cfg.k,\n", - " covariance_type=cfg.gmm_covariance_type,\n", - " n_init=cfg.gmm_n_init,\n", - " random_state=cfg.random_state,\n", - " )\n", - " labels = model.fit_predict(X)\n", - " return ClusterRunResult(\"gmm\", labels, len(set(labels)), model)\n", - "\n", - "\n", - "print(\"✅ Clustering algorithms defined (K-Means, DBSCAN, GMM).\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 7 — Cluster Evaluator\n", - "Silhouette, Davies-Bouldin, Calinski-Harabasz scoring with pass/fail gate." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Evaluator and configurator ready.\n" - ] - } - ], - "source": [ - "# ── Cluster Evaluator ────────────────────────────────────────────────────────\n", - "\n", - "@dataclass\n", - "class EvaluationResult:\n", - " algorithm: str\n", - " labels: np.ndarray\n", - " n_clusters: int\n", - " silhouette: float\n", - " davies_bouldin: float\n", - " calinski_harabasz: float\n", - " passes: bool\n", - " all_scores: dict = field(default_factory=dict)\n", - "\n", - "\n", - "class ClusterEvaluator:\n", - " \"\"\"\n", - " Evaluates all three algorithm outputs and selects the best one.\n", - " Pass criteria: silhouette ≥ threshold AND davies_bouldin ≤ threshold.\n", - " \"\"\"\n", - "\n", - " def __init__(self, sil_threshold: float, db_threshold: float):\n", - " self.sil_threshold = sil_threshold\n", - " self.db_threshold = db_threshold\n", - "\n", - " def _score_one(self, X: np.ndarray, result: ClusterRunResult) -> dict:\n", - " lbl = result.labels\n", - " valid = lbl[lbl != -1] # exclude DBSCAN noise\n", - " X_v = X[lbl != -1]\n", - "\n", - " if len(set(valid)) < 2 or len(X_v) < 10:\n", - " return {\"silhouette\": -1.0, \"davies_bouldin\": 99.0, \"calinski_harabasz\": 0.0}\n", - "\n", - " sample = min(2000, len(X_v))\n", - " sil = silhouette_score(X_v, valid, sample_size=sample)\n", - " db = davies_bouldin_score(X_v, valid)\n", - " ch = calinski_harabasz_score(X_v, valid)\n", - " return {\"silhouette\": round(sil, 4), \"davies_bouldin\": round(db, 4),\n", - " \"calinski_harabasz\": round(ch, 2)}\n", - "\n", - " def evaluate(\n", - " self,\n", - " X: np.ndarray,\n", - " results: dict[str, ClusterRunResult],\n", - " ) -> EvaluationResult:\n", - " scored = {}\n", - " for name, res in results.items():\n", - " s = self._score_one(X, res)\n", - " s[\"n_clusters\"] = res.n_clusters\n", - " scored[name] = s\n", - " log.info(\n", - " \" [%s] k=%d | sil=%.4f | DB=%.4f | CH=%.1f\",\n", - " name, res.n_clusters, s[\"silhouette\"], s[\"davies_bouldin\"], s[\"calinski_harabasz\"]\n", - " )\n", - "\n", - " # Pick best by silhouette\n", - " best_name = max(scored, key=lambda n: scored[n][\"silhouette\"])\n", - " best_s = scored[best_name]\n", - " best_res = results[best_name]\n", - " passes = (best_s[\"silhouette\"] >= self.sil_threshold and\n", - " best_s[\"davies_bouldin\"] <= self.db_threshold)\n", - "\n", - " return EvaluationResult(\n", - " algorithm = best_name,\n", - " labels = best_res.labels,\n", - " n_clusters = best_res.n_clusters,\n", - " silhouette = best_s[\"silhouette\"],\n", - " davies_bouldin = best_s[\"davies_bouldin\"],\n", - " calinski_harabasz = best_s[\"calinski_harabasz\"],\n", - " passes = passes,\n", - " all_scores = scored,\n", - " )\n", - "\n", - "\n", - "evaluator = ClusterEvaluator(SILHOUETTE_THRESHOLD, DB_THRESHOLD)\n", - "configurator = ClusteringConfigurator(K_RANGE)\n", - "print(\"✅ Evaluator and configurator ready.\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 8 — 🔁 Modeling Loop\n", - "Runs all three algorithms per iteration. Retries with reconfigured parameters if evaluation fails." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\joblib\\externals\\loky\\backend\\context.py\", line 257, in _count_physical_cores\n", - " cpu_info = subprocess.run(\n", - " \"wmic CPU Get NumberOfCores /Format:csv\".split(),\n", - " capture_output=True,\n", - " text=True,\n", - " )\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 554, in run\n", - " with Popen(*popenargs, **kwargs) as process:\n", - " ~~~~~^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1039, in __init__\n", - " self._execute_child(args, executable, preexec_fn, close_fds,\n", - " ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " pass_fds, cwd, env,\n", - " ^^^^^^^^^^^^^^^^^^^\n", - " ...<5 lines>...\n", - " gid, gids, uid, umask,\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " start_new_session, process_group)\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"c:\\Users\\UmairAhmed\\anaconda3\\Lib\\subprocess.py\", line 1554, in _execute_child\n", - " hp, ht, pid, tid = _winapi.CreateProcess(executable, args,\n", - " ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n", - " # no special security\n", - " ^^^^^^^^^^^^^^^^^^^^^\n", - " ...<4 lines>...\n", - " cwd,\n", - " ^^^^\n", - " startupinfo)\n", - " ^^^^^^^^^^^^\n", - "13:09:00 | INFO | K search → scores: {2: np.float64(0.3332), 3: np.float64(0.3), 4: np.float64(0.2545), 5: np.float64(0.1989), 6: np.float64(0.1822)} | selected k=2 (sil=0.3332)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "────────────────────────────────────────────────────────────\n", - " Modeling Loop — Iteration 1/5 | k=2\n", - "────────────────────────────────────────────────────────────\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "13:09:00 | INFO | [kmeans] k=2 | sil=0.3386 | DB=1.1594 | CH=1240.2\n", - "13:09:00 | INFO | [dbscan] k=1 | sil=-1.0000 | DB=99.0000 | CH=0.0\n", - "13:09:01 | INFO | [gmm] k=2 | sil=0.3412 | DB=1.1442 | CH=1232.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " K-Means clusters : 2\n", - " DBSCAN clusters : 1 (excl. noise)\n", - " GMM clusters : 2\n", - "\n", - " Best algorithm : GMM\n", - " Silhouette score : 0.3412 (threshold ≥ 0.25)\n", - " Davies-Bouldin : 1.1442 (threshold ≤ 2.0)\n", - " Calinski-Harabasz: 1232.0\n", - " Evaluation PASS : ✅ YES\n", - "\n", - " 🎯 Accepted on iteration 1.\n", - "\n", - "════════════════════════════════════════════════════════════\n", - " MODELING LOOP COMPLETE in 1.0s\n", - " Algorithm : GMM\n", - " Clusters : 2\n", - " Silhouette: 0.3412\n", - "════════════════════════════════════════════════════════════\n" - ] - } - ], - "source": [ - "# ── Modeling Loop ────────────────────────────────────────────────────────────\n", - "\n", - "def modeling_loop(\n", - " X: np.ndarray,\n", - " configurator: ClusteringConfigurator,\n", - " evaluator: ClusterEvaluator,\n", - " max_iterations: int,\n", - ") -> tuple[EvaluationResult, ClusteringConfig]:\n", - " \"\"\"\n", - " Implements the core retry loop from the architecture diagram.\n", - " Returns the best EvaluationResult and the config that produced it.\n", - " \"\"\"\n", - " config = configurator.configure(X)\n", - " best_eval: EvaluationResult | None = None\n", - "\n", - " for iteration in range(1, max_iterations + 1):\n", - " print(f\"\\n{'─'*60}\")\n", - " print(f\" Modeling Loop — Iteration {iteration}/{max_iterations} | k={config.k}\")\n", - " print(f\"{'─'*60}\")\n", - "\n", - " # Run all three clustering algorithms\n", - " results: dict[str, ClusterRunResult] = {\n", - " \"kmeans\": run_kmeans(X, config),\n", - " \"dbscan\": run_dbscan(X, config),\n", - " \"gmm\": run_gmm(X, config),\n", - " }\n", - "\n", - " print(f\" K-Means clusters : {results['kmeans'].n_clusters}\")\n", - " print(f\" DBSCAN clusters : {results['dbscan'].n_clusters} (excl. noise)\")\n", - " print(f\" GMM clusters : {results['gmm'].n_clusters}\")\n", - "\n", - " # Evaluate\n", - " eval_result = evaluator.evaluate(X, results)\n", - " print(f\"\\n Best algorithm : {eval_result.algorithm.upper()}\")\n", - " print(f\" Silhouette score : {eval_result.silhouette:.4f} (threshold ≥ {SILHOUETTE_THRESHOLD})\")\n", - " print(f\" Davies-Bouldin : {eval_result.davies_bouldin:.4f} (threshold ≤ {DB_THRESHOLD})\")\n", - " print(f\" Calinski-Harabasz: {eval_result.calinski_harabasz:.1f}\")\n", - " print(f\" Evaluation PASS : {'✅ YES' if eval_result.passes else '❌ NO'}\")\n", - "\n", - " if eval_result.passes:\n", - " best_eval = eval_result\n", - " print(f\"\\n 🎯 Accepted on iteration {iteration}.\")\n", - " break\n", - " else:\n", - " print(f\"\\n ↩️ Poor separation. Reconfiguring for next iteration...\")\n", - " config = configurator.reconfigure(X, config, iteration)\n", - "\n", - " if best_eval is None:\n", - " print(\"\\n⚠️ Max iterations reached without passing. Using best found result.\")\n", - " best_eval = eval_result # use last iteration's result\n", - "\n", - " return best_eval, config\n", - "\n", - "\n", - "# ── Execute the loop ──────────────────────────────────────────────────────────\n", - "t0 = time.time()\n", - "best_eval, final_config = modeling_loop(X, configurator, evaluator, MAX_ITERATIONS)\n", - "elapsed = time.time() - t0\n", - "\n", - "print(f\"\\n{'═'*60}\")\n", - "print(f\" MODELING LOOP COMPLETE in {elapsed:.1f}s\")\n", - "print(f\" Algorithm : {best_eval.algorithm.upper()}\")\n", - "print(f\" Clusters : {best_eval.n_clusters}\")\n", - "print(f\" Silhouette: {best_eval.silhouette:.4f}\")\n", - "print(f\"{'═'*60}\")\n", - "\n", - "# Attach cluster labels back to raw data\n", - "labeled_df = raw_df.copy()\n", - "labeled_df[\"cluster_id\"] = best_eval.labels\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 9 — Cluster Visualisation (PCA 2D Projection)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABrgAAAfSCAYAAADUTv42AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAT/gAAE/4BB5Q5hAABAABJREFUeJzs3Xd4VGX2wPHv9EkPNYQUOqGE3pUOq9gpKwsoItZ1V+WHui6riA1U7AqKuyK6ooKCdAGV3pSyQZCShB4SQgjpk0mm3t8fcYYMmUlCOnA+z+PzmPvecqYy9577nqNSFEVBCCGEEEIIIYQQQgghhBBCiKuEurYDEEIIIYQQQgghhBBCCCGEEOJKSIJLCCGEEEIIIYQQQgghhBBCXFUkwSWEEEIIIYQQQgghhBBCCCGuKpLgEkIIIYQQQgghhBBCCCGEEFcVSXAJIYQQQgghhBBCCCGEEEKIq4okuIQQQgghhBBCCCGEEEIIIcRVRRJcQgghhBBCCCGEEEIIIYQQ4qoiCS4hhBBCCCGEEEIIIYQQQghxVZEElxBCCCGEEEIIIYQQQgghhLiqSIJLCCGEEEIIIYQQQgghhBBCXFUkwSWEEEIIIYQQQgghhBBCCCGuKpLgEkIIIYQQQgghhBBCCCGEEFcVSXAJIarMoUOHmDFjBiNGjKBz58507tyZm2++mRkzZpCYmOh1m2nTphETE8OcOXNqONoiJ06cqJXjXu22bdvGs88+y80330yXLl3o3LkzQ4cO5f/+7/9Yv349iqJ43W7OnDnExMQQExNDt27dsFqtZR7r2WefdW9z+fvEtTwmJoZ58+aVua+zZ896bFOVTpw4QadOnfjuu+8qtP3u3buJiYlh6NChHstdsSYnJ7uXTZw4kZiYGJYtW1apmOsaX5/HwsJCUlJSajiaktauXcu4cePo2rUrPXr04J577uHnn3+u0L527NjBAw88QM+ePenatSt33nkn//nPf8r1mXD58ssviYmJYdq0aeVaPz8/n0GDBjFx4kSv49u3b6ddu3b88ssv5Y5BCCGEEKIqbNy4kSeffJJBgwYRGxtLnz59GDlyJG+//bbP34HefhO7zjeK/z7y9Tv7alfab+SaOs91Op2sWLGCRx55hP79+xMbG0vfvn0ZO3Ysc+fOJTMzs0biqG115fxMURSGDh1KTEwMw4YN83le7uLtXLOuKO059fb+rsuPRQhRvSTBJYSoNLvdzqxZsxgzZgzffvstqampREdH07RpU1JSUvj2228ZNWoU//nPf2o7VDeTycT06dN55JFHajuUq0pKSgoTJkzg4YcfZuXKlaSnpxMdHU3r1q0xmUysW7eOKVOm8Je//IWMjIxS92U2m9m1a1ep69hsNrZs2VKu2DZs2FDmOj/99FO59nWlFEXhX//6F5GRkYwZM6ZajnEtK+3zuHXrVm699VZ2795dC5Fd8umnnzJ16lT2799PREQEDRs2ZN++fTz++OPlSq4Wt3jxYh588EF27tyJ0WgkOjqaU6dO8c477zBu3DhMJlOZ+0hNTeW9994r9zEVRWHGjBmcP3/e5zoDBgygb9++PP/88xQUFJR730IIIYQQFWWz2fj73//O3/72N3788Uc0Gg3t27cnODiY48eP8+mnn3LrrbeycuXK2g61TvH1G7kmz3NNJhMTJkzgn//8J9u3b8ff35/27dvj7+/PoUOHmDNnDiNGjCjznE9UnX379rmTnsnJyfz666+1HFHVslqtvP3229x11121HYoQog6RBJcQolIUReGvf/0rX375JeHh4cyePZu4uDjWrFnD+vXr+eWXX3jkkUdwOBy88847LFy4sLZDBuDw4cMsWbKkzDuaxCWpqamMGzeO//3vf7Rq1Yp58+axe/duVq9ezbJly/jll1/4z3/+Q/PmzTlw4AAPPPAAdrvd6760Wi1QdlJq9+7d5OTklBmbVqvl0KFDpV68Byo826Ysy5Yt48CBAzzxxBNoNJoK7aNz586sXbuWL774omqDuwqU9nmcP39+rc/eOnjwIO+++y7+/v4sXLiQH374gR9//JF58+ah1+v54IMPOHToULn2dezYMWbOnIlKpWLmzJns2LGDVatWsWHDBjp16sThw4d5++23y9zPyy+/jNlsLtcx7XY7L7zwAmvWrClz3f/7v/8jJSWF+fPnl2vfQgghhBCV8e6777Jhwwbat2/P2rVr2bRpE0uWLOHnn39m586dTJw4kcLCQp577jkOHjzose3s2bNZu3Ytf/rTn2op+trj6zdyTZ7nPvfcc+zfv58bbriBTZs28dNPP7FkyRI2bdrE5s2bufXWW8nJyeHxxx+v9d/z14tVq1YBcOONNwLw/fff12Y4leLt833hwgU+/fRTbDZbLUYmhKhrJMElhKiU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YPv27SxfvpwTJ06Qnp7O1KlTWbZsGYC7yoSvnlBGo5GYmBj335V9LbydM7mej++//96d7PLlzJkz5e7jW3zGU3GtW7cG4NSpU+5lUVFRdOvWjf3797Np0yb3bK0ffvgBuDTDqyyrV69GURSPkoQukZGRdOnShQMHDrB06VKGDx9e6r5cz0tpbSjatWvHuXPn3H9X9lyz+GzCquDt9XZ9xn2d03l7fV2JSm+l6l3nZOWpEiSEqH6S4BJCVFh0dDQ7d+50/wgqy8WLF3E4HOX+cXgloqKiWL58OR999BE//fQTubm5bNiwgQ0bNvDyyy9z11138eKLL7pLifniuih+7tw5jx9t3hTv7ePibf8hISEsXbqUefPm8cMPP3Dx4kV27NjBjh07eO211xg2bBgzZ84stcfP0qVLr6hu9pXyVrvaJSoqCoPBgMVi4eTJk17L6r355psllg0dOrTM2R8qlYphw4bx9ddfs3HjRu655x6OHTvGqVOnGDt27BU3bB42bBgvvvgimzZtwul0olar+emnn1CpVO7ZYlXJ9R7wVWLygw8+4KuvvuK7777jxIkT/P777/z+++989NFHtGvXjtdff73UE7WylPV+dnHdWebtbk0XVyLHVRe+Ii6/87C869bUcQ4dOlTuGUmu19ZVIiM3N9fnuuXp01Ueer2ee+65h1deecX9uBYuXMjBgwe55557yt2Priq43tPevueEEEIIIapb8+bNad68Offeey+LFy/mxRdfJD09nS1btlxRlYfiyvvbGWr+93NFzz/r2nFUKhXt2rWjXbt2PPjgg3zwwQd88sknHD58mMOHD9OxY0dycnIA3+dQl6vsa+HtdS9+M1xZCcoreT683QwKl2K/vKT5nXfeyf79+1m7di133nknDoeD9evXo1ary13lZfXq1UDRYymeGLzc9u3bSU9PLzWh5JrhVNprc/nrUB2vT2VUZH+lPd6KVOkQQtQsSXAJISpswIABLFq0iD179qAoSpn/8H/99dd8/PHHDBo0iP/85z9l7t/X3TAFBQVelzdt2pRZs2bx0ksv8dtvv7Fr1y42b97M0aNH+f777zEYDLz44oulHtN1x9HLL7/snkZfFerVq8dzzz3HtGnTOHToELt27WLr1q3s37+fDRs2YLPZSn1OUlNTy7yQX110Oh19+vRh27Zt/Pzzz17LelTGn/70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RbZt28bevXv59V//9bJjh4aG+OxnP8u+fftKrtnd3b2wX0AhRIkzZ87w8Y9/nL1797Jz504+9alPMTw8XPHYsbEx/vW//tfs3LmTXbt28fGPf5zz58+XHfflL3+ZRx55hO3bt7Nz504ef/xxnn322bLjRkdH+Y//8T/y4IMPsnXrVt761rfypS99iWw2W3LcgQMH+NVf/VXuueceNm3axN69e/nlX/5ljhw5UnLc448/zoMPPkhfXx9PPvkke/bsYdu2bXz4wx/m8OHDr/+LJIRYcJ2dnXzyk5/knnvuYfv27fzyL/8y58+f5+GHH+bxxx8HCvP/Nm7cyNjYGL/xG7/B3r172bFjBx/72Mfo6+sjnU7zH//jf+See+5h165dfPSjHy15T5qaJ/inf/qnfP/73+e9730vW7Zs4aGHHuL//J//A8CLL77IY489xtatW9m3bx9/9md/huu6i/I1WWqkRaG44Q4dOsTXvvY1Pv3pT8vNFbGg1q9fz/r16yvum/olec2aNTdzSeI2Z9s2nZ2d7Nixo+L+ZcuWcejQIfL5PKZp3uTViaXA5/Pxz/7ZP6u476WXXiKVSrF9+/abuyixJFmWxec+9zk2bNjAP/2n/1TaXgohrsn58+f55V/+ZQzD4C//8i9ZtWoVAMlkkve///20trbyT/7JP2H//v08/fTTxONxuru78fl8PProoxw/fpwf/OAHjI2N8dWvfrV43b/7u7/j3/7bf0tdXR3vfOc78fv9PPvss/zKr/wKn/vc5/jwhz9cPPaLX/wif/mXf8mmTZt45JFHcF2Xl156iaeeeoojR47w3e9+F1Wd/szu8ePH+X//7/+xe/duPvjBD3Lo0CGefvppzp07x7e+9S0Astksv/RLv1S8sfW2t72Ny5cv861vfYvnn3+eZ555hnA4fHO+yELcQU6cOMEv/uIvks/nefOb30wsFuO5555j//79FY//1Kc+hWEYvO9976O3t5cf/vCH7N+/n7/9278tvh/9/9m793Ar6zr//68NgQIqhgcUBUsbSSQ8MWgiKIiiJkgUGll5Gv16xFNjX7Vp0vyOMopHxmNqnpt0LEwFCsJTmAY4OpqAUXlMUskDKiBufn9w7T1uwQNK8XvX43FdXlf7Xvd9r89esddeez3X/flceumlOe+887LlllvmK1/5ShYtWpTx48fnqKOOygUXXJA99tgjydKove++++a5555L3759M3jw4DzyyCO56KKL8uijj+biiy9Oq1atMmnSpBxzzDFZd911M3jw4LRr1y4zZ87MPffckwceeCB33HFHunbt2jzG119/Pfvvv386dOiQL37xi5k7d24mTJiQAw88MD//+c9bzDIDrBp/+MMfMnLkyLz88svZbbfdstFGG2XKlCn56le/msbGxmywwQbN+y5ZsqT5dcjw4cPz2GOP5a677spRRx2VDh065E9/+lP23nvvPPvss5k0aVIOP/zw3HHHHS3eG5o4cWJ+97vfZc8990zv3r0zbty4nHbaafnDH/6QG2+8MYMGDcp2222X22+/PWPGjEmnTp3y5S9/+a/+uPytEbj4i1q0aFG+/e1vZ8stt2yu4vCXNn369Pz0pz/Nuuuum4EDB67q4VDI/PnzkyRrrbXWcm9fc801s2TJksyfPz+dOnX6aw6Nv3ELFy7MWWedlSTZb7/9VvFo+Ftw2WWXZc6cObnlllvSunXrVT0coJDnnnsuBx98cBYvXpwf/OAHLT5QNm/evOyxxx45//zz09DQkIULF2aXXXbJ3XffnZ122imXX355WrdunSVLlmTEiBH59a9/nblz56Zz5855/vnnc/rpp2fzzTfPddddl44dOyZJjjvuuHzta1/L6NGjM2DAgHTt2jVz587NNddckx122CFXX311c8hqbGzM/vvvnxkzZuQ3v/lNevbs2Ty22bNn5+STT27+IEljY2O+/vWvZ9q0aXnkkUfSq1evTJ06NbNmzcpRRx2VUaNGNR/btA7mpEmTMmzYsL/8gwx/Z84444wsWLAgV155ZT7/+c8nSUaNGpUDDjggL7zwwjL7d+jQITfffHPz32V33nlnjj/++Jx99tm59NJLkyRXX311unXrlh/96Ef5xCeWvr154IEHZvDgwbnpppuaA9fZZ5+d5557LqeffnqL19knnnhibr/99vzqV7/KjjvumHPOOSdrr712xo0b1+JvvXPPPTeXXXZZfv7znzcvhZAkL7/8crbffvuce+65zfd/3nnn5dJLL824ceNy6KGHrsyHEPgI/u3f/i3z5s3Lf/zHf2TQoEFJkuOPPz4HHnhgpk+f3mLfxsbGdOjQIddee23atm2bJUuWZNiwYXnsscey+eabZ9y4cc2zRY0aNSoTJ07Mo48+2uID0jNnzsyll16aAQMGJEn69OmTY445Jtdcc03OPvvsDB06NMnSgLb33nvnzjvvFLhWAlMUssL69++f7t27v+9/F110UZLk4osvzpNPPpkzzjjDmyt8aCvyb+zd5syZk6OPPjqNjY057bTT0q5du7/y6KmsaWq497o6q02bNkmWxntYWRYvXpwTTjghM2fOzKBBg7L77ruv6iFR3Jw5c3LppZfmwAMPTI8ePVb1cIBC5s2bl4MOOiivvvpqrrjiinzuc59bZp9vfOMbaWhoSLL0yuQtt9wySXLAAQc0/83X0NCQXr16JVkazJLktttuy6JFizJq1KjmuJUk7du3z5FHHpnFixfntttuS7L0tdjo0aNz8sknt7hKq1WrVvnHf/zH5rG+U/v27bP//vu32Ldv375Jlk5PlCz9dHay9GqSd05NdtBBB+Wee+7JPvvss2IPGPCB5s6dm+nTp6d///7NcStJ1l577Rx77LHLPeaII45o8aHDvfbaK1tttVXuueeevPbaa0mW/jzPmzcvv//975v369q1ayZOnJgrrrgiydK/237+85/nH/7hH5b5ENnRRx+dI444Ih07dkxjY2NOPPHEjB49epkPMjatY/ru55xk6XNHU9xKkn79+iVJnn766Q9+YIC/qHnz5uXee+/N9ttv3xy3kqWvMb75zW8u95ivfvWrze8HNTQ0ZOutt27e3hS3kmSrrbZK8r+vcZpssskmzXErSXP8Wm+99ZrjVrJ0tqn27dvn2Wef/RjfIU1cwcUK23PPPfPKK6+87z5bbLFFZs2ale9///s5+OCD33MaOVieD/tv7N1mzpyZQw45JPPmzcvxxx/f4hcYfBirrbZakqVTey1P03bhlJVl4cKFOf744zN58uRsueWWGT169KoeEsU1Njbm1FNPzQYbbJBjjjlmVQ8HKOab3/xmXnjhhXTr1q05XL3bJpts0uLr9u3bJ1k6lfM7Nb2uavpg0KOPPpok+eUvf5nHH3+8xb5Nr/1nzpyZJPnkJz+ZoUOHprGxMbNmzcqcOXPy1FNP5fHHH8/999+fJMusW7Hxxhs3fxipyZprrpnkf1/D7bjjjunatWumTJmSvn37pm/fvtl5552zyy67pHPnzu/72AAfTdPPe1P0fqf3mhp+eVN29+rVKw8//HBmz56d7bbbLvvtt18uv/zyDB06NFtttVX69euXAQMGtPhwz1NPPZU33nhjuff96U9/Oscdd1zz17vttluSpWvpzJ49O0899VRmz57dPI3i22+/vcw5PvWpT7X4+t3POcCq89hjj6WxsbE5Rr3TVltt1SJON/mor3GadOvWrcXXTe8dLW/JnrZt23quWEkELlbYySef/IH7vP3229lvv/2y4YYb5qijjvorjIq/JR/m39i73X///Tn66KMzf/78jBo1KocffvhfYGT8rVtjjTXSqlWr5k8FvlvTdmszsDK8+uqrOeKIIzJt2rT07NkzV155pX9bfGw33HBDHnrooVx11VViPLDCXn755fTv3z/33HNPLrnkkhZv/jZ5r+eWD1qftOl1VNNi68vz6quvNv/vCRMmZMyYMc1XX3Xo0CG9evXKP/zDP2TatGnNV2M1eXfcStJ8pVnTvu3atct//ud/5pJLLsmECRMyceLETJw4Ma1bt86ee+6Z0047ze9iWMmafvY7dOiwzG0dO3Zs/jl9p3XWWWeZbU3HN826ccIJJ6Rbt2754Q9/mP/+7//OQw89lAsvvDCf+cxn8r3vfS/bbrttczz/MD/XM2fOzBlnnJFf//rXSZY+p2y++ebp2bNnnnnmmeUe8+7nvXc/5wCrzp///Ocky38+ad269XKXnfior3GaNAWxj3o8H43AxV/EH//4x/zP//xPkiy3lD/22GPp3r17+vTpk+uuu+6vPTz+xvzsZz/LiSeemLfeemuZxalhRbRt2zZdunR5zz9gnnnmmWyyySamXOVje+GFF3LwwQdn9uzZ2X777XPxxRd7Q42V4mc/+1mStFgj4p2GDBmSJJk8efIyn0QEOOOMMzJ48OB84QtfyPe///0MGTIkm2222Uo5d9ObPlOmTEmXLl3ed9+HH344xx9/fDbccMOMGTMmW221VTbeeOM0NDRkzJgxmTZt2kcexzrrrJNvf/vbOfXUU/P444/nvvvuy3/913/l9ttvT4cOHXL66ad/5HMDy2qaanB5HyJ88803lxuDXnvttWVeG//pT39qcb6GhoaMGDEiI0aMyAsvvJCpU6dm4sSJmTx5co444ohMmTKlOYq9/vrryx3bG2+8kfbt22f+/Pk55JBDMn/+/HzrW9/KjjvumM022yxt2rTJvffemwkTJnz0BwBYJZqeQ5rWWn+393peoB6Bi7+ItdZaK0cfffRybxs7dmzWW2+97Lfffsu9RBNWxNSpU3PCCSeksbExo0ePNm8+H9t2222XcePG5emnn07Xrl2btz/11FOZO3euf2N8bE1/QM+ePTu77rprzj//fJ/oYqX54he/2LxWxDtNmjQpM2fOzMiRI7POOuu0WNcCoEmPHj3Srl27nHLKKTnqqKPyne98J9dff/1yr7BYUd27d8+kSZPy6KOPLhO4Zs2alZ/85Cfp27dvdtppp9x+++3Na+o2rWnTZM6cOUk+2hUS06ZNy8SJE/P1r3893bp1S48ePdKjR4+MHDkyn//85z9WOAOWr0ePHmloaMiMGTOWue2RRx5Z7jGPPfZYNtxww+avlyxZkocffrj5qqpXXnkl1157bbp27Zphw4ZlvfXWyz777JN99tknxx13XMaPH5/f/va36d69e9q0abPc+5kzZ0722muvHHzwwdluu+3y4osv5rDDDlvmQ0If5zkHWHW23HLLNDQ05OGHH17mtt/+9rcC198QgYu/iLXWWus9130YO3Zs1l9/fetC8LG9/PLL+eY3v5m33nor//7v/y48sFIMGzYs48aNy7nnnptzzz03DQ0NWbJkSc4777wkyb777ruKR0h1Z555ZmbNmpV+/frlwgsvXO7c3/BRDR8+fLnbn3322cycOTNf/epXs/nmm/+VRwVUM2jQoOyyyy656667csstt2TEiBEf+5xDhw7NpZdemnPPPTfbbbdd85RBixYtyve+9738+te/bl7MvWkh95deeqnFOSZNmpQpU6YkSRYvXrzCY3jppZdy7bXXprGxMf/yL//SvP1Pf/pT3nrrrRZvqAMrx3rrrZd+/frl3nvvzcSJEzN48OAkS6+euPDCC5d7zOWXX55+/fo1r3Nz4403Zs6cOdlnn32y+uqrp3Xr1rnuuuvSvn37DBw4sPmDO42NjXn++efTqlWrdO7cOauttlp222233Hnnnbn11ltbvE66/PLLkyR9+/Ztjlcvvvhii3H8/ve/zxVXXJHkoz3nAKtO586d07dv39x33325++67s/POOydZ+rrj7LPPXsWjY2XyjgpQ1vXXX5+XXnop66+/fp566qlcdNFFy+yzzTbbZKeddloFo6OqHXfcMXvttVfuvPPO/PGPf0zv3r0zbdq0PPTQQxk+fHh69+69qodIYU8//XRuvfXWJEnXrl1zySWXLLPP6quvnkMPPfSvPTQAaOHb3/527r///pxzzjnZddddP/b5PvWpT+Wf//mfc9ZZZ+ULX/hCBg4cmDXXXDNTpkzJk08+mcGDB2e33XZLkuy11165+uqr853vfCcPPPBA1llnnfzmN7/J1KlT06lTp7z00kt5+eWXV3gMAwYMyDbbbJPrr78+s2bNylZbbZXXXnst48ePT5s2bXLEEUd87O8TWNZ3vvOdfOUrX8mxxx6bQYMGZYMNNsjdd9/9nvu//PLLGTZsWAYMGJDf/e53mTJlSjbaaKOcdNJJSZaujzVq1Kh873vfyxe+8IXstttuWW211fKrX/0qv/nNbzJy5Mh07tw5SfJ//+//zfTp03PyySdnwoQJ2WyzzfLQQw/loYceytChQ7PTTjvljTfeyEYbbZRbb7018+bNy+abb55nn302kydPbp7msGk9H6COU089Nfvtt1+OOOKIDBo0KJ07d859993X/PPcqlWrVTxCVgaBCyiraQqRP/3pTxk7duxy9zn44IMFLlbY6NGjs9lmm+XHP/5xrrnmmnTp0iUnnnhiDjrooFU9NIqbMWNGGhsbkyz9JOryrL322gIXAKtc165dc9hhh+Wiiy7KmWeeuVLOedBBB+XTn/50rrrqqkyYMCFLlixJt27dcuqpp2bkyJHNbzRtscUWueyyy3LRRRdl4sSJadOmTTbeeOOcdNJJGThwYAYPHpz77rtvha+sb9u2bS677LJcccUVmTRpUq6//vqsttpq2W677XLkkUemV69eK+X7BFrq2rVr/vM//zPnn39+fvnLX2bBggXZfvvtc+qpp2bQoEHL7H/ZZZdlzJgxuemmm9K2bdsMGzYsJ554YtZdd93mfb72ta+lU6dOufbaa3PHHXdkwYIF+fSnP51/+Zd/yciRI5v369y5c26++eaMHTs2U6ZMydSpU7PBBhtk1KhROeyww5IsXSPwqquuytlnn50ZM2bkwQcfTJcuXTJixIgceeSR+dKXvpT7778/b7/9tvWYoZBNN900N910U8aMGZOpU6dm8eLF2WGHHXL++edn6NChadeu3aoeIitBwxKTyAIAAAAAAH8DGhsb8/TTT6dLly5p06ZNi9uefvrpDBo0KCNHjsx3v/vdVTNAVhrX4QEAAAAAAH8TGhoaMmzYsAwZMiSLFi1qcduVV16ZJNl+++1XxdBYyUxRCAAAAAAA/E1oaGjIV77ylVx11VUZOnRo+vfvn9atW2fGjBn57//+7+y0007ZY489VvUwWQlMUQgAAAAAAPzNaGxszH/913/l5ptvzu9///ssXrw4G2+8cYYMGZKDDjpomakLqUngAgAAAAAAoBRrcAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAC1cdNFF6d69+zL/bbnlltlhhx1y4IEHZtKkSe95/PPPP58LL7ww++yzT3r37p1evXplyJAhueCCC/Laa6994P1ff/316d69e15//fUVHvsFF1yQL3/5y1myZEnztt13332530/37t0zderUFsfPmzcv//qv/5pddtklW221VYYPH57x48d/6PtfvHhxLrvssgwePDif+9znsuuuu2bMmDHL/b4nT56c3XffPdtss02+8Y1vZM6cOcvsM2/evGy77bb5yU9+8uEfhL+ysWPHZsSIEWlsbFzVQwEAAADg70jDkne+CwjA372LLrooY8eOza677potttiiefvixYvzwgsv5M4778ybb76Z7373uxk5cmSLYydMmJBTTjklr7/+evr06ZPu3btnyZIlmTZtWmbOnJmNN944N954Yzp37rzc+542bVoOOeSQLFiwIDNmzEiHDh0+9Lh/+9vfZtiwYfnBD36Q3r17J0nefPPNbLvtttliiy0yYMCAZY4ZNmxYunbtmiSZP39+Ro4cmd/+9rfZa6+9sv7662fChAl57rnncsYZZ2TEiBHve/+NjY058sgjM2XKlGy00UYZMGBAXnrppfzsZz/LZpttlmuuuSadOnVKksydOzeDBg1Kt27d0q9fv0ycODFJMn78+Ky++urN5xw9enTuuuuu3H777WnduvWHfiz+mt54443svvvuOfTQQ3PAAQes6uEAAAAA8HfiE6t6AAD8/9OgQYMyfPjwZbaPGDEiI0eOzDnnnJNhw4alXbt2SZJf/epXOe6447LOOuvkBz/4QXr16tV8zJIlS3LFFVdkzJgxOeSQQzJu3Lhlgs0dd9yRU089NQsWLPhI4z3ttNOy/fbbN8etJHniiSfS2NiYPffcM4ceeuj7Hv+DH/wgs2fPbhGzDj/88IwYMSKjR4/OHnvskTXXXPM9j//JT36SKVOmZJtttsn3v//9rLHGGkmSu+++O4cddljOOeec/Nu//VuS5Kc//WkWL16cq666Kp07d86ee+6ZfffdN/fcc0923333JEsj2I033pgzzzzz/7dxK0nat2+ff/qnf8r555+fL3zhC1l33XVX9ZAAAAAA+DtgikIAVsg222yTbbfdNvPnz8/06dOTJG+//XZOPvnkLFmyJBdffHGLuJUkDQ0NOeywwzJgwIA88cQTmTBhQvNt8+bNy9FHH50TTjghnTp1yiabbLLCY3r44Yfz4IMPZv/992+xfdasWUmSzTff/APPcfPNN6dz58750pe+1LytY8eOOfTQQ/Paa6/lZz/72fsef8cddyRJTjnllOa4lSQ777xz+vbtm5/85CeZN29ekuSZZ55Jp06dmq9k++xnP5skefrpp5uPu+SSS9KtW7fsueeeHzj2Ve3LX/5yGhsbc8MNN6zqoQAAAADwd0LgAmCFrb/++kmSl19+OUly//3357nnnkvfvn2z1VZbvedxRx99dL7zne+0CGBPPPFEJk2alOHDh+fHP/7xe05f+H6uvvrqdOzYMf3792+x/cMGrueffz7PP/98evfunVatWv5q7NOnT5Kl0ye+n2eeeSZt2rTJlltuucxt3bt3z9tvv52HH344ydJw9uabbzavFda0RlfTFWLPPPNMbrnllowaNSoNDQ3ve7/v9Oijj6Z79+456aSTlrltyZIl2WWXXdK/f//m9bJeeumlnHXWWdljjz3Sq1evbL311hk6dGiuvvrqFuuY3XrrrenevXvuvPPOHHDAAenZs2cGDhyYuXPnJknWWGONDBgwIDfddNNHvgIPAAAAAFaEKQoBWGFPPfVUkjTHqPvuuy9JsuOOO77vcT179kzPnj1bbOvWrVvGjRuX7t27f6SxLFiwIJMnT86AAQPyiU+0/LU2a9astGvXLhMnTswtt9ySp556Kuutt16GDh2aI444Im3btk2S/P73v0+S5vW43qlLly5paGho3ue9tG3bNo2NjXn77beXmVKwKWA988wzSZJevXrl9ddfz/XXX5/hw4fnyiuvTENDQ7beeuskydixY7P55ptnt912W6HHomfPntl0000zefLkLFq0qPn7S5Lp06fnj3/8Yw4++OC0atUqr732Wvbdd9/MnTs3AwcOzG677ZYXX3wxEydOzFlnnZWFCxfm8MMPb3H+M844IxtssEG+/vWvZ+7cuS1iZN++fTN+/PhMnTo1AwcOXKFxAwAAAMCKcgUXACvkF7/4RR577LGst956zVdrPf/880mST33qUyt8vg033PAjx60keeihh7Jo0aLlXjk1e/bsvPnmm7n88svTu3fvjBgxIp/4xCdy8cUX57DDDsvixYuT/G+AWmuttZY5R5s2bdKuXbvMnz//fcfRs2fPvP3225k0aVKL7QsWLMgvf/nLJGk+x6677poBAwbkjDPOyLbbbpurrroqBx98cDbffPPMmTMnt912W4499tjmczRdcfVhDBkyJPPnz88999zTYvudd96ZJBk6dGiS5KabbsozzzyT008/PRdeeGFOPPHEnHnmmbnlllvS0NDQPOXiO6222mq58cYb861vfSvnnntui9s+97nPJUkeeOCBDz1WAAAAAPioXMEFwHJNmjQpzz77bPPXixYtyhNPPJF77703rVu3zr/+6782XyHUFIjat2//Vx/nY489liT5zGc+02L7/Pnz06VLl2y22Wa5+OKLs/baaydJFi5cmGOPPTZTpkzJD3/4w3zta1/LG2+8kSQtrnh6pzZt2mThwoXvO45vfOMbue222/Ld7343jY2N2XnnnfPCCy/k3//935uncnzntH+XXHJJfvGLX+TJJ59Mr1690rt37yTJhRdemM997nPZeeedM2fOnJx00kl57LHH0q1bt3z3u9/9wKvkhgwZkgsuuCDjx4/PoEGDkiwNZBMnTsxnPvOZbLHFFkmSnXbaKR07dmwOXk023XTTrLvuus3rhb1T//79s/rqqy/3fjfddNO0atWq+f8PAAAAAPhLErgAWK7Jkydn8uTJzV+3adMm66yzTgYNGpQDDjgg2267bfNtTfHolVde+WsPMy+99FKS5JOf/GSL7WussUZ+/OMfL7P/aqutllNPPTVTpkzJnXfema997WtZbbXVkiRvvfXWcu/jrbfeSrt27d53HFtssUVGjx6dU089NSeeeGLz9p49e+aEE07IGWec0eIcDQ0N2XXXXVuc4/HHH8/EiRNz1VVXJUlOOumkNDY25vLLL8+4ceNyzDHHZPLkyc2P9/J07do122yzTX7xi19k4cKFWW211fLAAw/kxRdfzNe//vXm/Xr06JEePXpk/vz5efzxx/OHP/whv/vd7/I///M/eemll9KxY8dlzr3xxhu/5/22bds2a6yxxnLDGAAAAACsbAIXAMt15plnZvjw4R9q36bw0bQ213t5++238/TTT3+kqQzfS9O0fx8UoN6pa9eu6dixY/OaWE0xp+lKtHd66623smDBgqy55pofeN699947ffr0yZQpU/LKK6+ke/fu6devX2666aYkyTrrrPO+x59//vnp3bt3dtxxx8ycOTOPPvpoLr300vTv3z9bb711xo8fn5/+9KctQtXyDBkyJA899FDuvvvu7L777rnjjjvS0NCQvffeu3mfhQsX5uyzz86PfvSj5qvTunTpkj59+mT27NktrjZr8kGPcbt27fLqq6++7z4AAAAAsDJYgwuAj61fv35J0rzW1Hv51a9+lcGDB+eoo45aaff9XnHqz3/+c6ZNm9Ycsd5pyZIlzVc3Jf+7dtjy9n3uuefS2NiYT3/60x9qPOuvv37222+/HHbYYdl5553TqlWrPProo0mWnUbxnR566KHcddddzWtv/eEPf0iSdOvWLcnS9cE++clPfmBETJI999wzbdq0yfjx47N48eL8/Oc/zzbbbNPiCqyzzjor1113XQYMGJBrrrkmDz74YKZMmZLRo0e/51SNH+S1115rfkwBAAAA4C9J4ALgY9tmm23yqU99Kg888ECmT5/+nvtdd911SfKB60itiHXXXTfJ0qD1Tvfff3/233//XHzxxcsc8+ijj2bBggXp2bNnkqVXLnXp0iXTp09f5sqlBx98MEmy9dZbv+84rrnmmvTp0ye/+c1vWmxftGhR7rrrrqy33nr57Gc/+57Hn3feeenbt2/+8R//McnSdbOSpVe9vfNcrVp98K/uTp06pW/fvrn33nvzy1/+Mi+//HKGDBnSYp+f/vSnWW+99XLBBRdkhx12aA6Ff/7zn5unfVwRCxcuzBtvvJENN9xwhY8FAAAAgBUlcAHwsbVu3TqnnHJKkuTYY4/NI4880uL2xYsX59xzz82UKVOy6aab5stf/vJKu+/u3bsnSZ544okW23faaad06NAht99+e2bNmtW8ff78+fl//+//JUn233//5u1Dhw7Ns88+2zydYJK8+uqr+f73v5+11lore+yxxweO45VXXsmNN97YvG3JkiU5/fTTM2/evBxyyCHvGafuv//+PPDAAxk1alTztqYrxpoeyyeffDKvvvpqNtlkk/cdxzu/n9deey3nnntu2rRps8z4V1999SxcuLDFlW+LFi3K6aefnsbGxvdcj+y9zJ49O0neN+IBAAAAwMpiDS4AVoqdd945p512Wk477bTsu+++2X777bPFFltk/vz5efDBB/Pkk09mo402yqWXXrpSp7Hbbrvt0qFDhzz00EMttq+11lr59re/nVNOOSX77bdf9tprr6y++uq566678uyzz+b//J//k969ezfvf+ihh2bChAk5/fTT88ADD6RLly6ZOHFinn322Zx11llZY401mvd94IEH8uCDD6ZPnz7ZfvvtkyQ77LBDBg4cmJtvvjl//OMf89nPfjYzZszIjBkz0r9//xYx7d3OO++87LLLLi2uEttiiy3So0ePnHXWWZk1a1buvffedOzYcZkrsd7LwIED0759+8ycOTMDBgxIp06dWtw+dOjQXHnllfnSl76UXXfdNW+99VbzY7P22mvn1VdfzaJFiz70dIVNj//nP//5D7U/AAAAAHwcruACYKX5yle+knHjxmXffffNiy++mB/96Ee57bbbsvrqq+eYY47Jbbfd9qGvQPqw2rZtm379+mXGjBl54403Wtw2fPjwXHXVVenVq1fGjx+fW2+9Neuss07OOeecnHDCCS32XWONNXLDDTfki1/8Yh544IH88Ic/TKdOnTJ27Nh88YtfbLHvgw8+mLFjxzZPX9jkvPPOy+GHH56nn346N9xwQ1599dX88z//c/7jP/7jPUPRL37xizz88MMtrt5qctFFF6VHjx656aab0qZNm1x88cVZc801P9Tj0q5du+y2225Jkr333nuZ24877rgcc8wxSZIbbrghkydPzmabbZZrr702+++/fxobGz9wTbV3mjp1ajp27Ni8HhsAAAAA/CU1LHn3YiMAUMz06dPz1a9+NWedddYyMYq/vBdffDE777xzDj300Bx33HGrejgAAAAA/B1wBRcA5W233Xbp06dPfvSjH63qofxduvXWW9OmTZt84xvfWNVDAQAAAODvhMAFwN+Eb33rW3nkkUdWaFo9Pr758+fn6quvzpFHHrnMOl8AAAAA8JcicAHwN6Fnz575p3/6p4wZMyZm3/3rufrqq7PhhhvmkEMOWdVDAQAAAODviDW4AAAAAAAAKMUVXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAAAKUIXAAAAAAAAJQicAEAAAAAAFCKwAUAAAAAAEApAhcAAAAAAAClCFwAAAAAAACUInABAAAAAABQisAFAAAAAABAKQIXAAAAAAAApQhcAAAAAAAAlCJwAQAAAAAAUIrABQAAAAAAQCkCFwAAAAAA8P+1d8euXtV9AMc/Ny+RJklBtykbHDLcJChMGlyChlpbDNJJ0KGtlhqa/Ata6tbaEBhhoxCh1B/g3YrgIqJFEGKkDbfh4cYjFo8+3evvvuH1grN8z+d7fmd//845kCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAAAkCJwAQAAAAA7zocffjjHjh275/lffvll3n333Tly5MgcPnx4Tp06Nevr69s+B8BiLG1sbGws+iYAAAAAADZ98803c+rUqVlZWZkLFy78z/nbt2/PG2+8MT/++OO89dZbs3fv3lldXZ2lpaX54osv5vHHH9+WOQAWZ3nRNwAAAAAAsOmzzz6bDz74YP7444973nPu3Lm5fPnyrK6uzksvvTQzMy+//PK89tpr8+mnn87bb7+9LXMALI5XFAIAAAAAO8KJEyfmvffemxdeeGEOHTp0z/vOnz8/+/fv/ytGzcwcOHBgXnzxxTl//vy2zQGwOAIXAAAAALAjXLlyZd5///356KOP5tFHH73nfZcvX/7bIHbo0KFZX1+fX3/9dVvmAFgcrygEAAAAAHaEL7/8ch5++OH72nPz5s25cePGPPXUU3ede/LJJ2dm5urVq7O8vLylc/v27buv+wRga3mCCwAAAADYEe43bs38J3DNzDzyyCN3ndtc++2337Z8DoDFErgAAAAAgKyNjY2ZmVlaWvrHmYceemjL5wBYLK8oBAAAAAAemN9//31u3Lhxx9qePXvu65tb/21z361bt/72tzZntnoOgMXyVwMAAAAA4IH56quv5ujRo3ccq6ur//f19u7dO4899thcv379rnObaysrK1s+B8BieYILAAAAAHhgjh49Op988skda08//fS/uuZzzz03a2trd62vra3NM888M/v27duWOQAWxxNcAAAAAMADs7KyMkeOHLnj+LeB65VXXpkffvhhLl269Nfa999/P99+++28+uqr2zYHwOIsbWx+NREAAAAAYIc4fvz4XLlyZS5cuHDH+s8//zwXL16cZ599dg4ePDgzM7dv357XX399fvrppzl58uTs3r17Pv7441leXp7PP/98nnjiiW2ZA2BxBC4AAAAAYMf5p8D13XffzZtvvjmnT5+eM2fO/LV+7dq1OXv27Hz99deza9euef755+edd96Z/fv337F/q+cAWAyBCwAAAAAAgBTf4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACBF4AIAAAAAACDlTzaRUfhVNuY+AAAAAElFTkSuQmCC", - "text/plain": [ - "
    " - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "✅ Saved: cluster_visualisation.png\n" - ] - } - ], - "source": [ - "# ── PCA 2D Cluster Visualisation ─────────────────────────────────────────────\n", - "\n", - "pca2 = PCA(n_components=2, random_state=42)\n", - "X_2d = pca2.fit_transform(X)\n", - "var_explained = pca2.explained_variance_ratio_\n", - "\n", - "fig, axes = plt.subplots(1, 2, figsize=(16, 6))\n", - "\n", - "# ── Left: cluster scatter ─────────────────────────────────────────────────────\n", - "labels_for_plot = best_eval.labels\n", - "unique_labels = sorted(set(labels_for_plot))\n", - "colors = PALETTE[:len(unique_labels)]\n", - "\n", - "for lbl, col in zip(unique_labels, colors):\n", - " mask = labels_for_plot == lbl\n", - " label_name = f\"Cluster {lbl}\" if lbl != -1 else \"Noise\"\n", - " axes[0].scatter(X_2d[mask, 0], X_2d[mask, 1],\n", - " c=col, alpha=0.55, s=18, label=label_name, edgecolors=\"none\")\n", - "\n", - "axes[0].set_title(\n", - " f\"Clusters — {best_eval.algorithm.upper()} \"\n", - " f\"(silhouette={best_eval.silhouette:.3f})\"\n", - ")\n", - "axes[0].set_xlabel(f\"PC1 ({var_explained[0]*100:.1f}% var)\")\n", - "axes[0].set_ylabel(f\"PC2 ({var_explained[1]*100:.1f}% var)\")\n", - "axes[0].legend(framealpha=0.8)\n", - "\n", - "# ── Right: evaluation score comparison bar chart ──────────────────────────────\n", - "algos = list(best_eval.all_scores.keys())\n", - "sil_sc = [best_eval.all_scores[a][\"silhouette\"] for a in algos]\n", - "bar_colors = [PALETTE[2] if a == best_eval.algorithm else PALETTE[0] for a in algos]\n", - "\n", - "bars = axes[1].bar(algos, sil_sc, color=bar_colors, width=0.4, edgecolor=\"white\")\n", - "axes[1].axhline(SILHOUETTE_THRESHOLD, color=\"red\", linestyle=\"--\",\n", - " linewidth=1.5, label=f\"Threshold ({SILHOUETTE_THRESHOLD})\")\n", - "axes[1].set_ylim(0, max(sil_sc) * 1.3)\n", - "axes[1].set_title(\"Silhouette Score by Algorithm\")\n", - "axes[1].set_ylabel(\"Silhouette Score\")\n", - "axes[1].legend()\n", - "for bar, val in zip(bars, sil_sc):\n", - " axes[1].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.005,\n", - " f\"{val:.3f}\", ha=\"center\", va=\"bottom\", fontsize=10)\n", - "\n", - "plt.tight_layout()\n", - "fig.savefig(OUTPUT_DIR / \"cluster_visualisation.png\", dpi=150, bbox_inches=\"tight\")\n", - "plt.show()\n", - "print(\"✅ Saved: cluster_visualisation.png\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 10 — Explainability Layer\n", - "Permutation-based feature importance (SHAP-style), PCA loadings, and inertia movement analysis." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "⏳ Building explainability report (may take ~30s)...\n", - " Computing permutation feature importances...\n", - " Computing PCA loadings...\n", - " Computing per-cluster profiles...\n", - "✅ Explainability complete in 1.9s\n", - " Top 8 driving features: ['days_since_last_purchase', 'age', 'avg_order_value', 'nps_score', 'annual_spend', 'purchase_frequency', 'lifetime_months', 'product_category']\n" - ] - } - ], - "source": [ - "# ── Explainability Layer ─────────────────────────────────────────────────────\n", - "# Computes: (1) permutation feature importance, (2) PCA component loadings,\n", - "# (3) per-cluster feature means for interpretability.\n", - "\n", - "@dataclass\n", - "class ExplainabilityReport:\n", - " top_features: list[str]\n", - " feature_importances: dict[str, float] # feature → importance score\n", - " pca_loadings: pd.DataFrame # component × feature\n", - " cluster_profiles: pd.DataFrame # cluster × feature mean (raw scale)\n", - " pca_variance_ratio: list[float]\n", - "\n", - "\n", - "def compute_permutation_importance(\n", - " X: np.ndarray,\n", - " labels: np.ndarray,\n", - " feature_names: list[str],\n", - " n_repeats: int = 10,\n", - ") -> dict[str, float]:\n", - " \"\"\"\n", - " Permutation importance: how much does silhouette drop when feature is shuffled?\n", - " Higher drop → feature is more important for cluster separation.\n", - " \"\"\"\n", - " rng = np.random.default_rng(0)\n", - " valid_mask = labels != -1\n", - " Xv, lv = X[valid_mask], labels[valid_mask]\n", - "\n", - " if len(set(lv)) < 2:\n", - " return {f: 0.0 for f in feature_names}\n", - "\n", - " baseline = silhouette_score(Xv, lv, sample_size=min(1000, len(Xv)))\n", - " importances: dict[str, float] = {}\n", - "\n", - " for i, fname in enumerate(feature_names):\n", - " drops = []\n", - " for _ in range(n_repeats):\n", - " Xp = Xv.copy()\n", - " rng.shuffle(Xp[:, i])\n", - " s = silhouette_score(Xp, lv, sample_size=min(1000, len(Xv)))\n", - " drops.append(baseline - s)\n", - " importances[fname] = round(float(np.mean(drops)), 5)\n", - "\n", - " return dict(sorted(importances.items(), key=lambda x: -x[1]))\n", - "\n", - "\n", - "def build_explainability_report(\n", - " X: np.ndarray,\n", - " labels: np.ndarray,\n", - " feature_names: list[str],\n", - " raw_df: pd.DataFrame,\n", - " n_top: int,\n", - ") -> ExplainabilityReport:\n", - " print(\" Computing permutation feature importances...\")\n", - " importances = compute_permutation_importance(X, labels, feature_names)\n", - " top_features = list(importances.keys())[:n_top]\n", - "\n", - " print(\" Computing PCA loadings...\")\n", - " n_components = min(5, len(feature_names))\n", - " pca_full = PCA(n_components=n_components, random_state=42)\n", - " pca_full.fit(X)\n", - " loadings_df = pd.DataFrame(\n", - " np.abs(pca_full.components_),\n", - " columns=feature_names,\n", - " index=[f\"PC{i+1}\" for i in range(n_components)],\n", - " )\n", - "\n", - " print(\" Computing per-cluster profiles...\")\n", - " profiled = raw_df.copy()\n", - " profiled[\"_cluster\"] = labels\n", - " num_cols = [c for c in schema.numeric_cols if c in profiled.columns]\n", - " cluster_profiles = profiled.groupby(\"_cluster\")[num_cols].mean().round(2)\n", - "\n", - " return ExplainabilityReport(\n", - " top_features = top_features,\n", - " feature_importances = importances,\n", - " pca_loadings = loadings_df,\n", - " cluster_profiles = cluster_profiles,\n", - " pca_variance_ratio = pca_full.explained_variance_ratio_.tolist(),\n", - " )\n", - "\n", - "\n", - "print(\"⏳ Building explainability report (may take ~30s)...\")\n", - "t0 = time.time()\n", - "explain_report = build_explainability_report(\n", - " X, best_eval.labels, fe.feature_names, raw_df, N_TOP_FEATURES\n", - ")\n", - "print(f\"✅ Explainability complete in {time.time()-t0:.1f}s\")\n", - "print(f\" Top {N_TOP_FEATURES} driving features: {explain_report.top_features}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 11 — Explainability Plots" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "ename": "KeyError", - "evalue": "\"['product_category'] not in index\"", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[11], line 19\u001b[0m\n\u001b[0;32m 16\u001b[0m \u001b[38;5;66;03m# ── Right: cluster profile heatmap ───────────────────────────────────────────\u001b[39;00m\n\u001b[0;32m 17\u001b[0m profile_z \u001b[38;5;241m=\u001b[39m (explain_report\u001b[38;5;241m.\u001b[39mcluster_profiles \u001b[38;5;241m-\u001b[39m explain_report\u001b[38;5;241m.\u001b[39mcluster_profiles\u001b[38;5;241m.\u001b[39mmean()) \\\n\u001b[0;32m 18\u001b[0m \u001b[38;5;241m/\u001b[39m explain_report\u001b[38;5;241m.\u001b[39mcluster_profiles\u001b[38;5;241m.\u001b[39mstd()\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m---> 19\u001b[0m profile_z \u001b[38;5;241m=\u001b[39m profile_z[explain_report\u001b[38;5;241m.\u001b[39mtop_features[:\u001b[38;5;241m8\u001b[39m]] \u001b[38;5;66;03m# keep top features\u001b[39;00m\n\u001b[0;32m 21\u001b[0m sns\u001b[38;5;241m.\u001b[39mheatmap(\n\u001b[0;32m 22\u001b[0m profile_z\u001b[38;5;241m.\u001b[39mT, ax\u001b[38;5;241m=\u001b[39maxes[\u001b[38;5;241m1\u001b[39m],\n\u001b[0;32m 23\u001b[0m cmap\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRdBu_r\u001b[39m\u001b[38;5;124m\"\u001b[39m, center\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, annot\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, fmt\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.2f\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 24\u001b[0m linewidths\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.5\u001b[39m, cbar_kws\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlabel\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mZ-score vs. mean\u001b[39m\u001b[38;5;124m\"\u001b[39m},\n\u001b[0;32m 25\u001b[0m )\n\u001b[0;32m 26\u001b[0m axes[\u001b[38;5;241m1\u001b[39m]\u001b[38;5;241m.\u001b[39mset_title(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCluster Profiles — Top Driving Features\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m(Z-scored mean values)\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "File \u001b[1;32mc:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\pandas\\core\\frame.py:4108\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m 4106\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_iterator(key):\n\u001b[0;32m 4107\u001b[0m key \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(key)\n\u001b[1;32m-> 4108\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39m_get_indexer_strict(key, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcolumns\u001b[39m\u001b[38;5;124m\"\u001b[39m)[\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m 4110\u001b[0m \u001b[38;5;66;03m# take() does not accept boolean indexers\u001b[39;00m\n\u001b[0;32m 4111\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(indexer, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdtype\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m) \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mbool\u001b[39m:\n", - "File \u001b[1;32mc:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:6200\u001b[0m, in \u001b[0;36mIndex._get_indexer_strict\u001b[1;34m(self, key, axis_name)\u001b[0m\n\u001b[0;32m 6197\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 6198\u001b[0m keyarr, indexer, new_indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reindex_non_unique(keyarr)\n\u001b[1;32m-> 6200\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_raise_if_missing(keyarr, indexer, axis_name)\n\u001b[0;32m 6202\u001b[0m keyarr \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtake(indexer)\n\u001b[0;32m 6203\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(key, Index):\n\u001b[0;32m 6204\u001b[0m \u001b[38;5;66;03m# GH 42790 - Preserve name from an Index\u001b[39;00m\n", - "File \u001b[1;32mc:\\Users\\UmairAhmed\\anaconda3\\Lib\\site-packages\\pandas\\core\\indexes\\base.py:6252\u001b[0m, in \u001b[0;36mIndex._raise_if_missing\u001b[1;34m(self, key, indexer, axis_name)\u001b[0m\n\u001b[0;32m 6249\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNone of [\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkey\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m] are in the [\u001b[39m\u001b[38;5;132;01m{\u001b[39;00maxis_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m]\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 6251\u001b[0m not_found \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(ensure_index(key)[missing_mask\u001b[38;5;241m.\u001b[39mnonzero()[\u001b[38;5;241m0\u001b[39m]]\u001b[38;5;241m.\u001b[39munique())\n\u001b[1;32m-> 6252\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mnot_found\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not in index\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[1;31mKeyError\u001b[0m: \"['product_category'] not in index\"" - ] - }, - { - "data": { - "image/png": "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Dz8oLi5OX375ZY6X8G7fvr1Wr16tV155RW3atFGJEiVM7xx/5JFHdPnyZcXFxZmu4dtvv9W0adO0c+dOubi46O+//9YPP/wgJycnBQcHS5Jq1Kih119/XVOmTFGbNm3UrFkzOTk5afPmzfrrr7/k7++vFi1a5KjO+zVu3Di99NJLCgkJUePGjfX444/r999/17Zt2/TII49ozJgxpr6vvfaadu7cqenTp2vnzp16/PHH9dNPP2X5soGUEWb/97//1RdffKHTp0+rcuXK2rZtm5KTk/Xoo4+a9e3fv7+2b9+ur776Srt375a3t7fi4uK0du1apaamavz48dl6Z/o/BQYGat26dVq6dKmOHj2qevXq6ezZs1q/fr1q1aqlAQMGZKl52rRpio2N1euvv57j8wEAAAAAAAAAAAC4M2ao30V4eLjKlSunb7/9VmfOnFG/fv00f/58FS1aVJL01FNPafbs2apdu7ZWr16tlStXqkmTJvryyy9N7+POji5duujLL7+Ui4uL1qxZo6VLl6pWrVqaN2+e/vOf/+S47iZNmmjGjBmqUqWKVqxYoRUrVkiSJk6cqA8//FCSTMuzlypVSuHh4XrhhRd06tQphYWFadu2bWrevLmWLFlimoUvScHBwfr888/l4uKitWvXavHixSpevLjeeustffjhh/n27u5atWpp6dKl6tKli44cOaL58+fr999/V+fOnbVkyRJVr17d1NfJyUkLFixQt27ddOTIES1evFg1atRQaGholuM++uijmj9/vnx8fLRlyxZ99913ql27thYsWGD27nIpYxWAsLAwDR48WImJiVq4cKG2b98uX19fhYeH3/eXC+zs7DRnzhwNGTJEiYmJWrBggaKjoxUQEKCIiAiVLFkyS83e3t6ytbVVu3bt7uucAAAAAAAAAAAAACyzMd6+XjUkSUFBQYqKitKePXuyBJgoGGJiYtS8eXP5+/vrk08+sXY59y01NVWNGjVS7dq1NXfu3Fw9dlJSkuld9V8fXaoLRa7m6vEBAMCD+7z9FJUtXtraZeAO9u/fL0lyd3e3ciXIbYV5bG//nODq6mr6wjmQF3jekJ8K8+925D+eN+QnnjfkJ5435AdrfE5ghjrwL7Zo0SJdvnxZXbt2tXYpAAAAAAAAAAAAQIHDO9SRqzZs2KAjR45ku//gwYPzsJqCa8iQITpx4oRO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Gj9+vPbs2aOSJUtm2b5lyxbNnTtXBw8eVFpammrWrKlu3brpxRdfzNc6AQAAAACFl4ODg0JCQhQSEnLHPr6+vjp27JhZ2/r16/O6NAAAAAB4aPAO9UKqR48emj179n3vf/ToUbVv31779u0zaw8JCdELL7zwgNXljjvVmNeio6P1wQcf3HH7N998owEDBuj48eNq06aNunbtqvj4eL377rsaP358PlYKAAAAAAAAAAAA4G6YoV5IXb58+YH2v3btmlJSUrK0Dx48+IGOm5vuVGNeWr16td566y3dunXL4vb4+HhNmzZNjz76qCIjI1WhQgVJ0rBhw9S9e3dFRESoc+fOevrpp/OzbAAAAAAAAAAAAAAWMEMdyAVXrlxRSEiIhg8frnLlyql69eoW+23fvl03btzQSy+9ZArTJcnR0VEvv/yyqQ8AAAAAAAAAAAAA6yNQ/38pKSn6+OOP1a5dO7m7u8vX11f9+/dXdHS0qU+zZs3k6+ubZd/NmzfLYDBo5syZZn27deumI0eO6KWXXpK7u7saN26syZMnKyEhwWz/nPSVpJMnT2r48OFq0KCBXF1d5e/vr48//lg3b97MctygoCAtXrxY9evXl4eHh15//XUZDAbFxsYqLi5OBoNBo0ePztG9mjlzpnr27ClJmjdvngwGg3bt2iUp4x3qAQEBZv1v3Lihjz76SP7+/nJ3d5efn58mTZqkuLi4u57nwIED8vDwUIMGDXTy5ElTe0JCgqZNm6bmzZvL1dVVjRs31oQJE3T16tVs1Xjq1CkNGTJETZo0kaurq5o3b64JEyboypUrOboPtztx4oQ2bNiggIAARUZGqmLFihb71apVS8OGDVOTJk2ybCtWrJikjPslSTExMTIYDJo1a5bWrVunjh07ys3NTc2bN9fChQslSTt27FBgYKDpvs6ZM0fp6en3fR0AAAAAAAAAAAAA/ocl3//fuHHjtHjxYvn4+KhRo0aKj4/X6tWr9fPPP2vBggWqW7dujo958eJF9ezZU9WqVVP37t21d+9eff311/r111+1cOFCOTg45Ljv3r17FRwcrOTkZDVr1kyVK1dWdHS0Zs2apW3btikiIkLFixc3HffEiROaOHGiOnTooFu3bqlhw4aqVq2awsLClJKSor59+6p27do5ui4fHx916tRJkZGR8vDw0H/+8x85Oztb7Hvz5k1169ZNR48elYeHh5o2bao//vhDYWFh+vXXX7VgwQJTkHy7kydPql+/frK3t9dXX32lxx9/XJJ0/fp1de/eXcePH9ezzz6rli1b6s8//1RERIR++uknffvttypbtuwda7x8+bJ69+6ta9euqWXLlipfvrwOHz6s8PBw7d69W8uWLZOdnV2O7ockVatWTStWrJDBYLhrv6eeekpPPfWUxW2bNm2SJD355JNm7evWrdMff/yhVq1aydvbWytWrND777+vP//8UwsXLpSfn5+8vLy0atUqffjhhypXrpy6dOmS42sAAAAAAAAAAAAAYI5AXRkh7Xfffad69eopPDzc1N6uXTvTDO/7CdRjYmLUokULffLJJ7K1tZXRaNRbb72lpUuXatGiRQoKCspR37S0NI0aNUqpqamaO3euGjRoIElKT0/XuHHj9M033yg0NFSvv/666bhXr17VO++8o5deesmstsjISCUmJt7XO88zZ+lnhtV3O8acOXN09OhRDRw4UMOGDTO1f/TRR5o9e7ZWrlyprl27mu1z9uxZvfzyy0pNTdXXX39tFkDPmDFDx48f18SJE81C49WrV2v48OH64IMPNGnSpDvWGB4ervPnz2vSpEnq3Lmzaf8xY8Zo2bJl2rt3r7y9vXN8Tx577DE99thjOd4v06+//qqVK1fq0UcfVbNmzcy2HT16VLNnz1bTpk0lZXyhYfDgwQoLC9MHH3yg9u3bS5ICAgLUtm1brVmzhkAdyGUpKSk6fPiwtcvIltTUVEnS/v37rVwJchtjW3AxtgUXY1twFeaxNRqN1i4BAAAAAIB8xZLv/89oNOrs2bM6d+6cqc3Hx0fr16/XuHHj7uuYtra2euONN2Rrm3GbbWxsNHz4cNnb22vVqlU57rtnzx799ddf6tChgylMz9x35MiRKl26tJYuXZrlLzj8/f3vq/7csHr1apUuXVohISFm7b1791a/fv1UrVo1s/YrV64oODhY8fHx+uKLL1SnTh3TttTUVC1fvly1a9fOEhi3adNGTz31lFavXq3k5OQ71pN5b/bv36+0tDRT++jRo/XLL7/cV5j+oE6ePKmQkBClp6fr/fffN1thQJKqV69uCtMlydPTU5JUvnx5U5guZcxsL1GihGJjY/OncAAAAAAAAAAAAKCAY4a6JCcnJ7Vu3VqrV69WixYt5OXlpUaNGqlp06aq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JNWsWVNffPGFjEajGjRooDZt2mj58uX2VgV4LBXktRGePPb2N8ZOyCl7+1o6rveRE/b2N65RYQt7+1vZsmVlNBr1888/a9asWbp69aouXryosWPH6uLFi+rdu3c+lh6PowkTJmj16tVq3LixTfnye5zAbR9AIXTr1i1Jf979lZmbm5tMJpNu3bqlcuXKZZvfzc0ty770i/mbN2/anBb2c2TbSlLt2rXtLjNyxtFta826deu0b98+GQwG+fj42FR+ZK+g2vb8+fPy9/c3v/7ggw8UGBhoewWQLUe37dWrVzVlyhQFBwcrMDBQCQkJdtcB2XNk+/7yyy9KSUnRwYMHdevWLRmNRl27dk2xsbEaPny4zp07p0GDBuVJveDYtv39998lSR999JF56bkXX3xRmzdv1pgxY/T7779bLJsIPAn+Cte9eHLY29+yw9gJmeVFX+N6Hzllb3/jGhW2yIvvt48//lju7u6KiIhQRESEefvQoUP1zjvv5H2h8Vh76aWXcpUvv8cJBNSBQuju3buSZPH83IycnZ0lKdu7xtKXK7OWPz3vH3/8YXNa2M+RbQvHKui2jY+P1+jRo+Xs7KzJkyfLyckp54XHQxVU26akpKhr1666f/++YmNjFR4erps3b2rgwIG2VwJWObptw8PDlZKSojFjxuS+0MgxR7bv9evXVatWLTVp0kTjx49X0aJFJUlJSUnq0qWLPv30UwUHB8tgMNhRI6RzZNumn2vv3r1atmyZ6tatK0kaOHCgOnbsqLlz56pt27aqXr16bqsDPHYK+roXTxZ7+5s1jJ1gTV70Na73kVP29jeuUWGLvPh+W7FihaKiolS1alW1bNlSd+/e1ZYtWzR//nzVqFFDrVq1yvuC44mT3+MElnwHCqHixYtLSgumWJO+vWTJkjbnz5zXlrSwnyPbFo5VkG27a9cu9e/fX3/88YemTJkib29v2wqPhyqotq1Ro4bGjRuniRMnat26dapdu7Zmz56tw4cP214JWOXIto2Li9OaNWv03nvvqXLlyvYVHDniyPZt2rSpoqOjNWnSJHMwXZIqV66sgQMHymQyKTo6Opc1QWaObNsiRdKG3J07dzb/UClJFStWVL9+/XT//n1t3LgxN9UAHluMaeBI9va3zBg7ITv29jWu92ELe/sb16iwhb39bd++fZo4caLq1aunqKgoffjhhwoP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", - "text/plain": [ - "
    " - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# ── Explainability Plots ─────────────────────────────────────────────────────\n", - "\n", - "fig, axes = plt.subplots(1, 2, figsize=(17, 6))\n", - "\n", - "# ── Left: feature importance bar ─────────────────────────────────────────────\n", - "top_n = 10\n", - "names = list(explain_report.feature_importances.keys())[:top_n]\n", - "scores = list(explain_report.feature_importances.values())[:top_n]\n", - "bar_c = [PALETTE[2] if n in explain_report.top_features else PALETTE[0] for n in names]\n", - "\n", - "axes[0].barh(names[::-1], scores[::-1], color=bar_c[::-1], edgecolor=\"white\")\n", - "axes[0].set_title(\"Feature Importance\\n(Silhouette drop on permutation)\")\n", - "axes[0].set_xlabel(\"Mean silhouette drop\")\n", - "axes[0].axvline(0, color=\"gray\", linewidth=0.8)\n", - "\n", - "# ── Right: cluster profile heatmap ───────────────────────────────────────────\n", - "profile_z = (explain_report.cluster_profiles - explain_report.cluster_profiles.mean()) \\\n", - " / explain_report.cluster_profiles.std().replace(0, 1)\n", - "profile_z = profile_z[explain_report.top_features[:8]] # keep top features\n", - "\n", - "sns.heatmap(\n", - " profile_z.T, ax=axes[1],\n", - " cmap=\"RdBu_r\", center=0, annot=True, fmt=\".2f\",\n", - " linewidths=0.5, cbar_kws={\"label\": \"Z-score vs. mean\"},\n", - ")\n", - "axes[1].set_title(\"Cluster Profiles — Top Driving Features\\n(Z-scored mean values)\")\n", - "axes[1].set_xlabel(\"Cluster ID\")\n", - "axes[1].set_ylabel(\"\")\n", - "\n", - "plt.tight_layout()\n", - "fig.savefig(OUTPUT_DIR / \"explainability.png\", dpi=150, bbox_inches=\"tight\")\n", - "plt.show()\n", - "print(\"✅ Saved: explainability.png\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 12 — Local LLM Client (Ollama)\n", - "Thin client wrapping the Ollama `/api/generate` endpoint. Handles streaming, retries, and JSON extraction." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "❌ Ollama not reachable at http://localhost:11434: HTTPConnectionPool(host='localhost', port=11434): Max retries exceeded with url: /api/tags (Caused by NewConnectionError(': Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it'))\n", - "\n", - "⚠️ Ollama is not running. Start it with: ollama serve\n", - " Then pull the model with: ollama pull llama3\n", - "\n", - " Persona identification will use FALLBACK mode (rule-based).\n" - ] - } - ], - "source": [ - "# ── Ollama Local LLM Client ──────────────────────────────────────────────────\n", - "\n", - "class OllamaClient:\n", - " \"\"\"\n", - " Thin, production-grade client for Ollama's local LLM API.\n", - " Supports streaming, retries, timeout, and structured JSON extraction.\n", - " \"\"\"\n", - "\n", - " def __init__(self, host: str, model: str, timeout: int = 120):\n", - " self.host = host.rstrip(\"/\")\n", - " self.model = model\n", - " self.timeout = timeout\n", - " self._endpoint = f\"{self.host}/api/generate\"\n", - "\n", - " def health_check(self) -> bool:\n", - " try:\n", - " r = requests.get(f\"{self.host}/api/tags\", timeout=5)\n", - " models = [m[\"name\"] for m in r.json().get(\"models\", [])]\n", - " available = any(self.model in m for m in models)\n", - " if not available:\n", - " print(f\"⚠️ Model '{self.model}' not found. Available: {models}\")\n", - " return True\n", - " except Exception as e:\n", - " print(f\"❌ Ollama not reachable at {self.host}: {e}\")\n", - " return False\n", - "\n", - " def generate(\n", - " self,\n", - " prompt: str,\n", - " system: str | None = None,\n", - " temperature: float = 0.3,\n", - " max_retries: int = 2,\n", - " ) -> str:\n", - " \"\"\"\n", - " Generate a response. Returns the full text.\n", - " Retries on transient errors.\n", - " \"\"\"\n", - " payload: dict = {\n", - " \"model\": self.model,\n", - " \"prompt\": prompt,\n", - " \"stream\": False,\n", - " \"options\": {\n", - " \"temperature\": temperature,\n", - " \"num_predict\": 1024,\n", - " },\n", - " }\n", - " if system:\n", - " payload[\"system\"] = system\n", - "\n", - " last_error = None\n", - " for attempt in range(1, max_retries + 2):\n", - " try:\n", - " r = requests.post(\n", - " self._endpoint,\n", - " json=payload,\n", - " timeout=self.timeout,\n", - " )\n", - " r.raise_for_status()\n", - " return r.json().get(\"response\", \"\").strip()\n", - " except requests.Timeout:\n", - " last_error = f\"Timeout after {self.timeout}s\"\n", - " except requests.RequestException as e:\n", - " last_error = str(e)\n", - " if attempt <= max_retries:\n", - " wait = 2 ** attempt\n", - " log.warning(\"Ollama attempt %d failed (%s). Retrying in %ds...\", attempt, last_error, wait)\n", - " time.sleep(wait)\n", - "\n", - " raise RuntimeError(f\"Ollama failed after {max_retries+1} attempts: {last_error}\")\n", - "\n", - " def extract_json(self, text: str) -> dict | list:\n", - " \"\"\"Extract the first JSON object/array from LLM output.\"\"\"\n", - " match = re.search(r\"(\\{.*\\}|\\[.*\\])\", text, re.DOTALL)\n", - " if not match:\n", - " raise ValueError(f\"No JSON found in LLM response:\\n{text[:400]}\")\n", - " return json.loads(match.group(1))\n", - "\n", - "\n", - "# ── Initialise and health-check ───────────────────────────────────────────────\n", - "ollama = OllamaClient(OLLAMA_HOST, OLLAMA_MODEL, OLLAMA_TIMEOUT)\n", - "is_up = ollama.health_check()\n", - "\n", - "if is_up:\n", - " print(f\"✅ Ollama is reachable at {OLLAMA_HOST}\")\n", - " print(f\" Model: {OLLAMA_MODEL}\")\n", - "else:\n", - " print(f\"\\n⚠️ Ollama is not running. Start it with: ollama serve\")\n", - " print(f\" Then pull the model with: ollama pull {OLLAMA_MODEL}\")\n", - " print(f\"\\n Persona identification will use FALLBACK mode (rule-based).\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 13 — 🤖 Persona Identification Layer (Local LLM)\n", - "For each cluster, builds a rich statistical profile and asks llama3 to generate a named persona with description, traits, and business recommendations." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# ── Persona Identification Layer ─────────────────────────────────────────────\n", - "\n", - "@dataclass\n", - "class PersonaResult:\n", - " cluster_id: int | str\n", - " persona_name: str # e.g. \"Cluster A\"\n", - " archetype: str # e.g. \"The Loyal Champion\"\n", - " description: str\n", - " key_traits: list[str]\n", - " business_recommendations: list[str]\n", - " cluster_size: int\n", - " cluster_pct: float\n", - " top_features: dict[str, float] # feature → mean value\n", - "\n", - "\n", - "PERSONA_SYSTEM_PROMPT = \"\"\"You are a senior customer analytics expert and strategic advisor.\n", - "You analyse customer cluster profiles and generate precise, actionable personas.\n", - "Always respond with ONLY valid JSON — no preamble, no explanation, no markdown fences.\n", - "The JSON must contain exactly these keys:\n", - " archetype: string (2-5 word evocative label, e.g. 'The Loyal Champion')\n", - " description: string (2-3 sentences describing who this customer is)\n", - " key_traits: list of 4 strings (concise behavioural characteristics)\n", - " business_recommendations: list of 3 strings (specific, actionable strategies)\n", - "\"\"\"\n", - "\n", - "def build_cluster_profile_text(\n", - " cluster_id: int,\n", - " profile_row: pd.Series,\n", - " cluster_pct: float,\n", - " top_features: dict[str, float],\n", - " top_feature_names: list[str],\n", - ") -> str:\n", - " \"\"\"Build a rich textual summary of a cluster's statistical profile.\"\"\"\n", - " lines = [\n", - " f\"CLUSTER {cluster_id} PROFILE\",\n", - " f\" Size: {int(cluster_pct*100)}% of total customers\",\n", - " \"\",\n", - " \" Key metrics (mean values):\",\n", - " ]\n", - " for feat in top_feature_names[:8]:\n", - " if feat in profile_row.index:\n", - " lines.append(f\" - {feat}: {profile_row[feat]:.2f}\")\n", - " lines += [\"\", \" Feature importances (contribution to separation):\"]\n", - " for feat, imp in list(top_features.items())[:5]:\n", - " lines.append(f\" - {feat}: {imp:.4f}\")\n", - " return \"\\n\".join(lines)\n", - "\n", - "\n", - "def identify_personas_with_llm(\n", - " client: OllamaClient,\n", - " best_eval: EvaluationResult,\n", - " explain_report: ExplainabilityReport,\n", - " raw_df: pd.DataFrame,\n", - " business_objective: str,\n", - " fallback: bool = False,\n", - ") -> list[PersonaResult]:\n", - " \"\"\"\n", - " For each cluster: build profile → call local LLM → parse persona JSON.\n", - " Falls back to rule-based persona labels if Ollama is unavailable.\n", - " \"\"\"\n", - " personas: list[PersonaResult] = []\n", - " labels = best_eval.labels\n", - " total = (labels != -1).sum()\n", - "\n", - " cluster_ids = sorted(c for c in set(labels) if c != -1)\n", - "\n", - " for cid in cluster_ids:\n", - " mask = labels == cid\n", - " size = mask.sum()\n", - " pct = size / total\n", - " name_map = {0: \"A\", 1: \"B\", 2: \"C\", 3: \"D\", 4: \"E\"}\n", - " letter = name_map.get(cid, str(cid))\n", - "\n", - " # Numeric profile\n", - " num_cols = [c for c in schema.numeric_cols if c in raw_df.columns]\n", - " profile_row = raw_df[mask][num_cols].mean()\n", - " top_features_dict = {\n", - " k: v for k, v in explain_report.feature_importances.items()\n", - " if v > 0\n", - " }\n", - "\n", - " profile_text = build_cluster_profile_text(\n", - " cluster_id = letter,\n", - " profile_row = profile_row,\n", - " cluster_pct = pct,\n", - " top_features = top_features_dict,\n", - " top_feature_names = explain_report.top_features,\n", - " )\n", - "\n", - " if fallback:\n", - " # Rule-based fallback when Ollama is unavailable\n", - " archetype = f\"Cluster {letter} Persona\"\n", - " description = f\"Cluster {letter} contains {size:,} customers ({pct*100:.1f}% of total). Statistical profiling complete; LLM descriptions require Ollama.\"\n", - " key_traits = [f\"Cluster size: {size:,}\", f\"Share: {pct*100:.1f}%\",\n", - " \"LLM offline — run ollama serve\", \"Retrigger Cell 13\"]\n", - " recs = [\"Start Ollama: ollama serve\", f\"Pull model: ollama pull {OLLAMA_MODEL}\", \"Re-run this cell\"]\n", - " else:\n", - " prompt = (\n", - " f\"Business objective: {business_objective}\\n\\n\"\n", - " f\"{profile_text}\\n\\n\"\n", - " f\"Generate a precise customer persona for Cluster {letter}. \"\n", - " f\"The persona must be grounded in the metrics above and serve the stated business objective. \"\n", - " f\"Respond ONLY with valid JSON.\"\n", - " )\n", - " print(f\" 🤖 Calling {OLLAMA_MODEL} for Cluster {letter} ({size:,} customers)...\")\n", - " t0 = time.time()\n", - " raw_response = client.generate(prompt, system=PERSONA_SYSTEM_PROMPT, temperature=0.3)\n", - " elapsed_llm = time.time() - t0\n", - " print(f\" Response in {elapsed_llm:.1f}s\")\n", - "\n", - " try:\n", - " parsed = client.extract_json(raw_response)\n", - " archetype = parsed.get(\"archetype\", f\"Cluster {letter} Persona\")\n", - " description = parsed.get(\"description\", \"\")\n", - " key_traits = parsed.get(\"key_traits\", [])\n", - " recs = parsed.get(\"business_recommendations\", [])\n", - " except (ValueError, json.JSONDecodeError) as e:\n", - " log.warning(\" JSON parse failed for cluster %s: %s\", letter, e)\n", - " archetype = f\"Cluster {letter}\"\n", - " description = raw_response[:300]\n", - " key_traits = []\n", - " recs = []\n", - "\n", - " personas.append(PersonaResult(\n", - " cluster_id = cid,\n", - " persona_name = f\"Cluster {letter}\",\n", - " archetype = archetype,\n", - " description = description,\n", - " key_traits = key_traits,\n", - " business_recommendations = recs,\n", - " cluster_size = int(size),\n", - " cluster_pct = round(float(pct), 4),\n", - " top_features = {k: round(float(profile_row.get(k, 0)), 2)\n", - " for k in explain_report.top_features[:5]\n", - " if k in profile_row.index},\n", - " ))\n", - "\n", - " return personas\n", - "\n", - "\n", - "# ── Execute Persona Identification ────────────────────────────────────────────\n", - "use_fallback = not is_up\n", - "\n", - "print(\"\\n\" + \"═\"*60)\n", - "print(\" PERSONA IDENTIFICATION LAYER\")\n", - "print(\" Using local LLM:\" if not use_fallback else \" ⚠️ Using rule-based FALLBACK (Ollama offline)\")\n", - "print(\"═\"*60)\n", - "\n", - "personas = identify_personas_with_llm(\n", - " client = ollama,\n", - " best_eval = best_eval,\n", - " explain_report = explain_report,\n", - " raw_df = raw_df,\n", - " business_objective = BUSINESS_OBJECTIVE,\n", - " fallback = use_fallback,\n", - ")\n", - "\n", - "print(f\"\\n✅ {len(personas)} personas identified.\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 14 — Ground in Business Objective\n", - "LLM synthesises a strategic summary mapping all personas to the business objective, then assigns each to Cluster A / B / C buckets." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# ── Business Objective Grounding ─────────────────────────────────────────────\n", - "\n", - "GROUNDING_SYSTEM = \"\"\"You are a Chief Strategy Officer synthesising customer segmentation results\n", - "into an executive-level strategic report.\n", - "Respond with ONLY valid JSON containing:\n", - " executive_summary: string (3-4 sentences — overall findings and strategic implication)\n", - " cluster_priority: list of objects, each with:\n", - " cluster: string\n", - " archetype: string\n", - " priority: string (\"High\" | \"Medium\" | \"Low\")\n", - " strategic_action: string (one concrete next action)\n", - " quick_wins: list of 3 strings (immediate actions any team can take this week)\n", - "\"\"\"\n", - "\n", - "def ground_in_business_objective(\n", - " client: OllamaClient,\n", - " personas: list[PersonaResult],\n", - " objective: str,\n", - " fallback: bool = False,\n", - ") -> dict:\n", - " if fallback:\n", - " return {\n", - " \"executive_summary\": \"Ollama offline. Start Ollama and re-run to get LLM-generated strategic grounding.\",\n", - " \"cluster_priority\": [{\"cluster\": p.persona_name, \"archetype\": p.archetype,\n", - " \"priority\": \"TBD\", \"strategic_action\": \"Run Ollama to generate\"} for p in personas],\n", - " \"quick_wins\": [\"Start Ollama: ollama serve\", f\"Pull model: ollama pull {OLLAMA_MODEL}\", \"Re-run notebook\"],\n", - " }\n", - "\n", - " persona_summaries = []\n", - " for p in personas:\n", - " persona_summaries.append(\n", - " f\" {p.persona_name} — {p.archetype}\\n\"\n", - " f\" Size: {p.cluster_size:,} ({p.cluster_pct*100:.1f}%)\\n\"\n", - " f\" Description: {p.description[:200]}\\n\"\n", - " f\" Top traits: {'; '.join(p.key_traits[:3])}\"\n", - " )\n", - "\n", - " prompt = (\n", - " f\"Business Objective:\\n{objective}\\n\\n\"\n", - " f\"Identified Customer Personas:\\n\" + \"\\n\\n\".join(persona_summaries) + \"\\n\\n\"\n", - " f\"Ground these personas in the stated business objective. \"\n", - " f\"Identify priorities and strategic actions. Respond ONLY with valid JSON.\"\n", - " )\n", - "\n", - " print(\" 🤖 Grounding personas in business objective...\")\n", - " t0 = time.time()\n", - " raw = client.generate(prompt, system=GROUNDING_SYSTEM, temperature=0.2)\n", - " print(f\" LLM response in {time.time()-t0:.1f}s\")\n", - "\n", - " try:\n", - " return client.extract_json(raw)\n", - " except Exception as e:\n", - " log.warning(\"Grounding JSON parse failed: %s\", e)\n", - " return {\"executive_summary\": raw[:500], \"cluster_priority\": [], \"quick_wins\": []}\n", - "\n", - "\n", - "grounding = ground_in_business_objective(ollama, personas, BUSINESS_OBJECTIVE, fallback=use_fallback)\n", - "\n", - "print(\"\\n\" + \"═\"*60)\n", - "print(\" BUSINESS OBJECTIVE GROUNDING COMPLETE\")\n", - "print(\"═\"*60)\n", - "print(\"\\n📋 Executive Summary:\")\n", - "print(f\" {grounding.get('executive_summary', 'N/A')}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 15 — 📊 Final Persona Report\n", - "Prints the full structured output: Cluster A, B, C with archetypes, traits, recommendations, and strategic grounding." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# ── Final Persona Report ─────────────────────────────────────────────────────\n", - "\n", - "CLUSTER_LETTERS = {0: \"A\", 1: \"B\", 2: \"C\", 3: \"D\", 4: \"E\"}\n", - "\n", - "def print_persona_report(personas: list[PersonaResult], grounding: dict, objective: str):\n", - " divider = \"═\" * 68\n", - " subdiv = \"─\" * 68\n", - "\n", - " print(f\"\\n{divider}\")\n", - " print(f\" PERSONA IDENTIFICATION REPORT\")\n", - " print(f\" Business Objective: {objective[:70]}...\")\n", - " print(f\"{divider}\")\n", - "\n", - " for p in personas:\n", - " letter = CLUSTER_LETTERS.get(p.cluster_id, str(p.cluster_id))\n", - " print(f\"\\n{'▌'} CLUSTER {letter} ╔══ {p.archetype} ══╗\")\n", - " print(f\" Size : {p.cluster_size:,} customers ({p.cluster_pct*100:.1f}% of total)\")\n", - " print(f\" Description :\")\n", - " # Word-wrap the description\n", - " words, line = p.description.split(), \"\"\n", - " for word in words:\n", - " if len(line) + len(word) + 1 > 65:\n", - " print(f\" {line}\")\n", - " line = word\n", - " else:\n", - " line = f\"{line} {word}\".strip()\n", - " if line:\n", - " print(f\" {line}\")\n", - "\n", - " if p.key_traits:\n", - " print(f\" Key Traits :\")\n", - " for t in p.key_traits:\n", - " print(f\" • {t}\")\n", - "\n", - " if p.top_features:\n", - " print(f\" Top Metrics (mean):\")\n", - " for feat, val in p.top_features.items():\n", - " print(f\" {feat:<30}: {val:>10.2f}\")\n", - "\n", - " if p.business_recommendations:\n", - " print(f\" Recommendations:\")\n", - " for r in p.business_recommendations:\n", - " print(f\" → {r}\")\n", - " print(f\" {subdiv}\")\n", - "\n", - " # Strategic priorities\n", - " priorities = grounding.get(\"cluster_priority\", [])\n", - " if priorities:\n", - " print(f\"\\n{'▌'} STRATEGIC PRIORITIES\")\n", - " for cp in priorities:\n", - " print(f\" [{cp.get('priority','?'):6}] {cp.get('cluster','')} — {cp.get('strategic_action','')}\")\n", - "\n", - " # Quick wins\n", - " qw = grounding.get(\"quick_wins\", [])\n", - " if qw:\n", - " print(f\"\\n{'▌'} QUICK WINS (This Week)\")\n", - " for i, w in enumerate(qw, 1):\n", - " print(f\" {i}. {w}\")\n", - "\n", - " print(f\"\\n{divider}\\n\")\n", - "\n", - "\n", - "print_persona_report(personas, grounding, BUSINESS_OBJECTIVE)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 16 — Persona Visualisation\n", - "Radar chart per cluster + cluster size distribution." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# ── Persona Visualisation ────────────────────────────────────────────────────\n", - "\n", - "fig = plt.figure(figsize=(18, 7))\n", - "\n", - "# ── Left: cluster size pie ────────────────────────────────────────────────────\n", - "ax_pie = fig.add_subplot(1, 3, 1)\n", - "sizes = [p.cluster_size for p in personas]\n", - "labels_pie = [f\"{p.persona_name}\\n{p.archetype[:20]}\" for p in personas]\n", - "wedge_colors = PALETTE[:len(personas)]\n", - "\n", - "wedges, texts, autotexts = ax_pie.pie(\n", - " sizes, labels=labels_pie, colors=wedge_colors,\n", - " autopct=\"%1.1f%%\", startangle=140,\n", - " wedgeprops={\"edgecolor\": \"white\", \"linewidth\": 1.5},\n", - ")\n", - "for at in autotexts:\n", - " at.set_fontsize(10)\n", - "ax_pie.set_title(\"Cluster Size Distribution\", fontsize=13, pad=15)\n", - "\n", - "# ── Right: radar charts ───────────────────────────────────────────────────────\n", - "top_radar_feats = explain_report.top_features[:6]\n", - "num_cols_radar = [f for f in top_radar_feats if f in raw_df.columns\n", - " and pd.api.types.is_numeric_dtype(raw_df[f])][:6]\n", - "n_feats = len(num_cols_radar)\n", - "\n", - "if n_feats >= 3:\n", - " angles = np.linspace(0, 2 * np.pi, n_feats, endpoint=False).tolist()\n", - " angles += angles[:1]\n", - "\n", - " for idx, p in enumerate(personas[:3]):\n", - " ax = fig.add_subplot(1, 3, idx + 2, polar=True) if idx < 2 else None\n", - " if idx == 0:\n", - " ax = fig.add_subplot(1, 3, 2, polar=True)\n", - " elif idx == 1:\n", - " ax = fig.add_subplot(1, 3, 3, polar=True)\n", - " else:\n", - " break\n", - "\n", - " mask = best_eval.labels == p.cluster_id\n", - " means = raw_df[mask][num_cols_radar].mean()\n", - " global_min = raw_df[num_cols_radar].min()\n", - " global_max = raw_df[num_cols_radar].max()\n", - " normed = ((means - global_min) / (global_max - global_min + 1e-9)).values.tolist()\n", - " normed += normed[:1]\n", - "\n", - " ax.plot(angles, normed, color=PALETTE[idx], linewidth=2)\n", - " ax.fill(angles, normed, color=PALETTE[idx], alpha=0.25)\n", - " ax.set_xticks(angles[:-1])\n", - " ax.set_xticklabels(num_cols_radar, size=8)\n", - " ax.set_ylim(0, 1)\n", - " ax.set_title(f\"{p.persona_name}\\n{p.archetype[:18]}\", size=10, pad=14,\n", - " color=PALETTE[idx], fontweight=\"bold\")\n", - "\n", - "plt.suptitle(\"Customer Persona Profiles\", fontsize=15, fontweight=\"bold\", y=1.01)\n", - "plt.tight_layout()\n", - "fig.savefig(OUTPUT_DIR / \"persona_profiles.png\", dpi=150, bbox_inches=\"tight\")\n", - "plt.show()\n", - "print(\"✅ Saved: persona_profiles.png\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cell 17 — Export Results\n", - "Saves labeled dataset (CSV), persona report (JSON), and pipeline metadata." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# ── Export Results ───────────────────────────────────────────────────────────\n", - "\n", - "# 1. Labeled dataset\n", - "cluster_letter_map = {p.cluster_id: p.persona_name for p in personas}\n", - "labeled_df[\"persona\"] = labeled_df[\"cluster_id\"].map(cluster_letter_map).fillna(\"Noise\")\n", - "labeled_df[\"archetype\"] = labeled_df[\"cluster_id\"].map(\n", - " {p.cluster_id: p.archetype for p in personas}\n", - ").fillna(\"N/A\")\n", - "\n", - "output_csv = OUTPUT_DIR / \"labeled_customers.csv\"\n", - "labeled_df.to_csv(output_csv, index=False)\n", - "print(f\"✅ Labeled dataset → {output_csv}\")\n", - "\n", - "# 2. Persona report JSON\n", - "report = {\n", - " \"pipeline_metadata\": {\n", - " \"algorithm\": best_eval.algorithm,\n", - " \"n_clusters\": best_eval.n_clusters,\n", - " \"silhouette_score\": best_eval.silhouette,\n", - " \"davies_bouldin\": best_eval.davies_bouldin,\n", - " \"calinski_harabasz\": best_eval.calinski_harabasz,\n", - " \"top_features\": explain_report.top_features,\n", - " \"ollama_model\": OLLAMA_MODEL,\n", - " \"business_objective\": BUSINESS_OBJECTIVE,\n", - " },\n", - " \"personas\": [\n", - " {\n", - " \"cluster_id\": p.cluster_id,\n", - " \"persona_name\": p.persona_name,\n", - " \"archetype\": p.archetype,\n", - " \"description\": p.description,\n", - " \"key_traits\": p.key_traits,\n", - " \"business_recommendations\": p.business_recommendations,\n", - " \"cluster_size\": p.cluster_size,\n", - " \"cluster_pct\": p.cluster_pct,\n", - " \"top_feature_means\": p.top_features,\n", - " }\n", - " for p in personas\n", - " ],\n", - " \"strategic_grounding\": grounding,\n", - "}\n", - "\n", - "output_json = OUTPUT_DIR / \"persona_report.json\"\n", - "with open(output_json, \"w\") as f:\n", - " json.dump(report, f, indent=2)\n", - "print(f\"✅ Persona report → {output_json}\")\n", - "\n", - "# 3. Per-cluster CSVs\n", - "for p in personas:\n", - " mask = labeled_df[\"cluster_id\"] == p.cluster_id\n", - " out = OUTPUT_DIR / f\"{p.persona_name.replace(' ','_').lower()}_customers.csv\"\n", - " labeled_df[mask].to_csv(out, index=False)\n", - " print(f\"✅ {p.persona_name} customers → {out} ({mask.sum():,} rows)\")\n", - "\n", - "print(f\"\\n🎉 Pipeline complete. All outputs in: {OUTPUT_DIR.resolve()}/\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ✅ Pipeline Architecture Summary\n", - "\n", - "| Step | Module | Description |\n", - "|------|--------|-------------|\n", - "| 1 | **Data Input** | CSV / Parquet / Excel / Synthetic loader with schema inference |\n", - "| 2 | **Feature Engineering** | Imputation → Label encoding → IQR clipping → StandardScaler |\n", - "| 3 | **Clustering Config** | Silhouette-guided k selection over configurable k range |\n", - "| 4 | **K-Means Runner** | Distance-based clustering with k-means++ initialisation |\n", - "| 5 | **DBSCAN Runner** | Density-based clustering; handles irregular cluster shapes |\n", - "| 6 | **GMM Runner** | Probabilistic soft assignment via Expectation-Maximization |\n", - "| 7 | **Cluster Evaluator** | Silhouette + Davies-Bouldin + Calinski-Harabasz; pass/fail gate |\n", - "| 8 | **Modeling Loop** | Retries up to `MAX_ITERATIONS` with reconfiguration on failure |\n", - "| 9 | **Explainability** | Permutation feature importance + PCA loadings + cluster profiles |\n", - "| 10 | **Persona ID (LLM)** | Ollama/llama3 generates archetype, traits, recommendations per cluster |\n", - "| 11 | **Business Grounding** | LLM synthesises executive summary + strategic priorities |\n", - "| 12 | **Export** | Labeled CSV, per-cluster CSVs, full JSON report, PNG plots |\n", - "\n", - "### Local LLM Setup\n", - "```bash\n", - "# 1. Install Ollama\n", - "curl -fsSL https://ollama.com/install.sh | sh\n", - "\n", - "# 2. Start the server\n", - "ollama serve\n", - "\n", - "# 3. Pull the model\n", - "ollama pull llama3\n", - "\n", - "# 4. Run this notebook end-to-end\n", - "```\n", - "\n", - "### Extending the Pipeline\n", - "- **Swap LLM**: Change `OLLAMA_MODEL` to `mistral`, `llama3:70b`, `phi3`, etc.\n", - "- **Real data**: Set `DATA_SOURCE = \"csv\"` and `DATA_PATH = \"your_file.csv\"`\n", - "- **More algorithms**: Add new runner functions following the `run_kmeans` pattern\n", - "- **SHAP values**: Install `shap` and replace `compute_permutation_importance()` with `shap.KernelExplainer`\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.13.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From eb639cf71eb7fd42b061bdf4ed63742886b875a2 Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 13:02:46 +0530 Subject: [PATCH 12/13] Update segplus pipeline and config --- segplus/config.py | 62 ++++++++++++++++++++++++--- segplus/final_segplus_pipeline2.ipynb | 40 +++++++++-------- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/segplus/config.py b/segplus/config.py index e771370..e38c9c9 100644 --- a/segplus/config.py +++ b/segplus/config.py @@ -6,6 +6,7 @@ from pathlib import Path from typing import Optional +import pandas as pd import yaml log = logging.getLogger("segplus.config") @@ -49,14 +50,25 @@ def numerical_columns(self) -> list[str]: def load_domain_config(domain_key: str, domains_dir: Path | None = None) -> DomainConfig: - """Load a domain configuration from YAML.""" + """Load a domain configuration from YAML. Falls back to empty direct-ingest config if missing.""" d = domains_dir or _DOMAINS_DIR yaml_path = d / f"{domain_key}.yaml" if not yaml_path.exists(): - available = [f.stem for f in d.glob("*.yaml") if not f.stem.startswith("_")] - raise FileNotFoundError( - f"Domain '{domain_key}' not found at {yaml_path}. " - f"Available: {available}" + log.warning( + "Domain YAML '%s' not found. Falling back to direct-ingest config (no YAML rules).", + yaml_path, + ) + return DomainConfig( + domain_key=domain_key, + display_name=domain_key.replace("_", " ").title(), + features={}, + required_columns=[], + feature_engineering=[], + eda_analyses=[], + persona_prompt_template="", + scaling_exclude=[], + categorical_columns=[], + metadata={"source": "direct_no_yaml_fallback"}, ) with open(yaml_path, "r", encoding="utf-8") as f: @@ -95,6 +107,46 @@ def list_available_domains(domains_dir: Path | None = None) -> list[str]: return sorted(f.stem for f in d.glob("*.yaml") if not f.stem.startswith("_")) +def build_domain_config_from_dataframe( + df: pd.DataFrame, + domain_key: str = "direct_ingest", + exclude_cols: list[str] | None = None, +) -> DomainConfig: + """ + Build a DomainConfig directly from dataframe schema (no YAML dependency). + This is the recommended path when users provide only an Excel file. + """ + excludes = set(c.lower() for c in (exclude_cols or [])) + cols = [c for c in df.columns if c.lower() not in excludes] + + categorical_cols: list[str] = [] + for c in cols: + s = df[c] + n_unique = s.nunique(dropna=True) + ratio = n_unique / max(len(s), 1) + is_cat = ( + pd.api.types.is_object_dtype(s) + or pd.api.types.is_categorical_dtype(s) + or pd.api.types.is_bool_dtype(s) + or (pd.api.types.is_numeric_dtype(s) and (n_unique <= 10 and ratio < 0.05)) + ) + if is_cat: + categorical_cols.append(c) + + return DomainConfig( + domain_key=domain_key, + display_name=domain_key.replace("_", " ").title(), + features={"all": cols}, + required_columns=[], + feature_engineering=[], + eda_analyses=[], + persona_prompt_template="", + scaling_exclude=[], + categorical_columns=categorical_cols, + metadata={"source": "direct_dataframe_schema"}, + ) + + # ── Pipeline Config ────────────────────────────────────────────────────────── @dataclass diff --git a/segplus/final_segplus_pipeline2.ipynb b/segplus/final_segplus_pipeline2.ipynb index d2b827e..f4d8652 100644 --- a/segplus/final_segplus_pipeline2.ipynb +++ b/segplus/final_segplus_pipeline2.ipynb @@ -98,8 +98,8 @@ "if str(project_root) not in sys.path:\n", " sys.path.insert(0, str(project_root))\n", "\n", - "from segplus.config import PipelineConfig, load_domain_config\n", - "from segplus.data_input import import_and_validate\n", + "from segplus.config import PipelineConfig, build_domain_config_from_dataframe\n", + "from segplus.data_input import load_data, infer_schema, validate_schema\n", "from segplus.feature_engineering import FeatureEngineer\n", "from segplus.modeling_loop import modeling_loop\n", "from segplus.evaluation import run_stability_test\n", @@ -146,20 +146,21 @@ } ], "source": [ - "# Configuration (edit these as needed)\n", + "# Configuration (Excel direct-ingest, no domain YAML)\n", "default_data_path = project_root / \"final_enterprise_clustering_dataset_single_sheet.xlsx\"\n", "default_output_dir = project_root / \"segplus_output\"\n", "\n", "config = PipelineConfig(\n", " data_path=str(default_data_path),\n", - " domain_key=\"financial_services\", # or \"retail\"\n", + " domain_key=\"direct_ingest\",\n", " sheet_name=None,\n", " k_range=(2, 8),\n", " max_iterations=5,\n", " pca_variance_threshold=0.85,\n", " output_dir=str(default_output_dir),\n", - " ollama_host=\"http://localhost:11434\", # local Ollama endpoint\n", - " ollama_model=\"qwen2.5:7b\", # primary local model`n ollama_timeout=240,\n", + " ollama_host=\"http://localhost:11434\",\n", + " ollama_model=\"qwen2.5:7b\",\n", + " ollama_timeout=240,\n", " business_objective=(\n", " \"Identify distinct customer segments to personalise marketing campaigns, \"\n", " \"improve retention for high-value customers, and convert mid-tier customers \"\n", @@ -180,14 +181,10 @@ "output_dir = Path(config.output_dir)\n", "output_dir.mkdir(parents=True, exist_ok=True)\n", "\n", - "domain_config = load_domain_config(config.domain_key, domains_dir=project_root / \"domains\")\n", - "print(\"Domain:\", domain_config.display_name)\n", "print(\"Data:\", config.data_path)\n", "print(\"Output:\", output_dir)\n", "print(\"Ollama host:\", config.ollama_host)\n", - "print(\"Primary LLM:\", config.ollama_model)\n", - "\n", - "\n" + "print(\"Primary LLM:\", config.ollama_model)\n" ] }, { @@ -217,19 +214,26 @@ } ], "source": [ - "# 1) Data Input + Validation\n", - "df_raw, quality_report, schema = import_and_validate(\n", - " file_path=config.data_path,\n", - " domain_config=domain_config,\n", - " auto_map=True,\n", - " sheet_name=config.sheet_name,\n", + "# 1) Data Input + Validation (no YAML)\n", + "df_raw = load_data(config.data_path, sheet_name=config.sheet_name)\n", + "\n", + "# Build domain config directly from dataframe schema\n", + "_domain_key = config.domain_key if config.domain_key else \"direct_ingest\"\n", + "domain_config = build_domain_config_from_dataframe(\n", + " df_raw,\n", + " domain_key=_domain_key,\n", + " exclude_cols=config.exclude_cols,\n", ")\n", "\n", + "schema = infer_schema(df_raw)\n", + "quality_report = validate_schema(df_raw, domain_config, schema)\n", + "\n", "print(quality_report.summary())\n", "if not quality_report.passed:\n", " raise ValueError(\"Data quality checks failed. Fix input data and rerun.\")\n", "\n", - "print(\"Raw shape:\", df_raw.shape)\n" + "print(\"Raw shape:\", df_raw.shape)\n", + "print(\"Inferred categorical columns:\", domain_config.categorical_columns[:15])\n" ] }, { From 07338d2f273ab49fb69b1c7d4395b2bc86f0e1ca Mon Sep 17 00:00:00 2001 From: umairahmed0912 Date: Mon, 9 Mar 2026 13:09:40 +0530 Subject: [PATCH 13/13] Update final segplus pipeline notebook --- segplus/final_segplus_pipeline2.ipynb | 153 ++++++++++++-------------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/segplus/final_segplus_pipeline2.ipynb b/segplus/final_segplus_pipeline2.ipynb index f4d8652..22bec32 100644 --- a/segplus/final_segplus_pipeline2.ipynb +++ b/segplus/final_segplus_pipeline2.ipynb @@ -2,6 +2,7 @@ "cells": [ { "cell_type": "markdown", + "id": "c0c4075e", "metadata": {}, "source": [ "# SegPlus Final End-to-End Pipeline\n", @@ -137,7 +138,6 @@ "name": "stdout", "output_type": "stream", "text": [ - "Domain: Financial Services\n", "Data: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\final_enterprise_clustering_dataset_single_sheet.xlsx\n", "Output: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\n", "Ollama host: http://localhost:11434\n", @@ -197,8 +197,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-06 22:49:51,635 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n", - "2026-03-06 22:49:51,833 | INFO | segplus.data_input | Data quality: PASSED\n" + "2026-03-09 12:43:26,707 | INFO | segplus.data_input | Loaded final_enterprise_clustering_dataset_single_sheet.xlsx: 120000 rows x 27 cols\n" ] }, { @@ -209,7 +208,8 @@ " Rows: 120,000 | Columns: 27\n", " Duplicates: 0\n", " Status: PASSED\n", - "Raw shape: (120000, 27)\n" + "Raw shape: (120000, 27)\n", + "Inferred categorical columns: ['delinquency_flag_x', 'CreditCard', 'Investment', 'Loan']\n" ] } ], @@ -246,13 +246,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-06 22:49:51,888 | WARNING | segplus.feature_engineering | FE rule 'wealth_tier' failed: name 'investment_portfolio_value' is not defined\n", - "2026-03-06 22:49:51,902 | WARNING | segplus.feature_engineering | FE rule 'digital_vs_branch_ratio' failed: name 'digital_engagement_score' is not defined\n", - "2026-03-06 22:49:51,918 | WARNING | segplus.feature_engineering | FE rule 'product_depth' failed: name 'has_credit_card' is not defined\n", - "2026-03-06 22:49:51,926 | WARNING | segplus.feature_engineering | FE rule 'spending_to_income_ratio' failed: name 'monthly_spending' is not defined\n", - "2026-03-06 22:49:51,942 | WARNING | segplus.feature_engineering | FE rule 'risk_category' failed: name 'debt_to_income_ratio' is not defined\n", - "2026-03-06 22:49:52,618 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", - "2026-03-06 22:49:52,619 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" + "2026-03-09 12:43:27,584 | INFO | segplus.feature_engineering | PCA: 7 components explain 87.2% variance\n", + "2026-03-09 12:43:27,585 | INFO | segplus.feature_engineering | Feature engineering complete: 26 features -> 7-dim output\n" ] }, { @@ -374,22 +369,22 @@ " ^^^^\n", " startupinfo)\n", " ^^^^^^^^^^^^\n", - "2026-03-06 22:49:58,214 | INFO | segplus.clustering | K search: scores={2: np.float64(0.202), 3: np.float64(0.2145), 4: np.float64(0.1609), 5: np.float64(0.1639), 6: np.float64(0.1444), 7: np.float64(0.1399), 8: np.float64(0.141)} | best k=3 (sil=0.2145)\n", - "2026-03-06 22:50:00,159 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", - "2026-03-06 22:50:00,161 | INFO | segplus.modeling_loop | ============================================================\n", - "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", - "2026-03-06 22:50:00,162 | INFO | segplus.modeling_loop | ============================================================\n", - "2026-03-06 22:50:00,815 | INFO | segplus.clustering | [kmeans] clusters=3\n", - "2026-03-06 22:50:25,748 | INFO | segplus.clustering | [dbscan] clusters=178\n", - "2026-03-06 22:50:44,501 | INFO | segplus.clustering | [gmm] clusters=3\n", - "2026-03-06 22:50:44,663 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2115 | DB=1.5251 | CH=31125.2 | cov=1.00\n", - "2026-03-06 22:50:44,946 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.2252 | DB=0.8652 | CH=142.0 | cov=1.00\n", - "2026-03-06 22:50:45,068 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0667 | DB=3.5552 | CH=13484.7 | cov=1.00\n", - "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", - "2026-03-06 22:50:45,071 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", - "2026-03-06 22:50:45,072 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2115 pass=True\n", - "2026-03-06 22:50:45,073 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2115 | DB=1.5251 | PASS=True\n", - "2026-03-06 22:50:45,074 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" + "2026-03-09 12:43:30,308 | INFO | segplus.clustering | K search: scores={2: np.float64(0.1996), 3: np.float64(0.2036), 4: np.float64(0.1656), 5: np.float64(0.1648), 6: np.float64(0.1443), 7: np.float64(0.1333), 8: np.float64(0.1348)} | best k=3 (sil=0.2036)\n", + "2026-03-09 12:43:31,440 | INFO | segplus.clustering | DBSCAN eps estimated: 1.661 (knee at index 119999)\n", + "2026-03-09 12:43:31,442 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-09 12:43:31,442 | INFO | segplus.modeling_loop | Modeling Loop - Iteration 1/5 | k=3\n", + "2026-03-09 12:43:31,443 | INFO | segplus.modeling_loop | ============================================================\n", + "2026-03-09 12:43:31,810 | INFO | segplus.clustering | [kmeans] clusters=3\n", + "2026-03-09 12:43:48,045 | INFO | segplus.clustering | [dbscan] clusters=178\n", + "2026-03-09 12:44:03,897 | INFO | segplus.clustering | [gmm] clusters=3\n", + "2026-03-09 12:44:04,007 | INFO | segplus.evaluation | [kmeans] k=3 | sil=0.2117 | DB=1.5251 | CH=31125.2 | cov=1.00\n", + "2026-03-09 12:44:04,207 | INFO | segplus.evaluation | [dbscan] k=178 | sil=-0.1921 | DB=0.8652 | CH=142.0 | cov=1.00\n", + "2026-03-09 12:44:04,304 | INFO | segplus.evaluation | [gmm] k=3 | sil=0.0720 | DB=3.5552 | CH=13484.7 | cov=1.00\n", + "2026-03-09 12:44:04,304 | INFO | segplus.evaluation | Composite ranking: kmeans=0.875 | dbscan=0.325 | gmm=0.300\n", + "2026-03-09 12:44:04,305 | INFO | segplus.evaluation | Winner: kmeans (composite=0.875)\n", + "2026-03-09 12:44:04,305 | INFO | segplus.experiment_log | Experiment 1: kmeans k=3 sil=0.2117 pass=True\n", + "2026-03-09 12:44:04,306 | INFO | segplus.modeling_loop | Best: kmeans | sil=0.2117 | DB=1.5251 | PASS=True\n", + "2026-03-09 12:44:04,306 | INFO | segplus.modeling_loop | Evaluation PASSED on iteration 1.\n" ] }, { @@ -398,7 +393,7 @@ "text": [ "Best algorithm: kmeans\n", "Clusters: 3\n", - "Silhouette: 0.2115\n", + "Silhouette: 0.2117\n", "Davies-Bouldin: 1.5251\n", "Passes gate: True\n" ] @@ -442,13 +437,13 @@ " \n", " 0\n", " 1\n", - " 2026-03-06T22:50:45.072458\n", + " 2026-03-09T12:44:04.305923\n", " 3\n", " 1.661\n", " full\n", " kmeans\n", " 3\n", - " 0.2115\n", + " 0.2117\n", " 1.5251\n", " 31125.2\n", " True\n", @@ -460,10 +455,10 @@ ], "text/plain": [ " iteration timestamp k eps gmm_cov best_algorithm \\\n", - "0 1 2026-03-06T22:50:45.072458 3 1.661 full kmeans \n", + "0 1 2026-03-09T12:44:04.305923 3 1.661 full kmeans \n", "\n", " n_clusters silhouette davies_bouldin calinski_harabasz passed \\\n", - "0 3 0.2115 1.5251 31125.2 True \n", + "0 3 0.2117 1.5251 31125.2 True \n", "\n", " reconfig_strategy \n", "0 None " @@ -505,14 +500,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-06 22:50:57,856 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", - "2026-03-06 22:50:57,859 | INFO | segplus.explainability | Computing feature importances...\n", - "2026-03-06 22:51:08,907 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", - "2026-03-06 22:51:08,940 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", - "2026-03-06 22:51:08,944 | INFO | segplus.explainability | Computing PCA loadings...\n", - "2026-03-06 22:51:08,945 | INFO | segplus.explainability | Computing inertia curve...\n", - "2026-03-06 22:51:12,627 | INFO | segplus.explainability | Computing cluster profiles...\n", - "2026-03-06 22:51:12,729 | INFO | segplus.explainability | Building ordered convergence drivers...\n" + "2026-03-09 12:44:11,558 | INFO | segplus.evaluation | Stability (kmeans): ARI=0.988 +/- 0.006 (threshold=0.70, stable=True)\n", + "2026-03-09 12:44:11,561 | INFO | segplus.explainability | Computing feature importances...\n", + "2026-03-09 12:44:18,121 | WARNING | segplus.explainability | TreeSHAP failed (only length-1 arrays can be converted to Python scalars), falling back to RF feature_importances_\n", + "2026-03-09 12:44:18,142 | INFO | segplus.explainability | Feature importance computed via RF feature_importances_\n", + "2026-03-09 12:44:18,146 | INFO | segplus.explainability | Computing PCA loadings...\n", + "2026-03-09 12:44:18,146 | INFO | segplus.explainability | Computing inertia curve...\n", + "2026-03-09 12:44:20,124 | INFO | segplus.explainability | Computing cluster profiles...\n", + "2026-03-09 12:44:20,189 | INFO | segplus.explainability | Building ordered convergence drivers...\n" ] }, { @@ -872,24 +867,19 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-06 22:51:17,003 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", - "2026-03-06 22:53:19,121 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 22:54:37,832 | INFO | segplus.ollama_client | Ollama response received (534 chars)\n", - "2026-03-06 22:55:12,181 | INFO | segplus.ollama_client | Ollama response received (14 chars)\n", - "2026-03-06 22:55:12,184 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'Elite Spenders'\n", - "2026-03-06 22:55:12,202 | INFO | segplus.persona_generation | Persona generated: Cluster A -> Elite Spenders\n", - "2026-03-06 22:57:14,441 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 22:57:55,579 | INFO | segplus.ollama_client | Ollama response received (551 chars)\n", - "2026-03-06 22:58:37,127 | INFO | segplus.ollama_client | Ollama response received (17 chars)\n", - "2026-03-06 22:58:37,130 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", - "2026-03-06 23:00:39,228 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 23:02:14,255 | INFO | segplus.ollama_client | Ollama response received (839 chars)\n", - "2026-03-06 23:02:50,674 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", - "2026-03-06 23:02:50,678 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", - "2026-03-06 23:02:50,721 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", - "2026-03-06 23:04:52,791 | WARNING | segplus.ollama_client | Ollama attempt 1 failed (Timeout after 120s). Retrying in 2s...\n", - "2026-03-06 23:06:56,881 | WARNING | segplus.ollama_client | Ollama attempt 2 failed (Timeout after 120s). Retrying in 4s...\n", - "2026-03-06 23:09:02,941 | WARNING | segplus.persona_generation | Business grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n" + "2026-03-09 12:44:24,482 | INFO | segplus.ollama_client | Ollama reachable. Model 'qwen2.5:7b' available.\n", + "2026-03-09 12:47:02,703 | INFO | segplus.ollama_client | Ollama response received (695 chars)\n", + "2026-03-09 12:47:26,233 | INFO | segplus.ollama_client | Ollama response received (12 chars)\n", + "2026-03-09 12:47:26,236 | INFO | segplus.persona_generation | Focused naming for Cluster A: 'High Rollers'\n", + "2026-03-09 12:47:26,247 | INFO | segplus.persona_generation | Persona generated: Cluster A -> High Rollers\n", + "2026-03-09 12:49:15,034 | INFO | segplus.ollama_client | Ollama response received (625 chars)\n", + "2026-03-09 12:49:39,299 | INFO | segplus.ollama_client | Ollama response received (18 chars)\n", + "2026-03-09 12:49:39,307 | INFO | segplus.persona_generation | Persona generated: Cluster B -> Credit Risk Strategists\n", + "2026-03-09 12:51:31,781 | INFO | segplus.ollama_client | Ollama response received (659 chars)\n", + "2026-03-09 12:51:54,394 | INFO | segplus.ollama_client | Ollama response received (16 chars)\n", + "2026-03-09 12:51:54,396 | INFO | segplus.persona_generation | Persona generated: Cluster C -> Credit Risk Strategists\n", + "2026-03-09 12:51:54,421 | INFO | segplus.persona_generation | Grounding personas in business objective...\n", + "2026-03-09 12:55:23,911 | INFO | segplus.ollama_client | Ollama response received (2919 chars)\n" ] }, { @@ -897,7 +887,7 @@ "output_type": "stream", "text": [ "Generated personas: 3\n", - "Executive summary: LLM grounding failed: Ollama failed after 3 attempts: Timeout after 120s\n", + "Executive summary: Our analysis reveals three distinct customer segments: High Rollers, Credit Risk Strategists with Higher Credit Scores, and Credit Risk Strategists with Lower Credit Scores. High Rollers represent the highest value and should be prioritized for premium product offerings. Credit Risk Strategists with Higher Credit Scores are loyal and should be retained through personalized loyalty programs. Lower Credit Score Strategists present a risk but have potential for growth through targeted credit enhancement programs.\n", "persona_df columns: ['cluster', 'genai_persona_name', 'profile_descriptor', 'description', 'cluster_size', 'cluster_pct', 'ordered_top_features', 'genai_recommendations', 'categorization_basis', 'naming_rationale']\n" ] }, @@ -938,13 +928,13 @@ " \n", " 0\n", " Cluster A\n", - " Elite Spenders\n", + " High Rollers\n", " High Value Score & High Monthly Spend Y\n", " High-Value Premium Spenders are among the most...\n", " 8774\n", " 0.0731\n", " value_score:0.1, monthly_spend_y:25414.84, mon...\n", - " Targeted Upselling of Premium Products | Perso...\n", + " Tailor premium offers and services to enhance ...\n", " value_score, monthly_spend_y, monthly_spend_x,...\n", " Second-pass focused LLM naming from profile: H...\n", " \n", @@ -953,11 +943,11 @@ " Cluster B\n", " Credit Risk Strategists – Higher Credit Score ...\n", " High Credit Score & Low Risk Score\n", - " These customers are highly creditworthy and lo...\n", + " Creditworthy Loyalists are high-income, low-ri...\n", " 56782\n", " 0.4732\n", " credit_score:827.07, credit_score_cluster:827....\n", - " Target with premium product promotions | Enhan...\n", + " Target with premium product promotions | Offer...\n", " credit_score, credit_score_cluster, risk_score...\n", " LLM returned generic name; using business-styl...\n", " \n", @@ -966,11 +956,11 @@ " Cluster C\n", " Credit Risk Strategists – Lower Credit Score C...\n", " Low Credit Score & High Risk Score\n", - " Budget-conscious Credit Risk Takers are custom...\n", + " These customers have slightly lower credit sco...\n", " 54444\n", " 0.4537\n", " credit_score:692.54, credit_score_cluster:692....\n", - " Offer tailored credit products with flexible t...\n", + " Offer personalized financial education and bud...\n", " credit_score, credit_score_cluster, risk_score...\n", " LLM returned generic name; using business-styl...\n", " \n", @@ -980,7 +970,7 @@ ], "text/plain": [ " cluster genai_persona_name \\\n", - "0 Cluster A Elite Spenders \n", + "0 Cluster A High Rollers \n", "1 Cluster B Credit Risk Strategists – Higher Credit Score ... \n", "2 Cluster C Credit Risk Strategists – Lower Credit Score C... \n", "\n", @@ -991,8 +981,8 @@ "\n", " description cluster_size \\\n", "0 High-Value Premium Spenders are among the most... 8774 \n", - "1 These customers are highly creditworthy and lo... 56782 \n", - "2 Budget-conscious Credit Risk Takers are custom... 54444 \n", + "1 Creditworthy Loyalists are high-income, low-ri... 56782 \n", + "2 These customers have slightly lower credit sco... 54444 \n", "\n", " cluster_pct ordered_top_features \\\n", "0 0.0731 value_score:0.1, monthly_spend_y:25414.84, mon... \n", @@ -1000,9 +990,9 @@ "2 0.4537 credit_score:692.54, credit_score_cluster:692.... \n", "\n", " genai_recommendations \\\n", - "0 Targeted Upselling of Premium Products | Perso... \n", - "1 Target with premium product promotions | Enhan... \n", - "2 Offer tailored credit products with flexible t... \n", + "0 Tailor premium offers and services to enhance ... \n", + "1 Target with premium product promotions | Offer... \n", + "2 Offer personalized financial education and bud... \n", "\n", " categorization_basis \\\n", "0 value_score, monthly_spend_y, monthly_spend_x,... \n", @@ -1117,15 +1107,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-06 23:09:06,354 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", - "2026-03-06 23:09:06,629 | INFO | segplus.visualization | Saved: feature_importance.png\n", - "2026-03-06 23:09:38,632 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", - "2026-03-06 23:09:39,175 | INFO | segplus.visualization | Saved: pca_loadings.png\n", - "2026-03-06 23:09:39,422 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", - "2026-03-06 23:09:39,526 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", - "2026-03-06 23:09:40,057 | INFO | segplus.visualization | Saved: persona_radar.png\n", - "2026-03-06 23:09:40,212 | INFO | segplus.visualization | Saved: experiment_history.png\n", - "2026-03-06 23:09:40,356 | INFO | segplus.visualization | Saved: elbow_curve.png\n" + "2026-03-09 12:55:27,692 | INFO | segplus.visualization | Saved: cluster_scatter.png\n", + "2026-03-09 12:55:32,434 | INFO | segplus.visualization | Saved: feature_importance.png\n", + "2026-03-09 12:56:01,854 | INFO | segplus.visualization | Saved: shap_summary.png, shap_summary_bar.png, shap_interpretation.csv\n", + "2026-03-09 12:56:03,099 | INFO | segplus.visualization | Saved: pca_loadings.png\n", + "2026-03-09 12:56:03,653 | INFO | segplus.visualization | Saved: cluster_profiles.png\n", + "2026-03-09 12:56:03,848 | INFO | segplus.visualization | Saved: cluster_sizes.png\n", + "2026-03-09 12:56:04,758 | INFO | segplus.visualization | Saved: persona_radar.png\n", + "2026-03-09 12:56:05,102 | INFO | segplus.visualization | Saved: experiment_history.png\n", + "2026-03-09 12:56:05,498 | INFO | segplus.visualization | Saved: elbow_curve.png\n" ] }, { @@ -1171,7 +1161,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-06 23:09:42,767 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" + "2026-03-09 12:56:08,644 | INFO | segplus.experiment_log | Experiment log saved: c:\\Users\\UmairAhmed\\OneDrive - Blend 360\\Documents\\Segmentation_Plus\\segplus_output\\experiment_log.json\n" ] }, { @@ -1270,6 +1260,7 @@ }, { "cell_type": "markdown", + "id": "772cf844", "metadata": {}, "source": [ "## Notes\n",