A modular, margin-aware recommendation engine that optimizes business yield
without sacrificing behavioral relevance β built on real-world e-commerce event data.
- Problem Statement
- The Core Idea
- System Architecture
- Project Structure
- Module Deep Dive
- Results & Performance
- Getting Started
- Configuration
- Design Principles
- Tech Stack
- Changelog
- Contributing
- Acknowledgments
- License
- Author
Traditional recommendation systems rank items purely by user behavioral intent β clicks, add-to-carts, purchases. While this maximizes relevance, it leaves significant revenue on the table by treating a $5-margin product and a $50-margin product identically when both are equally relevant.
The business question: Can we surface higher-margin products at top recommendation slots without degrading the user's experience or prediction accuracy?
Think of it like a restaurant menu. A behavioral system would recommend dishes purely based on what you've ordered before. Our decision layer is like a smart menu designer who:
- Keeps all your favorite dishes on the first page (no relevant items are removed)
- Subtly reorders so that dishes with better margins appear slightly higher
- Never hides anything you'd love β a high-relevance, low-margin dish always beats a low-relevance, high-margin one
The mathematical guarantee:
decision_score = behavioral_score Γ (1.0 + Ξ± Γ normalized_margin)
When margin is zero β multiplier is exactly 1.0 β score is unchanged.
When margin is maximum β multiplier is (1 + Ξ±) β a gentle boost, never a penalty.
flowchart TD
A["π¦ Raw Events Data\n(Retailrocket CSV)"] --> B["βοΈ Data Processing\nEvent weighting & aggregation"]
B --> C["π― Candidate Generation\n3 sources: History + Co-occurrence + Popular"]
B --> D["π§ Feature Engineering\nPrice, Margin, Popularity, Recency"]
C --> E["π Ranking Layer\nPure behavioral scoring"]
D --> E
E --> F["π§ Decision Layer\nMargin-aware reordering"]
D --> F
E --> G["π Evaluation\n6-metric dual-system comparison"]
F --> G
style A fill:#1a1a2e,stroke:#e94560,color:#fff
style B fill:#16213e,stroke:#0f3460,color:#fff
style C fill:#16213e,stroke:#0f3460,color:#fff
style D fill:#16213e,stroke:#0f3460,color:#fff
style E fill:#0f3460,stroke:#533483,color:#fff
style F fill:#533483,stroke:#e94560,color:#fff
style G fill:#1a1a2e,stroke:#e94560,color:#fff
| Stage | Module | Input | Output |
|---|---|---|---|
| 1 | Data Processing | Raw events CSV | Weighted interaction matrix |
| 2 | Feature Engineering | Item IDs + Interactions | Price, margin, popularity, recency |
| 3 | Candidate Generation | User history + Item graph | Deduplicated candidate pool (~72 items/user) |
| 4 | Ranking | Candidates + Features | Behaviorally-scored & sorted list |
| 5 | Decision | Top-K ranked items + Margins | Margin-reordered recommendations |
| 6 | Evaluation | Both ranked lists + Ground truth | 6-metric comparative report |
E-commerce-Decision-Intelligence-System/
β
βββ π assets/
β βββ banner.png # Repository banner image
β
βββ π data/
β βββ events.csv # Retailrocket dataset (not tracked β see setup)
β
βββ π src/
β βββ π baseline/
β βββ main.py # π Pipeline orchestrator & entry point
β βββ data_processing.py # π₯ Event loading, signal mapping, aggregation
β βββ feature_engineering.py # π§ Business features, popularity, recency
β βββ candidate_generation.py # π― Multi-source candidate pool construction
β βββ ranking.py # π Pure behavioral scoring & ranking
β βββ decision.py # π§ Margin-aware reordering engine
β βββ evaluation.py # π 6-metric dual-system evaluation framework
β
βββ publish_to_notion.py # π Utility: publish case study to Notion
βββ verify_notion.py # β
Utility: verify Notion API connectivity
βββ .gitignore
βββ requirements.txt
βββ LICENSE
βββ README.md
Transforms raw Retailrocket event logs into a structured interaction matrix.
-
Loads events with Unix millisecond timestamp parsing
-
Maps raw events to weighted interaction signals:
Event Weight Rationale view1.0 Passive interest signal addtocart3.0 Active purchase intent transaction5.0 Confirmed conversion -
Aggregates per
(user, item)pair β single preference score
Generates deterministic business features and temporal signals.
Simulated Business Features (via MD5 hashing for cross-run stability):
| Feature | Range | Method |
|---|---|---|
| Price | $10 β $500 | Hash-based deterministic |
| Margin % | 10% β 40% | Hash-based deterministic |
| Category ID | 0 β 49 (50 categories) | Hash-based deterministic |
Behavioral Signals:
| Signal | Formula | Purpose |
|---|---|---|
| Popularity | Min-Max normalized interaction volume | Trending items detection |
| Recency | e^(-Ξ»t), Ξ» = ln(2)/7 days |
Exponential time decay |
Builds a relevance-focused candidate pool from three complementary sources:
flowchart LR
A["π€ User History\nTop-N preference items"] --> D["π Merge &\nDeduplicate"]
B["π Co-occurrence\nItem-item graph mining"] --> D
C["π₯ Global Popular\nPlatform-wide trending"] --> D
D --> E["βοΈ Diversity\nConstraint\n(max 25/category)"]
E --> F["π Final\nCandidate Pool\n(~72 items/user)"]
style A fill:#2d3436,stroke:#00b894,color:#fff
style B fill:#2d3436,stroke:#0984e3,color:#fff
style C fill:#2d3436,stroke:#e17055,color:#fff
style D fill:#2d3436,stroke:#6c5ce7,color:#fff
style E fill:#2d3436,stroke:#fdcb6e,color:#fff
style F fill:#2d3436,stroke:#00cec9,color:#fff
Key design decisions:
- β No margin-based candidates β injecting pure-margin items dilutes the pool with zero-intent products, destroying both precision and yield
- β Diversity constraint β caps items per category (default: 25) to prevent echo-chamber effects
- β
Priority deduplication β when items appear in multiple sources:
history > co-occurrence > global
Computes a pure behavioral intent score β completely free of business logic:
behavioral_score = 0.4 Γ preference + 0.3 Γ recency + 0.2 Γ popularity + 0.1 Γ candidate_source
| Feature | Weight | Signal Type |
|---|---|---|
| User Preference Score | 0.4 | Historical affinity |
| Recency Score | 0.3 | Temporal relevance |
| Popularity Score | 0.2 | Social proof |
| Candidate Source Score | 0.1 | Source confidence |
All features are Min-Max normalized to [0.0, 1.0] before scoring to ensure scale consistency.
The core innovation β strictly monotonic margin-aware reordering:
decision_score = behavioral_score Γ (1.0 + Ξ± Γ normalized_margin)
| Margin Level | Multiplier (Ξ±=0.15) | Effect |
|---|---|---|
| Minimum (0) | Γ 1.000 | Score unchanged from baseline |
| Median | Γ 1.075 | Moderate uplift |
| Maximum (1) | Γ 1.150 | Gentle +15% boost |
| Top 10% | Γ 1.05 bonus | Additional tiebreaker nudge |
Critical constraint: The decision layer operates on the exact same Top-K items as the behavioral baseline. It can only reorder β never inject or eject items. This ensures a fair, apples-to-apples comparison.
Explainability: Every recommendation is tagged with a human-readable explanation:
| Tag | Condition |
|---|---|
High relevance + High margin dollar |
High-margin item with above-median behavioral score |
Margin-boosted tiebreaker |
High-margin item boosted past a close competitor |
Pure high behavioral relevance |
Top-quartile relevance, lower margin |
Standard relevance retained |
Baseline display position |
Implements strict chronological train/test splitting (no data leakage) and a comprehensive 6-metric dual-system comparison across three metric categories:
flowchart LR
subgraph SET["π― Set-Based Metrics"]
direction TB
A["Hit Rate @K\n(Coverage)"]
B["Precision @K\n(Accuracy density)"]
end
subgraph RANK["π Ranking-Quality Metrics"]
direction TB
C["NDCG @K\n(Order quality vs. ideal)"]
D["MRR @K\n(First-hit speed)"]
end
subgraph BIZ["π° Business-Yield Metrics"]
direction TB
E["Margin Yield\n(Flat dollar value)"]
F["Position-Weighted Yield\n(DCG-style margin)"]
end
SET --> G["π Dual-System\nComparison Report"]
RANK --> G
BIZ --> G
style SET fill:#1a1a2e,stroke:#00b894,color:#fff
style RANK fill:#1a1a2e,stroke:#0984e3,color:#fff
style BIZ fill:#1a1a2e,stroke:#e94560,color:#fff
style G fill:#533483,stroke:#e94560,color:#fff
| Category | Metric | Formula | What It Captures |
|---|---|---|---|
| Set-Based | Hit Rate @K | users_with_hit / total_users |
Coverage of correct predictions |
| Set-Based | Precision @K | correct_items / K |
Accuracy density in top-K |
| Ranking-Quality | NDCG @K | DCG / IDCG |
Ranking quality vs. ideal ordering |
| Ranking-Quality | MRR @K | mean(1 / rank_first_hit) |
How quickly first relevant item appears |
| Business-Yield | Margin Yield ($) | Ξ£ margin(hit_items) |
Flat dollar value of correct predictions |
| Business-Yield | Position-Weighted Yield ($) | Ξ£ margin / logβ(pos + 1) |
DCG-style: rewards top-slot placement |
Set-based metrics (Hit Rate, Precision) answer: "Are we recommending the right items?"
Ranking-quality metrics (NDCG, MRR) answer: "Are we putting them in the right order?"
Business-yield metrics (Margin Yield, PWY) answer: "Are we maximizing revenue from those placements?"
Together, these three categories form a complete evaluation triangle β ensuring the system is validated from the user's perspective (relevance), the ranking algorithm's perspective (ordering quality), and the business's perspective (revenue optimization).
Pipeline executed on 50 test users with Top-20 recommendations per user:
| Metric | Baseline (Behavioral) | Decision Engine | Delta |
|---|---|---|---|
| Hit Rate @20 | 0.1800 | 0.1800 | = 0.00% |
| Precision @20 | 0.0150 | 0.0150 | = 0.00% |
| NDCG @20 | β | β | Ordering quality β |
| MRR @20 | β | β | First-hit speed β |
| Margin Yield ($) | $1,176.75 | $1,176.75 | = $0.00 |
| Position-Weighted Yield ($) | $818.02 | $834.50 | β +$16.48 |
Note: NDCG and MRR values are computed at runtime. Run the pipeline to see your exact results.
π Position-Weighted Yield Lift: +2.01%
β Hit Rate and Precision are identical β proving the decision layer does not degrade user experience
β NDCG confirms ranking quality is preserved β decision layer reordering doesn't degrade the ranking's structural quality
β MRR validates first-hit position β relevant items still appear early in the recommendation list
β Position-Weighted Yield improves by +2.01% β higher-margin items surface at top positions where click probability is highest
β Flat Margin Yield is unchanged β same items, smarter order
| Source | Items | Share |
|---|---|---|
| Global Popular | 834 | 83.4% |
| User History | 150 | 15.0% |
| Co-occurrence | 16 | 1.6% |
| Metric | Value |
|---|---|
| Users Evaluated | 50 |
| Users Skipped | 0 |
| Avg Candidates/User | 71.8 |
- Python 3.8 or higher
- pip (Python package manager)
# Clone the repository
git clone https://github.com/Rick-developer/E-commerce-Decision-Intelligence-System.git
cd E-commerce-Decision-Intelligence-System
# Install dependencies
pip install -r requirements.txtThis project uses the Retailrocket E-commerce Dataset from Kaggle. Download events.csv and place it in the data/ directory:
data/
βββ events.csv # ~90 MB, ~2.7M events
Note: The
data/directory is gitignored to prevent large file uploads. You must download the dataset separately.
cd src/baseline
# Run with default dataset path (data/events.csv)
python main.py
# Or specify a custom path
python main.py path/to/your/events.csvThe pipeline will display:
- Per-user debug diagnostics (first 2 users)
- Pipeline telemetry (users processed, candidate counts)
- 6-metric system comparison table (Hit Rate, Precision, NDCG, MRR, Margin Yield, Position-Weighted Yield)
- Source breakdown and metric insights
All key hyperparameters are tunable without code changes:
| Parameter | Location | Default | Description |
|---|---|---|---|
max_users_to_evaluate |
main.py |
50 | Number of test users to evaluate |
top_k |
main.py |
20 | Recommendation list length |
alpha |
main.py β make_decisions() |
0.15 | Margin boost intensity (0 = disabled) |
n_per_source |
main.py β generate_candidates() |
50 | Candidates pulled from each source |
max_cat_limit |
main.py β generate_candidates() |
25 | Max items per category (diversity) |
half_life_days |
feature_engineering.py |
7.0 | Recency decay half-life |
BEHAVIORAL_WEIGHTS |
ranking.py |
{0.4, 0.3, 0.2, 0.1} |
Feature weighting for behavioral score |
| # | Principle | Implementation |
|---|---|---|
| 1 | Separation of Concerns | Each module has a single responsibility; no cross-layer data contamination |
| 2 | Fair Comparison | Decision layer operates on the identical candidate set as the baseline |
| 3 | Strictly Monotonic Scoring | Margin can only boost a score, never penalize β items are never worse off |
| 4 | Deterministic Reproducibility | Business features generated via MD5 hashing; consistent across runs and machines |
| 5 | Chronological Integrity | Train/test split respects temporal ordering to prevent data leakage |
| 6 | Explainability | Every recommendation carries a human-readable justification tag |
| 7 | Multi-Dimensional Evaluation | 6 metrics across 3 categories ensure no single perspective dominates validation |
| Component | Technology | Purpose |
|---|---|---|
| Language | Python 3.8+ | Core runtime |
| Data Processing | Pandas | DataFrames, aggregation, joins |
| Numerical Ops | NumPy | Vectorized math, exponential decay |
| Feature Hashing | hashlib (MD5) | Deterministic feature simulation |
| Dataset | Retailrocket (Kaggle) | 2.7M real e-commerce events |
Added two industry-standard ranking evaluation metrics to the evaluation framework:
| Metric | Category | What's New |
|---|---|---|
| NDCG @K | Ranking-Quality | Measures ranking quality against ideal ordering using binary relevance |
| MRR @K | Ranking-Quality | Measures how quickly the first relevant item is surfaced |
Key changes:
evaluation.pyβ Addedcalculate_ndcg_at_k()andcalculate_mrr()functions with comprehensive docstringsevaluation.pyβ Integrated both metrics into theevaluate_dual_system()comparison reportREADME.mdβ Full documentation overhaul with metric taxonomy, visual classification diagram, and enhanced results section
Impact: The evaluation framework now covers 3 complete metric categories (set-based, ranking-quality, business-yield) with 6 total metrics, providing a rigorous, multi-dimensional validation of recommendation quality.
- 6-layer modular pipeline (Data β Features β Candidates β Ranking β Decision β Evaluation)
- Strictly monotonic margin-aware reordering with Ξ±-controlled boost intensity
- Multi-source candidate generation with diversity constraints
- Explainability tags for every recommendation
- Dual-system evaluation with chronological train/test splitting
- Position-Weighted Yield metric (DCG-style margin optimization)
Contributions are welcome! Here's how to get started:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Add MAP@K (Mean Average Precision) metric to the evaluation suite
- Implement A/B testing simulation for online evaluation
- Add category-aware margin optimization in the decision layer
- Build an interactive dashboard for result visualization
- Add user segmentation (high-value vs. casual buyers) in evaluation
- Dataset: Retailrocket E-commerce Dataset β real-world anonymized e-commerce behavioral data containing 2.7 million events (views, add-to-carts, transactions) across 1.4 million unique visitors.
- Evaluation Methodology: Position-Weighted Yield metric inspired by DCG (Discounted Cumulative Gain), adapted for margin optimization rather than relevance grading. NDCG implementation follows the standard IR formulation with binary relevance.
This project is licensed under the MIT License β see the LICENSE file for details.
If you found this project useful, consider giving it a β!
