Mathematics
An Elbow, or Nothing
elbow-helper detects the elbows of diminishing-returns curves, with quantified uncertainty. When the evidence is missing, it abstains.

How many clusters should an automatic classification keep? When should a model stop training? At what budget does an advertising channel saturate? These three questions share one silhouette: a curve of diminishing returns, rising fast then flattening out. The point where it stops paying off has an anatomical name: the elbow, or knee. Before it, every extra unit earns its keep; past it, you are just insisting.
Finding that point looks easy, and that is the trap: an elbow-detection algorithm always answers something, even on a perfect straight line or on pure noise. elbow-helper asks a harder question: is this candidate strong, unique, persistent, reproducible, and unlikely under a no-elbow model? If a single one of those conditions fails, it abstains and says why.
The textbook case: k-means inertia against the number of clusters. The detected elbow, its confidence interval, and the quantified evidence beside it.
Motivation
Existing heuristics, starting with the Kneedle algorithm that serves as the reference, are excellent at proposing a location. They carry no notion of confidence, though: a point, with no error bar, no probability, no right to withdraw. On a noisy curve, that lone point is easy to over-trust: you pick four clusters, size a cache, stop an experiment, on the strength of a noise artifact.
A radiologist looking at a blurry scan does not diagnose; they write that the image does not support a conclusion and order a second scan. A statistical procedure facing a noisy curve deserves the same restraint: conclude only what the data supports. The parallel has its limit, and the limit is instructive: the radiologist exercises judgment, while the procedure applies thresholds calibrated once and for all, which makes it more predictable and less subtle at the same time.
elbow-helper's design priority is therefore
explicit: minimize false elbows, even at the cost of more abstentions. The output contract forces the
calling code to face this: either a ClearKnee with a position, a 90%
confidence interval and quantified evidence, or a NoClearKnee with a
machine-readable reason code. No silent fallback to a doubtful estimate: abstention is handled, never
bypassed.
How it works
It starts with an honest definition of the word "elbow". Take a curve shaped like \(\sqrt{x}\), rising fast then settling down, and subtract the diagonal joining its two endpoints: what remains is a bump, zero at both ends, largest where the curve pulls hardest away from a straight line. That peak is the elbow. After normalizing the data to the unit square, the difference curve reads:
Its local maxima are the candidates. A sensitivity threshold then decides whether a peak is a real elbow or a mere wiggle: the candidate must dominate its neighborhood by a margin proportional to a parameter \(S\):
where the bar denotes the mean spacing between consecutive x values. The larger \(S\), the wider the required margin. This search is replayed over a whole grid of smoothing windows and sensitivities, and only candidates that come back at the same place across scales survive: a real elbow persists when the curve is blurred a little, a noise accident vanishes.
Then comes model confirmation. A real elbow is a change of slope: a straight line, then a different slope past the point \(k\). The hinge function \(\max(0, x - k)\), exactly zero before \(k\) and linear after, builds that broken line in one piece, with no jump:
The coefficient \(c\) carries the whole story of the bend: \(c = 0\) gives back a plain line with no elbow at all, and the further \(c\) sits from zero, the sharper the slope breaks at \(k\). This broken model must beat the plain line on two counts. First under blocked cross-validation: whole contiguous chunks of the curve are held out, and the model must predict the hidden chunks well, a single held-out point being too easy to guess from its immediate neighbors. Second under the BIC (Bayesian Information Criterion), a score that rewards goodness of fit while charging for every extra parameter: the elbow has to earn its place.
Two robustness trials remain. The bootstrap: the entire search is replayed on copies of the curve obtained by reshuffling the residual noise, and the elbow must be redetected in at least 90% of the replays, at the same place, with a tight interval. And the null test: thousands of pure straight lines carrying the same noise level are simulated, measuring the probability \(p\) that a line with no elbow at all would produce, by chance, evidence as strong as the one observed. Both bars must clear:
Only a candidate that clears every gate
becomes a ClearKnee. The diagnostic figure lays that case file out next
to the curve; on abstention, it switches to an honest state, curve grayed out and reason displayed,
never a marker implying more certainty than the data contains.
The same subtle elbow, at two noise levels: detected and bracketed on the left, an owned abstention on the right.
And when the curve changes regime several
times, three pricing tiers on a demand curve say, the question becomes: how many breaks, and where?
robust_knees answers it by exploring every number of segments with
dynamic programming, ranking candidates with a modified BIC where each extra break must earn its cost,
then confirming the winner with a permutation test: thousands of reshuffles of the curve, none carrying
any true break, must almost all do worse than the real fit. Since running more tests means more chances
to get lucky, a Bonferroni correction tightens each test's bar in proportion to how many are run.
The whole thing stands on a single
computational dependency, NumPy: the locator is rewritten from scratch, and the diagnostic figure is
hand-authored SVG, with no plotting library. Every formula in the chain, from normalization to the
permutation test, is derived step by step in the repository's mathematical note (doc/ELBOW-en.tex), written intuition-first, with a worked example before
every formula.
Conclusion
A detector that abstains serves you better than a detector that always answers. "No clear elbow" is real information: it keeps you from sizing a system, stopping an experiment or settling a budget on a fold of randomness. The displayed confidence is paid for in abstentions; that is a trade I stand by.
elbow-helper installs in one line, pip install elbow-helper, and can be tried with nothing installed in the
online
sandbox, where the full pipeline runs in your browser without uploading your data. The code, the
examples and the mathematical note live at github.com/warith-harchaoui/elbow-helper. Bring a curve; you will leave with a
defensible elbow, or with a good reason not to believe in one.