Turning 3,900 retail transactions into revenue, loyalty, and marketing insights.
- Business Problem
- Project Highlights
- Tech Stack
- Workflow
- Dataset
- Data Preparation (Python)
- SQL Analysis
- Power BI Dashboard
- Key Insights & Recommendations
- Repository Structure
- How to Run
- Skills Demonstrated
- Author
A leading retail company has noticed shifting purchase patterns across demographics, product categories, and sales channels. Management wants to know which factors, such as discounts, reviews, seasons, shipping, and subscriptions, actually drive consumer decisions and repeat purchases.
Core question: How can the company leverage consumer shopping data to identify trends, improve customer engagement, and optimize marketing and product strategies?
- π§Ή Cleaned and engineered a 3,900-record dataset in Python (missing-value imputation, feature engineering, schema standardization)
- ποΈ Loaded data into PostgreSQL programmatically using SQLAlchemy
- π Answered 10 business questions with SQL using CTEs, window functions, subqueries, and conditional aggregation
- π Built an interactive Power BI dashboard with KPI cards, drill-down charts, and four dynamic slicers
- π‘ Translated findings into actionable recommendations for marketing, pricing, and loyalty strategy
| Layer | Tools |
|---|---|
| Language | Python 3, SQL |
| Data Processing | Pandas, NumPy |
| Database | PostgreSQL (MySQL and SQL Server connection code also included) |
| DB Connectivity | SQLAlchemy, psycopg2 |
| Visualization | Power BI Desktop, DAX |
| Environment | Jupyter Notebook, pgAdmin, Anaconda |
| Version Control | Git, GitHub |
Raw CSV Data
β
βΌ
βββββββββββββββββββββ
β Python (Pandas) β β Clean, impute, engineer features
βββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββ
β PostgreSQL β β Load via SQLAlchemy, query with SQL
βββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββ
β Power BI β β Interactive dashboard & insights
βββββββββββββββββββββ
Source: Customer shopping behavior dataset Β· Size: 3,900 rows Γ 18 columns
| Column | Description |
|---|---|
customer_id |
Unique customer identifier |
age, gender |
Customer demographics |
item_purchased, category |
Product purchased (25 items across 4 categories) |
purchase_amount |
Transaction value in USD |
location |
US state (50 unique) |
size, color, season |
Product attributes and seasonality |
review_rating |
Customer rating (2.5 to 5.0) |
subscription_status |
Subscriber or non-subscriber |
shipping_type |
Standard, Express, Free, Store Pickup, etc. |
discount_applied |
Whether a discount was used |
previous_purchases |
Number of prior purchases (loyalty proxy) |
payment_method |
Preferred payment type |
frequency_of_purchases |
How often the customer buys |
All steps are in Customer_Shopping_Behavior_Analysis.ipynb.
| Step | Action | Why |
|---|---|---|
| 1 | Loaded data and ran .info(), .describe() |
Understand structure and distributions |
| 2 | Found 37 missing values in Review Rating |
Only column with nulls |
| 3 | Imputed with median rating per product category | More accurate than a global median; robust to outliers |
| 4 | Standardized column names to snake_case |
SQL-friendly, consistent naming |
| 5 | Engineered age_group using quartiles (pd.qcut) |
Segment into Young Adult, Adult, Middle-aged, Senior with balanced sizes |
| 6 | Engineered purchase_frequency_days |
Converted text frequencies to numeric days for analysis |
| 7 | Verified discount_applied = promo_code_used for all rows and dropped the duplicate column |
Removed redundant feature |
| 8 | Loaded cleaned data into PostgreSQL with SQLAlchemy | Enables SQL analysis and Power BI connection |
# Example: category-aware imputation
df['Review Rating'] = df.groupby('Category')['Review Rating'].transform(
lambda x: x.fillna(x.median())
)All queries are in customer_behavior_sql_queries.sql.
| # | Business Question | Techniques |
|---|---|---|
| Q1 | Revenue by gender | GROUP BY, SUM |
| Q2 | Discount users who still spent above average | Subquery |
| Q3 | Top 5 products by average review rating | AVG, ROUND, LIMIT |
| Q4 | Standard vs Express shipping spend | Filtering, AVG |
| Q5 | Do subscribers spend more? | Multi-metric aggregation |
| Q6 | Top 5 products by discount rate | Conditional aggregation (CASE WHEN) |
| Q7 | Segment customers: New / Returning / Loyal | CTE, CASE |
| Q8 | Top 3 products within each category | CTE, ROW_NUMBER() OVER (PARTITION BY ...) |
| Q9 | Are repeat buyers more likely to subscribe? | Filtering, grouping |
| Q10 | Revenue contribution by age group | GROUP BY, ORDER BY |
π Sample query: Top 3 products per category (click to expand)
WITH item_counts AS (
SELECT category,
item_purchased,
COUNT(customer_id) AS total_orders,
ROW_NUMBER() OVER (
PARTITION BY category
ORDER BY COUNT(customer_id) DESC
) AS item_rank
FROM customer
GROUP BY category, item_purchased
)
SELECT item_rank, category, item_purchased, total_orders
FROM item_counts
WHERE item_rank <= 3;File: customer_behavior_dashboard.pbix, connected live to the PostgreSQL customer table.
KPI Cards
- Total number of customers
- Average purchase amount
- Average review rating
Visuals
- π© % of customers by subscription status (donut)
- π Revenue by category and sales by category (column charts)
- π Revenue by age group and sales by age group (bar charts)
Interactive Slicers
- Subscription status Β· Gender Β· Category Β· Shipping type
β οΈ Before publishing: run your queries and replace the bracketed placeholders below with your real numbers. Recruiters look for specific figures.
- Revenue by gender: [Male/Female] customers generate [X]% of total revenue.
-
Subscribers: Subscribers spend [more/less/similar] on average (
$[X] vs $ [Y]) than non-subscribers. -
Shipping: [Express/Standard] shipping is associated with a higher average order value (
$[X] vs $ [Y]). - Loyalty: [X]% of customers are classified as Loyal (more than 10 previous purchases).
- Age groups: [Age group] contributes the highest revenue at [X]%.
- Discounts: [Product] has the highest discount rate at [X]%.
| Finding | Recommended Action |
|---|---|
| Discount-heavy products | Review pricing and margin; avoid training customers to wait for sales |
| High-value shipping tier | Promote it at checkout for larger baskets |
| Low subscription conversion among repeat buyers | Target loyal customers with membership offers |
| Top-revenue age group | Focus campaigns and product mix on this segment |
| Top-rated products | Feature in marketing and cross-sell bundles |
Customer_Behavior_and_Revenue_Analytics/
β
βββ Customer_Shopping_Behavior_Analysis.ipynb # Data cleaning, feature engineering, SQL load
βββ customer_behavior_sql_queries.sql # 10 business-question queries
βββ customer_behavior_dashboard.pbix # Power BI dashboard
βββ customer_shopping_behavior.csv # Raw dataset
βββ README.md
1. Clone the repository
git clone https://github.com/Krishal-Modi/Customer_Behavior_and_Revenue_Analytics.git
cd Customer_Behavior_and_Revenue_Analytics2. Install dependencies
pip install pandas numpy sqlalchemy psycopg2-binary jupyter3. Create a PostgreSQL database
CREATE DATABASE customer_behavior;4. Run the notebook
Open Customer_Shopping_Behavior_Analysis.ipynb, update the connection details with your own credentials, and run all cells. This cleans the data and loads it into a table named customer.
5. Run the SQL queries
Open customer_behavior_sql_queries.sql in pgAdmin (or any SQL client) and execute the queries.
6. Open the dashboard
Open customer_behavior_dashboard.pbix in Power BI Desktop and point the data source to your PostgreSQL database.
π Security note: never commit real database passwords. Use environment variables or a
.envfile.
Data Cleaning Β· Feature Engineering Β· Exploratory Data Analysis Β· Advanced SQL (CTEs, Window Functions) Β· Customer Segmentation Β· KPI Design Β· Dashboard Development Β· Data Storytelling Β· Business Recommendations
Krishal Modi Master of Applied Computing, University of Windsor