This page is the "throw everything at it" companion to Binning and discretization . The parent note built the three strategies (equal-width, equal-frequency, custom). Here we grind through every case class binning can hit — skewed data, ties, outliers, zero-range degenerate input, negative numbers, edge-boundary points, and a couple of exam twists — so that when you meet one in the wild you have already seen its cousin.
Before we start, three symbols we will lean on constantly:
Definition The bin-assignment rule (half-open intervals)
Given sorted bin edges b 0 < b 1 < ⋯ < b k , a value x lands in bin i when
f ( x ) = i if b i − 1 ≤ x < b i .
The interval [ b i − 1 , b i ) is half-open : the left edge is included, the right edge is excluded . Picture a fence post at each edge; a point sitting exactly ON a post belongs to the bin to its right . The one exception is the very last bin, which we close on both ends [ b k − 1 , b k ] so the maximum value has a home.
H ( f ( X )) means (plain words)
H stands for entropy — a number that measures "how many distinct, unpredictable answers a variable produces," measured in bits. If binning outputs only one label for every input, there is nothing to predict, so H ( f ( X )) = 0 bits. The more distinct, evenly-used bin labels you have, the larger H ( f ( X )) . We only use it below as a counter of usable distinct outputs : zero means "the feature is constant and carries no information."
Definition Floor and ceiling — rounding to whole bins
Bin counts must be whole numbers, so we round with two named operations. Floor ⌊ y ⌋ means "the largest whole number not above y " — it rounds down (e.g. ⌊ 10.97 ⌋ = 10 ). Ceiling ⌈ y ⌉ means "the smallest whole number not below y " — it rounds up (e.g. ⌈ 10.97 ⌉ = 11 ). Picture a number line: floor slides you left to the nearest integer post, ceiling slides you right. Which one a library uses is a convention choice , and we will see it matters in Ex 9.
Intuition Why half-open, not "closest edge"?
If both edges were included, a point exactly on b 1 would belong to two bins at once — an illegal double-membership. Half-open intervals tile the number line: every real number falls in exactly one bin, no gaps, no overlaps. Look at figure s01 — each bucket owns its left wall and rents out its right wall to the next bucket.
Every worked example below is tagged with the cell it covers. The goal: no empty cells.
Cell
Case class
What could break
Covered by
A
Equal-width, well-spread data
nothing — baseline
Ex 1
B
Equal-width, right-skewed + outlier
empty middle bins
Ex 2
C
Equal-frequency on the same skewed data
interpolation between points
Ex 3
D
Point sitting exactly on an edge
double-membership / off-by-one
Ex 4
E
Negative values + zero crossing
sign handling, min < 0
Ex 5
F
Degenerate : all values identical (R = 0 )
divide-by-zero in width
Ex 6
G
Ties at a quantile boundary
equal-frequency can't split
Ex 7
H
Word problem: custom domain bins
choosing edges from meaning
Ex 8
I
Exam twist: choose k via Sturges
log rounding, off-by-one
Ex 9
J
Limiting behaviour: k = 1 and k = n
total loss vs. no compression
Ex 10
Worked example Ex 1 — Cell A: Equal-width baseline
Data : exam scores [ 10 , 20 , 35 , 50 , 65 , 80 , 90 ] , want k = 3 bins.
Forecast: guess the three edges before reading — will the bins be balanced?
Range R = max − min = 90 − 10 = 80 .
Why this step? Equal-width slices the span , so we need the span first.
Width w = R / k = 80/3 ≈ 26.667 .
Why? Three equal slabs of the number line.
Edges b i = 10 + i w : b 0 = 10 , b 1 ≈ 36.67 , b 2 ≈ 63.33 , b 3 = 90 .
Why? Start at min, add width repeatedly (parent's step-3 recipe).
Assign using [ b i − 1 , b i ) :
Bin 1 [ 10 , 36.67 ) : 10 , 20 , 35 → 3 points
Bin 2 [ 36.67 , 63.33 ) : 50 → 1 point
Bin 3 [ 63.33 , 90 ] : 65 , 80 , 90 → 3 points
Why this step? We must convert edges into memberships by the half-open rule — this is the moment binning actually happens; each score is tested against the walls (left included, right excluded) to find its home bucket.
Verify: counts sum to 3 + 1 + 3 = 7 = n . ✓ Every point placed once. Because the data was spread out, no bin is empty — this is the happy case.
Worked example Ex 2 — Cell B: Equal-width breaks on skew
Data : house prices [ 100 , 150 , 200 , 250 , 300 , 350 , 900 ] (thousands), k = 3 .
Forecast: one huge value at 900. What happens to the middle bin?
R = 900 − 100 = 800 . Why? span again.
w = 800/3 ≈ 266.667 . Why? equal slabs.
Edges = [ 100 , 366.67 , 633.33 , 900 ] . Why? 100 + i ⋅ 266.67 .
Assign each price by the half-open rule [ b i − 1 , b i ) :
[ 100 , 366.67 ) : 100 , 150 , 200 , 250 , 300 , 350 → 6 points
[ 366.67 , 633.33 ) : nothing → 0 points (empty!)
[ 633.33 , 900 ] : 900 → 1 point
Why this step? Only by walking every point through the walls do we discover the middle bucket catches nothing — the failure is invisible from the edges alone.
Verify: 6 + 0 + 1 = 7 . ✓ The single outlier at 900 stretched the range so far that the middle slab landed in a data desert. See figure s02 — the whole crowd is jammed into bucket 1.
Worked example Ex 3 — Cell C: Equal-frequency rescues the same data
Data : [ 100 , 150 , 200 , 250 , 300 , 350 , 900 ] , k = 3 , n = 7 .
Forecast: target ≈ 7/3 = 2.33 per bin. Where do the edges land?
We use linear interpolation between order statistics. With n points, the quantile at fraction p sits at position h = ( n − 1 ) p (0-indexed), value = x (⌊ h ⌋) + ( h − ⌊ h ⌋) ( x (⌊ h ⌋ + 1 ) − x (⌊ h ⌋) ) .
Why ( n − 1 ) and not n ? We are placing p on a ruler whose endpoints are the smallest and largest data points. With n points there are exactly n − 1 gaps between them. So p = 0 must land on the first point (position 0) and p = 1 on the last point (position n − 1 ). Multiplying by ( n − 1 ) is what stretches the fraction p ∈ [ 0 , 1 ] across those n − 1 gaps; using n would push p = 1 past the last point, off the ruler. (This is NumPy's default "linear" convention.)
Sort (already sorted). Why? quantiles need order.
Q ( 1/3 ) : h = 6 ⋅ 3 1 = 2.0 → exactly x ( 2 ) = 200 (0-indexed → the 3rd value).
Why? h landed on an integer, no interpolation needed.
Q ( 2/3 ) : h = 6 ⋅ 3 2 = 4.0 → exactly x ( 4 ) = 300 .
Edges = [ 100 , 200 , 300 , 900 ] . Assign with the half-open rule [ b i − 1 , b i ) :
[ 100 , 200 ) : 100 , 150 → 2
[ 200 , 300 ) : 200 , 250 → 2
[ 300 , 900 ] : 300 , 350 , 900 → 3
Why this step? The quantile edges are only promises of balance; we confirm the promise by actually assigning each point through the walls and counting.
Verify: 2 + 2 + 3 = 7 . ✓ Now the outlier is quarantined in the last bin and no bin is empty. Trade-off: widths are 100 , 100 , 600 — the last bin is a huge, hard-to-interpret price range. Compare with figure s02 (equal-width) vs the balanced counts here.
Worked example Ex 4 — Cell D: A point sitting exactly on an edge
Data : [ 0 , 5 , 10 , 15 , 20 ] , edges chosen as [ 0 , 10 , 20 ] (k = 2 ). Which bin gets 10?
Forecast: naive intuition says "10 is on the boundary, flip a coin." The rule says otherwise.
Apply [ b i − 1 , b i ) : bin 1 = [ 0 , 10 ) , bin 2 = [ 10 , 20 ] (last bin closed).
Why this step? Half-open means the left edge belongs to the bin; 10 = b 1 is the left edge of bin 2.
So 10 → bin 2, not bin 1.
Why? "left included, right excluded" — a point on a post joins the bucket to its right.
Assign all:
Bin 1 [ 0 , 10 ) : 0 , 5 → 2
Bin 2 [ 10 , 20 ] : 10 , 15 , 20 → 3
Verify: 2 + 3 = 5 . ✓ Also check 0 (the very first left edge) is included — it is, because bin 1 is [ 0 , … ) . And 20 (the max) is included because the last bin is closed. Two potential off-by-one traps, both handled.
Worked example Ex 5 — Cell E: Negatives crossing zero
Data : temperatures [ − 8 , − 3 , 0 , 4 , 12 ] °C, equal-width k = 2 .
Forecast: min is negative . Does the width formula still work? (Yes — subtraction handles signs.)
R = max − min = 12 − ( − 8 ) = 20 . Why? span is always max minus min ; the double-negative gives a positive span.
w = 20/2 = 10 . Why? two equal slabs.
Edges = − 8 + i ⋅ 10 = [ − 8 , 2 , 12 ] . Why? start at the (negative) min, add width.
Assign:
[ − 8 , 2 ) : − 8 , − 3 , 0 → 3 (note 0 lands here, since − 8 ≤ 0 < 2 )
[ 2 , 12 ] : 4 , 12 → 2
Verify: 3 + 2 = 5 . ✓ Zero is not special — it is just another value inside bin 1. The formula never cared about signs; it only cares about order along the number line. See figure s03 for the number line crossing zero.
Worked example Ex 6 — Cell F: Degenerate, all values identical
Data : [ 7 , 7 , 7 , 7 ] , ask for k = 3 equal-width bins.
Forecast: something must break — spot it before computing.
R = 7 − 7 = 0 . Why? span of a constant is zero.
w = R / k = 0/3 = 0 . Why? the formula plows ahead and gives width 0 .
Edges = [ 7 , 7 , 7 , 7 ] — all collapse to a single point. Bins are [ 7 , 7 ) which is empty as an interval, so no well-defined half-open bin can hold anything except the closed last one [ 7 , 7 ] .
Why does this matter? You cannot slice a point into 3 pieces. Libraries either raise an error or dump everything into one bin.
Correct handling: detect R = 0 up front and return a single degenerate bin containing all n points.
Verify: all 4 values equal, so any sensible discretizer must output the same label for all of them — entropy H ( f ( X )) = 0 (one symbol, nothing to predict; see the entropy definition above). ✓ There is nothing to distinguish, so a constant feature after binning is (correctly) useless — a good reason to drop constant columns before binning.
Worked example Ex 7 — Cell G: Ties at a quantile boundary
Data : [ 1 , 2 , 2 , 2 , 2 , 3 ] , equal-frequency k = 2 , n = 6 .
Forecast: the median wants to split the four 2's. Can it?
Target n / k = 3 per bin. Why? balanced counts.
Median edge Q ( 1/2 ) : position h = ( n − 1 ) ⋅ 0.5 = 2.5 → interpolate x ( 2 ) and x ( 3 ) , both = 2 → edge = 2 .
Why? the ties make interpolation return the tie value.
Assign [ 1 , 2 ) then [ 2 , 3 ] :
[ 1 , 2 ) : only 1 → 1 point
[ 2 , 3 ] : 2 , 2 , 2 , 2 , 3 → 5 points
Verify: 1 + 5 = 6 . ✓ But we wanted 3-and-3 and got 1-and-5! Why equal-frequency failed: a bin edge cannot fall inside a run of identical values — all four 2's must go to the same bin, so no edge can separate them. This is the fundamental limit: equal-frequency can only balance bins when there are enough distinct values. Fix: merge to fewer bins, or accept the imbalance, or add a tiny jitter (with caution — that fabricates precision).
Worked example Ex 8 — Cell H: Word problem, custom domain bins
Statement: A lender scores applicants by annual income (USD). Policy says: below the poverty line $15k = high risk; $15k–$50k working class; $50k–$100k middle class; above $100k upper class. Applicant incomes: [ 8 k , 15 k , 42 k , 100 k , 250 k ] . Assign each to a custom bin.
Forecast: two applicants sit exactly on policy thresholds (15k, 100k). Which side do they fall?
Custom edges from policy: [ 0 , 15 k , 50 k , 100 k , ∞ ] , giving 4 bins.
Why this step? Edges come from meaning (poverty line, class thresholds), not from data spread — this is the whole point of custom binning (parent's Strategy 3).
Apply half-open [ b i − 1 , b i ) :
8 k ∈ [ 0 , 15 k ) → high risk
15 k ∈ [ 15 k , 50 k ) → working class (on the post → right bucket)
42 k ∈ [ 15 k , 50 k ) → working class
100 k ∈ [ 100 k , ∞ ) → upper class (again post → right bucket)
250 k ∈ [ 100 k , ∞ ) → upper class
Why this step? We must use the same half-open convention here as everywhere else (Ex 4), otherwise a threshold applicant like the $15k one would be assigned inconsistently; "left included, right excluded" fixes each borderline case to the bucket on its right.
Counts per bin: high 1, working 2, middle 0, upper 2.
Why is middle empty and that's OK? With custom bins we don't require balance — an empty class is meaningful information ("no middle-class applicants today").
Verify: 1 + 2 + 0 + 2 = 5 applicants placed. ✓ The threshold applicants (15k→working, 100k→upper) landed via the half-open rule exactly as Ex 4 predicted — consistency across the page. A model can now emit a readable rule: IF income < 15k THEN flag_high_risk. This pairs naturally with one-hot encoding to feed the bin labels to a linear model, and with decision trees which effectively bin on their own.
Worked example Ex 9 — Cell I: Exam twist, pick
k with Sturges' rule
Statement: You have n = 1000 samples. How many histogram bins does Sturges' rule recommend, and roughly what does k ≈ n give instead?
Forecast: these two heuristics disagree a lot — guess which is larger.
Sturges: k = 1 + log 2 n , then round to an integer. Why this tool? log 2 answers "how many yes/no splits distinguish n points?" — each bin edge is roughly one binary split, so 2 k ≈ n ⇒ k ≈ log 2 n (parent's derivation).
log 2 1000 = ln 1000/ ln 2 ≈ 9.9658 . So 1 + log 2 n ≈ 10.97 .
Why round? bin count must be a whole number. Rounding convention matters: this page uses floor ⌊ ⋅ ⌋ (round down, defined above), giving ⌊ 10.97 ⌋ = 10 . Other formulations use ceiling ⌈ ⋅ ⌉ (round up) ⌈ 10.97 ⌉ = 11 , or nearest-integer rounding (round ( 10.97 ) = 11 ); NumPy's bin='sturges' uses ceiling. So expect 10 or 11 depending on the library — state your convention on an exam.
Square-root rule: k ≈ n , so 1000 ≈ 31.6 ⇒ ⌊ 31.6 ⌋ = 31 bins.
Why n as a tool, and where does it come from? It answers a different question than Sturges: "how do I keep each bin populated as the sample grows?" If you want k bins each holding about k samples, then k × k = n , i.e. k = n — bins and their occupancy grow together at the same rate. This is the default heuristic in several spreadsheet/BI tools (and Excel's histogram helper) precisely because it never leaves bins near-empty. It grows far faster than Sturges' log 2 n , giving finer resolution but risking noisier, sparser bins.
Verify: Sturges (floor) → 10 , Sturges (ceiling) → 11 , sqrt (floor) → 31 . ✓ For a smooth roughly-normal dataset Sturges' coarser ≈ 10 bins avoids overfitting the histogram; for revealing multimodal structure the sqrt's 31 bins may be safer. Neither is a law — the parent insists you cross-validate. The bias/variance dial behind this choice lives in the bias–variance tradeoff .
Worked example Ex 10 — Cell J: The two limiting cases
k = 1 and k = n
Statement: Take any data, say [ 3 , 7 , 7 , 11 , 20 ] (n = 5 , distinct values { 3 , 7 , 11 , 20 } ). What happens at the extremes k = 1 and k = n ?
Forecast: one extreme destroys all information, the other keeps everything — which is which?
k = 1 : one bin [ min , max ] = [ 3 , 20 ] swallows all 5 points. Every x maps to label 1.
Why? one bucket = one symbol out. The binned feature is constant ⇒ output entropy H ( f ( X )) = 0 bits (recall the entropy definition above: one label means zero information).
What it looks like: the whole number line painted a single color — maximal compression, maximal information loss.
k = n = 5 : five bins, but the data has only 4 distinct values (two 7's tie). At best you recover 4 usable labels; the two 7's cannot be separated (same lesson as Ex 7).
Why? binning is a function of value, so identical inputs give identical outputs. With ties you can never reach n distinct bins.
What it looks like: nearly one-point-per-bucket — almost no compression, almost no denoising benefit.
Verify: at k = 1 , number of distinct output labels = 1 . At k = n , distinct labels ≤ number of distinct input values = 4 < 5 . ✓ So the useful range of k is bounded above by the count of distinct values — a hard ceiling the sqrt/Sturges heuristics silently assume you respect.
Recall Quick self-check
On which side of an edge does a point that equals b 1 fall? ::: Into the bin to its right, [ b 1 , b 2 ) — left edge included, right excluded.
Why does equal-width leave empty middle bins on skewed data? ::: A far outlier stretches max − min , so the width is huge and the sparse middle range catches no points (Ex 2).
Why can't equal-frequency always give equal counts? ::: An edge cannot split a run of identical (tied) values, so all ties share one bin (Ex 7, Ex 10).
What is the width formula's output when all values are equal? ::: w = 0 ; degenerate, must be handled as a single bin (Ex 6).
What does H ( f ( X )) = 0 tell you about a binned feature? ::: It has only one label — it is constant and carries no information, so drop it.
Sturges' bin count for n = 1000 ? ::: ⌊ 1 + log 2 1000 ⌋ = 10 (or 11 with ceiling rounding).
Mnemonic "Left Lives, Right Runs"
The L eft edge L ives inside the bin; the R ight edge R uns off to the next bin. Only the final bin closes its door.
Related dives: outliers that these bins tame connect to handling missing/anomalous data , and once binned you can multiply bin labels together as feature interactions .