mcpField
I
inventory-optimization

inventory-optimization

github.com/kishorkukrejaその他84123 回インストール3 週間前に更新
リポジトリ

inventory-optimization について

Inventory Optimizationは、需要、リードタイム、コストを基に在庫管理と補充方針を検討するスキルです。発注量、安全在庫、発注点、SKU分類を扱い、在庫コストとサービス水準の均衡を支援します。

主な機能

  1. 01EOQ、発注点、安全在庫の計算
  2. 02連続レビュー・定期レビュー方針の設定
  3. 03ABC・XYZ分析によるSKU分類
  4. 04サービス水準と保有コストの分析
  5. 05複数SKUへの予算配分の最適化

活用シーン

  1. 01SKUごとの発注量と発注点を設定
  2. 02価値や需要変動に応じて在庫方針を分類
  3. 03在庫投資、回転率、欠品リスクを評価
  4. 04予算内で複数SKUの在庫を配分

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill inventory-optimization

インストール後、Claude Code で/inventory-optimizationを入力して読み込まれたか確認します。

詳細

在庫最適化

あなたは在庫の最適化と管理の専門家です。目標は、在庫コストとサービスレベルのバランスを取り、顧客の需要を満たしながら総コストを最小限に抑える最適な在庫水準、発注点、在庫方針を決定することです。

初期評価

在庫を最適化する前に、次の点を把握してください。

  1. ビジネスの背景

    • どの製品/SKUの在庫を最適化する必要がありますか?
    • 現在の在庫投資額と在庫回転率はどのくらいですか?
    • 目標サービスレベル(充足率、欠品率)はどのくらいですか?
    • 現在の課題は何ですか?(過剰在庫、不足、資金の固定化)
  2. 需要の特性

    • 需要パターンはどのようなものですか?(安定、変動、季節性、断続的)
    • 需要の変動性(変動係数)はどのくらいですか?
    • 過去の販売データはありますか?(理想的には12~24か月分)
    • 予測精度(MAPE)はどのくらいですか?
  3. 供給パラメーター

    • サプライヤーからのリードタイムはどのくらいですか?
    • リードタイムの変動性はどのくらいですか?
    • 最小発注数量(MOQ)はいくつですか?
    • 発注コストと制約はどのようなものですか?
  4. コスト構造

    • 製品の単価はいくらですか?
    • 1回の発注あたりの発注/段取りコストはいくらですか?
    • 在庫保管コスト率(年間)は何%ですか?
    • 欠品/バックオーダーのコストはいくらですか?

在庫最適化のフレームワーク

主な在庫に関する意思決定

1. どれだけ発注するか?(発注量)

  • 経済的発注量(EOQ)
  • 定量発注
  • ロット・フォー・ロット発注
  • 数量割引の考慮

2. いつ発注するか?(発注点)

  • 連続レビュー(s, Q)方針
  • 定期レビュー(s, S)方針
  • タイムフェーズ発注
  • 動的安全在庫

3. 安全在庫をどれだけ持つか?

  • サービスレベルの目標
  • 需要の変動性
  • リードタイムの変動性
  • コストとサービスのトレードオフ

基本モデル

経済的発注量(EOQ)

基本的なEOQの公式:

EOQ = sqrt((2 * D * S) / H)

Where:
  D = Annual demand (units)
  S = Ordering cost per order ($)
  H = Holding cost per unit per year ($)

総コスト:

TC = (D/Q) * S + (Q/2) * H + D * C

Where:
  Q = Order quantity
  C = Unit cost

Pythonでの実装:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def eoq(annual_demand, order_cost, holding_cost_rate, unit_cost):
    """
    Calculate Economic Order Quantity

    Parameters:
    - annual_demand: Annual demand in units
    - order_cost: Cost per order ($)
    - holding_cost_rate: Holding cost as % of unit cost (e.g., 0.25 for 25%)
    - unit_cost: Cost per unit ($)

    Returns:
    - Dictionary with EOQ, total cost, orders per year, etc.
    """

    # Holding cost per unit per year
    holding_cost = unit_cost * holding_cost_rate

    # EOQ formula
    eoq_qty = np.sqrt((2 * annual_demand * order_cost) / holding_cost)

    # Number of orders per year
    orders_per_year = annual_demand / eoq_qty

    # Total annual cost
    ordering_cost_total = (annual_demand / eoq_qty) * order_cost
    holding_cost_total = (eoq_qty / 2) * holding_cost
    purchase_cost = annual_demand * unit_cost
    total_cost = ordering_cost_total + holding_cost_total + purchase_cost

    # Order interval (days)
    order_interval = 365 / orders_per_year

    return {
        'EOQ': round(eoq_qty, 0),
        'Orders_Per_Year': round(orders_per_year, 1),
        'Order_Interval_Days': round(order_interval, 1),
        'Total_Annual_Cost': round(total_cost, 2),
        'Ordering_Cost': round(ordering_cost_total, 2),
        'Holding_Cost': round(holding_cost_total, 2),
        'Purchase_Cost': round(purchase_cost, 2)
    }

