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 フィート):最優先の位置で、売上の 40%を占めます
- 胸の高さ(3~4 フィート):次に優先度の高い位置で、売上の 30%を占めます
- 腰の高さ(2~3 フィート):第 3 層で、売上の 20%を占めます
- 床面(0~2 フィート):視認性が低く、売上の 10%を占めます
- 目線より上(5~6 フィート):在庫のあふれ分や、時折購入される商品を配置します
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:小売スペースのインテリジェンス
よくある課題と解決策
課題:商品サイズのばらつき
問題:
- 商品によってサイズが異なります
- 形状が不規則で、きれいに収まりません
- 陳列の仕方が適切でないと、スペースが無駄になります
解決策:
- 棚の高さをモジュール式にする
- 仕切りを調整可能にする
- サイズ別に商品をグループ化する
- 小さな商品を縦に積み重ねる
- 形状が特殊な商品向けに専用什器を用意する
課題:品ぞろえの頻繁な変更
問題:
- 新商品が頻繁に投入されます
- 季節ごとに商品が入れ替わります
- プラノグラムの再作成に手間がかかります
解決策:
- 柔軟に変更できるプラノグラムのゾーンを設ける
- 新商品向けの「注目エリア」を設ける
- マイクロカテゴリー方式を採用する(入れ替えが容易です)
- デジタルプラノグラムを活用する(簡単に更新できます)
- プラノグラム遵守状況の確認を自動化する
課題:店舗形態の多様性
問題:
- 店舗の規模が異なります
- レイアウトに違いがあります
- 1つのプラノグラムですべての店舗に対応できません
解決策:
- 店舗をクラスター化する(A/B/C形式)
- モジュール式のプラノグラムを採用する
- 基本区画と柔軟に変更できる区画を設ける
- 店舗ごとのプラノグラム生成を自動化する
- ガイドラインの範囲内で地域に合わせてカスタマイズする
課題:運用の複雑さ
問題:
- 商品の補充が難しいです
- レイアウト変更の実施に作業時間がかかります
- 遵守状況の監視が困難です
解決策:
- 運用実現性を評価する
- レイアウト変更時の商品移動を最小限に抑える
- 段階的に導入する
- 写真による遵守状況確認アプリを活用する
- プラノグラムを簡素化する
課題:複数の目標のバランスを取る
問題:
- 売上の最大化と利益の最大化
- 顧客体験と効率性
- ブランド要件と最適化
- 見た目の魅力とスペースの生産性
解決策:
- 多目的最適化を行う
- 重み付けスコアリングシステムを導入する
- ブランドや顧客体験に関する要件を制約条件にする
- 異なるアプローチを A/B テストする
- カテゴリーキャプテンと連携する
出力形式
プラノグラム最適化レポート
エグゼクティブサマリー:
- カテゴリー:飲料(清涼飲料セクション)
- 現在の実績:週あたり1平方フィートあたり450ドル
- 最適化後の実績:週あたり1平方フィートあたり580ドル(+29%)
- 棚数:12台(4フィート区画)
- SKU数:85 SKU
最適化前と最適化後の実績:
| 指標 | 現在 | 最適化後 | 改善 |
|---|---|---|---|
| 週あたり1平方フィートあたりの売上 | 450ドル | 580ドル | +29% |
| 週あたり1平方フィートあたりの利益 | 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% |
クロスマーチャンダイジングの機会:
- チップス+ディップのクラスター:チップスの隣にサルサを追加(年間売上8,000ドル増)
- パスタ+ソース:利便性を高めるためにまとめて陳列(年間売上12,000ドル増)
- 製菓材料:小麦粉、砂糖、重曹をまとめて陳列(年間売上6,000ドル増)
導入計画:
| フェーズ | 作業 | 対象SKU | 作業時間 | 期間 |
|---|---|---|---|---|
| フェーズ1 | フェイス数を調整(移動なし) | 25 | 8時間 | 1週目 |
| フェーズ2 | 売れ行きの良い商品を目線の高さに移動 | 15 | 12時間 | 2週目 |
| フェーズ3 | 販売実績の低い商品を取扱中止 | 13 | 4時間 | 3週目 |
| フェーズ4 | 最終調整と片付け | すべて | 6時間 | 4週目 |
リスクと軽減策:
| リスク | 影響 | 発生確率 | 軽減策 |
|---|---|---|---|
| 棚替え中の欠品 | 中 | 中 | 棚替え前に在庫を積み増し、段階的に実施 |
| 顧客の混乱 | 低 | 高 | わかりやすい表示、スタッフへの事前説明 |
| 作業ミス | 中 | 中 | 写真による遵守確認、店舗訪問 |
確認事項
さらに詳しい情報が必要な場合:
- 最適化が必要なカテゴリー/部門は何ですか?
- そのカテゴリーにはSKUがいくつありますか?
- 現在の1平方フィートあたりの売上はいくらですか?
- どのような什器を使用していますか?(棚、ゴンドラ、エンドキャップ)
- 商品の寸法データはありますか?
- SKU別の過去の売上データはありますか?
- スペース弾力性のデータはありますか?(フェイス数を変えたテスト)
- 制約はありますか?(ブランド要件、最低フェイス数)
- 対象は1店舗ですか、それともチェーン全体ですか?
関連スキル
- retail-allocation:店舗への初期在庫配分
- retail-replenishment:補充戦略
- demand-forecasting:SKU/店舗別の需要予測
- inventory-optimization:安全在庫とサービスレベル
- supply-chain-analytics:スペース生産性の指標
- warehouse-slotting-optimization:倉庫における類似の概念
コメント
Markdown 対応