Back to Knowledge Base

Reading Percentiles in Monthly Stats

Edit

How to interpret percentile columns in M-Lab Monthly Stats data, including the counterintuitive polarity of latency and loss, and what p50 vs p95 tells you.

intermediate Data AccessInternet QualityResearch & Analysis

Monthly Stats files store the full percentile distribution of each metric across all NDT tests in a given geography and month. Understanding what percentiles mean β€” and a critical quirk in how latency and loss are stored β€” is essential for correct analysis.

πŸ’‘

What a Percentile Means Here

A percentile column metric_pN answers: β€œWhat was the metric value at or below which N% of tests fell?”

For example, download_p50 is the median download speed β€” half of all NDT tests in that geography/month were slower, half were faster.

Available percentiles in Monthly Stats: 1, 5, 10, 25, 50, 75, 90, 95, 99.

The distribution tells a richer story than a single number

PercentileWhat it represents
p50Typical experience β€” the median user
p25–p75The β€œmiddle 50%” β€” the interquartile range
p95 / p99Near-best performance β€” the top 5% or 1% of tests
p5 / p1Near-worst performance β€” the bottom 5% or 1%

A wide gap between p25 and p75 signals high variability β€” some users have very fast connections while others are very slow. A narrow band means more uniform service.

The Polarity Quirk: Latency and Loss Are Inverted

This is the most important thing to understand about Monthly Stats percentiles.

For download and upload speed, higher is better. download_p95 is the 95th percentile of speed β€” only 5% of tests were faster. It represents near-best performance.

For latency and loss, lower is better. But the percentile numbering still follows the same convention β€” latency_p95 is the 95th percentile of latency values, meaning 95% of tests had lower latency. It therefore represents near-worst latency (only 5% of tests had higher latency).

In summary:

Metricp5 meansp95 means
Download / UploadNear-worst speedNear-best speed
LatencyNear-best latency (lowest values)Near-worst latency (highest values)
LossNear-best loss (lowest values)Near-worst loss (highest values)

Why does this matter?

If you naively plot latency_p95 alongside download_p95 expecting both to represent β€œgood” performance, you will draw the wrong conclusions. Geographies with high latency_p95 have worse latency, not better.

The Internet Quality Barometer (IQB) handles this by applying the polarity correctly when computing scores: it uses download_p95 (high = good) but latency_p5 or latency_p50 (low = good) as inputs.

Code example

# Correct: for latency, LOWER values are better, so nsmallest finds best
best_latency = df.nsmallest(10, "latency_p50")[["country_code", "latency_p50"]]

# Correct: for download, HIGHER values are better
best_download = df.nlargest(10, "download_p50")[["country_code", "download_p50"]]

# Wrong: this finds countries with worst latency, not best
worst_approach = df.nlargest(10, "latency_p50")  # ← these are the SLOWEST countries

Which Percentile Should I Use?

The right choice depends on your question:

Use p50 (median) when you want the typical user experience. The median is robust to outliers and represents a realistic β€œwhat does this network feel like for most people?” summary.

Use p95 for download/upload when you want near-peak performance β€” useful for understanding what fast connections look like in an area. The IQB framework uses p95 download/upload as an optimistic baseline for its quality thresholds.

Use p5 for latency/loss when you want near-best latency β€” the lowest latency achieved by 95% of users. This is the IQB convention.

Use p25–p75 to understand variability and equity. A location where download_p75 / download_p25 is very large has high inequality between its fast and slow users.

Sample Count and Reliability

The sample_count column records how many NDT tests contributed to each row. Rows with very few tests have noisy percentiles:

# Filter out low-confidence rows before analysis
df_reliable = df[df["sample_count"] >= 100]

As a rough guide:

  • < 30 tests: very unreliable β€” avoid using percentile estimates
  • 30–100 tests: usable with caution, especially for p50
  • > 100 tests: generally reliable for p25–p75
  • > 500 tests: reliable for extreme percentiles (p5, p95)

Finer-grained slices (city, city+ASN) will have far more low-count rows than country-level data, especially for smaller cities or minority ISPs.

Further Reading