# Example usage
result = eoq(
    annual_demand=10000,
    order_cost=100,
    holding_cost_rate=0.25,
    unit_cost=50
)

print(f"Optimal Order Quantity: {result['EOQ']} units")
print(f"Order {result['Orders_Per_Year']} times per year")
print(f"Order every {result['Order_Interval_Days']} days")
print(f"Total Annual Cost: ${result['Total_Annual_Cost']:,.2f}")

数量割引を考慮したEOQ:

def eoq_with_discounts(annual_demand, order_cost, holding_cost_rate, price_breaks):
    """
    EOQ with all-units quantity discount

    price_breaks: list of tuples [(qty, price), ...]
    Example: [(0, 50), (500, 48), (1000, 45)]
    """

    results = []

    for qty_break, unit_price in price_breaks:
        holding_cost = unit_price * holding_cost_rate

        # Calculate EOQ at this price
        eoq_qty = np.sqrt((2 * annual_demand * order_cost) / holding_cost)

        # If EOQ < qty_break, use qty_break as order quantity
        order_qty = max(eoq_qty, qty_break)

        # Total cost at this quantity
        ordering_cost = (annual_demand / order_qty) * order_cost
        holding_cost_total = (order_qty / 2) * holding_cost
        purchase_cost = annual_demand * unit_price
        total_cost = ordering_cost + holding_cost_total + purchase_cost

        results.append({
            'Quantity_Break': qty_break,
            'Unit_Price': unit_price,
            'EOQ_at_Price': round(eoq_qty, 0),
            'Order_Quantity': round(order_qty, 0),
            'Total_Cost': round(total_cost, 2)
        })

    # Find minimum cost option
    results_df = pd.DataFrame(results)
    optimal = results_df.loc[results_df['Total_Cost'].idxmin()]

    return results_df, optimal

# Example with quantity discounts
price_breaks = [
    (0, 50),      # 0-499: $50/unit
    (500, 48),    # 500-999: $48/unit
    (1000, 45)    # 1000+: $45/unit
]

results_df, optimal = eoq_with_discounts(
    annual_demand=10000,
    order_cost=100,
    holding_cost_rate=0.25,
    price_breaks=price_breaks
)

print(results_df)
print(f"\nOptimal: Order {optimal['Order_Quantity']} units at ${optimal['Unit_Price']}/unit")

安全在庫と発注点

安全在庫の計算

サービスレベル方式:

from scipy import stats
import numpy as np

def safety_stock(demand_std, lead_time_days, service_level=0.95):
    """
    Calculate safety stock based on service level

    Parameters:
    - demand_std: Standard deviation of daily demand
    - lead_time_days: Lead time in days
    - service_level: Target service level (e.g., 0.95 for 95%)

    Returns:
    - Safety stock quantity
    """

    # Z-score for desired service level
    z = stats.norm.ppf(service_level)

    # Safety stock = Z * std_dev during lead time
    # Assuming demand is independent across days
    std_during_lt = demand_std * np.sqrt(lead_time_days)

    ss = z * std_during_lt

    return round(ss, 0)

def safety_stock_variable_lt(demand_avg, demand_std, lead_time_avg,
                              lead_time_std, service_level=0.95):
    """
    Safety stock with variable demand AND lead time

    More comprehensive formula accounting for both sources of variability
    """

    z = stats.norm.ppf(service_level)

    # Combined variance formula
    variance = (lead_time_avg * demand_std**2 +
                demand_avg**2 * lead_time_std**2)

    std_during_lt = np.sqrt(variance)

    ss = z * std_during_lt

    return round(ss, 0)

