Skip to main content

Chapter 3 · Data Science

Exploratory Data Analysis (EDA) in Python: Complete Guide

Learn exploratory data analysis (EDA) in Python with pandas, Seaborn, and Matplotlib. Explore distributions, correlations, outliers, trends, and relationships.

By Updated 18 min Beginner

Banner for "Data Science with Python" showing a snake and data analysis tools
On this page

Once a dataset has been cleaned and validated, the next step is to understand what the data actually shows. This process is called exploratory data analysis (EDA).

In Python, EDA usually combines pandas for data inspection and summary statistics with Seaborn and Matplotlib for visualisation. These tools help you examine distributions, compare groups, detect outliers, explore correlations, identify trends, and discover relationships before moving on to statistical modelling or machine learning.

In this chapter, you will learn how to perform exploratory data analysis in Python using:

  • pandas for summaries and data inspection
  • Matplotlib for chart structure and customisation
  • Seaborn for statistical visualisations
  • SciPy for a normal Q-Q plot

By the end of the chapter, you will be able to choose suitable charts, explore numerical and categorical variables, create and interpret a correlation heatmap, assess distributions with a Q-Q plot, and communicate findings without overstating what the data proves.

What Is Exploratory Data Analysis (EDA) in Python?

Exploratory data analysis is the process of examining a dataset before formal modelling or hypothesis testing.

EDA helps you answer questions such as:

  • What does a typical observation look like?
  • How widely are values distributed?
  • Are variables skewed or approximately symmetric?
  • Which categories occur most frequently?
  • Are there missing values or unusual observations?
  • Do two variables appear to move together?
  • Do groups show different distributions?
  • Are there patterns that deserve further investigation?

EDA is exploratory rather than confirmatory. It helps generate questions and identify promising directions, but a visual pattern alone is not proof of causation or statistical significance.

Why Exploratory Data Analysis and Data Visualisation Matter

The primary purpose of data visualisation is insight, not decoration.

Well-designed charts can help you:

  • Understand the shape of a distribution
  • Compare groups and categories
  • Identify possible outliers
  • Detect trends over time
  • Explore relationships between variables
  • Discover unexpected data-quality problems
  • Communicate findings clearly

A chart should answer a question. Adding more colours, labels, or visual effects does not automatically make it more informative.

How to Perform Exploratory Data Analysis in Python

The following sections provide a practical EDA workflow using a cleaned pandas DataFrame named df.

Start by importing the required libraries:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats

You can set a consistent Seaborn theme for the notebook:

sns.set_theme(style="whitegrid")

The example columns used in this chapter include:

  • price
  • age
  • salary
  • gender
  • city
  • rating
  • date
  • sales

Replace these names with columns from your own dataset.

Start EDA with a pandas Data Audit

Visualisation should not be the first action. Begin by confirming the shape, columns, data types, and missing values in the DataFrame.

Preview the DataFrame

df.head()

Inspect random records to avoid focusing only on the first rows:

df.sample(5, random_state=42)

Check the Number of Rows and Columns

print(f"Rows: {df.shape[0]}")
print(f"Columns: {df.shape[1]}")

Inspect pandas Data Types

df.info()

This is especially important before plotting because numbers stored as text may be treated as categories.

Check Missing Values in pandas

missing_summary = pd.DataFrame({
    "missing_count": df.isna().sum(),
    "missing_percentage": df.isna().mean().mul(100).round(2)
})

missing_summary.sort_values(
    "missing_percentage",
    ascending=False
)

Missing values can affect sample sizes and may cause some plots or statistical functions to ignore rows.

Review Summary Statistics with pandas

df.describe()

This shows statistics such as:

  • Count
  • Mean
  • Standard deviation
  • Minimum
  • Quartiles
  • Maximum

For numerical and categorical columns:

df.describe(include="all")

Inspect Categorical Value Counts

df["gender"].value_counts(dropna=False)

To view proportions:

df["gender"].value_counts(
    normalize=True,
    dropna=False
).mul(100).round(2)

These summaries provide context for the charts that follow.

