BitBootcampBitBootcamp ← all explainers 🔄 Review ⚙ Settings

DA-01-016-P · Primer — Comparing Groups with Boxplots

The idea in one sentence

A boxplot squeezes each group's whole distribution into one compact box, so lining several boxes up on a shared axis lets you compare center, spread, and outliers across groups at a single glance.

Why it exists

A raw table of "morning vs. evening wait times" hides the answer inside hundreds of numbers, and a single average can lie to you — two shifts can share the same mean while one is calm and the other swings wildly. The question you're really asking is comparative: which group is typically higher, which is more consistent, and which has weird cases hiding in the tail? You could draw a histogram per group, but stacked or overlapping histograms get noisy fast and are hard to line up fairly. The boxplot exists to answer all three sub-questions — center, spread, outliers — in a shape small enough that ten groups still fit on one chart, side by side, measured against the same ruler.

How it works

Each box is built from five numbers: the median (the line inside), the first and third quartiles Q1 and Q3 (the box's bottom and top, holding the middle 50% of the data), and two "whiskers" that reach out to the most extreme points still within 1.5×IQR of the box; anything past that is drawn as an individual dot — a flagged outlier. Read a single box top-to-bottom as "where's the middle, how tall is the spread, are there stragglers." The power comes from putting boxes side by side on one shared y-axis: because every group is measured on the same ruler, a higher box means a higher center, a taller box means more spread, and a lone dot means an outlier — all comparable at a glance. In pandas you split the values into one list per group, then hand that list-of-lists to matplotlib's boxplot, which draws them in a row.

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({
    "shift": ["Morning","Morning","Morning","Morning","Morning",
              "Evening","Evening","Evening","Evening","Evening",
              "Night","Night","Night","Night","Night"],
    "wait_min": [4, 5, 5, 6, 7,
                 6, 7, 8, 9, 22,       # 22 is one unusually long evening wait
                 3, 4, 4, 5, 6],
})

groups = ["Morning", "Evening", "Night"]
data = [df.loc[df["shift"] == g, "wait_min"] for g in groups]   # one list of waits per shift

fig, ax = plt.subplots()
ax.boxplot(data)                 # 3 boxes drawn in a row on ONE shared y-axis
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(groups)
ax.set_ylabel("wait_min")

# What the chart shows: Night has the lowest, tightest box (median 4);
# Evening's box sits highest (median 8) AND shows a lone dot at 22 above its
# whisker — a flagged outlier that a plain average would have quietly inflated.
print(df.groupby("shift")["wait_min"].median())   # Evening 8, Morning 5, Night 4

The one gotcha

The comparison is only honest when every box shares the same axis — never place boxes on separate charts with auto-scaled y-axes and eyeball "which is bigger," because a taller-looking box might just be zoomed in. The second trap: a box says nothing about how many points built it. A group with 4 observations and a group with 4,000 can draw identical boxes, yet one is a rumor and the other is solid evidence — so pair boxplots with a per-group count (df.groupby("shift").size()) before you trust any gap you see.

See it — reading three boxes on one shared ruler

flowchart TD
    A["Values split into<br/>one list per group"] --> B["Draw boxes side by side<br/>on ONE shared y-axis"]
    B --> C["Box HEIGHT<br/>= spread (IQR)"]
    B --> D["Median LINE<br/>= typical value"]
    B --> E["Lone DOT past whisker<br/>= outlier"]
    C --> F["Compare center, spread,<br/>outliers at a glance"]
    D --> F
    E --> F
    F --> G["Check group counts<br/>before trusting gaps"]

The one-line takeaway

Boxplots on a shared axis turn "compare these groups" into a glance: higher box = higher center, taller box = more spread, lone dot = outlier — just confirm each group has enough points to believe.

Where you'll meet it

Comparing response times across servers, test scores across classrooms, prices across neighborhoods, or delivery times across carriers — anywhere you have a number measured within several labeled groups and need to see who's typically higher, who's more erratic, and who's hiding a few wild cases.

Named concepts: boxplots, median and quartiles side by side, comparing distributions across groups