# Example: Basic safety stock
ss = safety_stock(
    demand_std=50,        # Daily demand std dev
    lead_time_days=14,    # 2 week lead time
    service_level=0.95    # 95% service level
)
print(f"Safety Stock: {ss} units")

# Example: Variable lead time
ss_var = safety_stock_variable_lt(
    demand_avg=100,       # Avg daily demand
    demand_std=50,        # Std dev of daily demand
    lead_time_avg=14,     # Avg lead time (days)
    lead_time_std=3,      # Std dev of lead time (days)
    service_level=0.95
)
print(f"Safety Stock (variable LT): {ss_var} units")
発注点(ROP)

公式:

ROP = (Average Daily Demand × Lead Time) + Safety Stock

Pythonでの実装:

def reorder_point(demand_avg_daily, lead_time_days, safety_stock):
    """
    Calculate reorder point

    ROP = Expected demand during lead time + Safety stock
    """

    expected_demand_lt = demand_avg_daily * lead_time_days
    rop = expected_demand_lt + safety_stock

    return round(rop, 0)

def rop_with_review_period(demand_avg_daily, lead_time_days,
                           review_period_days, safety_stock):
    """
    Reorder point with periodic review

    Must cover lead time + review period
    """

    total_period = lead_time_days + review_period_days
    expected_demand = demand_avg_daily * total_period
    rop = expected_demand + safety_stock

    return round(rop, 0)

# Example
rop = reorder_point(
    demand_avg_daily=100,
    lead_time_days=14,
    safety_stock=200
)
print(f"Reorder Point: {rop} units")
print(f"When inventory hits {rop}, place an order")

在庫方針モデル

(s, Q)連続レビュー方針

説明:

  • 在庫を継続的に監視します
  • 在庫ポジションがs(発注点)以下になったら、Q単位を発注します
  • Qには通常、EOQを設定します
class ContinuousReviewPolicy:
    """(s, Q) continuous review inventory policy"""

    def __init__(self, reorder_point, order_quantity):
        self.s = reorder_point
        self.Q = order_quantity
        self.inventory_position = 0
        self.on_hand = 0
        self.on_order = 0
        self.orders_placed = []

    def check_and_order(self, current_on_hand, current_on_order):
        """Check if order should be placed"""

        self.on_hand = current_on_hand
        self.on_order = current_on_order
        self.inventory_position = current_on_hand + current_on_order

        if self.inventory_position <= self.s:
            # Place order
            order = {
                'quantity': self.Q,
                'inventory_position': self.inventory_position,
                'on_hand': self.on_hand,
                'on_order': self.on_order
            }
            self.orders_placed.append(order)
            return True, self.Q

        return False, 0

    def simulate(self, demand_series, lead_time=14):
        """Simulate inventory policy over time"""

        inventory = []
        current_inv = self.Q  # Start with one order quantity
        on_order_queue = []

        for day, demand in enumerate(demand_series):
            # Receive orders (if any arrive today)
            arrivals = [o for o in on_order_queue if o['arrival_day'] == day]
            for arrival in arrivals:
                current_inv += arrival['quantity']
                on_order_queue.remove(arrival)

            # Satisfy demand
            current_inv = max(0, current_inv - demand)

            # Check if order needed
            current_on_order = sum(o['quantity'] for o in on_order_queue)
            should_order, order_qty = self.check_and_order(current_inv, current_on_order)

            if should_order:
                on_order_queue.append({
                    'quantity': order_qty,
                    'order_day': day,
                    'arrival_day': day + lead_time
                })

            inventory.append({
                'day': day,
                'on_hand': current_inv,
                'demand': demand,
                'on_order': current_on_order,
                'order_placed': should_order
            })

        return pd.DataFrame(inventory)

# Example simulation
np.random.seed(42)
demand_series = np.random.poisson(100, 365)  # 365 days of demand

policy = ContinuousReviewPolicy(
    reorder_point=1600,
    order_quantity=1000
)

results = policy.simulate(demand_series, lead_time=14)
print(f"Average inventory: {results['on_hand'].mean():.0f} units")
print(f"Stockouts: {(results['on_hand'] == 0).sum()} days")
print(f"Orders placed: {results['order_placed'].sum()}")
(R, S)定期レビュー方針

説明:

  • R期間ごと(例:毎週)に在庫を確認します
  • S(補充目標水準)まで発注します
  • 発注量は現在の在庫ポジションに応じて変わります