How to Choose the Right Chart for EDA

The chart should match the data types and the question you want to answer.

Analysis goalVariablesUseful charts
Examine a numerical distributionOne numerical variableHistogram, KDE plot, box plot, ECDF
Examine category frequenciesOne categorical variableCount plot, bar chart
Compare a number across groupsOne categorical and one numerical variableBox plot, violin plot, strip plot, point plot, bar plot
Explore a numerical relationshipTwo numerical variablesScatter plot, regression plot
Explore change over timeDate/time and numerical variableLine plot
Compare several numerical variablesMultiple numerical variablesCorrelation heatmap, pair plot
Add a third grouping variableTwo variables plus a categoryHue, marker style, faceting

Avoid choosing a chart only because it looks impressive. A simple plot that answers a clear question is usually more effective.

Univariate Analysis in Python: Explore One Variable

Univariate analysis examines one variable at a time.

For numerical variables, focus on:

  • Centre
  • Spread
  • Shape
  • Skewness
  • Gaps
  • Extreme values

For categorical variables, focus on:

  • Frequency
  • Proportion
  • Rare categories
  • Missing or unexpected labels

Create a Histogram with Seaborn

A histogram groups numerical values into intervals called bins and displays how many observations fall inside each interval.

price = df["price"].dropna()

plt.figure(figsize=(10, 6))

sns.histplot(
    data=price,
    bins=20,
    kde=True
)

plt.title("Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Number of Observations")
plt.tight_layout()
plt.show()

Use the histogram to examine:

  • Whether the distribution is symmetric or skewed
  • Whether it has one or several peaks
  • Whether values are concentrated in a narrow range
  • Whether there are gaps or extreme values

The number of bins affects the appearance of the chart. Too few bins can hide structure, while too many can make random variation look meaningful.

You can ask Seaborn to determine the binning automatically:

plt.figure(figsize=(10, 6))

sns.histplot(
    data=df,
    x="price",
    bins="auto"
)

plt.title("Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Number of Observations")
plt.tight_layout()
plt.show()

Create a KDE Plot with Seaborn

The kde=True argument adds a kernel density estimate to the histogram.

A KDE creates a smooth estimate of the distribution:

plt.figure(figsize=(10, 6))

sns.kdeplot(
    data=df,
    x="price",
    fill=True
)

plt.title("Estimated Density of Product Prices")
plt.xlabel("Price")
plt.ylabel("Density")
plt.tight_layout()
plt.show()

A KDE can make the overall shape easier to see, but it is an estimate rather than a direct count. Its appearance depends on the smoothing bandwidth and can be misleading for small datasets, bounded variables, or strongly discrete values.

Use the histogram alongside the KDE rather than treating the smooth curve as the raw data.

Create a Box Plot to Find Potential Outliers

A box plot summarises the median, quartiles, interquartile range, and values beyond the whiskers.

plt.figure(figsize=(8, 6))

sns.boxplot(
    data=df,
    y="price"
)

plt.title("Box Plot of Product Prices")
plt.ylabel("Price")
plt.tight_layout()
plt.show()

The main components are:

  • The line inside the box represents the median
  • The box spans the first to the third quartile
  • The box width in the value direction represents the interquartile range
  • The whiskers extend according to the box-plot rule
  • Points beyond the whiskers are potential outliers

A point beyond a whisker is not automatically an error. It may be an unusual but valid observation.

Create an ECDF Plot with Seaborn

An empirical cumulative distribution function, or ECDF, shows the proportion of observations at or below each value.

plt.figure(figsize=(10, 6))

sns.ecdfplot(
    data=df,
    x="price"
)

plt.title("Cumulative Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Cumulative Proportion")
plt.tight_layout()
plt.show()

An ECDF is useful for questions such as:

  • What percentage of products cost no more than a certain amount?
  • What value contains the lowest 75% of observations?
  • How do two complete distributions compare?

Unlike a histogram, an ECDF does not require selecting bins.

Create a Q-Q Plot in Python

A quantile-quantile plot compares the observed quantiles of a variable with the theoretical quantiles of a selected distribution.

