Histograms and KDE in Python

Visualize Distributions with Histograms and KDE — Data Analysis with Python.

Focus: visualize distributions with histograms and kde

Sponsored

You’ve cleaned your data, filtered out the noise, and computed summary statistics — but when you plot a histogram, the shape of your distribution suddenly tells a story that averages and standard deviations simply can’t convey. Without a clear view of how your data is distributed, you risk making decisions based on misleading metrics, missing multi-modal patterns, or misjudging outliers. In this lesson, you’ll master histograms and kernel density estimation (KDE) — the two most powerful tools in Python for visualizing distributions — and learn exactly when to use each one.

The problem this lesson solves

Imagine you’re analyzing customer purchase amounts. The mean is $45, but is that representative? If most customers spend $20 and a few spend $500, the mean hides the true story. Raw numbers and summary statistics fail to reveal the shape of your data — whether it’s symmetric, skewed, bimodal, or full of outliers.

A histogram solves this by binning your data into intervals and counting how many observations fall into each bin. A KDE plot smooths those counts into a continuous curve, making underlying patterns even easier to spot. Together, they give you an immediate, visual answer to: “What does my data actually look like?”

This lesson teaches you to visualize distributions with histograms and KDE using Python’s most popular libraries — Matplotlib and Seaborn — so you can quickly explore any dataset and make informed analytical decisions.

Core concept / mental model

Think of a histogram as a bar chart of your data’s frequency. You split the range of values into equal-width intervals (bins), then count how many data points fall into each bin. The height of each bar represents the count, and the overall shape of the bars reveals the distribution.

A KDE plot (kernel density estimation) is like a smoothed histogram. Instead of discrete bars, it places a smooth curve over the data by summing small “bumps” (kernels) centered at each data point. The result is a continuous probability density function — the area under the curve always equals 1, and the curve’s peaks show where data is most concentrated.

Mental model: If a histogram is a rugged mountain range, a KDE is the smooth ridge line you see from a distance. Both show elevation (frequency), but the KDE makes the overall silhouette clearer.

Pro tip: In Seaborn, sns.histplot(kde=True) shows both — you get the discrete bins and the smooth curve in one plot.

How it works step by step

Let’s break down how to create these plots, from raw data to a polished visualization.

Step 1: Load your data

Start with a pandas DataFrame — the standard data structure for analysis. For this lesson, we’ll use a sample of customer ages.

import pandas as pd
import numpy as np

# Sample data: ages of 1000 customers (normally distributed around 35)
np.random.seed(42)
ages = np.random.normal(loc=35, scale=10, size=1000)
df = pd.DataFrame({'age': ages})
df.head()

Step 2: Create a basic histogram

Use Matplotlib’s plt.hist() for a quick look, or Seaborn’s sns.histplot() for a prettier, more feature-rich plot.

import matplotlib.pyplot as plt
import seaborn as sns

# Basic histogram with Matplotlib
plt.hist(df['age'], bins=20, edgecolor='black')
plt.title('Customer Age Distribution')
plt.xlabel('Age')
plt.ylabel('Frequency')
plt.show()

Step 3: Add a KDE curve

Seaborn makes it trivial to combine both:

sns.histplot(df['age'], bins=20, kde=True)
plt.title('Age Distribution with KDE')
plt.xlabel('Age')
plt.ylabel('Frequency')
plt.show()

Step 4: Interpret the plot

Look for: - Peaks: Where is the distribution centered? - Spread: How wide is the curve? - Skewness: Does one tail extend longer than the other? - Multiple modes: Are there two distinct peaks? That suggests mixed populations.

Hands-on walkthrough

Now, let’s apply this to a realistic dataset — the Titanic passenger ages, which is often used in data analysis tutorials. We’ll load the data, clean it, and visualize the distribution.

Load and inspect the data

# Load Titanic dataset (you may need to download it)
url = 'https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv'
df = pd.read_csv(url)

# Check for missing values
print(df['Age'].isnull().sum())  # Output: 177

# Drop missing ages for simplicity
df_clean = df.dropna(subset=['Age'])
print(df_clean['Age'].describe())

Create histogram and KDE

import seaborn as sns
import matplotlib.pyplot as plt

sns.histplot(df_clean['Age'], bins=30, kde=True, color='skyblue')
plt.title('Titanic Passenger Age Distribution')
plt.xlabel('Age')
plt.ylabel('Count')
plt.show()

Expected output: You’ll see a right-skewed distribution with a peak around 25–30 years, a secondary bump near infancy, and a long tail toward older ages.

Compare with a KDE-only plot

Sometimes you want just the smooth curve, especially when comparing multiple groups:

sns.kdeplot(data=df_clean, x='Age', hue='Sex', shade=True)
plt.title('Age Distribution by Sex')
plt.show()

