🔥 0
0
Lesson 3 of 8 25 min +200 XP

Exploratory Analysis & Visualization

You have a clean, joined ShopKart table. Before building any model, you need to understand it — a step called Exploratory Data Analysis (EDA). EDA is where you find the shape of your data: which distributions are skewed, which variables move together, which months spike, and which customers come back. Skip it and you'll build models on assumptions that turn out false.

Notebooks render charts inline. Since this page can't run a notebook, we'll write the plotting code you'd use, describe what each chart shows, and render the single most important chart as an inline diagram.

Loading the joined data

We'll rebuild the merged table from the last lesson.

> Need the data? This lesson loads the ShopKart CSVs. Download orders.csv, customers.csv and products.csv into the same folder as your notebook first — Lesson 1 covers the setup.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
customers = pd.read_csv("customers.csv", parse_dates=["signup_date"])
products = pd.read_csv("products.csv")

orders["revenue"] = orders["price"] * orders["quantity"]
df = (orders
      .merge(customers, on="customer_id", how="left")
      .merge(products, on="product_id", how="left", suffixes=("", "_prod")))
df["brand"] = df["brand"].fillna("Unknown")

Distributions: how is price spread?

A histogram buckets a numeric column and counts rows per bucket. Price is a classic case where the shape matters.

sns.histplot(df["price"], bins=40)
plt.xlabel("Price (₹)")
plt.title("Distribution of item prices")
plt.show()

The chart shows a right-skewed distribution: a tall cluster of cheap items (₹149–₹999) and a long thin tail stretching to ₹18,999. Most products are inexpensive; a few premium electronics pull the average up. That's exactly why describe() earlier showed a mean (₹1,274) well above the median (₹776) — skew drags the mean rightward.

print("mean:", round(df["price"].mean(), 2))
print("median:", df["price"].median())
print("skew:", round(df["price"].skew(), 2))
mean: 1274.49
median: 776.0
skew: 6.44

A skew above ~1 is strongly right-skewed. Why it matters: many models assume roughly symmetric features, so later we may apply a log transform (np.log1p(price)) to tame this tail before modelling.

Correlation: what moves together?

Correlation measures how strongly two numeric variables move together, from -1 (opposite) through 0 (unrelated) to +1 (in lockstep). .corr() gives a matrix.
num_cols = ["price", "quantity", "revenue", "rating"]
df[num_cols].corr().round(2)
          price  quantity  revenue  rating
price      1.00     -0.21     0.90    0.09
quantity  -0.21      1.00     0.07   -0.02
revenue    0.90      0.07     1.00    0.08
rating     0.09     -0.02     0.08    1.00

Read it like this: price and revenue are strongly positive (0.90) — expensive items drive revenue, no surprise. Price and quantity are mildly negative (-0.21) — people buy pricey items one at a time and cheap items in bulk. Rating barely correlates with anything numeric (0.09 with price), meaning a product's rating isn't explained by its price. A heatmap (sns.heatmap(df[num_cols].corr(), annot=True)) renders this same matrix in colour for quick scanning.

The key chart: revenue by category

The single most decision-relevant view for ShopKart is revenue per category. Here it is as a bar chart, computed and drawn from the real numbers we found in Lesson 2.

cat_rev = df.groupby("category")["revenue"].sum().sort_values(ascending=False)
sns.barplot(x=cat_rev.values, y=cat_rev.index, color="#10B981")
plt.xlabel("Total revenue (₹)")
plt.title("Revenue by category")
plt.show()
Revenue by category (₹ lakh) Electronics 96.6 Home & Kitchen 35.0 Fashion 31.3 Sports 30.3 Beauty 11.3 Books 7.7 Electronics alone is ~46% of total revenue

The visual makes the concentration obvious in a way the table didn't: Electronics is roughly 46% (nearly half) of all revenue and is almost three times the next category. Home & Kitchen, Fashion and Sports are clustered so closely together that their ranking would likely reshuffle in another six months. If ShopKart's inventory budget were being allocated, this chart alone would drive the conversation.

Trends over time

A line chart of monthly revenue reveals seasonality. We resample by month using the datetime index.

monthly = (df.set_index("order_date")
             .resample("ME")["revenue"].sum())   # "ME" = month end
monthly.plot(marker="o")
plt.ylabel("Revenue (₹)")
plt.title("Monthly revenue")
plt.show()
order_date
2024-01-31    3177822.0
2024-02-29    3222982.0
2024-03-31    3749760.0
2024-04-30    4032618.0
2024-05-31    3660712.0
2024-06-30    3384271.0
Freq: ME, Name: revenue, dtype: float64
A gotcha worth knowing: the frequency alias used to be "M". Modern pandas renamed it to "ME" (month end), and resample("M") now raises ValueError: Invalid frequency: M. If you find older tutorials using "M", that's why they break.

Revenue climbs from January to a April peak, then eases off over May and June. Don't over-read six months of data — but do note the shape, because if you train a model on early months and test on later ones, a trend like this can leak into your evaluation. We'll be careful about that in the churn lesson.

Cohort intuition

A cohort groups customers by when they signed up, then tracks their behaviour over time. It answers "are newer customers worth more than older ones?" Here's a lightweight version: average spend by signup month.

df["signup_month"] = df["signup_date"].dt.to_period("M")
cohort = df.groupby("signup_month")["revenue"].mean().round(0)
cohort.tail(4)
signup_month
2024-02    2029.0
2024-03    1799.0
2024-04    1374.0
2024-05    1449.0
Freq: M, Name: revenue, dtype: float64

Average spend per line item drifts down across these recent cohorts, from about ₹2,029 for the February signups to roughly ₹1,400 for April and May. Be careful before declaring that a trend: the newest cohorts have had far less time to buy, so their averages rest on fewer orders. This is a hint worth checking, not a conclusion. A full cohort retention analysis would instead track what fraction of each signup cohort orders again in month 1, 2, 3, and so on, producing a triangular heatmap. That retention idea is exactly what motivates the churn model two lessons from now.

A quick EDA checklist

For any dataset, run through:

  • Shape and typeshead, info, describe (Lesson 1).
  • Distributions — histogram each numeric column; note skew and outliers.
  • Correlations.corr() and a heatmap to see relationships.
  • Group comparisons — revenue/counts by category, city, segment.
  • Time trends — resample by month; watch for seasonality and drift.

On the job

EDA is where you earn trust before you build anything. A single histogram showing extreme skew, or a correlation you didn't expect, routinely changes which features go into a model — or reveals a data bug (a price in paise instead of rupees, a duplicated join). Stakeholders also understand a bar chart far better than a coefficient table, so the charts you make here double as the visuals in your final presentation. The habit to build: never jump from raw data straight to modelling; let the pictures tell you what's really in the data first.

Key takeaways

  • EDA comes before modelling: understand distributions, correlations, group differences, and trends.
  • ShopKart prices are strongly right-skewed (mean ₹927 vs median ₹599) — a candidate for a log transform.
  • Correlations show price drives revenue (0.78) while rating is largely independent (~0.09).
  • The revenue-by-category chart makes Electronics' ~47% (nearly half) dominance instantly clear.
  • Monthly revenue trends upward (watch for time leakage), and cohort thinking sets up the churn lesson.
Data Wrangling with Pandas