The following example compares price with a normal distribution:

price = df["price"].dropna()

plt.figure(figsize=(8, 6))

stats.probplot(
    price,
    dist="norm",
    plot=plt
)

plt.title("Normal Q-Q Plot of Product Prices")
plt.tight_layout()
plt.show()

How to Interpret a Q-Q Plot

  • Points that follow the reference line reasonably closely are consistent with an approximately normal distribution.
  • A curved pattern may indicate skewness.
  • Strong departures at the ends may indicate heavier or lighter tails than a normal distribution.
  • Isolated distant points may indicate unusual observations.

A Q-Q plot is a visual diagnostic, not a formal proof that the data is normal.

The interpretation also depends on sample size. Small samples may look irregular because of random variation, while large samples can reveal small departures that may not be practically important.

Create a Count Plot for Categorical Data

A count plot displays the number of observations in each category.

category_order = (
    df["city"]
    .value_counts()
    .index
)

plt.figure(figsize=(12, 6))

sns.countplot(
    data=df,
    x="city",
    order=category_order
)

plt.title("Number of Observations by City")
plt.xlabel("City")
plt.ylabel("Count")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()

Sorting categories by frequency makes large differences easier to see.

Check whether low-frequency categories are genuine, misspelled, or overly specific before combining them.

Bivariate Analysis in Python: Explore Two Variables

Bivariate analysis examines the relationship between two variables.

The appropriate chart depends on whether the variables are:

  • Numerical and numerical
  • Categorical and numerical
  • Categorical and categorical
  • Time-based and numerical

Create a Scatter Plot with Seaborn

A scatter plot displays one numerical variable on each axis.

plot_data = df.dropna(
    subset=["age", "salary"]
)

plt.figure(figsize=(10, 6))

sns.scatterplot(
    data=plot_data,
    x="age",
    y="salary"
)

plt.title("Relationship Between Age and Salary")
plt.xlabel("Age")
plt.ylabel("Salary")
plt.tight_layout()
plt.show()

Look for:

  • Upward or downward trends
  • Curved relationships
  • Clusters
  • Changes in spread
  • Isolated observations
  • Empty regions

A visible trend suggests an association, but it does not show that one variable causes the other.

Add a Third Variable with Seaborn hue

Use hue to represent a third variable:

plot_data = df.dropna(
    subset=["age", "salary", "gender"]
)

plt.figure(figsize=(10, 6))

sns.scatterplot(
    data=plot_data,
    x="age",
    y="salary",
    hue="gender",
    alpha=0.75
)

plt.title("Age and Salary by Gender")
plt.xlabel("Age")
plt.ylabel("Salary")
plt.legend(title="Gender")
plt.tight_layout()
plt.show()

This can reveal whether groups occupy different regions of the chart.

Do not interpret group differences without considering sample size, role, experience, location, selection effects, and other variables that may influence the result.

Add a Regression Line with Seaborn

A regression plot adds a fitted linear trend:

plot_data = df.dropna(
    subset=["age", "salary"]
)

plt.figure(figsize=(10, 6))

sns.regplot(
    data=plot_data,
    x="age",
    y="salary",
    scatter_kws={"alpha": 0.6}
)

plt.title("Linear Trend Between Age and Salary")
plt.xlabel("Age")
plt.ylabel("Salary")
plt.tight_layout()
plt.show()

The line summarises a linear relationship. It can be unhelpful when the true pattern is curved or when outliers strongly influence the fit.

Use the underlying scatter points to judge whether a straight line is a reasonable summary.

Compare Groups with a Box Plot

Averages can hide important differences in spread, skewness, and outliers.

A grouped box plot shows more of the distribution:

plt.figure(figsize=(12, 6))

sns.boxplot(
    data=df,
    x="city",
    y="rating"
)

plt.title("Rating Distribution by City")
plt.xlabel("City")
plt.ylabel("Rating")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()

This allows you to compare:

  • Medians
  • Interquartile ranges
  • Overall spread
  • Potential outliers
  • Differences in distribution shape

