Understanding the Empirical Cumulative Distribution Function (ECDF)
ECDFs turn raw data into percentiles and SLA thresholds without binning assumptions. A practical guide with examples and pitfalls.
If you have ever stared at a histogram and wondered what fraction of users finished onboarding in under five minutes, the empirical cumulative distribution function (ECDF) is the direct answer. Unlike a density plot, an ECDF gives you exact cumulative probabilities from data without assuming a bell curve or picking bin widths.
Definition in plain language
Given (n) sorted observations (x_{(1)} \le x_{(2)} \le \cdots \le x_{(n)}), the ECDF is
[ \hat F(x) = \frac{1}{n} \sum_{i=1}^{n} \mathbf{1}{x_i \le x} ]
Read that as: at any value (x), (\hat F(x)) is the proportion of sample points at or below (x). It always starts at 0, ends at 1, and only jumps upward at observed data points (or smoothed variants if you choose a different estimator).
For a dataset [2, 5, 5, 9]:
| x | ECDF F̂(x) |
|---|---|
| below 2 | 0 |
| 2 | 0.25 |
| 5 | 0.75 |
| 9 | 1.0 |
No bins, no kernel bandwidth—just the data talking.
ECDF vs histogram vs KDE
Histograms hide sensitivity to bin edges. Kernel density estimates can look smooth but depend on bandwidth. The ECDF is stepwise and honest: every jump is 1/n, so you see how much each point matters.
Trade-offs:
- ECDF: great for quantiles and “% below threshold”; awkward for multimodal shape intuition.
- Histogram: intuitive peaks; bin choice changes the story.
- KDE: smooth curves; can imply mass where none exists if bandwidth is wrong.
In exploratory analysis, plot ECDF alongside a histogram when sample sizes are moderate (roughly 30–10,000). For huge data, compute ECDF on a sample or use streaming quantile sketches.
Quantiles without guessing
The (p)-th quantile (q_p) satisfies (\hat F(q_p) \approx p). On a plot, draw a horizontal line at (y = 0.9) and read where it crosses the ECDF—that is the 90th percentile.
This is how SREs turn latency logs into SLO language: “99% of requests completed below 400 ms” is an ECDF statement.
Worked example in Python
import numpy as np
import matplotlib.pyplot as plt
data = np.array([12, 18, 22, 22, 30, 41, 55, 60, 60, 60, 95])
def ecdf(values):
x = np.sort(values)
y = np.arange(1, len(x) + 1) / len(x)
return x, y
x, y = ecdf(data)
plt.step(x, y, where="post")
plt.xlabel("Value")
plt.ylabel("F(x)")
plt.title("ECDF of sample")
plt.grid(True, alpha=0.3)
plt.show()
# 90th percentile via interpolation on the ECDF
p90 = np.quantile(data, 0.9)
print("p90:", p90)
numpy.quantile and pandas.Series.quantile implement the same idea with interpolation rules; know your method= / interpolation= argument when comparing tools.
Comparing two groups
Overlay two ECDFs to compare distributions without t-tests assuming normality. If one curve is consistently to the left, that group tends toward smaller values.
Example questions ECDFs answer well:
- Did experiment B reduce checkout time for most users, not just the average?
- What percentage of accounts exceed the fraud threshold?
- At which load level did 95% of servers still stay under CPU cap?
When sample sizes differ wildly, compare on a common grid of quantiles (Q–Q plot is related machinery).
Statistical properties (why textbooks care)
For i.i.d. data, the Glivenko–Cantelli theorem says (\hat F) converges uniformly to the true CDF (F). The Dvoretzky–Kiefer–Wolfowitz inequality bounds how fast, which motivates confidence bands around an ECDF in formal inference.
For interviews and day-to-day work, remember the practical bit: each jump is 1/n, so single points in small samples move the curve a lot.
Big data and streaming
Exact ECDF on billions of rows is expensive. Common approaches:
- t-digest / KLL sketches for approximate quantiles
- Random sampling with reported confidence
- Per-shard ECDF merge only if you accept approximation error
If you only need a few quantiles (p50, p95, p99), prefer dedicated streaming quantile algorithms over materializing full sorted arrays.
Common mistakes
- Treating ECDF as PDF — areas under the ECDF are not probabilities of intervals; use differences: (P(a < X \le b) \approx \hat F(b) - \hat F(a)).
- Ignoring ties — duplicate values create flat steps; that is correct, not a bug.
- Extrapolating past max — ECDF does not predict beyond observed max/min without a model.
- Comparing censored data — survival analysis needs Kaplan–Meier, not a naive ECDF.
FAQ
What does “ecdf” mean in search results?
Usually empirical cumulative distribution function in statistics, machine learning, and data engineering contexts.
Is ECDF only for numeric data?
For ordered categories you can define it; for purely nominal data, ECDF is less meaningful.
How does ECDF relate to the CDF?
CDF is the true population function; ECDF is the sample estimate. They meet as (n) grows.
Should I report mean or ECDF percentiles for latency?
Report percentiles (from ECDF or quantile sketches). Means hide long tails that users feel.
ECDF in machine learning workflows
Model evaluation often reports a single AUC or accuracy, but product teams ask percentile questions: “How bad are the worst 5% of predictions?” Score an eval set, plot ECDF of loss or error, and read off the loss value at 0.95— that is your tail risk.
Calibration curves relate predicted probabilities to outcomes; ECDFs of absolute error complement them when targets are continuous (forecasting, latency prediction).
In A/B tests, ECDFs of per-user metrics reveal whether a lift is driven by a few outliers or broad improvement—averages alone routinely mislead growth teams.
R and SQL snippets
R (stats package):
x <- c(12, 18, 22, 22, 30, 41, 55, 60, 95)
plot(ecdf(x), main = "ECDF")
quantile(x, probs = c(0.5, 0.9))
SQL (window functions, PostgreSQL-style):
SELECT
value,
cume_dist() OVER (ORDER BY value) AS ecdf
FROM measurements;
cume_dist() estimates the ECDF for discrete rows; for ties, behavior matches “proportion ≤ value” with standard SQL tie-breaking—always verify against your warehouse docs.
Teaching and interviews
Interviewers mention ECDF when testing whether candidates understand distributions beyond mean/variance. Be ready to:
- Sketch an ECDF from five numbers
- Explain why ECDF jumps are height
1/n - Convert between percentile questions and ECDF readings
Students confuse ECDF with the probability density function; emphasize that ECDF values are always between 0 and 1 and never exceed 1 at any x.
Plotting tips in real dashboards
- Use step plots (
plt.step(..., where="post")) rather than line plots that imply values between jumps. - For heavy-tailed metrics (latency), consider a log-scaled x-axis so the left side of the ECDF remains readable.
- When presenting to executives, annotate two points: median (p50) and p95—most decisions hinge on those, not the full curve.
Export ECDF charts as static images for postmortems; interactive hover is nice in notebooks but email-friendly PNGs still win in incident reviews.
When you report a single number (“p99 latency is 420 ms”), attach the ECDF thumbnail or a link to the dashboard panel. Stakeholders trust curves more than isolated metrics because they can see how steep the tail is—whether a few outliers dominate or the whole distribution shifted.
The ECDF is a small idea with outsized leverage: it turns lists of numbers into decisions about thresholds, SLAs, and fairness across groups—without pretending your data is Gaussian. Keep it in your default plotting toolkit next to the histogram you already use.
Comments
Loading comments…