📊 WMSパワーアップ！倉庫運用の効率と利益を最大化 | 第6回: 容量管理とスペース最適化

 ## はじめに
倉庫のスペースは有限であり、その効率的な利用がコストと運用効率を左右します。非効率な**容量管理**は、過剰な賃料や在庫滞留を引き起こします。**WMS**（倉庫管理システム）は、スペースの使用状況を追跡し、需要を**予測**することで、**スペース最適化**を実現します。本シリーズの第6回では、**WMS**を活用して倉庫の占有率を監視、需要を予測し、スペースを最大限に活用する方法を解説します。`Python`（`pandas`）で占有率を分析、Flask APIで需要予測、Reactと`Chart.js`でダッシュボードを構築するコードを紹介します。目標は、臨時倉庫の賃料を40%削減し、スペース利用率を15%向上させることです。

## なぜ容量管理が重要か
非効率なスペース利用は、以下のような問題を引き起こします：
- **賃料の無駄**：空きスペースが30%なのに臨時倉庫を借用、月間100万円の追加コスト。
- **在庫滞留**：過密エリアで商品が埋もれ、ピッキングに30分余計にかかる。
- **ピーク時の混乱**：繁忙期にスペース不足で入庫遅延、注文キャンセルが月間50件。
- **非効率な配置**：高頻度商品が奥に、低頻度商品が手前に配置。

筆者の経験では、ある倉庫がスペースを目視管理した結果、占有率が70%を超え、繁忙期に臨時倉庫を借用して月間150万円のコストが発生しました。**WMS**による**容量管理**と**予測**を導入後、スペース利用率が90%に向上し、臨時賃料がゼロになりました。

## 技術要件
**容量管理**を最適化するための技術要件は以下の通りです：
- **スペース追跡**：空きスペース、占有率、過密エリアをリアルタイム監視。
- **需要予測**：入出庫データに基づくスペース需要の予測。
- **最適化**：再配置、動的ラック、臨時倉庫の提案。
- **データベース**：`PostgreSQL`でロケーションと在庫を管理。
- **ダッシュボード**：占有率と予測を可視化。

## 容量管理アーキテクチャ
以下は、**WMS**を使った容量管理のアーキテクチャ概要です：
1. **データベース**：`PostgreSQL`（`locations`, `stocks`, `transactions`テーブル）。
2. **バックエンド**：`Flask`でスペース分析と予測APIを提供。
3. **スクリプト**：`Python`（`pandas`）で占有率を計算。
4. **フロントエンド**：`React`と`Chart.js`で占有率ダッシュボードを表示。
5. **スケーラビリティ**：数千ロケーションを処理。

## スペース占有率分析
倉庫の占有率を計算し、過密エリアを特定します。以下は、`Python`スクリプトの例です。

```python
import pandas as pd
import psycopg2

# データベース接続
def get_db_connection():
    return psycopg2.connect(
        dbname="wms_db",
        user="postgres",
        password="password",
        host="localhost",
        port="5432"
    )

# 占有率分析
def analyze_space_occupancy():
    conn = get_db_connection()
    query = """
        SELECT l.id, l.code, l.capacity, COALESCE(SUM(s.quantity), 0) as occupied
        FROM locations l
        LEFT JOIN stocks s ON l.id = s.location_id
        GROUP BY l.id, l.code, l.capacity
    """
    df = pd.read_sql(query, conn)
    conn.close()
    
    # 占有率計算
    df['occupancy_rate'] = df['occupied'] / df['capacity'] * 100
    df['status'] = df['occupancy_rate'].apply(
        lambda x: '過密' if x > 90 else '最適' if x > 50 else '空き'
    )
    
    # 集計
    summary = df.groupby('status').agg({
        'code': 'count',
        'occupancy_rate': 'mean'
    }).reset_index()
    
    # 結果をCSVに保存
    df.to_csv('space_occupancy.csv', index=False)
    return df, summary

if __name__ == '__main__':
    occupancy_df, summary = analyze_space_occupancy()
    print(summary)
```

### コードのポイント
1. **占有率**：ロケーションごとの在庫量を容量で割り、百分率を計算。
2. **ステータス**：90%以上は「過密」、50%以下は「空き」と分類。
3. **集計**：エリアごとの状態を要約、CSVに出力。
4. **拡張性**：数千ロケーションを効率的に処理。

### 分析の活用
- **過密エリア**：エリアA-01（95%）→再配置または動的ラック導入。
- **空きエリア**：エリアC-10（20%）→新入庫を優先。
- **全体傾向**：空きスペースが30%→臨時倉庫の借用を回避。

## 需要予測API
入出庫データに基づくスペース需要を予測します。以下は、Flask APIの例です。