Show Individual Observations with a Strip Plot

For a smaller dataset, a strip plot displays the individual observations:

plt.figure(figsize=(12, 6))

sns.stripplot(
    data=df,
    x="city",
    y="rating",
    jitter=True,
    alpha=0.6
)

plt.title("Individual Ratings by City")
plt.xlabel("City")
plt.ylabel("Rating")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()

A strip plot can reveal sample size and overlapping values that an average alone would hide.

For larger datasets, consider a box plot, violin plot, or a sampled subset to reduce overplotting.

Compare Group Means with a Seaborn Bar Plot

A Seaborn bar plot estimates a summary statistic for each category. The default estimator is the mean.

plt.figure(figsize=(12, 6))

sns.barplot(
    data=df,
    x="city",
    y="rating",
    estimator="mean",
    errorbar=("ci", 95)
)

plt.title("Mean Rating by City with 95% Confidence Intervals")
plt.xlabel("City")
plt.ylabel("Mean Rating")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()

The bars display estimated means, while the error bars communicate uncertainty around those estimates.

Confidence intervals do not show the full distribution. Combine a bar plot with counts, box plots, or individual observations when group sizes or variation matter.

To deliberately remove uncertainty intervals:

sns.barplot(
    data=df,
    x="city",
    y="rating",
    errorbar=None
)

Do this only when the simplified chart still communicates the information responsibly.

A line plot is useful when observations follow a meaningful time order.

First, ensure that the date column is a datetime type:

df["date"] = pd.to_datetime(
    df["date"],
    errors="coerce"
)

Aggregate daily sales:

daily_sales = (
    df.dropna(subset=["date", "sales"])
    .groupby("date", as_index=False)["sales"]
    .sum()
    .sort_values("date")
)

Plot the result:

plt.figure(figsize=(12, 6))

sns.lineplot(
    data=daily_sales,
    x="date",
    y="sales"
)

plt.title("Total Sales Over Time")
plt.xlabel("Date")
plt.ylabel("Total Sales")
plt.tight_layout()
plt.show()

Look for:

  • Long-term trends
  • Seasonal patterns
  • Sudden changes
  • Missing periods
  • Unusual spikes
  • Changes in variability

A line connecting unordered categories can imply a sequence that does not exist. Use line plots only when the order between x-axis values is meaningful.

Multivariate Exploratory Data Analysis in Python

Multivariate analysis explores more than two variables at once.

Useful tools include:

  • Correlation matrices
  • Heatmaps
  • Pair plots
  • Hue and marker mappings
  • Faceted charts
  • Grouped summaries

Calculate a Correlation Matrix with pandas

A correlation coefficient summarises the direction and strength of an association between two numerical variables.

Calculate the Pearson correlation matrix:

corr_matrix = df.corr(
    method="pearson",
    numeric_only=True
)

corr_matrix

Pearson correlation measures linear association.

The coefficient ranges from -1 to 1:

  • Values near 1 indicate a strong positive linear association
  • Values near -1 indicate a strong negative linear association
  • Values near 0 indicate little linear association

A value near zero does not prove that no relationship exists. The relationship may be non-linear.

Correlation also does not establish causation. A relationship may be influenced by confounding variables, selection effects, reverse direction, or coincidence.

Create a Correlation Heatmap with Seaborn

A heatmap makes a correlation matrix easier to scan.

corr_matrix = df.corr(
    method="pearson",
    numeric_only=True
)

plt.figure(figsize=(10, 8))

sns.heatmap(
    corr_matrix,
    annot=True,
    fmt=".2f",
    vmin=-1,
    vmax=1,
    center=0,
    cmap="coolwarm",
    square=True
)

plt.title("Pearson Correlation Matrix")
plt.tight_layout()
plt.show()

The colour scale is fixed between -1 and 1, making the positive and negative correlations easier to compare.

Hide Half of a Correlation Heatmap

A correlation matrix is symmetrical. You can hide the upper triangle to reduce duplication:

corr_matrix = df.corr(
    method="pearson",
    numeric_only=True
)