class PeriodicReviewPolicy:
    """(R, S) periodic review inventory policy"""

    def __init__(self, review_period, order_up_to_level):
        self.R = review_period
        self.S = order_up_to_level

    def calculate_order_qty(self, current_position):
        """Calculate order quantity to reach S"""
        return max(0, self.S - current_position)

    def simulate(self, demand_series, lead_time=14):
        """Simulate periodic review policy"""

        inventory = []
        current_inv = self.S  # Start at order-up-to level
        on_order_queue = []

        for day, demand in enumerate(demand_series):
            # Receive orders
            arrivals = [o for o in on_order_queue if o['arrival_day'] == day]
            for arrival in arrivals:
                current_inv += arrival['quantity']
                on_order_queue.remove(arrival)

            # Satisfy demand
            current_inv = max(0, current_inv - demand)

            # Check if it's a review day
            should_order = (day % self.R == 0)
            order_qty = 0

            if should_order:
                current_on_order = sum(o['quantity'] for o in on_order_queue)
                current_position = current_inv + current_on_order
                order_qty = self.calculate_order_qty(current_position)

                if order_qty > 0:
                    on_order_queue.append({
                        'quantity': order_qty,
                        'order_day': day,
                        'arrival_day': day + lead_time
                    })

            inventory.append({
                'day': day,
                'on_hand': current_inv,
                'demand': demand,
                'order_qty': order_qty,
                'review_day': should_order
            })

        return pd.DataFrame(inventory)

# Example
policy = PeriodicReviewPolicy(
    review_period=7,      # Weekly review
    order_up_to_level=2100
)

results = policy.simulate(demand_series, lead_time=14)
print(f"Average inventory: {results['on_hand'].mean():.0f} units")
print(f"Total orders: {(results['order_qty'] > 0).sum()}")

ABC分析とセグメンテーション

ABC分類

手法:

  • A品目:金額ベースで上位20%のSKU、売上の約80%
  • B品目:次の30%のSKU、売上の約15%
  • C品目:下位50%のSKU、売上の約5%
def abc_analysis(df, sku_col='sku', demand_col='annual_demand',
                 price_col='unit_price'):
    """
    Perform ABC analysis on inventory

    Parameters:
    - df: DataFrame with SKU, demand, and price
    - Returns: DataFrame with ABC classification
    """

    # Calculate annual value
    df = df.copy()
    df['annual_value'] = df[demand_col] * df[price_col]

    # Sort by value descending
    df = df.sort_values('annual_value', ascending=False)

    # Calculate cumulative percentage
    total_value = df['annual_value'].sum()
    df['cumulative_value'] = df['annual_value'].cumsum()
    df['cumulative_pct'] = df['cumulative_value'] / total_value * 100

    # Classify
    def classify(pct):
        if pct <= 80:
            return 'A'
        elif pct <= 95:
            return 'B'
        else:
            return 'C'

    df['abc_class'] = df['cumulative_pct'].apply(classify)

    # Add ranking
    df['rank'] = range(1, len(df) + 1)

    return df

# Example usage
inventory_data = pd.DataFrame({
    'sku': [f'SKU_{i}' for i in range(1, 101)],
    'annual_demand': np.random.randint(100, 10000, 100),
    'unit_price': np.random.uniform(10, 500, 100)
})

abc_result = abc_analysis(inventory_data)

# Summary by class
summary = abc_result.groupby('abc_class').agg({
    'sku': 'count',
    'annual_value': 'sum'
}).round(0)

summary['pct_skus'] = summary['sku'] / summary['sku'].sum() * 100
summary['pct_value'] = summary['annual_value'] / summary['annual_value'].sum() * 100

print(summary)
XYZ分析(需要の変動性)

分類:

  • X:変動性が低い(CV < 0.5) - 予測可能
  • Y:変動性が中程度(0.5 ≤ CV < 1.0) - 中程度
  • Z:変動性が高い(CV ≥ 1.0) - 予測困難
def xyz_analysis(df, demand_history_col='demand_history'):
    """
    Classify items by demand variability

    demand_history_col should contain list/array of historical demand
    """

    def classify_variability(demands):
        if len(demands) < 2:
            return 'Z'  # Insufficient data

        mean_demand = np.mean(demands)
        std_demand = np.std(demands)

        if mean_demand == 0:
            return 'Z'

        cv = std_demand / mean_demand  # Coefficient of variation

        if cv < 0.5:
            return 'X'
        elif cv < 1.0:
            return 'Y'
        else:
            return 'Z'

    df = df.copy()
    df['xyz_class'] = df[demand_history_col].apply(classify_variability)

    return df

