关于 planogram-optimization
面向零售商的货架图优化技能,帮助依据销售、利润、商品属性和门店条件分配货架空间与商品排面。内容涵盖空间生产率、陈列位置、商品邻接及实施规划。
主要功能
- 01按销售与利润分配货架空间
- 02分析货架空间与销售关系
- 03规划商品排面和陈列位置
- 04优化互补商品邻接
- 05制定调整与实施方案
适用场景
- 01提升品类每平方英尺销售额
- 02根据商品周转率调整排面
- 03规划互补商品的交叉陈列
- 04为门店陈列调整制定分阶段计划
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill planogram-optimization安装后在 Claude Code 中输入/planogram-optimization确认已加载。
详细介绍
货架陈列图优化
你是零售货架陈列图优化与空间管理方面的专家。你的目标是帮助零售商通过优化货架空间分配、确定商品排面数,以及设计高效的门店布局,在每平方英尺的空间内实现销售额和盈利能力最大化,同时兼顾商品可见度、顾客体验和运营效率。
初步评估
优化货架陈列图之前,请先了解:
-
门店背景
- 门店业态是什么?(杂货、服装、电子产品、药房)
- 门店面积和布局如何?(平方英尺、货架数量)
- 客流模式如何?(入口位置、收银台位置)
- 目标顾客的人口统计特征是什么?
- 门店位于哪类地点?(市区、郊区、购物中心)
-
品类特征
- 需要优化哪个品类/部门?
- 品类中有多少个 SKU?
- 商品尺寸是多少?(高度、宽度、深度)
- 单位销量如何?(畅销品与滞销品)
- 各 SKU 的利润率如何?
- 是否需要考虑保质期?(易腐商品、季节性商品)
-
当前表现
- 当前每平方英尺的销售额是多少?
- 缺货频率如何?
- 各货架的空间生产力如何?
- 顾客对布局的满意度如何?
- 补货的人工成本是多少?
-
业务目标
- 目标是最大化收入还是利润?
- 目标服务水平是多少?(商品有货率)
- 是否有交叉陈列目标?
- 是否有品牌或促销要求?
- 是否有运营限制?(补货频率、人工)
货架陈列图优化框架
空间生产力原则
1. 空间弹性
- 货架空间与销售额之间的关系
- 边际效益递减:空间增加并不总能带来更多销售
- 各 SKU 的最佳排面数因商品而异
2. 空间分配规则
- 高周转商品:增加排面,放置在视线高度
- 高利润率商品:放置在优质位置
- 冲动购买商品:放在端架和收银台附近
- 目的性购买商品:可放在店铺深处(以吸引顾客经过更多区域)
- 互补商品:组成交叉陈列组合
3. 货架高度的影响
- 视线高度(4-5 ft):黄金位置,占销售额的 40%
- 胸部高度(3-4 ft):次优位置,占销售额的 30%
- 腰部高度(2-3 ft):第三优位置,占销售额的 20%
- 地面高度(0-2 ft):可见度低,占销售额的 10%
- 视线以上(5-6 ft):用于溢出陈列,满足偶尔购买需求
4. 商品邻接
- 将相关商品放在一起(意面 + 酱料)
- 通过颜色分区提升视觉吸引力
- 按尺寸递增排列(从小到大)
- 按价格递增排列(从低到高)
空间与销售额分析
空间弹性建模
import numpy as np
import pandas as pd
from scipy.optimize import minimize
import matplotlib.pyplot as plt
class SpaceElasticityAnalyzer:
"""
Analyze space elasticity - relationship between shelf space and sales
Space Elasticity = % change in sales / % change in shelf space
"""
def __init__(self, historical_data):
"""
Parameters:
- historical_data: DataFrame with space/sales experiments
columns: ['sku', 'period', 'facings', 'sales_units', 'sales_dollars']
"""
self.data = historical_data
def calculate_space_elasticity(self, sku):
"""
Calculate space elasticity coefficient
Using log-log regression: log(Sales) = a + b * log(Facings)
b is the space elasticity
"""
sku_data = self.data[self.data['sku'] == sku].copy()
if len(sku_data) < 5:
return {'error': 'Insufficient data'}
# Log transformation
sku_data['log_facings'] = np.log(sku_data['facings'])
sku_data['log_sales'] = np.log(sku_data['sales_units'] + 1)
# Linear regression in log-log space
X = sku_data['log_facings'].values.reshape(-1, 1)
y = sku_data['log_sales'].values
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
elasticity = model.coef_[0]
r_squared = model.score(X, y)
# Interpretation
if elasticity > 0.8:
interpretation = 'High elasticity - sales very responsive to space'
elif elasticity > 0.4:
interpretation = 'Moderate elasticity - typical'
elif elasticity > 0.1:
interpretation = 'Low elasticity - limited response to space'
else:
interpretation = 'Very low elasticity - sales not space-dependent'
return {
'sku': sku,
'elasticity': elasticity,
'r_squared': r_squared,
'interpretation': interpretation,
'model': model
}
def estimate_sales_at_facings(self, sku, target_facings):
"""
Estimate sales at a given number of facings
Uses fitted elasticity model
"""
elasticity_result = self.calculate_space_elasticity(sku)
if 'error' in elasticity_result:
return None
model = elasticity_result['model']
log_facings = np.log(target_facings)
log_sales_pred = model.predict([[log_facings]])[0]
estimated_sales = np.exp(log_sales_pred) - 1
return max(0, estimated_sales)
def find_optimal_facings(self, sku, cost_per_facing, profit_per_unit,
max_facings=20):
"""
Find optimal number of facings to maximize profit
Balance: More facings = more sales but higher space cost
"""
elasticity_result = self.calculate_space_elasticity(sku)
if 'error' in elasticity_result:
return {'error': 'Cannot optimize without elasticity data'}
facings_range = range(1, max_facings + 1)
results = []
for facings in facings_range:
estimated_sales = self.estimate_sales_at_facings(sku, facings)
# Calculate profit
revenue = estimated_sales * profit_per_unit
space_cost = facings * cost_per_facing
profit = revenue - space_cost
results.append({
'facings': facings,
'estimated_sales': estimated_sales,
'revenue': revenue,
'space_cost': space_cost,
'profit': profit,
'profit_per_facing': profit / facings if facings > 0 else 0
})
results_df = pd.DataFrame(results)
# Find optimal
optimal_idx = results_df['profit'].idxmax()
optimal = results_df.iloc[optimal_idx]
return {
'optimal_facings': optimal['facings'],
'expected_sales': optimal['estimated_sales'],
'expected_profit': optimal['profit'],
'elasticity': elasticity_result['elasticity'],
'all_scenarios': results_df
}
# Example usage
np.random.seed(42)
# Generate sample data - simulate space elasticity
historical_data = []
for sku_id in range(1, 6):
# Each SKU has different elasticity
base_sales = np.random.uniform(50, 200)
elasticity = np.random.uniform(0.2, 0.7)
for period in range(20):
facings = np.random.randint(2, 15)
# Sales = base * (facings ^ elasticity) + noise
sales = base_sales * (facings ** elasticity) + np.random.normal(0, 10)
sales = max(0, sales)
historical_data.append({
'sku': f'SKU{sku_id:03d}',
'period': period,
'facings': facings,
'sales_units': sales,
'sales_dollars': sales * np.random.uniform(3, 8)
})
historical_df = pd.DataFrame(historical_data)
# Analyze elasticity
analyzer = SpaceElasticityAnalyzer(historical_df)
elasticity = analyzer.calculate_space_elasticity('SKU001')
print(f"Space Elasticity: {elasticity['elasticity']:.3f}")
print(f"Interpretation: {elasticity['interpretation']}")
print(f"R-squared: {elasticity['r_squared']:.3f}")
# Find optimal facings
optimization = analyzer.find_optimal_facings(
sku='SKU001',
cost_per_facing=2.5, # Cost per facing per week
profit_per_unit=4.0, # Profit margin per unit
max_facings=15
)
print(f"\nOptimal facings: {optimization['optimal_facings']}")
print(f"Expected weekly sales: {optimization['expected_sales']:.0f} units")
print(f"Expected weekly profit: ${optimization['expected_profit']:.2f}")
货架陈列图优化模型
货架级空间分配
class PlanogramOptimizer:
"""
Optimize product placement and facings on a fixture
Maximize sales/profit per square foot
"""
def __init__(self, fixture_config, products_data):
"""
Parameters:
- fixture_config: Dict with fixture dimensions
{'shelves': 5, 'width_inches': 48, 'depth_inches': 12}
- products_data: DataFrame with product info
columns: ['sku', 'width_inches', 'depth_inches', 'height_inches',
'weekly_sales', 'profit_per_unit', 'min_facings', 'max_facings']
"""
self.fixture = fixture_config
self.products = products_data
def calculate_space_productivity(self, allocation):
"""
Calculate sales and profit per square foot for an allocation
allocation: Dict {sku: {'shelf': shelf_num, 'facings': count}}
"""
total_sales = 0
total_profit = 0
space_used = {} # Track space used per shelf
for sku, placement in allocation.items():
product = self.products[self.products['sku'] == sku].iloc[0]
# Calculate space consumption
facings = placement['facings']
width_per_facing = product['width_inches']
total_width = facings * width_per_facing
shelf = placement['shelf']
# Update space tracking
if shelf not in space_used:
space_used[shelf] = 0
space_used[shelf] += total_width
# Calculate sales (with space elasticity effect)
base_sales = product['weekly_sales']
elasticity = product.get('space_elasticity', 0.4)
# Diminishing returns: sales = base * (facings ^ elasticity)
adjusted_sales = base_sales * (facings ** elasticity)
total_sales += adjusted_sales
total_profit += adjusted_sales * product['profit_per_unit']
# Calculate space utilization
total_space_sqft = (
self.fixture['shelves'] *
self.fixture['width_inches'] *
self.fixture['depth_inches'] / 144 # Convert to sqft
)
sales_per_sqft = total_sales / total_space_sqft if total_space_sqft > 0 else 0
profit_per_sqft = total_profit / total_space_sqft if total_space_sqft > 0 else 0
# Check constraints
valid = True
for shelf, width_used in space_used.items():
if width_used > self.fixture['width_inches']:
valid = False
return {
'total_sales': total_sales,
'total_profit': total_profit,
'sales_per_sqft': sales_per_sqft,
'profit_per_sqft': profit_per_sqft,
'space_utilization': space_used,
'valid': valid
}
def greedy_allocation(self, objective='profit'):
"""
Greedy algorithm to allocate products to fixture
Prioritize by profit per square foot (or sales per sqft)
"""
# Calculate priority score for each product
self.products['priority'] = self.products.apply(
lambda row: self._calculate_priority(row, objective),
axis=1
)
# Sort by priority
sorted_products = self.products.sort_values('priority', ascending=False)
# Allocate
allocation = {}
shelf_space_remaining = {
i: self.fixture['width_inches'] for i in range(self.fixture['shelves'])
}
for idx, product in sorted_products.iterrows():
sku = product['sku']
width = product['width_inches']
min_facings = product.get('min_facings', 1)
max_facings = product.get('max_facings', 10)
# Try to allocate to best shelf position
# Eye level (middle shelves) are most valuable
shelf_priority = self._get_shelf_priority_order(self.fixture['shelves'])
allocated = False
for shelf in shelf_priority:
max_facings_possible = int(shelf_space_remaining[shelf] / width)
if max_facings_possible >= min_facings:
# Allocate optimal number of facings
facings = min(max_facings, max_facings_possible)
allocation[sku] = {
'shelf': shelf,
'facings': facings,
'position': 'center' # Simplified
}
# Update remaining space
shelf_space_remaining[shelf] -= facings * width
allocated = True
break
if not allocated:
# Could not fit this product
pass
return allocation
def _calculate_priority(self, product, objective):
"""Calculate priority score for product placement"""
if objective == 'profit':
# Profit per unit of space
space_per_unit = product['width_inches'] * product['depth_inches']
return (product['weekly_sales'] * product['profit_per_unit']) / space_per_unit
else: # sales
space_per_unit = product['width_inches'] * product['depth_inches']
return product['weekly_sales'] / space_per_unit
def _get_shelf_priority_order(self, num_shelves):
"""
Get shelf allocation priority
Eye level (middle) is most valuable
"""
if num_shelves <= 3:
return list(range(num_shelves))
# Middle shelves first
middle = num_shelves // 2
priority = [middle]
# Alternate above and below middle
for offset in range(1, num_shelves):
if middle + offset < num_shelves:
priority.append(middle + offset)
if middle - offset >= 0:
priority.append(middle - offset)
return priority
def optimize_with_constraints(self, objective='profit',
category_constraints=None):
"""
Optimize with business constraints
Constraints:
- Minimum facings per SKU
- Maximum facings per SKU
- Product grouping (keep related products together)
- Brand requirements
"""
# Use greedy as baseline
allocation = self.greedy_allocation(objective)
# Calculate performance
performance = self.calculate_space_productivity(allocation)
return allocation, performance
def create_visual_planogram(self, allocation):
"""
Create visual representation of planogram
Returns ASCII art / simple visualization
"""
# Group by shelf
shelves = {}
for sku, placement in allocation.items():
shelf = placement['shelf']
if shelf not in shelves:
shelves[shelf] = []
product = self.products[self.products['sku'] == sku].iloc[0]
width = product['width_inches'] * placement['facings']
shelves[shelf].append({
'sku': sku,
'facings': placement['facings'],
'width': width
})
# Print planogram
print(f"\nPLANOGRAM - {self.fixture['width_inches']}\" wide x {self.fixture['shelves']} shelves")
print("=" * 60)
for shelf in range(self.fixture['shelves'] - 1, -1, -1): # Top to bottom
print(f"Shelf {shelf + 1}:", end=" ")
if shelf in shelves:
for item in shelves[shelf]:
# Display SKU with facings
display = f"[{item['sku']}x{item['facings']}]"
print(display, end=" ")
else:
print("(empty)", end="")
print()
print("=" * 60)
# Example
fixture_config = {
'shelves': 5,
'width_inches': 48,
'depth_inches': 12
}
products_data = pd.DataFrame({
'sku': [f'SKU{i:03d}' for i in range(1, 16)],
'width_inches': np.random.uniform(3, 8, 15),
'depth_inches': np.random.uniform(4, 10, 15),
'height_inches': np.random.uniform(6, 12, 15),
'weekly_sales': np.random.uniform(10, 100, 15),
'profit_per_unit': np.random.uniform(2, 8, 15),
'space_elasticity': np.random.uniform(0.3, 0.6, 15),
'min_facings': 1,
'max_facings': np.random.randint(4, 12, 15)
})
optimizer = PlanogramOptimizer(fixture_config, products_data)
# Optimize
allocation, performance = optimizer.optimize_with_constraints(objective='profit')
print(f"Total weekly sales: ${performance['total_sales']:.0f}")
print(f"Total weekly profit: ${performance['total_profit']:.0f}")
print(f"Profit per sqft: ${performance['profit_per_sqft']:.2f}")
# Visualize
optimizer.create_visual_planogram(allocation)
品类管理整合
商品组合与空间优化
class CategorySpaceManager:
"""
Manage category-level space allocation
Decide how much space each category/subcategory gets
"""
def __init__(self, store_data):
self.store = store_data
def allocate_space_to_categories(self, categories_data,
total_space_sqft):
"""
Allocate store space across categories
Methods:
- Sales-based: Proportional to sales
- Profit-based: Proportional to profit
- Hybrid: Balance sales and profit
"""
# Calculate each category's contribution
categories_data['sales_contribution'] = (
categories_data['annual_sales'] /
categories_data['annual_sales'].sum()
)
categories_data['profit_contribution'] = (
categories_data['annual_profit'] /
categories_data['annual_profit'].sum()
)
# Hybrid allocation (60% sales, 40% profit)
categories_data['allocation_weight'] = (
categories_data['sales_contribution'] * 0.6 +
categories_data['profit_contribution'] * 0.4
)
# Allocate space
categories_data['allocated_space_sqft'] = (
categories_data['allocation_weight'] * total_space_sqft
)
# Calculate expected productivity
categories_data['current_sales_per_sqft'] = (
categories_data['annual_sales'] /
categories_data['current_space_sqft']
)
categories_data['expected_sales_per_sqft'] = (
categories_data['annual_sales'] /
categories_data['allocated_space_sqft']
)
return categories_data[[
'category', 'current_space_sqft', 'allocated_space_sqft',
'annual_sales', 'annual_profit', 'current_sales_per_sqft',
'expected_sales_per_sqft'
]]
def recommend_space_adjustments(self, categories_data):
"""
Identify categories that need more or less space
Based on:
- Sales per sqft vs. store average
- Growth trends
- Profit margins
"""
store_avg_sales_per_sqft = (
categories_data['annual_sales'].sum() /
categories_data['current_space_sqft'].sum()
)
recommendations = []
for idx, category in categories_data.iterrows():
current_productivity = category['annual_sales'] / category['current_space_sqft']
ratio_to_avg = current_productivity / store_avg_sales_per_sqft
if ratio_to_avg > 1.3:
recommendation = 'Expand space'
reason = f"High productivity ({ratio_to_avg:.1f}x store average)"
change_pct = '+15 to +25%'
elif ratio_to_avg < 0.7:
recommendation = 'Reduce space'
reason = f"Low productivity ({ratio_to_avg:.1f}x store average)"
change_pct = '-15 to -25%'
else:
recommendation = 'Maintain space'
reason = 'Productivity in line with average'
change_pct = '±5%'
recommendations.append({
'category': category['category'],
'recommendation': recommendation,
'reason': reason,
'suggested_change': change_pct,
'productivity_ratio': ratio_to_avg
})
return pd.DataFrame(recommendations)
# Example
categories_data = pd.DataFrame({
'category': ['Dairy', 'Bakery', 'Produce', 'Meat', 'Frozen', 'Beverages'],
'current_space_sqft': [800, 600, 1200, 900, 1500, 2000],
'annual_sales': [1_200_000, 800_000, 1_500_000, 1_800_000, 1_400_000, 2_200_000],
'annual_profit': [180_000, 240_000, 300_000, 360_000, 210_000, 330_000]
})
manager = CategorySpaceManager({})
# Allocate space
allocation = manager.allocate_space_to_categories(categories_data, total_space_sqft=7000)
print("Category Space Allocation:")
print(allocation)
# Recommendations
recommendations = manager.recommend_space_adjustments(categories_data)
print("\nSpace Adjustment Recommendations:")
print(recommendations)
交叉陈列与邻接
class CrossMerchandisingOptimizer:
"""
Optimize product adjacencies for cross-selling
Place complementary products near each other
"""
def __init__(self, products_data, affinity_matrix):
"""
Parameters:
- products_data: Product information
- affinity_matrix: Cross-purchase patterns
affinity_matrix[i][j] = likelihood customer buys j given they buy i
"""
self.products = products_data
self.affinity = affinity_matrix
def identify_product_clusters(self, min_affinity=0.3):
"""
Cluster products with high affinity
Products that are frequently bought together
"""
from sklearn.cluster import AgglomerativeClustering
# Use affinity matrix for clustering
clustering = AgglomerativeClustering(
n_clusters=None,
distance_threshold=1 - min_affinity,
affinity='precomputed',
linkage='average'
)
# Convert affinity to distance
distance_matrix = 1 - self.affinity
clusters = clustering.fit_predict(distance_matrix)
self.products['cluster'] = clusters
return self.products[['sku', 'cluster']]
def score_adjacency(self, sku1, sku2):
"""
Score how beneficial it is to place two products adjacent
Higher score = more beneficial
"""
idx1 = self.products[self.products['sku'] == sku1].index[0]
idx2 = self.products[self.products['sku'] == sku2].index[0]
# Bidirectional affinity
affinity_1_to_2 = self.affinity[idx1, idx2]
affinity_2_to_1 = self.affinity[idx2, idx1]
# Combined score
adjacency_score = (affinity_1_to_2 + affinity_2_to_1) / 2
return adjacency_score
def recommend_adjacencies(self, sku, top_n=5):
"""
Recommend products to place next to a given SKU
Based on cross-purchase affinity
"""
idx = self.products[self.products['sku'] == sku].index[0]
# Get affinities for this product
affinities = self.affinity[idx, :]
# Sort and get top N
top_indices = np.argsort(affinities)[::-1][:top_n + 1] # +1 to exclude self
recommendations = []
for other_idx in top_indices:
other_sku = self.products.iloc[other_idx]['sku']
if other_sku == sku:
continue # Skip self
recommendations.append({
'sku': other_sku,
'affinity_score': affinities[other_idx],
'rationale': 'Frequently purchased together'
})
return recommendations[:top_n]
# Example
n_products = 20
products_data = pd.DataFrame({
'sku': [f'SKU{i:03d}' for i in range(1, n_products + 1)]
})
# Generate sample affinity matrix
# (in practice, this comes from transaction data)
np.random.seed(42)
affinity_matrix = np.random.rand(n_products, n_products) * 0.5
np.fill_diagonal(affinity_matrix, 1.0) # Product always purchased with itself
# Make it symmetric (for simplicity)
affinity_matrix = (affinity_matrix + affinity_matrix.T) / 2
optimizer = CrossMerchandisingOptimizer(products_data, affinity_matrix)
# Identify clusters
clusters = optimizer.identify_product_clusters(min_affinity=0.3)
print("Product Clusters:")
print(clusters.groupby('cluster')['sku'].apply(list))
# Get adjacency recommendations
recommendations = optimizer.recommend_adjacencies('SKU001', top_n=5)
print(f"\nRecommended adjacencies for SKU001:")
for rec in recommendations:
print(f" {rec['sku']}: {rec['affinity_score']:.2f}")
工具与库
Python 库
优化:
scipy.optimize:非线性优化pulp、pyomo:用于空间分配的线性规划ortools:用于货架陈列图的约束规划
机器学习:
scikit-learn:用于商品分组的聚类mlxtend:关联规则挖掘(购物篮分析)
可视化:
matplotlib、seaborn:货架陈列图可视化plotly:交互式布局PIL(Pillow):基于图像的货架陈列图
商业软件
货架陈列图软件:
- JDA/Blue Yonder Intactix:企业级空间规划
- RELEX Solutions:空间与商品组合优化
- Galleria by Movista:视觉陈列
- Apollo by Shelf Logic:AI 驱动的货架陈列图
- SCORPION by ESL:货架陈列图自动化
品类管理:
- Nielsen Spaceman:空间规划与优化
- IRI ProSpace:空间生产力分析
- Symphony RetailAI:AI 驱动的品类管理
专用工具:
- SmartDraw:基础货架陈列图创建
- PlanoHero:云端货架陈列图软件
- Quant:零售空间智能分析
常见挑战与解决方案
挑战:产品尺寸差异
问题:
- 产品尺寸各不相同
- 不规则形状难以整齐摆放
- 摆放不当造成空间浪费
解决方案:
- 模块化货架高度
- 可调节隔板
- 按尺寸对产品分组
- 小件商品垂直堆叠
- 为异形商品定制货架配件
挑战:商品组合频繁变动
问题:
- 频繁引入新产品
- 季节性轮换
- 重新规划商品陈列图耗费大量人力
解决方案:
- 灵活的商品陈列图区域
- 为新产品设置“热点”区域
- 采用微型品类方式(更易更换)
- 数字化商品陈列图(易于更新)
- 自动化商品陈列图合规性检查
挑战:门店业态多样
问题:
- 门店规模各不相同
- 布局存在差异
- 一种商品陈列图无法适用于所有门店
解决方案:
- 对门店进行分类(A/B/C 类业态)
- 采用模块化商品陈列图方案
- 设置核心区域与灵活区域
- 按门店自动生成商品陈列图
- 在指导原则范围内进行本地化定制
挑战:运营复杂
问题:
- 补货困难
- 执行陈列调整耗费人力和时间
- 难以监控合规情况
解决方案:
- 评估运营可行性并打分
- 调整陈列时尽量减少 SKU 移动
- 分阶段实施
- 使用照片合规检查应用
- 简化商品陈列图
挑战:平衡多重目标
问题:
- 销售额最大化与利润最大化之间的取舍
- 客户体验与效率之间的取舍
- 品牌要求与优化之间的取舍
- 视觉吸引力与空间利用效率之间的取舍
解决方案:
- 多目标优化
- 加权评分系统
- 对品牌和体验要求设置约束
- 对不同方案进行 A/B 测试
- 与品类负责人协作
输出格式
货架图优化报告
执行摘要:
- 品类:饮料(碳酸饮料区)
- 当前表现:$450/平方英尺/周
- 优化后表现:$580/平方英尺/周(+29%)
- 货架数量:12 个货架(每段 4 英尺)
- SKU 数量:85 个 SKU
当前与优化后的表现对比:
| 指标 | 当前 | 优化后 | 改善幅度 |
|---|---|---|---|
| 每平方英尺每周销售额 | $450 | $580 | +29% |
| 每平方英尺每周利润 | $95 | $135 | +42% |
| 空间利用率 | 78% | 94% | +16 个百分点 |
| SKU 数量 | 85 | 72 | -13 个 SKU |
| 每个 SKU 的平均排面数 | 3.2 | 4.5 | +41% |
主要调整 — SKU 级别:
| SKU | 产品 | 当前排面数 | 优化后排面数 | 变化 | 原因 |
|---|---|---|---|---|---|
| SKU001 | Coke 12pk | 4 | 8 | +4 | 销量高,对空间较敏感 |
| SKU015 | Pepsi 2L | 6 | 4 | -2 | 空间弹性低,占用空间过多 |
| SKU023 | LaCroix variety | 2 | 6 | +4 | 品类持续增长,空间配置不足 |
| SKU045 | Generic cola | 3 | 0 | -3(停售) | 单个排面销量不佳 |
货架层级规划:
PLANOGRAM - Soft Drinks Section (48" x 5 shelves)
============================================================
Shelf 5: [Coke12pkx8] [Pepsi12pkx6] [Sprite12pkx5]
Shelf 4: [Coke2Lx6] [Pepsi2Lx4] [DrPepper2Lx4] [Sprite2Lx4]
Shelf 3: [LaCroixX6] [BublyX5] [Perrier6pkx4]
Shelf 2: [CokeCansx4] [PepsiCansx4] [Energy6pkx5]
Shelf 1: [2LSparkling1] [2LSparkling2] [Juice4pkx3]
============================================================
各货架的空间产出:
| 货架 | 当前 $/平方英尺/周 | 优化后 $/平方英尺/周 | 改善幅度 |
|---|---|---|---|
| 货架 1(视线高度) | $620 | $780 | +26% |
| 货架 2(视线高度) | $580 | $750 | +29% |
| 货架 3(胸部高度) | $480 | $610 | +27% |
| 货架 4(腰部高度) | $380 | $490 | +29% |
交叉陈列机会:
- 薯片 + 蘸酱组合:在薯片旁增加莎莎酱(年度销售额增加 $8K)
- 意面 + 意面酱:集中陈列,方便顾客选购(年度销售额增加 $12K)
- 烘焙用品:将面粉、糖、小苏打集中陈列(年度销售额增加 $6K)
实施计划:
| 阶段 | 行动 | 涉及 SKU 数量 | 工时 | 时间安排 |
|---|---|---|---|---|
| 阶段 1 | 调整排面数(不移动商品) | 25 | 8 小时 | 第 1 周 |
| 阶段 2 | 将高销量商品移至视线高度 | 15 | 12 小时 | 第 2 周 |
| 阶段 3 | 停售表现不佳的商品 | 13 | 4 小时 | 第 3 周 |
| 阶段 4 | 最终调整与整理 | 全部 | 6 小时 | 第 4 周 |
风险与缓解措施:
| 风险 | 影响 | 概率 | 缓解措施 |
|---|---|---|---|
| 调整期间缺货 | 中 | 中 | 调整前增加库存,分阶段实施 |
| 顾客困惑 | 低 | 高 | 设置清晰标识,向员工说明 |
| 执行错误 | 中 | 中 | 拍照检查执行情况,走访门店 |
待询问的问题
如需了解更多背景:
- 需要优化哪个品类/部门?
- 该品类有多少个 SKU?
- 当前每平方英尺的销售额是多少?
- 使用哪些货架?(搁架、岛式货架、端架)
- 是否有商品尺寸数据?
- 是否有按 SKU 划分的历史销售数据?
- 是否有空间弹性数据?(测试不同排面数)
- 有哪些限制条件?(品牌要求、最少排面数)
- 这是针对一家门店还是整个连锁体系?
相关技能
- retail-allocation:门店初始库存分配
- retail-replenishment:补货策略
- demand-forecasting:按 SKU/门店进行需求预测
- inventory-optimization:安全库存与服务水平
- supply-chain-analytics:空间产出指标
- warehouse-slotting-optimization:适用于仓库的类似概念
评论
支持 Markdown