This reveals that female passengers’ ages are slightly more concentrated in the 20–30 range, while males have more spread — a pattern that histograms alone would make harder to compare.

Compare options / when to choose what

Both histograms and KDE have strengths and weaknesses. Here’s a quick comparison:

Feature Histogram KDE
Data representation Discrete bins, counts Continuous smooth curve
Bin width sensitivity High — changes shape dramatically Low — bandwidth controls smoothness
Outlier impact Visible as isolated bars Can create weird tails
Best for Quick, exact counts, large datasets Comparing multiple distributions, small-to-medium data
Computation cost Fast, even on millions of points Slower on huge datasets
Readability Easy to interpret counts Cleaner, but no counts

When to choose what: - Use a histogram when you need exact frequencies or when your dataset is enormous (millions of rows). - Use KDE when you want to compare several distributions on the same axes, or when your data is small and you need a smooth representation. - In practice, you’ll often use both togethersns.histplot(kde=True) gives you the best of both worlds.

Pro tip: For histograms, always experiment with the bins parameter. Too few bins hide detail; too many create noise. A good starting point is bins=20–30 or use bins='auto'.

Troubleshooting & edge cases

Even experienced analysts hit snags. Here are common issues and fixes:

1. Histogram looks broken or empty

Symptom: Bars don’t align with your data, or the plot is blank.

Cause: The bins parameter is too large or too small, or your data contains NaN values.

Fix: - Check for missing values: df['col'].isnull().sum() and drop them. - Experiment with bins or use bins='auto' (NumPy’s automatic binning).

2. KDE curve extends into negative values

Symptom: The smooth curve goes below zero even though your data is all positive (e.g., age).

Cause: The default Gaussian kernel has infinite support, so it “leaks” outside the data range.

Fix: - Use cut=0 in sns.kdeplot() to restrict the curve to the data range. - Or better, log-transform the data if it’s right-skewed.

3. Comparing groups with KDE — curves clipped

Symptom: When using hue, the curves get cut off at the edges.

Fix: Set clip=(0, None) to avoid negative values, or adjust the cut parameter.

4. Performance issues on large datasets

Symptom: Plotting takes forever.

Fix: - For histograms, sample your data or increase bin width. - For KDE, you can reduce the number of points by using gridsize in sns.kdeplot().

What you learned & what's next

You now understand how to visualize distributions with histograms and KDE — from the core concepts to practical implementation in Python. You learned to:

  • Explain the difference between histograms and KDE plots.
  • Create both using Matplotlib and Seaborn.
  • Add KDE curves to histograms for richer insight.
  • Troubleshoot common issues like bin sizing and curve leakage.

This skill is foundational for the next lesson in this track, where you’ll explore comparing distributions across groups — using these same visualization techniques to uncover differences between categories (like male vs. female passengers). The patterns you’ll see will directly inform your feature engineering and modeling decisions.

Keep practicing — grab any dataset you have and start plotting!

Practice recap

Now it’s your turn: load any dataset (e.g., the Iris dataset) and create a histogram with KDE for one numeric column. Try different bins values and observe how the shape changes. Then use hue to compare distributions across categories. This hands-on practice will solidify your understanding before moving to the next lesson on group comparisons.

Common mistakes

  • Using too few or too many bins — few bins hide the shape, many make it noisy. Experiment or use bins='auto'.
  • Forgetting to drop NaN values — histograms and KDE plots silently fail on missing data.
  • Interpreting KDE curve height as a count — it’s a density, not a frequency, so the y-axis scale differs from histograms.
  • Warning not to use df.hist() on a DataFrame with many columns — it creates a subplot for every column, which can be overwhelming.

Variations

  1. Use plt.hist() from Matplotlib for quick, low-dependency plots.
  2. Use Seaborn’s displot() with kind='hist' for a figure-level interface with faceting.
  3. Add a rug plot (rug=True) in Seaborn to show individual data points for small datasets.

Real-world use cases

  • Analyzing customer purchase amounts to identify skewness and decide whether to use median rather than mean in reporting.
  • Checking the distribution of model residuals to verify normality assumptions before applying linear regression.
  • Comparing age distributions between two user groups to spot demographic differences that may drive product decisions.

Key takeaways

  • Histograms use bins to show frequency; KDE smooths the data into a continuous density curve.
  • Seaborn’s histplot(kde=True) combines both for a single, informative plot.
  • Bin width and bandwidth dramatically affect interpretation — always experiment and justify your choice.
  • Use histograms for large datasets and exact counts; use KDE for comparing multiple distributions.
  • Always handle missing data before plotting, otherwise your visualization will be misleading.
  • Visualizing distributions is a crucial first step before any statistical modeling or feature engineering.

Sponsored

Sponsored