mask = np.triu(
    np.ones_like(
        corr_matrix,
        dtype=bool
    )
)

plt.figure(figsize=(10, 8))

sns.heatmap(
    corr_matrix,
    mask=mask,
    annot=True,
    fmt=".2f",
    vmin=-1,
    vmax=1,
    center=0,
    cmap="coolwarm",
    square=True
)

plt.title("Lower Triangle of the Correlation Matrix")
plt.tight_layout()
plt.show()

For datasets with many numerical columns, annotations may become unreadable. Remove annot=True, increase the figure size, or display a selected group of features.

Pearson vs Spearman Correlation in pandas

Pearson correlation focuses on linear association.

Spearman correlation uses ranks and can capture a monotonic relationship that is not necessarily linear:

pearson_corr = df.corr(
    method="pearson",
    numeric_only=True
)

spearman_corr = df.corr(
    method="spearman",
    numeric_only=True
)

Compare the results when scatter plots suggest a curved but consistently increasing or decreasing pattern.

Neither method proves causation.

Create a Pair Plot with Seaborn

A pair plot creates a grid of pairwise charts:

selected_columns = [
    "age",
    "salary",
    "price",
    "rating",
    "gender"
]

pair_data = df[selected_columns].dropna()

sns.pairplot(
    data=pair_data,
    hue="gender",
    corner=True,
    diag_kind="hist"
)

plt.show()

Pair plots are useful for quickly scanning a small collection of features.

They can become slow and visually crowded when the dataset has many columns or observations. Select only the variables relevant to the question.

Compare Groups with Seaborn Facets

Faceting creates separate panels for groups:

sns.relplot(
    data=df,
    x="age",
    y="salary",
    col="city",
    col_wrap=3,
    kind="scatter",
    height=4
)

plt.show()

Small multiples make it easier to compare the same relationship under different conditions without placing every group in one crowded chart.

Ensure that panels use comparable scales unless there is a clear reason not to.

How to Improve Python Data Visualisations

A technically correct chart can still be difficult to interpret.

Write Descriptive Chart Titles and Axis Labels

Avoid titles such as:

Price Plot

Prefer a title that explains what is shown:

Distribution of Product Prices After Data Cleaning

Axis labels should include units when relevant:

plt.xlabel("Age (years)")
plt.ylabel("Annual Salary (€)")

Sort Categories Before Plotting

For frequency charts:

order = df["city"].value_counts().index

For comparisons by a calculated metric:

order = (
    df.groupby("city")["rating"]
    .mean()
    .sort_values(ascending=False)
    .index
)

Then pass the order to the plotting function:

sns.barplot(
    data=df,
    x="city",
    y="rating",
    order=order
)

Fix Overlapping Axis Labels

plt.xticks(
    rotation=45,
    ha="right"
)

Use plt.tight_layout() before plt.show() to reduce clipped labels.

Avoid Excessive Numerical Precision

A heatmap with many decimal places creates visual noise.

Use:

fmt=".2f"

Round summary tables to a sensible number of decimal places:

df.describe().round(2)

Consider Sample Size in EDA

A group with two observations should not be interpreted in the same way as a group with hundreds.

Check group sizes:

df.groupby("city").size().sort_values(
    ascending=False
)

Consider adding counts to the analysis or excluding groups that do not meet a documented minimum sample-size rule.

Avoid Misleading Chart Axes

Bar charts usually communicate magnitude relative to zero, so truncating the value axis can exaggerate small differences.

For a bar chart, verify the numerical axis begins at zero unless there is a strong reason and the choice is made explicit.

Line charts can sometimes use a narrower range to reveal meaningful variation, but the scale should remain clearly labelled.

Use Colour Only When It Adds Meaning

Colour should encode meaning.

Use colour to:

  • Distinguish groups
  • Show magnitude
  • Highlight a specific result
  • Separate positive and negative values

Do not assign a different colour to every bar when colour does not represent additional information.

Save a Matplotlib or Seaborn Chart

Use savefig() before show():

plt.figure(figsize=(10, 6))

sns.histplot(
    data=df,
    x="price",
    bins=20
)

