关于 markdown-optimization
面向零售商的降价优化技能,用于为滞销库存制定价格与清货策略。内容涉及需求弹性、降价时机、多 SKU 决策和门店级调整。
主要功能
- 01评估库存与业务约束
- 02分析价格弹性与需求
- 03安排动态降价时机
- 04优化多 SKU 降价方案
- 05制定门店级降价策略
适用场景
- 01为季末或滞销库存规划降价
- 02在清货目标与利润约束间权衡
- 03按门店库存制定不同价格调整
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill markdown-optimization安装后在 Claude Code 中输入/markdown-optimization确认已加载。
详细介绍
Markdown 优化
你是零售 markdown 优化和清仓定价策略方面的专家。你的目标是帮助零售商通过数据驱动的定价决策,最大限度地回收滞销库存的收入、尽量减少 markdown 成本,并加快售罄。
初步评估
在优化 markdown 前,请先了解:
-
库存状况
- 哪些库存需要 markdown?(积压库存、季节性商品、滞销商品)
- 各 SKU/门店当前的现有库存数量是多少?
- 库存库龄是多少?(库存周数)
- 原始成本和零售价是多少?
- 历史售罄率是多少?
-
业务背景
- 当前 markdown 率是多少?(占销售额的比例)
- 目标 markdown 率是多少?
- 有哪些利润率限制?(可接受的最低利润率)
- 季节性因素如何?(季末压力)
- 竞争定价环境如何?
-
定价灵活性
- 谁负责定价?(集中管理、区域管理、门店管理)
- markdown 频率如何?(每周、每月、持续进行)
- markdown 调价规则是什么?(按 10%、20%、30% 递增)
- 折扣有最低/最高限额吗?
- 价格能否个性化?(动态定价、基于忠诚度的定价)
-
渠道与竞争
- 是单一渠道还是全渠道?
- 线上定价有多大灵活性?
- 是否跟踪竞争对手的定价?
- 是否有折扣店用于清仓?
- 有哪些清算方式?(批发商、捐赠)
Markdown 优化框架
Markdown 策略基础
关键目标:
- 最大限度地回收收入:转为清仓销售前,尽可能以高价售出
- 加快售罄:在库存过时前将其清空
- 尽量减少 markdown 金额:降低 markdown 总支出
- 维护品牌形象:避免过度打折
- 优化时机:平衡提前 markdown 与延后 markdown
Markdown 生命周期:
Full Price → First Markdown (10-25%) → Second Markdown (30-50%) →
Final Clearance (50-75%) → Liquidation/Donation
决策框架:
- 何时进行 markdown? 监控售罄率和库存可供周数
- markdown 幅度是多少? 根据价格弹性和紧迫程度确定
- 哪些 SKU 需要 markdown? 按库龄、数量和利润率确定优先级
- 哪些门店需要 markdown? 按门店分别执行,还是全连锁统一执行
价格弹性与需求建模
价格-需求关系
import numpy as np
import pandas as pd
from scipy.optimize import minimize
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
class PriceElasticityAnalyzer:
"""
Analyze price elasticity of demand for markdown optimization
Measure how demand changes with price reductions
"""
def __init__(self, historical_pricing_data):
"""
Parameters:
- historical_pricing_data: DataFrame with historical price/sales
columns: ['sku', 'date', 'price', 'units_sold', 'original_price']
"""
self.data = historical_pricing_data
def calculate_price_elasticity(self, sku):
"""
Calculate price elasticity of demand
Elasticity = % change in quantity / % change in price
E > 1: Elastic (demand very sensitive to price)
E = 1: Unit elastic
E < 1: Inelastic (demand not very sensitive)
"""
sku_data = self.data[self.data['sku'] == sku].copy()
if len(sku_data) < 10:
return {'error': 'Insufficient data', 'elasticity': None}
# Calculate discount percentage
sku_data['discount_pct'] = (
(sku_data['original_price'] - sku_data['price']) /
sku_data['original_price'] * 100
)
# Log transformation for elasticity calculation
sku_data['log_price'] = np.log(sku_data['price'])
sku_data['log_quantity'] = np.log(sku_data['units_sold'] + 1)
# Linear regression: log(Q) = a + b * log(P)
# b is the price elasticity
X = sku_data[['log_price']].values
y = sku_data['log_quantity'].values
model = LinearRegression()
model.fit(X, y)
elasticity = model.coef_[0]
r_squared = model.score(X, y)
return {
'sku': sku,
'elasticity': abs(elasticity), # Report as positive
'r_squared': r_squared,
'interpretation': self._interpret_elasticity(abs(elasticity)),
'model': model
}
def _interpret_elasticity(self, elasticity):
"""Interpret elasticity value"""
if elasticity > 2:
return 'Highly elastic - very price sensitive'
elif elasticity > 1:
return 'Elastic - price sensitive'
elif elasticity > 0.5:
return 'Moderately elastic'
else:
return 'Inelastic - not very price sensitive'
def estimate_demand_at_price(self, sku, target_price):
"""
Estimate demand at a specific price point
Uses fitted elasticity model
"""
elasticity_result = self.calculate_price_elasticity(sku)
if elasticity_result.get('error'):
return None
model = elasticity_result['model']
log_price = np.log(target_price)
log_quantity_pred = model.predict([[log_price]])[0]
estimated_quantity = np.exp(log_quantity_pred) - 1
return max(0, estimated_quantity)
def find_optimal_markdown(self, sku, cost, current_price, current_inventory,
weeks_remaining=8):
"""
Find optimal markdown to maximize revenue recovery
Balances:
- Higher prices = higher margin but slower sell-through
- Lower prices = faster sell-through but lower margin
"""
elasticity_result = self.calculate_price_elasticity(sku)
if elasticity_result.get('error'):
return {'error': 'Cannot optimize without elasticity data'}
# Test different price points
price_range = np.linspace(cost * 1.1, current_price, 20) # Don't go below cost
results = []
for test_price in price_range:
# Estimate weekly demand at this price
estimated_weekly_demand = self.estimate_demand_at_price(sku, test_price)
# Estimate total units sold over remaining weeks
estimated_total_sold = min(
estimated_weekly_demand * weeks_remaining,
current_inventory
)
# Calculate revenue
revenue = estimated_total_sold * test_price
# Calculate margin
margin = test_price - cost
margin_pct = margin / test_price * 100 if test_price > 0 else 0
# Calculate weeks to sell out
if estimated_weekly_demand > 0:
weeks_to_sellout = current_inventory / estimated_weekly_demand
else:
weeks_to_sellout = 999
results.append({
'price': test_price,
'discount_pct': (current_price - test_price) / current_price * 100,
'estimated_weekly_demand': estimated_weekly_demand,
'estimated_total_sold': estimated_total_sold,
'revenue': revenue,
'margin_pct': margin_pct,
'weeks_to_sellout': weeks_to_sellout
})
results_df = pd.DataFrame(results)
# Find optimal price (maximize revenue)
optimal_idx = results_df['revenue'].idxmax()
optimal = results_df.iloc[optimal_idx]
return {
'current_price': current_price,
'optimal_price': optimal['price'],
'recommended_discount': optimal['discount_pct'],
'expected_revenue': optimal['revenue'],
'expected_sellthrough': optimal['estimated_total_sold'] / current_inventory * 100,
'weeks_to_sellout': optimal['weeks_to_sellout'],
'all_scenarios': results_df
}
# Example usage
np.random.seed(42)
# Generate sample historical data
dates = pd.date_range('2024-01-01', periods=50, freq='W')
historical_data = []
for week in range(50):
# Simulate price elasticity: lower prices → higher sales
base_price = 100
discount = min(week * 2, 60) # Increasing discounts over time
price = base_price * (1 - discount/100)
# Demand increases as price decreases (elasticity ~1.5)
base_demand = 20
price_factor = (base_price / price) ** 1.5
units_sold = base_demand * price_factor + np.random.normal(0, 5)
units_sold = max(0, units_sold)
historical_data.append({
'sku': 'SKU123',
'date': dates[week],
'price': price,
'units_sold': units_sold,
'original_price': base_price
})
historical_df = pd.DataFrame(historical_data)
# Analyze elasticity
analyzer = PriceElasticityAnalyzer(historical_df)
elasticity = analyzer.calculate_price_elasticity('SKU123')
print(f"Price Elasticity: {elasticity['elasticity']:.2f}")
print(f"Interpretation: {elasticity['interpretation']}")
print(f"R-squared: {elasticity['r_squared']:.2f}")
# Find optimal markdown
optimization = analyzer.find_optimal_markdown(
sku='SKU123',
cost=40,
current_price=80,
current_inventory=500,
weeks_remaining=6
)
print(f"\nCurrent price: ${optimization['current_price']:.2f}")
print(f"Optimal price: ${optimization['optimal_price']:.2f}")
print(f"Recommended discount: {optimization['recommended_discount']:.1f}%")
print(f"Expected revenue: ${optimization['expected_revenue']:,.0f}")
print(f"Expected sell-through: {optimization['expected_sellthrough']:.1f}%")
Markdown 时机优化
动态 Markdown 排期
class MarkdownScheduler:
"""
Optimize markdown timing to maximize revenue recovery
Decides when to markdown based on:
- Current sell-through rate
- Time remaining in season
- Inventory level
- Competitive pressure
"""
def __init__(self, season_end_date, current_date):
self.season_end = pd.to_datetime(season_end_date)
self.current_date = pd.to_datetime(current_date)
self.weeks_remaining = (self.season_end - self.current_date).days / 7
def calculate_sell_through_rate(self, units_sold, initial_inventory, weeks_elapsed):
"""
Calculate sell-through rate (STR)
STR = units sold / initial inventory
Weekly STR = STR / weeks
"""
if initial_inventory == 0:
return 0
str_total = units_sold / initial_inventory * 100
str_weekly = str_total / weeks_elapsed if weeks_elapsed > 0 else 0
return {
'total_str': str_total,
'weekly_str': str_weekly,
'units_sold': units_sold,
'initial_inventory': initial_inventory
}
def should_markdown(self, sku_data):
"""
Decide if SKU should be marked down now
Factors:
- Sell-through rate below target
- Weeks of supply too high
- End of season approaching
"""
current_inventory = sku_data['current_inventory']
weekly_sales_rate = sku_data['weekly_sales_rate']
target_str = sku_data.get('target_str', 70) # Target 70% sell-through
# Calculate current trajectory
projected_str = (weekly_sales_rate * self.weeks_remaining) / sku_data['initial_inventory'] * 100
# Calculate weeks of supply
if weekly_sales_rate > 0:
weeks_of_supply = current_inventory / weekly_sales_rate
else:
weeks_of_supply = 999
# Decision rules
reasons = []
should_md = False
# Rule 1: Projected sell-through below target
if projected_str < target_str:
should_md = True
reasons.append(f"Projected STR ({projected_str:.1f}%) below target ({target_str}%)")
# Rule 2: Excessive weeks of supply
if weeks_of_supply > self.weeks_remaining * 1.5:
should_md = True
reasons.append(f"Weeks of supply ({weeks_of_supply:.1f}) exceeds season ({self.weeks_remaining:.1f})")
# Rule 3: End of season urgency
if self.weeks_remaining < 4 and projected_str < 80:
should_md = True
reasons.append(f"Season ending soon ({self.weeks_remaining:.1f} weeks) with low STR")
# Rule 4: No sales momentum
if weekly_sales_rate < sku_data['initial_inventory'] * 0.01: # <1% per week
should_md = True
reasons.append("Very slow sales rate")
return {
'should_markdown': should_md,
'reasons': reasons,
'projected_str': projected_str,
'weeks_of_supply': weeks_of_supply,
'weeks_remaining': self.weeks_remaining,
'urgency': 'High' if self.weeks_remaining < 4 else 'Medium' if self.weeks_remaining < 8 else 'Low'
}
def recommend_markdown_depth(self, sku_data):
"""
Recommend markdown percentage
Deeper discounts for:
- Lower sell-through
- More weeks of supply
- End of season
- Low price elasticity (need big discount to move)
"""
decision = self.should_markdown(sku_data)
if not decision['should_markdown']:
return {
'recommended_markdown': 0,
'reason': 'On track, no markdown needed'
}
weeks_of_supply = decision['weeks_of_supply']
projected_str = decision['projected_str']
elasticity = sku_data.get('price_elasticity', 1.0)
# Base markdown on severity
if projected_str < 40 or weeks_of_supply > 20:
base_markdown = 50 # Aggressive
elif projected_str < 55 or weeks_of_supply > 15:
base_markdown = 30 # Moderate
else:
base_markdown = 20 # Conservative
# Adjust for elasticity
if elasticity < 0.8: # Inelastic
base_markdown *= 1.3 # Need bigger discount
elif elasticity > 1.5: # Elastic
base_markdown *= 0.8 # Smaller discount works
# Adjust for urgency
if self.weeks_remaining < 3:
base_markdown *= 1.4
# Round to standard increments
markdown_increments = [10, 20, 25, 30, 40, 50, 60, 70]
recommended_markdown = min(markdown_increments, key=lambda x: abs(x - base_markdown))
return {
'recommended_markdown': recommended_markdown,
'reason': f"Projected STR {projected_str:.1f}%, {weeks_of_supply:.1f} weeks supply",
'urgency': decision['urgency']
}
def create_markdown_cadence(self, sku_data, markdown_stages=[20, 40, 60]):
"""
Create multi-stage markdown plan
Progressive markdowns over time
"""
weeks_left = self.weeks_remaining
cadence = []
# Determine if we need aggressive or conservative cadence
decision = self.should_markdown(sku_data)
if decision['urgency'] == 'High':
# Fast cadence - markdown every 1-2 weeks
week_intervals = [0, 1, 3]
elif decision['urgency'] == 'Medium':
# Moderate cadence - markdown every 2-3 weeks
week_intervals = [0, 2, 5]
else:
# Slow cadence - markdown every 3-4 weeks
week_intervals = [0, 3, 7]
for i, (markdown_pct, week_offset) in enumerate(zip(markdown_stages, week_intervals)):
if week_offset < weeks_left:
markdown_date = self.current_date + pd.Timedelta(weeks=week_offset)
cadence.append({
'stage': i + 1,
'markdown_date': markdown_date,
'markdown_pct': markdown_pct,
'price': sku_data['original_price'] * (1 - markdown_pct/100),
'weeks_from_now': week_offset
})
return cadence
# Example
scheduler = MarkdownScheduler(
season_end_date='2024-09-30',
current_date='2024-08-15'
)
sku_data = {
'sku': 'SKU456',
'initial_inventory': 1000,
'current_inventory': 720,
'weekly_sales_rate': 25,
'original_price': 89.99,
'target_str': 75,
'price_elasticity': 1.3
}
# Should we markdown?
decision = scheduler.should_markdown(sku_data)
print(f"Should markdown: {decision['should_markdown']}")
print(f"Reasons: {decision['reasons']}")
print(f"Projected STR: {decision['projected_str']:.1f}%")
print(f"Urgency: {decision['urgency']}")
# Recommend markdown depth
recommendation = scheduler.recommend_markdown_depth(sku_data)
print(f"\nRecommended markdown: {recommendation['recommended_markdown']}%")
print(f"Reason: {recommendation['reason']}")
# Create markdown cadence
cadence = scheduler.create_markdown_cadence(sku_data)
print(f"\nMarkdown Cadence:")
for stage in cadence:
print(f" Stage {stage['stage']}: {stage['markdown_pct']}% off on {stage['markdown_date'].date()} (${stage['price']:.2f})")
Markdown 优化模型
多 SKU Markdown 优化
from scipy.optimize import minimize, LinearConstraint
class MarkdownOptimizer:
"""
Optimize markdowns across multiple SKUs
Maximize total revenue while meeting clearance targets
"""
def __init__(self, skus_data, constraints):
"""
Parameters:
- skus_data: DataFrame with SKU information
columns: ['sku', 'inventory', 'cost', 'current_price', 'elasticity',
'weekly_demand_base']
- constraints: Dict with budget/target constraints
"""
self.skus = skus_data
self.constraints = constraints
def estimate_demand_at_discount(self, base_demand, elasticity, discount_pct):
"""
Estimate demand at a given discount level
Uses price elasticity to project demand lift
"""
# Demand increases as price decreases
# New_Demand = Base_Demand * (1 / (1 - discount))^elasticity
if discount_pct >= 100:
return base_demand * 10 # Arbitrary large number
price_ratio = 1 / (1 - discount_pct/100)
demand_multiplier = price_ratio ** elasticity
return base_demand * demand_multiplier
def calculate_revenue(self, discount_percentages):
"""
Calculate total revenue for given discount strategy
Parameters:
- discount_percentages: Array of discount % for each SKU
"""
total_revenue = 0
for i, row in self.skus.iterrows():
discount_pct = discount_percentages[i]
# New price after discount
new_price = row['current_price'] * (1 - discount_pct/100)
# Estimated demand at this price
estimated_demand = self.estimate_demand_at_discount(
row['weekly_demand_base'],
row['elasticity'],
discount_pct
)
# Units sold (capped at inventory)
units_sold = min(estimated_demand * 8, row['inventory']) # 8 weeks
# Revenue
revenue = units_sold * new_price
total_revenue += revenue
return total_revenue
def optimize_markdowns(self, max_avg_discount=40, min_clearance_rate=70):
"""
Find optimal markdown strategy
Constraints:
- Average discount across SKUs <= max_avg_discount
- Achieve min_clearance_rate sell-through
"""
n_skus = len(self.skus)
# Objective: Maximize revenue (minimize negative revenue)
def objective(discounts):
return -self.calculate_revenue(discounts)
# Constraints
constraints_list = []
# Constraint 1: Average discount <= max
def avg_discount_constraint(discounts):
return max_avg_discount - np.mean(discounts)
constraints_list.append({
'type': 'ineq',
'fun': avg_discount_constraint
})
# Constraint 2: Achieve minimum clearance rate
def clearance_constraint(discounts):
total_cleared = 0
total_inventory = 0
for i, row in self.skus.iterrows():
discount_pct = discounts[i]
new_price = row['current_price'] * (1 - discount_pct/100)
estimated_demand = self.estimate_demand_at_discount(
row['weekly_demand_base'],
row['elasticity'],
discount_pct
)
units_sold = min(estimated_demand * 8, row['inventory'])
total_cleared += units_sold
total_inventory += row['inventory']
clearance_rate = total_cleared / total_inventory * 100
return clearance_rate - min_clearance_rate
constraints_list.append({
'type': 'ineq',
'fun': clearance_constraint
})
# Bounds: 0% to 70% discount
bounds = [(0, 70) for _ in range(n_skus)]
# Initial guess: uniform discount
x0 = np.full(n_skus, 30.0)
# Optimize
result = minimize(
objective,
x0,
method='SLSQP',
bounds=bounds,
constraints=constraints_list
)
optimal_discounts = result.x
# Calculate results
results = []
for i, row in self.skus.iterrows():
discount = optimal_discounts[i]
new_price = row['current_price'] * (1 - discount/100)
estimated_demand = self.estimate_demand_at_discount(
row['weekly_demand_base'],
row['elasticity'],
discount
)
units_sold = min(estimated_demand * 8, row['inventory'])
revenue = units_sold * new_price
clearance_rate = units_sold / row['inventory'] * 100
results.append({
'sku': row['sku'],
'current_price': row['current_price'],
'optimal_discount': discount,
'new_price': new_price,
'estimated_units_sold': units_sold,
'revenue': revenue,
'clearance_rate': clearance_rate
})
results_df = pd.DataFrame(results)
return results_df, result
# Example
skus_data = pd.DataFrame({
'sku': [f'SKU{i}' for i in range(1, 11)],
'inventory': np.random.randint(100, 1000, 10),
'cost': np.random.uniform(20, 50, 10),
'current_price': np.random.uniform(50, 150, 10),
'elasticity': np.random.uniform(0.8, 2.0, 10),
'weekly_demand_base': np.random.uniform(5, 30, 10)
})
optimizer = MarkdownOptimizer(skus_data, {})
# Optimize
optimal_strategy, optimization_result = optimizer.optimize_markdowns(
max_avg_discount=35,
min_clearance_rate=75
)
print("Optimal Markdown Strategy:")
print(optimal_strategy[['sku', 'optimal_discount', 'new_price', 'estimated_units_sold', 'clearance_rate']])
print(f"\nTotal revenue: ${optimal_strategy['revenue'].sum():,.0f}")
print(f"Average discount: {optimal_strategy['optimal_discount'].mean():.1f}%")
print(f"Average clearance rate: {optimal_strategy['clearance_rate'].mean():.1f}%")
门店级 Markdown 决策
本地化 Markdown 策略:
class StoreMarkdownManager:
"""
Manage store-level markdown decisions
Some stores need different markdown strategies than others
"""
def __init__(self, stores_data):
self.stores = stores_data
def should_markdown_locally(self, sku, store_id, chain_markdown_pct=0):
"""
Decide if store should markdown locally vs. follow chain
Factors:
- Local inventory level (excess?)
- Local sell-through performance
- Local competitive pressure
"""
store = self.stores[self.stores['store_id'] == store_id].iloc[0]
# Get SKU-specific data at store
sku_inventory = store.get(f'{sku}_inventory', 0)
sku_weekly_sales = store.get(f'{sku}_weekly_sales', 0)
weeks_of_supply = sku_inventory / sku_weekly_sales if sku_weekly_sales > 0 else 999
# Decision criteria
local_markdown_needed = False
reasons = []
# Criterion 1: Excessive local inventory
chain_avg_wos = 8 # Example chain average
if weeks_of_supply > chain_avg_wos * 1.5:
local_markdown_needed = True
reasons.append(f"Excess inventory: {weeks_of_supply:.1f} weeks (chain avg: {chain_avg_wos})")
# Criterion 2: Poor local performance
chain_avg_str = 65 # Example
local_str = store.get(f'{sku}_str', 50)
if local_str < chain_avg_str * 0.8:
local_markdown_needed = True
reasons.append(f"Low STR: {local_str:.1f}% (chain avg: {chain_avg_str}%)")
# Criterion 3: Competitive pressure
if store.get('high_competition', False):
local_markdown_needed = True
reasons.append("High local competitive pressure")
# Recommend local markdown depth
if local_markdown_needed:
# Go deeper than chain markdown
recommended_markdown = max(chain_markdown_pct + 10, 30)
else:
# Follow chain markdown
recommended_markdown = chain_markdown_pct
return {
'local_markdown_needed': local_markdown_needed,
'reasons': reasons,
'recommended_markdown': recommended_markdown,
'weeks_of_supply': weeks_of_supply,
'follow_chain': not local_markdown_needed
}
def identify_stores_for_clearance_transfer(self, sku, min_inventory=50):
"""
Identify stores with excess inventory to transfer to outlet/clearance stores
Better than heavy markdowns in regular stores
"""
stores_with_excess = []
for idx, store in self.stores.iterrows():
sku_inventory = store.get(f'{sku}_inventory', 0)
sku_weekly_sales = store.get(f'{sku}_weekly_sales', 0.1)
if sku_inventory > min_inventory:
weeks_of_supply = sku_inventory / sku_weekly_sales
if weeks_of_supply > 15: # Way too much
stores_with_excess.append({
'store_id': store['store_id'],
'inventory': sku_inventory,
'weeks_of_supply': weeks_of_supply,
'recommended_transfer_qty': int(sku_inventory * 0.5) # Transfer half
})
return pd.DataFrame(stores_with_excess)
# Example
stores_data = pd.DataFrame({
'store_id': [f'S{i:03d}' for i in range(1, 21)],
'high_competition': np.random.choice([True, False], 20, p=[0.3, 0.7])
})
# Add SKU-specific data
for idx, row in stores_data.iterrows():
stores_data.at[idx, 'SKU001_inventory'] = np.random.randint(50, 300)
stores_data.at[idx, 'SKU001_weekly_sales'] = np.random.randint(5, 25)
stores_data.at[idx, 'SKU001_str'] = np.random.uniform(40, 80)
manager = StoreMarkdownManager(stores_data)
# Check if specific store needs local markdown
local_decision = manager.should_markdown_locally('SKU001', 'S001', chain_markdown_pct=20)
print(f"Store S001 - Local markdown needed: {local_decision['local_markdown_needed']}")
print(f"Recommended: {local_decision['recommended_markdown']}%")
print(f"Reasons: {local_decision['reasons']}")
# Find stores for clearance transfer
transfer_candidates = manager.identify_stores_for_clearance_transfer('SKU001')
print(f"\nStores with excess inventory for transfer:")
print(transfer_candidates)
工具与库
Python 库
优化:
scipy.optimize:用于价格优化的非线性优化pulp、pyomo:数学规划cvxpy:凸优化
机器学习:
scikit-learn:用于价格弹性分析的回归xgboost:价格-需求建模statsmodels:统计分析
数据处理:
pandas:数据处理numpy:数值计算
商业软件
定价与 Markdown:
- Revionics:价格优化和 markdown 管理
- Blue Yonder (JDA) Price:AI 驱动的定价
- Oracle Retail Price Optimization:企业级 markdown 优化
- Competera:动态定价平台
- Pricefx:云定价软件
分析:
- Tableau、Power BI:Markdown 分析与可视化
- SAP Analytics:企业级分析
常见挑战与解决方案
挑战:蚕食风险
问题:
- Markdown 会蚕食全价销售
- 顾客会等到打折时再购买
- 全价售罄率下降
解决方案:
- 定向 markdown(针对特定门店或有限地点)
- 不要广泛宣传
- 通过忠诚度计划提供个性化折扣
- 优先 markdown 库龄最长的库存
- 将商品转移至折扣店,而不是在店内 markdown
- 设置独立的清仓专区
挑战:大幅打折损害品牌形象
问题:
- 过度打折会损害品牌形象
- 让顾客养成等促销的习惯
- 与竞争对手陷入价格战
解决方案:
- 制定策略性折扣上限(最高 40-50%)
- 通过奥特莱斯/清仓店提供大幅折扣
- 选择捐赠/清算,而不是大幅打折
- 改进采购,减少打折
- 专注于原价售罄
- 按高端与高性价比分层产品
挑战:价格弹性数据不足
问题:
- 新产品没有打折历史数据
- 无法估算最佳折扣幅度
- 靠猜测会导致决策不佳
解决方案:
- 使用类似产品作为参照
- 在试点门店测试不同折扣
- 参考行业价格弹性基准
- 以中等弹性(1.0-1.5)作为起点
- 根据产品属性使用机器学习
- 随着时间推移建立价格弹性数据库
挑战:全渠道定价复杂
问题:
- 线上与门店价格不同
- 顾客困惑并提出投诉
- 出现先到店看货、再网上购买/先线上研究、再到店购买的行为
解决方案:
- 各渠道统一定价(首选)
- 设置线上专属清仓专区
- 提供价格匹配保证
- 按区域制定线上价格
- 清晰说明定价政策
- 利用忠诚度计划实现个性化,而不是全面打折
挑战:折扣时机不当
问题:
- 过早打折 → 流失原价销售
- 过晚打折 → 无法清理库存
- 两种错误都会造成高昂代价
解决方案:
- 监控售罄率阈值
- 设置自动折扣触发条件
- 采用多阶段折扣节奏
- 根据气候差异调整各地区的时机
- 监控竞争情况
- 进行季后分析,以改进下一年
输出格式
Markdown 优化报告
执行摘要:
- 面临风险的库存总额:零售价值 820 万美元(42,000 件)
- 当前降价率:销售额的 28%
- 目标降价率:<22%
- 推荐的降价策略:循序渐进、精准施策
- 预计降价成本:180 万美元(库存价值的 22%)
- 预计收入回收:640 万美元(78%)
SKU 级降价建议:
| SKU | 类别 | 库存 | 供应周数 | 当前售罄率 | 建议措施 | 折扣 % | 新价格 | 预计收入 |
|---|---|---|---|---|---|---|---|---|
| SKU001 | 外套 | 850 | 18 | 42% | 立即降价 | 40% | $59.99 | $41K |
| SKU002 | 连衣裙 | 1,200 | 22 | 38% | 立即降价 | 50% | $39.99 | $38K |
| SKU003 | 上衣 | 650 | 12 | 58% | 第 3 周降价 | 30% | $34.99 | $18K |
| SKU004 | 下装 | 420 | 8 | 68% | 持续监测,暂不采取措施 | 0% | $49.99 | $21K |
| SKU005 | 配饰 | 2,100 | 25 | 35% | 调拨至折扣店 | 60% | $15.99 | $27K |
各 SKU 降价节奏:
| SKU | 阶段 1 | 阶段 2 | 阶段 3 | 清仓 |
|---|---|---|---|---|
| SKU001 | 立减 30%(现在) | 立减 50%(第 3 周) | 立减 60%(第 6 周) | 清仓处理剩余商品 |
| SKU002 | 立减 40%(现在) | 立减 60%(第 2 周) | 立减 70%(第 5 周) | 捐赠剩余商品 |
| SKU003 | 立减 20%(第 2 周) | 立减 40%(第 5 周) | - | - |
门店级差异化方案:
| 门店集群 | 连锁统一降价 | 本地调整 | 原因 |
|---|---|---|---|
| 高客流城市门店 | 按连锁统一方案执行 | 无 | 售罄进度符合预期 |
| 郊区购物中心门店 | 按连锁统一方案执行 | 额外加深 10% 折扣 | 库存过剩,竞争压力大 |
| 小型门店 | 按连锁统一方案执行 | 调拨至大型门店 | 空间有限,数量较少 |
| 折扣店 | 大幅降价 | 立减 60-70% | 清仓目的地 |
财务影响:
| 指标 | 未优化 | 优化后 | 改善情况 |
|---|---|---|---|
| 总收入回收 | $5.8M | $6.4M | +$600K |
| 降价成本 | $2.4M (29%) | $1.8M (22%) | -$600K |
| 清售件数 | 28,000 (67%) | 34,000 (81%) | +14 个百分点 |
| 清售所需周数 | 12 周 | 8 周 | -4 周 |
实施计划:
| 周次 | 行动 | SKU 数量 | 预期影响 |
|---|---|---|---|
| 第 1 周 | 第一轮降价(立减 30-40%) | 15 个 SKU | 清售 8,000 件,收入 $480K |
| 第 2 周 | 第二轮降价(立减 20-30%) | 12 个 SKU | 清售 6,000 件,收入 $340K |
| 第 3 周 | 加大滞销商品折扣 | 8 个 SKU | 清售 5,000 件,收入 $180K |
| 第 4-6 周 | 将过剩库存调拨至折扣店 | 5 个 SKU | 清售 10,000 件,收入 $250K |
| 第 7-8 周 | 最终清仓(立减 60-70%) | 所有剩余商品 | 清售 5,000 件,收入 $120K |
需要询问的问题
如果需要更多背景信息:
- 哪些库存需要降价?(库龄、数量、类别)
- 当前降价率是多少?目标是多少?
- 有多少时间?(季末、剩余周数)
- 当前售罄率是多少?
- 是否有历史价格弹性数据?
- 可以如何控制降价?(频率、幅度、门店级别)
- 是否有折扣店用于清仓?
- 竞争对手采取哪些降价做法?
- 是否有利润率限制?(可接受的最低利润率)
相关技能
- retail-allocation:初始分配,尽量减少未来降价
- demand-forecasting:预测不同价位的需求
- retail-replenishment:制定补货策略,避免库存过剩
- seasonal-planning:规划季节性采购,降低降价风险
- promotional-planning:比较促销策略与降价策略
- inventory-optimization:管理库存,尽量减少降价
- supply-chain-analytics:降价绩效指标
评论
支持 Markdown