# Combined ABC-XYZ matrix
def abc_xyz_matrix(df):
    """Create ABC-XYZ classification matrix"""

    matrix = pd.crosstab(df['abc_class'], df['xyz_class'],
                         values=df['sku'], aggfunc='count')

    return matrix
分類別の在庫方針
クラスサービスレベルレビュー頻度安全在庫手法
A-X99%毎日高連続レビュー、厳格な管理
A-Y98%毎日高連続レビュー
A-Z95%毎週非常に高定期レビュー、高い安全在庫
B-X97%毎週中定期または連続レビュー
B-Y95%毎週中定期レビュー
B-Z90%隔週高定期レビュー
C-X90%毎月低定期レビュー、簡易ルール
C-Y85%毎月中最小/最大ルール
C-Z80%必要に応じて低/なし受注時に発注するか、在庫を持たない

高度な在庫最適化

サービスレベルとコストのトレードオフ
def service_level_analysis(demand_std, lead_time, unit_cost,
                           holding_cost_rate, stockout_cost):
    """
    Analyze optimal service level balancing holding vs. stockout costs
    """

    service_levels = np.arange(0.80, 0.995, 0.01)
    results = []

    holding_cost_per_unit = unit_cost * holding_cost_rate

    for sl in service_levels:
        # Safety stock required
        z = stats.norm.ppf(sl)
        std_during_lt = demand_std * np.sqrt(lead_time)
        ss = z * std_during_lt

        # Holding cost
        holding_cost = ss * holding_cost_per_unit

        # Expected stockout cost
        # Simplified: (1 - service_level) * stockout_cost
        expected_stockouts = (1 - sl) * stockout_cost

        total_cost = holding_cost + expected_stockouts

        results.append({
            'service_level': sl,
            'safety_stock': round(ss, 0),
            'holding_cost': round(holding_cost, 2),
            'stockout_cost': round(expected_stockouts, 2),
            'total_cost': round(total_cost, 2)
        })

    results_df = pd.DataFrame(results)

    # Find optimal
    optimal_idx = results_df['total_cost'].idxmin()
    optimal = results_df.iloc[optimal_idx]

    return results_df, optimal

# Example
results_df, optimal = service_level_analysis(
    demand_std=50,
    lead_time=14,
    unit_cost=100,
    holding_cost_rate=0.25,
    stockout_cost=5000  # Cost per stockout event
)

print(f"Optimal service level: {optimal['service_level']:.1%}")
print(f"Safety stock: {optimal['safety_stock']} units")
print(f"Total cost: ${optimal['total_cost']:,.2f}")
在庫回転率の最適化

在庫回転率の公式:

Inventory Turns = Cost of Goods Sold (COGS) / Average Inventory Value
def inventory_metrics(annual_cogs, avg_inventory_value, target_turns=None):
    """
    Calculate inventory turnover metrics
    """

    turns = annual_cogs / avg_inventory_value
    days_on_hand = 365 / turns

    metrics = {
        'Inventory_Turns': round(turns, 2),
        'Days_On_Hand': round(days_on_hand, 1),
        'Avg_Inventory': avg_inventory_value
    }

    if target_turns:
        target_inventory = annual_cogs / target_turns
        reduction = avg_inventory_value - target_inventory
        metrics['Target_Inventory'] = round(target_inventory, 0)
        metrics['Inventory_Reduction'] = round(reduction, 0)
        metrics['Cash_Freed'] = round(reduction, 0)

    return metrics

# Example
metrics = inventory_metrics(
    annual_cogs=50_000_000,
    avg_inventory_value=10_000_000,
    target_turns=8
)

print(f"Current turns: {metrics['Inventory_Turns']}")
print(f"Days on hand: {metrics['Days_On_Hand']}")
if 'Target_Inventory' in metrics:
    print(f"Target inventory: ${metrics['Target_Inventory']:,.0f}")
    print(f"Cash to be freed: ${metrics['Cash_Freed']:,.0f}")
複数SKUの最適化
from scipy.optimize import minimize