```python
from flask import Flask, jsonify
from http import HTTPStatus
import psycopg2
from psycopg2.extras import RealDictCursor
import pandas as pd
from sklearn.linear_model import LinearRegression
import numpy as np
from datetime import datetime, timedelta

app = Flask(__name__)

def get_db_connection():
    return psycopg2.connect(
        dbname="wms_db",
        user="postgres",
        password="password",
        host="localhost",
        port="5432"
    )

@app.route('/api/space/forecast', methods=['GET'])
def forecast_space_demand():
    try:
        conn = get_db_connection()
        query = """
            SELECT DATE(t.created_at) as date, SUM(t.quantity) as volume
            FROM transactions t
            WHERE t.type = 'IN'
            AND t.created_at >= CURRENT_DATE - INTERVAL '90 days'
            GROUP BY DATE(t.created_at)
            ORDER BY date
        """
        df = pd.read_sql(query, conn)
        conn.close()
        
        # データ準備
        df['days'] = (pd.to_datetime(df['date']) - pd.to_datetime(df['date'].min())).dt.days
        X = df[['days']].values
        y = df['volume'].values
        
        # 線形回帰モデル
        model = LinearRegression()
        model.fit(X, y)
        
        # 未来30日の予測
        future_days = np.array([[df['days'].max() + i] for i in range(1, 31)])
        predictions = model.predict(future_days)
        
        forecast = [
            {
                'date': (datetime.now() + timedelta(days=i)).strftime('%Y-%m-%d'),
                'predicted_volume': round(pred, 2)
            }
            for i, pred in enumerate(predictions, 1)
        ]
        
        return jsonify({
            'message': 'スペース需要を予測しました',
            'forecast': forecast
        }), HTTPStatus.OK
    
    except Exception as e:
        return jsonify({'error': str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR

if __name__ == '__main__':
    app.run(debug=True)
```

### コードのポイント
1. **予測モデル**：過去90日の入庫データで線形回帰を学習。
2. **出力**：未来30日の入庫ボリュームを予測。
3. **拡張性**：季節性やピーク（例：ブラックフライデー）対応可能。
4. **エラーハンドリング**：データ不足やモデルエラーを検出。

### APIの使用例
リクエスト：
```bash
curl http://localhost:5000/api/space/forecast
```

レスポンス例：
```json
{
    "message": "スペース需要を予測しました",
    "forecast": [
        {"date": "2025-06-01", "predicted_volume": 1200.5},
        {"date": "2025-06-02", "predicted_volume": 1220.7},
        ...
    ]
}
```

## 占有率ダッシュボード
スペース利用状況を可視化するReactダッシュボードを構築します。

```jsx
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Pie } from 'react-chartjs-2';
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';

ChartJS.register(ArcElement, Tooltip, Legend);

const SpaceDashboard = () => {
    const [occupancyData, setOccupancyData] = useState(null);

    useEffect(() => {
        axios.get('http://localhost:5000/api/space/occupancy')
            .then(response => {
                const summary = response.data.summary;
                setOccupancyData({
                    labels: ['過密', '最適', '空き'],
                    datasets: [{
                        data: [
                            summary.find(s => s.status === '過密')?.count || 0,
                            summary.find(s => s.status === '最適')?.count || 0,
                            summary.find(s => s.status === '空き')?.count || 0
                        ],
                        backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56']
                    }]
                });
            })
            .catch(error => console.error('エラー:', error));
    }, []);

    if (!occupancyData) return <div>読み込み中...</div>;

    return (
        <div>
            <h1>倉庫スペースダッシュボード</h1>
            <Pie
                data={occupancyData}
                options={{
                    responsive: true,
                    plugins: { legend: { position: 'top' }, title: { display: true, text: 'スペース占有率' } }
                }}
            />
        </div>
    );
};

export default SpaceDashboard;
```

### ダッシュボードのポイント
1. **可視化**：過密、最適、空きエリアの割合を円グラフで表示。
2. **リアルタイム**：最新の占有率データを反映。
3. **ユーザビリティ**：管理者が一目でスペース状況を把握。
4. **拡張性**：エリアごとの詳細表示に対応可能。

## 実際のユースケース
以下は、**容量管理**が倉庫業務にどう役立つかの例です：
1. **賃料削減**：
   - 課題：臨時倉庫で月間100万円のコスト。
   - 解決策：**予測**でピーク需要を事前計画。
   - 結果：臨時賃料が40%削減。
2. **スペース利用向上**：
   - 課題：空きスペースが30%無駄。
   - 解決策：過密エリアを再配置、動的ラック導入。
   - 結果：利用率が75%から90%に向上。
3. **ピーク対応**：
   - 課題：繁忙期にスペース不足で入庫遅延。
   - 解決策：ダッシュボードで空きエリアを特定。
   - 結果：遅延が50件からゼロに。

## 実践のポイント
- **データ品質**：ロケーション容量と在庫データが正確か確認。
- **フィードバック**：作業員に再配置の影響を聞き、調整を。
- **ピーク計画**：予測データをもとに、ブラックフライデー前にスペースを解放。
- **動的ラック**：可動式棚を活用し、柔軟性を高める。
- **定期監視**：週次で占有率をレビューし、ボトルネックを解消。

## 学びのポイント
**スペースは資産**：効率的な**容量管理**は、コスト削減と運用効率の鍵です。筆者のプロジェクトでは、非効率なスペース管理で臨時倉庫に年間2000万円を費やしていました。**WMS**による**スペース最適化**と**予測**を導入後、コストが50%削減され、入出庫効率が25%向上しました。鍵は、データ駆動のリアルタイム監視と柔軟な対応です。

## 次回予告
次回はシリーズ最終回、**シリーズ総括**です。**WMS**を活用した倉庫最適化の全体像を振り返り、チェックリストと改善策を提案します。