plt.title("Distribution of Product Prices")
plt.xlabel("Price")
plt.ylabel("Number of Observations")
plt.tight_layout()

plt.savefig(
    "price-distribution.png",
    dpi=300,
    bbox_inches="tight"
)

plt.show()

A higher DPI produces a sharper raster image for reports and websites.

Complete Exploratory Data Analysis Workflow in Python

The following workflow provides a practical starting point for a new dataset.

Step 1: Understand the Dataset

df.head()
df.shape
df.info()

Step 2: Measure Data Quality

df.isna().sum()
df.duplicated().sum()

Step 3: Review Summary Statistics

df.describe(include="all")

Step 4: Explore Important Numerical Variables

sns.histplot(
    data=df,
    x="price",
    kde=True
)

plt.show()

Step 5: Explore Important Categories

sns.countplot(
    data=df,
    x="city"
)

plt.xticks(rotation=45)
plt.show()

Step 6: Examine Relationships

sns.scatterplot(
    data=df,
    x="age",
    y="salary",
    hue="gender"
)

plt.show()

Step 7: Compare Groups

sns.boxplot(
    data=df,
    x="city",
    y="rating"
)

plt.xticks(rotation=45)
plt.show()

Step 8: Review Correlations

corr_matrix = df.corr(
    numeric_only=True
)
sns.heatmap(
    corr_matrix,
    annot=True,
    fmt=".2f",
    vmin=-1,
    vmax=1,
    center=0,
    cmap="coolwarm"
)

plt.show()

Step 9: Record Findings and Questions

For every chart, write down:

  • What the chart shows
  • What surprised you
  • What could explain the pattern
  • Whether missing values or sample size affect the result
  • What should be investigated next
  • What the chart does not prove

This turns a notebook from a collection of plots into a structured analysis.

How to Write Exploratory Data Analysis Findings

A strong finding is specific and cautious.

Weak statement:

Older customers earn more.

Improved statement:

In this dataset, salary generally increases across the observed age range, although the scatter is wide and the chart does not establish that age causes higher salary.

Weak statement:

City A has the best ratings.

Improved statement:

City A has the highest observed mean rating, but the group contains fewer observations and its uncertainty interval overlaps with several other cities.

Weak statement:

Price is normally distributed.

Improved statement:

The histogram is approximately symmetric and most points in the Q-Q plot follow the reference line, although the upper tail shows a visible departure from normality.

Careful wording makes the analysis more accurate and credible.

Common Exploratory Data Analysis Mistakes

Treating Correlation as Causation

A high correlation does not prove that changing one variable will change the other.

Use language such as:

  • Associated with
  • Related to
  • Moves with
  • Shows a positive or negative relationship

Avoid causal language unless the study design and analysis support it.

Using Only Averages

Two groups can have the same mean but very different distributions.

Use box plots, violin plots, strip plots, counts, or uncertainty intervals to provide context.

Removing Outliers Before Exploring Them

Outliers may represent errors, rare events, or the most interesting observations in the dataset.

Investigate them before deciding how they should be treated.

Plotting Every Column Without a Question

Producing dozens of charts is not the same as performing EDA.

Begin with the analysis goal and select charts that can answer relevant questions.

Ignoring Missing Values

Different plots may use different numbers of observations after dropping missing values.

Track the sample size behind important comparisons.

Overloading a Chart

Too many categories, colours, annotations, and variables can hide the main pattern.

Split a complex chart into several focused charts when necessary.

Calling a Q-Q Plot a Normality Test

A Q-Q plot is a visual diagnostic. It helps assess how closely a sample follows a theoretical distribution, but interpretation is subjective and depends on sample size.

Hiding Uncertainty Without a Reason

Removing error bars can make group estimates look more certain than they are.

Show uncertainty when comparing estimated statistics such as group means.

Exploratory Data Analysis Checklist for Python

