Skip to main content

Week 7: Univariate Analysis & Visualization

📈 "Univariate" sounds intimidating. It just means: look at one variable at a time, properly, before comparing it to anything else.

🎯 Learning objectives

By the end of this week you can:

  • Visualize a numeric column's distribution with a histogram, and a categorical column's distribution with a bar chart.
  • Read a boxplot as a compact summary of a distribution's quartiles and outliers.
  • Choose the right chart type for a variable's type, and label charts so they're readable on their own.
  • Explain why the number of histogram bins is itself a meaningful choice, not an arbitrary default.

Lesson

Why visualize, not just summarize with numbers?

Week 6's mean/median/std describe a distribution with three numbers — but very different distributions can share the same mean and std. A chart shows shape: is it symmetric, skewed, bimodal (two humps), full of outliers? This is the core reason univariate visualization comes before anything more advanced.

Histograms: distribution of a numeric variable

A histogram bins a numeric column's values and shows how many fall in each bin — a direct visual of the frequency distribution, the plotted version of last week's mean/median/std numbers:

import matplotlib.pyplot as plt

df["math_score"].hist(bins=20, edgecolor="black")
plt.xlabel("Math score")
plt.ylabel("Number of students")
plt.title("Distribution of math scores")
plt.show()

Always label your axes and title your chart — a chart that only makes sense with the code that produced it next to it isn't finished.

Bin count is a real choice, not a default to ignore

Too few bins hides real structure (everything blurs into one or two lumps); too many bins shows noise as if it were meaningful structure (each bin has too few points to say anything reliable). There's no single universally correct number — try a couple of values and see which one tells the clearest, most honest story:

fig, axes = plt.subplots(1, 3, figsize=(12, 4))
for ax, n_bins in zip(axes, [5, 20, 50]):
df["math_score"].hist(bins=n_bins, ax=ax, edgecolor="black")
ax.set_title(f"{n_bins} bins")
plt.tight_layout()
plt.show()

plt.subplots(1, 3, figsize=(12, 4)) creates one figure with 3 side-by-side panels (axes is then a list of 3 individual plot areas) — a useful pattern whenever you want to compare a few variations of the same chart at once, which you'll reuse in Week 9.

Boxplots: quartiles and outliers at a glance

A boxplot draws the 25th percentile, median, and 75th percentile as a box, with "whiskers" extending to the typical range and individual points beyond that marked as potential outliers — a compact visual of exactly the quartile numbers .describe() already gave you, and exactly the same 1.5×IQR1.5 \times \text{IQR} rule from last week, drawn out visually:

df.boxplot(column="math_score")
plt.ylabel("Math score")
plt.title("Math score spread")
plt.show()

Boxplots become especially useful once you compare several groups' distributions side by side — which is exactly next week's bivariate topic.

Bar charts: distribution of a categorical variable

For a categorical column, .value_counts() (Week 6) plotted directly as a bar chart shows which categories are common vs. rare:

df["parental_level_of_education"].value_counts().plot(kind="bar")
plt.xlabel("Parental level of education")
plt.ylabel("Number of students")
plt.title("Parental education levels in the dataset")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()

plt.xticks(rotation=45, ha="right") rotates long category labels so they don't overlap — a small but common fix for readability once labels get longer than a couple of characters. plt.tight_layout() prevents rotated/long labels from getting cut off at the figure's edge.

Choosing the right chart

Variable typeChart
Numeric, want distribution shapeHistogram
Numeric, want quartiles/outliers, especially across groupsBoxplot
Categorical, want frequency of each categoryBar chart

A bar chart of a numeric column (treating each unique score as its own "category") or a histogram of a categorical column are both usually wrong choices — matching the chart to the variable's actual type is the first design decision, before any styling.

⚠️ Common pitfalls

  • Forgetting axis labels and a title. A chart that requires the reader to already know what it shows isn't finished — always label both axes and add a title, even for a "just exploring" chart you'll delete later.
  • Picking one bin count and never questioning it. As shown above, the same data can tell noticeably different visual stories at 5 vs. 20 vs. 50 bins — always sanity-check with at least two bin counts before trusting what a histogram's shape seems to say.
  • Using the wrong chart for the variable type. A histogram of a categorical column (like gender) or a bar chart of raw, un-aggregated numeric values are both signs the chart-choice table above wasn't consulted first.
  • Forgetting plt.show() (or a trailing bare expression) to actually display the chart, especially when chaining several plotting calls — depending on your environment, a chart built across multiple lines may not render until explicitly shown.

🧩 Challenges

Plot a histogram of reading_score with labeled axes and a title.

Create a boxplot of writing_score. Looking at it, does the distribution appear symmetric, or is the median noticeably closer to one edge of the box?

Plot a bar chart of the test_preparation_course column's category counts, with labeled axes.

Someone plots df["gender"].hist(). Explain why this is the wrong chart choice, and what they should use instead.

Plot writing_score as a histogram with 5 bins, then again with 50 bins. Describe how the apparent shape of the distribution changes between the two.

Create a single boxplot showing all three score columns (math_score, reading_score, writing_score) side by side, so their spreads can be compared at a glance.

🤔 Socratic Questions

  • Two distributions can have identical mean and standard deviation but very different shapes (e.g. one symmetric, one with two separate humps). Why does a histogram catch this difference while mean/std alone cannot?
  • A boxplot marks points beyond the whiskers as potential "outliers." Does that automatically mean those data points are errors that should be removed? What else might explain a legitimately unusual but correct value?
  • Why does plt.xticks(rotation=45, ha="right") matter more for parental_level_of_education (long category names) than for gender (short ones)? What general rule about label length and chart readability does this suggest?
  • If a colleague showed you only a 50-bin histogram of a variable and claimed to see "three distinct clusters," what would you want to check before trusting that claim, given what you now know about bin-count sensitivity?

✅ Weekly quiz

✅ Weekly quiz

1. A histogram is the right chart choice for:
2. A boxplot's box represents:
3. Why do two distributions with the same mean and std still need a chart to compare properly?
4. The right chart for a categorical column's value_counts() is:
5. Why check a histogram at more than one bin count?