# Possibilistic C-Means (PCM) > **Robust soft clustering via typicalities, less sensitive to noise and outliers than standard FCM.** --- ## 🔍 Overview **Possibilistic C-Means (PCM)** assigns each sample a **typicality** value per cluster (not forced to sum to 1). By decoupling cluster competition, PCM becomes more robust to outliers: atypical points get low typicalities across all clusters rather than being forced to belong somewhere. --- ## ⚙️ Class Definition ```python class soft_clustering.PCM( random_state: int = None, m: float = 2.0, alpha: float = 1.0, max_iter: int = 300, tol: float = 1e-5, init: str = 'kmeans++' ) ``` [🔗 Source on GitHub](https://github.com/soft-clustering/soft-clustering/blob/main/soft_clustering/_pcm.py) --- ## 📋 Parameters | Parameter | Type | Default | Description | |-----------------|--------|-----------|---------------------------------------------------------------------------------------------| | `random_state` | int | None | Seed for reproducible initialization and randomness. | | `m` | float | 2.0 | Fuzzifier (>1). Larger values yield softer typicalities. | | `alpha` | float | 1.0 | Scale factor in the update of per-cluster spread parameters `eta_k` (stability/robustness). | | `max_iter` | int | 300 | Maximum number of update iterations. | | `tol` | float | 1e-5 | Convergence tolerance on absolute improvement of the objective. | | `init` | str | 'kmeans++'| Initialization strategy for centers: `'kmeans++'` or `'random'`. | --- ## 🚀 Usage Examples ```python from soft_clustering import PCM import numpy as np np.random.seed(42) n = 50 X1 = np.random.randn(n, 2) * 0.25 + np.array([0.0, 0.0]) X2 = np.random.randn(n, 2) * 0.25 + np.array([2.5, 2.5]) X = np.vstack([X1, X2]) K = 2 # number of clusters model = PCM(random_state=42, max_iter=100, m=2.0, alpha=1.0, init='kmeans++') typicalities = model.fit_predict(X, K) print("Typicality matrix:\n", typicalities) ``` --- ## 📥 Input / 📤 Output - **Input to `fit_predict(X, K)`** - `X (np.ndarray or scipy.sparse)` of shape `(n_samples, n_features)`; sparse inputs are densified internally. - `K (int)`: number of clusters. - **Returns** - `typicalities (np.ndarray)` of shape `(n_samples, K)`: possibilistic typicality degrees per sample (rows are **not** constrained to sum to 1). --- ## 🛠️ Methods ### `fit_predict(X, K)` Fit the PCM model on the provided dataset and return the **typicality matrix**. PCM alternates between: (1) updating cluster centers using typicalities as weights, (2) updating per-cluster spreads `eta_k`, and (3) recomputing typicalities. **Parameters:** * `X` (`numpy.ndarray` or `scipy.sparse`, shape `(n_samples, n_features)`): Input data matrix. If sparse, it is converted to dense internally. * `K` (`int`): Number of clusters. **Returns:** * `typicalities` (`np.ndarray`, shape `(n_samples, K)`): Possibilistic typicality degrees per sample (not row-normalized). **Attributes set on the model:** * `centers_` (`np.ndarray`, shape `(K, n_features)`): Final cluster centers. * `typicalities_` (`np.ndarray`, shape `(n_samples, K)`): Final typicality matrix (same as return). * `etas_` (`np.ndarray`, shape `(K,)`): Per-cluster spread parameters. * `objective_trajectory_` (`np.ndarray`, shape `(t,)`): Objective values per iteration. [🔗 Source definition](https://github.com/soft-clustering/soft-clustering/blob/main/soft_clustering/_pcm.py) --- ## 📝 Implementation Notes - **Objective:** combines (i) typicality-weighted squared distances to centers and (ii) a penalty that discourages large typicalities away from centers via per-cluster scales `eta_k`. - **Alternating updates:** - Update **centers** as typicality-weighted means (using `typicality^m`). - Update **etas** from the current typicalities and within-cluster distances (scaled by `alpha`). - Update **typicalities** using current centers and `eta_k`; typicalities are clipped to `(0, 1]`. - **Not row-normalized:** typicalities do **not** have to sum to 1 across clusters (key difference from FCM). - **Numerical stability:** small epsilon added to denominators and distances; typicalities are clipped to avoid zeros; `eta_k` lower-bounded. - **Initialization:** centers via `'kmeans++'` (default) or `'random'`; initial `eta_k` from average within-cluster squared distances. - **Convergence:** stop when absolute improvement in objective ≤ `tol`, or after `max_iter`. - **Complexity (per iteration):** roughly `O(n * K * d)` time; memory `O(n * K + K * d)`. --- ## 📚 References 1. R. Krishnapuram, J. M. Keller (1993). **A Possibilistic Approach to Clustering.** *IEEE Transactions on Fuzzy Systems*, 1(2), 98–110.