def optimize_multi_sku_inventory(skus_data, total_budget, target_service_level=0.95):
    """
    Optimize inventory allocation across multiple SKUs with budget constraint

    skus_data: DataFrame with columns ['sku', 'demand_avg', 'demand_std',
                                        'lead_time', 'unit_cost', 'stockout_cost']
    """

    n_skus = len(skus_data)

    def objective(safety_stocks):
        """Minimize total cost (holding + expected stockouts)"""

        total_cost = 0

        for i, ss in enumerate(safety_stocks):
            row = skus_data.iloc[i]

            # Holding cost
            holding_cost = ss * row['unit_cost'] * 0.25  # 25% holding rate

            # Calculate achieved service level from safety stock
            z = ss / (row['demand_std'] * np.sqrt(row['lead_time']))
            service_level = stats.norm.cdf(z)

            # Stockout cost
            stockout_prob = 1 - service_level
            expected_stockout = stockout_prob * row['stockout_cost']

            total_cost += holding_cost + expected_stockout

        return total_cost

    def budget_constraint(safety_stocks):
        """Total inventory value must not exceed budget"""
        total_value = sum(
            ss * skus_data.iloc[i]['unit_cost']
            for i, ss in enumerate(safety_stocks)
        )
        return total_budget - total_value

    # Initial guess: equal allocation
    x0 = np.full(n_skus, total_budget / (n_skus * skus_data['unit_cost'].mean()))

    # Constraints
    constraints = [
        {'type': 'ineq', 'fun': budget_constraint}
    ]

    # Bounds: non-negative safety stock
    bounds = [(0, None) for _ in range(n_skus)]

    # Optimize
    result = minimize(objective, x0, method='SLSQP',
                     bounds=bounds, constraints=constraints)

    # Extract results
    optimal_ss = result.x

    results_df = skus_data.copy()
    results_df['optimal_safety_stock'] = optimal_ss
    results_df['inventory_value'] = optimal_ss * results_df['unit_cost']

    return results_df, result

# Example with multiple SKUs
skus_data = pd.DataFrame({
    'sku': ['A', 'B', 'C', 'D'],
    'demand_avg': [100, 200, 50, 150],
    'demand_std': [20, 40, 25, 30],
    'lead_time': [14, 7, 21, 14],
    'unit_cost': [50, 30, 100, 75],
    'stockout_cost': [500, 300, 1000, 600]
})

results_df, optimization = optimize_multi_sku_inventory(
    skus_data,
    total_budget=50000,
    target_service_level=0.95
)

print(results_df[['sku', 'optimal_safety_stock', 'inventory_value']])
print(f"\nTotal inventory value: ${results_df['inventory_value'].sum():,.0f}")

ツールとライブラリ

Python ライブラリ

在庫最適化:

  • numpy:数値計算
  • scipy:統計分布、最適化
  • pandas:データ操作
  • statsmodels:時系列分析

シミュレーション:

  • simpy:離散イベントシミュレーション
  • ciw:待ち行列ネットワークシミュレーション

最適化:

  • scipy.optimize:非線形最適化
  • pulp:線形計画法
  • pyomo:最適化モデリング

可視化:

  • matplotlib、seaborn:プロット作成
  • plotly:インタラクティブなグラフ
商用ソフトウェア

在庫計画:

  • SAP IBP:統合ビジネス計画
  • Blue Yonder (JDA):在庫最適化
  • Kinaxis RapidResponse:サプライチェーン計画
  • Logility:在庫最適化
  • o9 Solutions:デジタル計画プラットフォーム

特化型ツール:

  • Inventory Planner:Eコマースの在庫
  • Lokad:確率的予測と在庫
  • NetSuite:在庫管理機能を備えたERP
  • Fishbowl:在庫追跡・管理

よくある課題と解決策

課題:需要の変動性

問題:

  • 需要の変動が大きいと、安全在庫の必要量が増加します
  • 予測が困難です

解決策:

  • ABC-XYZ分析でセグメント化し、セグメントごとに異なる方針を適用します
  • 確率的予測を使用します(点推定ではなく分布を使用します)
  • 需要平準化の戦略を検討します(プロモーション管理など)
  • 予測頻度を上げます(月次ではなく週次にします)
  • リアルタイムデータを活用した需要センシングを導入します
課題:リードタイムの長期化

問題:

  • リードタイムが長くなるほど、必要な安全在庫が増加します
  • 欠品や陳腐化のリスクが高まります