Before completing your EDA, confirm that you have:

  • Checked the dataset shape and data types
  • Measured missing values
  • Reviewed numerical summary statistics
  • Reviewed category frequencies
  • Explored important numerical distributions
  • Checked potential outliers
  • Compared relevant groups
  • Examined important numerical relationships
  • Investigated trends over time when dates are available
  • Calculated correlations only for suitable numerical variables
  • Avoided interpreting correlation as causation
  • Considered sample sizes and uncertainty
  • Used clear titles and axis labels
  • Recorded findings and limitations
  • Identified questions for the next stage of analysis

Exploratory Data Analysis FAQ

What is exploratory data analysis (EDA) in Python?

Exploratory data analysis in Python is the process of using data inspection, summary statistics, and visualisation to understand a dataset before formal modelling or testing.

Common tools include pandas, Matplotlib, Seaborn, SciPy, and specialised profiling libraries.

What is the difference between Matplotlib and Seaborn for EDA?

Matplotlib is a general plotting library that provides detailed control over chart elements.

Seaborn is built on Matplotlib and provides a higher-level interface for statistical visualisations and DataFrame-oriented plotting.

They are commonly used together.

Which Python chart should I use to show a distribution?

Use a histogram to show frequencies across intervals.

A KDE can show a smooth estimate of the distribution, a box plot summarises quartiles and potential outliers, and an ECDF shows cumulative proportions.

Using more than one view can provide a better understanding of the same variable.

How do I create a correlation heatmap with pandas and Seaborn?

Calculate a numerical correlation matrix with pandas and pass it to Seaborn:

corr_matrix = df.corr(
    numeric_only=True
)
sns.heatmap(
    corr_matrix,
    annot=True,
    fmt=".2f",
    vmin=-1,
    vmax=1,
    center=0,
    cmap="coolwarm"
)
plt.show()

What does a correlation of zero mean?

A correlation near zero indicates little association of the type measured by the selected coefficient.

For Pearson correlation, that means little linear association. A strong non-linear relationship may still exist.

Does correlation prove causation?

No. Correlation measures association and does not establish a causal relationship.

How do I interpret a Q-Q plot?

Compare the plotted points with the reference line.

Points that approximately follow the line are consistent with the selected theoretical distribution. Systematic curves or departures at the tails indicate differences in shape.

Should I use a bar plot or box plot to compare groups?

Use a bar plot when the estimated group statistic itself is the focus and uncertainty is shown clearly.

Use a box plot when you want to compare medians, spread, and potential outliers. In EDA, box plots or plots of individual observations often provide more information than bars alone.

Why does Seaborn show error bars?

Functions that estimate a statistic, such as a group mean, can display uncertainty or variability around that estimate.

The exact interpretation depends on the selected errorbar setting.

How many charts should an EDA contain?

There is no fixed number.

Include enough charts to answer the important questions without repeating the same information or overwhelming the reader.

Next Steps After Exploratory Data Analysis

This chapter completes the first three stages of the data science workflow:

  1. Environment setup: Create a reliable local or cloud-based Python environment.
  2. Data cleaning: Transform raw data into a validated dataset.
  3. Exploratory data analysis: Use statistics and visualisation to understand distributions, relationships, and unusual observations.

You now know how to:

  • Inspect a DataFrame before plotting
  • Choose charts based on data types and analysis goals
  • Explore numerical and categorical distributions
  • Compare groups with appropriate context
  • Examine numerical relationships with scatter plots
  • Visualise trends over time
  • Create and interpret a correlation heatmap
  • Use a Q-Q plot as a normality diagnostic
  • Communicate patterns without confusing association with causation

The next stage is to turn the questions generated during EDA into formal statistical analyses or machine-learning experiments.

If you want to see these techniques applied to data where the distribution shape has real consequences, Value at Risk (VaR) vs CVaR turns a return distribution into a risk number and shows why the tail you spotted in a Q-Q plot is the part that matters, and the random walk explains where those distributions come from in the first place.

Subscribe / Stdin

Get the next part

New parts of Data Science with Python land in your inbox the day they publish. No spam, unsubscribe in one click.

We send your address to Kit, our email provider, and ask you to confirm by email before anything is sent. See our Privacy Statement.