Solving Lost Revenue with AI Assortment Management
A category manager spends hours analyzing spreadsheets, yet still misses hidden cannibalization effects and seasonal patterns. Our AI assortment management solution uses ML demand models and cannibalization analysis to optimize your product portfolio, resulting in markdown reduction and revenue increase. The models based on gradient boosting and LLMs uncover non-obvious dependencies and deliver ready-made recommendations for adding or removing products. The ML demand model is 2.5 times better than traditional ABC-XYZ analysis, driving revenue growth of 4-8% and reducing markdowns by 15-25%. In one project, the savings amounted to 1.5 million RUB in a single product category. For a chain with 2000 SKUs, the system delivered an annual saving of 4.5 million RUB. With over 5 years of experience and 40+ AI retail projects, our team delivers proven results. Get a consultation to assess the potential for your assortment.
The AI Assistant Capabilities
The system integrates advanced retail analytics for category management, including sales forecasting via gradient boosting and LLM recommendations, with easy CRM integration. It analyzes sales, seasonality, cannibalization, and shelf space constraints. At its core are an ML demand model and a cannibalization matrix. Below is the key component.
Assortment Optimization
Click to view the Python class
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from anthropic import Anthropic
class AssortmentOptimizer:
def __init__(self):
self.llm = Anthropic()
self.demand_model = None
self.cannibalization_matrix = None
def train_demand_model(self, sales_df: pd.DataFrame):
"""Demand forecasting model for new items"""
features = ['price', 'category_encoded', 'brand_encoded',
'seasonality_index', 'days_available', 'marketing_spend']
available = [f for f in features if f in sales_df.columns]
X = sales_df[available].fillna(0)
y = sales_df['weekly_units_sold']
self.demand_model = GradientBoostingRegressor(
n_estimators=200, learning_rate=0.05, random_state=42
)
self.demand_model.fit(X, y)
def estimate_cannibalization(self, category_sales: pd.DataFrame) -> pd.DataFrame:
"""Cannibalization matrix between products in the same category"""
# Cannibalization coefficient via sales correlation
pivot = category_sales.pivot_table(
index='week', columns='sku', values='units_sold', fill_value=0
)
# Negative correlation = cannibalization
corr = pivot.corr()
cannibalization = pd.DataFrame(
np.where(corr < -0.3, abs(corr), 0),
index=corr.index, columns=corr.columns
)
self.cannibalization_matrix = cannibalization
return cannibalization
def recommend_assortment_changes(self, current_assortment: pd.DataFrame,
candidates: pd.DataFrame,
shelf_space: int) -> dict:
"""Recommendations for assortment changes"""
# Current assortment metrics
performance = current_assortment.copy()
performance['margin_per_sqft'] = (
performance['weekly_margin'] /
performance['shelf_space_sqft'].clip(0.1)
)
performance['sales_velocity'] = performance['weekly_units_sold']
# Weak items
weak_threshold = performance['margin_per_sqft'].quantile(0.25)
to_remove = performance[
(performance['margin_per_sqft'] < weak_threshold) &
(performance['weeks_in_assortment'] > 8)
]['sku'].tolist()
# Strong candidates for addition
if self.demand_model is not None and not candidates.empty:
available_features = [f for f in self.demand_model.feature_names_in_
if f in candidates.columns]
X_cand = candidates[available_features].fillna(0)
candidates['predicted_demand'] = self.demand_model.predict(X_cand)
candidates['predicted_margin'] = (
candidates['predicted_demand'] * candidates['gross_margin']
)
to_add = candidates.nlargest(len(to_remove), 'predicted_margin')['sku'].tolist()
else:
to_add = []
# AI explanation of recommendations
explanation = self._explain_recommendations(to_remove, to_add, performance)
return {
'remove': to_remove,
'add': to_add,
'expected_margin_lift': len(to_remove) * performance['margin_per_sqft'].quantile(0.75) * 0.1,
'explanation': explanation
}
def _explain_recommendations(self, to_remove: list, to_add: list,
performance: pd.DataFrame) -> str:
if to_remove:
removed_stats = performance[performance['sku'].isin(to_remove)][
['sku', 'margin_per_sqft', 'weeks_in_assortment']
].to_dict('records')
else:
removed_stats = []
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=200,
messages=[{
"role": "user",
"content": f"""Explain these assortment change recommendations to a category manager.
Remove {len(to_remove)} SKUs: {removed_stats[:3]}
Add {len(to_add)} SKUs: {to_add[:3]}
2-3 sentences: business rationale for the changes."""
}]
)
return response.content[0].text
The AssortmentOptimizer component uses gradient boosting for demand forecasting of new items and correlation analysis to identify cannibalization. Weak SKUs are identified by a quartile threshold of margin per square foot. The AI explanation powered by Claude 3.5 makes recommendations transparent to the category manager.
ML Models vs Traditional Rules
Traditional ABC-XYZ analysis does not account for demand dynamics and cross-product effects. ML models trained on historical data predict demand with >85% accuracy (versus ~60% for expert methods). Additionally, the cannibalization matrix automatically uncovers SKUs that 'eat' each other's sales — impossible to do manually. The ML demand model is at least 1.4 times better than traditional methods, and accounting for cannibalization widens the gap to more than two times better.
Comparison table: Traditional vs ML
| Characteristic | Traditional ABC-XYZ | ML Demand Model |
|---|---|---|
| Forecast accuracy | ~60% | >85% |
| Cannibalization consideration | No | Yes |
| Seasonality adaptation | Fixed coefficients | Automatic learning |
| Recalculation time | Days | Hours |
| Recommendation explanation | No | LLM description |
Data Requirements for Accurate Forecasting
The system requires a minimum of 12 months of sales history with SKU-level breakdown, prices, promotional activity, and shelf space. The more features (seasonality, marketing), the more accurate the model. We also use external data: holiday calendar, macroeconomic indicators. This enables p99 prediction latency under 100 ms.
Implementation Process
- Data audit — collect and clean sales history (12+ months), verify quality.
- Model training — tune gradient boosting to your assortment, calibrate thresholds.
- Integration — connect API to your CRM/ERP, set up auto-updates.
- Testing — A/B test on a pilot category (2-4 weeks).
- Launch — roll out to the entire assortment, monitor metrics.
This process takes 4 to 8 weeks depending on data volume.
Practical Example
For a chain of 50 hypermarkets, we replaced manual ABC-XYZ analysis with an ML model. After implementation, markdowns dropped by 22% and revenue increased by 6% in a quarter. The system generates weekly recommendations that category managers apply in a few hours. Reduced markdowns yielded an additional profit of 3.2 million RUB per quarter.
What's Included in the Work?
| Stage | What We Do | Result |
|---|---|---|
| Analytics | Collect and clean sales data (12+ months) | Feature-rich dataset |
| Modeling | Train demand model, calculate cannibalization | Model + matrix |
| Integration | Embed recommendation module into your CRM/ERP | API wrapper |
| Documentation | Describe logic, metrics, operation instructions | Model card |
| Training | Train category managers | 2 webinars |
| Support | 3 months of post-production monitoring | Weekly reports |
When Should You Implement an AI Assistant?
If your assortment exceeds 500 SKUs and review frequency is once a month or less, the AI system delivers rapid ROI. It is especially effective for FMCG, fashion, and electronics with seasonal fluctuations. Our team has over 5 years on the market, 10+ years in production, and has delivered 40+ AI projects for retailers, with 30+ specifically in assortment optimization. We guarantee forecast accuracy of at least 85% after implementation. We will assess your assortment in 2 days — request a demo or contact us for a consultation.







