pip install ruptures★Pure-Python + a fast C kernel backend.conda install -c conda-forge rupturesSame package via conda-forge.import ruptures as rpt★The one import you need — all algos hang offrpt.from ruptures.metrics import precision_recallAlsohausdorff,randindex,meantime.
# shape (n_samples,) or (n_samples, n_dim)★Any 1-D or multivariate NumPy array.signal, bkps = rpt.pw_constant(n, dim, n_bkps, noise_std=2)★Piecewise-constant toy signal + true bkps.rpt.pw_linear(n, dim, n_bkps)Piecewise-linear (slope changes).rpt.pw_normal(n, n_bkps)2-D Gaussian — correlation flips (distribution).rpt.pw_wavy(n, n_bkps)Alternating sinusoid frequencies.# offline only — whole signal at oncenoteruptures is not streaming/online.
algo = rpt.Pelt(model="rbf").fit(signal)★Build a detector & precompute over the signal.bkps = algo.predict(pen=10)★Detect — returns segment-end indices.bkps = algo.fit_predict(signal, pen=10)Fit + predict in one call.rpt.display(signal, bkps); plt.show()★Eyeball the segmentation.
rpt.Pelt(model=…)★Exact + near-linear time (pruning). Unknown K viapen.rpt.Dynp(model=…)Exact optimum by dynamic programming — needsn_bkps. Slowest.rpt.Binseg(model=…)★Greedy recursive split — fast, approximate.rpt.BottomUp(model=…)Start over-segmented, merge up. Approximate.rpt.Window(width=40, model=…)Sliding-window discrepancy scan. Fast.rpt.KernelCPD(kernel="rbf")★C-accelerated; kernelslinear·rbf·cosine.
model="l2"★Mean shift (least squares) — fastest.model="l1"Median shift — robust to outliers.model="normal"Mean and variance (Gaussian).model="rbf"★Distribution change — non-parametric kernel.model="linear"Shift in a linear regression relationship.model="ar"Autoregressive coefficient change.model="rank" · "mahalanobis"Rank-based & Mahalanobis metrics.
.predict(n_bkps=5)★Known count — Dynp / Binseg / KernelCPD..predict(pen=10)★Penalty for unknown count — Pelt / Binseg / BottomUp / Window..predict(epsilon=100)Stop when total residual drops below a budget.pen = np.log(n) * dim * sigma**2A sensible BIC-flavoured starting penalty.# pass exactly ONE of the threemustn_bkps / pen / epsilon are mutually exclusive.
rpt.Pelt(min_size=2)★Floor on samples between change points.rpt.Pelt(jump=5)★Only test indices atk, 2k, 3k…— ↑ = faster, coarser.params={"gamma": 1.0}RBF bandwidth (else median heuristic).params={"order": 4}Lag order formodel="ar".# KernelCPD: jump is fixed at 1noteChanging it doesn't help the C backend.
bkps = [120, 250, 480, 500]★Each value = end index of a regime.bkps[-1] == len(signal)★The last entry is always the signal length.# segments = len(bkps); changes = len(bkps) - 1One fewer change than segments.np.split(signal, bkps[:-1])Slice the signal into its regimes.
rpt.display(signal, bkps)★Alternating shaded regimes.rpt.display(signal, true_bkps, pred_bkps)★Shading = truth · vertical lines = predicted.fig, axes = rpt.display(signal, bkps, figsize=(10,6))Returns Matplotlib objects to tweak.
precision_recall(true, pred, margin=10)★Hit if a pred is withinmarginof a true cp.hausdorff(true, pred)Worst-case distance between change points.randindex(true, pred)Segmentation agreement in[0, 1].meantime(true, pred)Mean distance to the nearest true cp.# all take bkps lists ending in nnoteSame formatpredict()returns.
class MyCost(rpt.base.BaseCost):Subclass to define a bespoke change.model = "" ; min_size = 2Required class attributes.def fit(self, signal): … ; def error(self, s, e):Precompute, then return a segment's cost.rpt.Pelt(custom_cost=MyCost())Plug it into any search method.
# higher pen ⇒ fewer breakpoints★It's the over-segmentation dial.pen0 = np.log(n) * dim * sigma**2BIC-style anchor; scale up/down from here.# sweep pen, plot n_bkps vs penLook for the elbow / stable plateau.# or just fix n_bkps if you know itSidesteps penalty tuning entirely.
# know the # of changes→ Dynp · KernelCPD · Binseg(n_bkps)# don't know the count→ Pelt · Binseg (pen)# need speed / long signal→ KernelCPD · Binseg · Window# need the exact optimum→ Dynp · Pelt# mean shift→model="l2"# distribution / non-linear→model="rbf"(or KernelCPD)