BitBootcampBitBootcamp ← all explainers 🔄 Review ⚙ Settings

DA-01-007-P · Primer — Distributions and Histograms

The idea in one sentence

A histogram shows you the whole shape of one numeric column — where the values pile up, where they thin out, and where a few stragglers hide — instead of crushing all that information into a single number like the mean.

Why it exists

The mean is a great party trick: one number that stands in for a thousand. But that compression is exactly the problem — a mean of 6 hours could mean "almost everything took about 6 hours," or "most things were instant and a handful took all week," and the average can't tell those two very different worlds apart. A histogram exists to un-compress the column back into a picture: it slices the number line into equal-width buckets called bins and draws a bar for how many values fall in each one. Suddenly you can see whether the data is one clean hump or two separate crowds, whether it leans left or right, and whether there's a long tail of rare-but-extreme values dragging your average around. That shape is not a nicety — it decides which summary number is even honest to report, which statistical tests are valid, and where your data-quality problems are hiding. Reading shape before trusting any single statistic is the difference between describing your data and being fooled by it.

How it works

A histogram answers one question: "how are this column's values spread out?" You hand it a numeric Series, it chops the range into bins equal-width buckets, counts how many values land in each, and draws that count as a bar — tall bar means "lots of values here," short or empty means "few or none." In pandas the whole thing is series.plot.hist(bins=...), riding on matplotlib underneath. As you scan the bars you read three features: modality (how many humps — one peak is unimodal, two peaks often means two mixed populations), skew (does one side have a long stretched-out shoulder — a right/positive skew leans its tail toward big values), and tails (those low far-out bars that are rare but real). The clue that shape matters: when the mean is noticeably bigger than the median, you're almost always looking at a right skew with a fat upper tail. Watch that exact tell show up in twelve support tickets:

import pandas as pd
import matplotlib.pyplot as plt

# 12 support tickets — hours to resolve
df = pd.DataFrame({
    "resolve_hrs": [1, 1, 2, 2, 2, 3, 3, 4, 6, 9, 15, 28],
})

print("mean:  ", round(df["resolve_hrs"].mean(), 1))   # 6.3 hrs
print("median:", df["resolve_hrs"].median())           # 3.0 hrs

# The histogram shows the SHAPE the mean hides:
df["resolve_hrs"].plot.hist(bins=6, edgecolor="black")
plt.xlabel("hours to resolve")
plt.ylabel("number of tickets")
# -> a tall LEFT bar (most tickets resolved fast) plus a long
#    RIGHT TAIL of a few slow tickets. That tail is exactly why
#    the mean (6.3) sits far above the median (3.0): right skew.
plt.show()

The two numbers already whisper it — mean 6.3 versus median 3.0 — but the histogram shows it: a fat bar of quick tickets on the left and a thin tail of painful ones on the right, so "average 6.3 hours" describes almost none of your actual tickets.

The one gotcha

Your bins choice can invent or erase shape that isn't really there — the histogram is a drawing, not a fact. Same column, different bin counts, genuinely different-looking stories: too few bins smears two separate peaks into one smooth blob and hides a real gap, while too many bins shatters a clean hump into a jagged comb of ones and twos that looks like noise or fake sub-peaks. Neither is "the" distribution — they're both just choices. So the discipline is: never trust the shape from a single bin setting. Re-draw with a few values (try bins=10, then 20, then 30) and keep the features that survive the change — a hump that stays a hump, a gap that stays a gap, a tail that stays a tail — and distrust any wiggle that appears at one setting and vanishes at the next. And always check the histogram against the mean-vs-median tell: if they disagree with what your eyes think they see, one of them is lying, and usually it's the bins.

See it — reading a histogram's shape, then stress-testing the bins

flowchart TD
    A["One numeric column<br/>(e.g. resolve_hrs)"] --> B["Draw histogram<br/>plot.hist(bins=...)"]
    B --> C["Read the shape"]
    C --> D["Modality:<br/>1 hump or 2?"]
    C --> E["Skew: leans<br/>left or right?"]
    C --> F["Tails: far-out<br/>rare bars?"]
    D --> G{"Re-draw with<br/>more/fewer bins"}
    E --> G
    F --> G
    G -->|"feature survives"| H["Real shape —<br/>trust it"]
    G -->|"feature vanishes"| I["Bin artifact —<br/>ignore it"]

The one-line takeaway

Plot the histogram before you trust the mean — the shape (modality, skew, tails) tells you whether one number can honestly stand in for the whole column, and re-binning tells you whether that shape is real.

Where you'll meet it

You'll meet distributions the first time a stakeholder brags that "average response time is 6 hours" and you plot the histogram and discover half the tickets take 45 minutes while a few take three days — the average describes literally no one. You'll meet bins every time a histogram looks suspiciously smooth or suspiciously spiky and you realize the shape changed the moment you changed the bin count. You'll meet skew and tails whenever you're about to report a mean, run a t-test, or set a "normal" threshold — right-skewed data with a fat tail quietly breaks all three, and switching to the median or a log scale saves you. And you'll meet modality when a single innocent column turns out to be two crowds wearing one label (weekday vs weekend traffic, free vs paid users), a two-humped histogram being the first and clearest sign that you should split before you summarize. Learning to read shape first is one of the earliest habits that separates an analyst who reports numbers from one who actually understands the data.

Named concepts: histograms, bins, shape: skew, modality, tails