解決策:

  • サプライヤーと連携してリードタイムを短縮します
  • ベンダー管理在庫(VMI)を導入します
  • 安全リードタイムの余裕を設定します
  • 重要品目について複数調達先の確保を検討します
  • 重要な補充には航空貨物を利用します
課題:過剰在庫

問題:

  • 動きの遅い在庫や陳腐化した在庫が多すぎます
  • 資金が拘束され、保管コストが発生します

解決策:

  • ABC分析を導入し、C品目に重点を置きます
  • 値下げ・在庫処分の戦略を実施します
  • サプライヤーとの返品契約を結びます
  • 需要予測を改善します
  • 動きの遅い品目の発注量を減らします
  • ロングテール品目にはドロップシッピングを検討します
課題:欠品とバックオーダー

問題:

  • 在庫不足により、販売機会を逃します
  • 顧客サービスが低下します

解決策:

  • 安全在庫を増やします(コストとサービスのトレードオフを考慮します)
  • 予測精度を改善します
  • リードタイムの変動を抑えます
  • 緊急配送の選択肢を導入します
  • サプライチェーンの可視性を高めます
  • 低販売量の品目には受注生産を検討します
課題:コストとサービスのバランス

問題:

  • 在庫を最小化することと、サービスを最大化することの目的が競合します

解決策:

  • 欠品コスト(販売機会の損失、ペナルティ)を定量化します
  • 最適化を用いて最適なトレードオフを見つけます
  • 在庫をセグメント化し、クラスごとに異なるサービスレベルを設定します
  • サービスレベル契約(SLA)を導入します
  • サービス提供コスト分析を使用します
課題:マルチエシェロンの複雑さ

問題:

  • 複数の拠点(工場、DC、店舗)に在庫があります
  • 全体を最適化することが困難です

解決策:

  • multi-echelon-inventory スキルを参照してください
  • ネットワーク最適化モデルを使用します
  • 需要主導型の補充を導入します
  • 計画を一元化します(ただし、在庫まで一元化する必要はありません)
  • ポストポーンメント戦略を検討します

出力形式

在庫最適化レポート

エグゼクティブサマリー:

  • 現在の在庫投資額と在庫回転率
  • 推奨する在庫水準とポリシー
  • 期待されるサービスレベルの向上
  • 運転資本への影響

SKU レベルの推奨事項:

SKUABCXYZ現在の平均在庫推奨平均在庫安全在庫発注点発注量ポリシーサービスレベル
SKU_001AX5004502001,6001,000(s,Q)99%
SKU_002BY300280120850500(R,S)95%
SKU_003CZ1505030250Min/Max月次85%

財務への影響:

指標現在最適化後改善
在庫総額$15M$12M-$3M (-20%)
在庫回転率4.56.0+1.5 (+33%)
在庫日数8161-20日
充足率92%97%+5ポイント
年間保管コスト$3.75M$3.0M-$750K

導入計画:

  1. フェーズ 1:A 品目(在庫価値の 80%)にポリシーを導入
  2. フェーズ 2:B 品目に展開
  3. フェーズ 3:C 品目の管理を簡素化
  4. 継続的な取り組み:実績に基づいて監視し、調整

質問事項

さらに詳しい情報が必要な場合:

  1. 最適化が必要な製品/SKU は何ですか?全体でいくつありますか?
  2. 現在の在庫投資額と在庫回転率はどのくらいですか?
  3. 目標とするサービスレベルはどのくらいですか?
  4. 需要パターンはどのようなものですか?(安定、変動、季節性、断続的)
  5. サプライヤーからのリードタイムはどのくらいですか?
  6. どのようなコストデータを利用できますか?(製品コスト、発注コスト、保管コスト率)
  7. この取り組みの目的は何ですか?(コスト削減、サービス向上、運転資本)

関連スキル

  • economic-order-quantity:EOQ モデルの詳細
  • demand-forecasting:在庫計画のための需要予測
  • multi-echelon-inventory:ネットワーク在庫の最適化
  • stochastic-inventory-models:確率論的アプローチ
  • newsvendor-problem:単一期間の在庫意思決定
  • supply-chain-analytics:KPI とパフォーマンス指標
  • abc-analysis:分類とセグメンテーション(別のスキルとして存在する場合)
  • warehouse-slotting-optimization:在庫配置の最適化

コメント