cruise-supply-chain について
クルーズ船の補給と海事サプライチェーン業務を支援し、調達、在庫、港湾作業の調整を扱うスキルです。複数港での補給、食品廃棄、冷蔵保管、積み込み計画をカバーします。
主な機能
- 01複数港にまたがる船舶補給の計画
- 02在庫PARレベルの最適化
- 03食品廃棄の削減
- 04温度要件に応じた冷蔵品の配置
- 05港での納品と積み込みの調整
活用シーン
- 01航路と寄港に合わせた物資の計画
- 02船内の食品・消耗品在庫の管理
- 03食品の発注・調理による廃棄の削減
- 04限られた寄港時間内での納品計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill cruise-supply-chainインストール後、Claude Code で/cruise-supply-chainを入力して読み込まれたか確認します。
詳細
クルーズ船サプライチェーン
クルーズ船のサプライチェーン管理と海事物流の専門家です。乗客の満足度を確保しながら、コスト、保管スペースの制約、港湾業務を管理し、クルーズ船への複雑な物資供給、在庫管理、物流を最適化することを目指します。
初期評価
クルーズ船のサプライチェーンを最適化する前に、以下を把握します。
-
船舶・船隊の概要
- 船隊の規模と船舶の種類は?
- 乗客定員と乗組員数は?
- 保管容量(常温、冷蔵、冷凍)は?
- ギャレーと飲食サービスの能力は?
-
航路・運航
- 航路の構成は?(カリブ海、地中海、アラスカ、世界一周クルーズ)
- 寄港地の巡回順と頻度は?
- 海上で過ごす日数と寄港中の日数は?
- 季節による変動は?
-
現在のサプライチェーン
- 物資の補給頻度と場所は?
- サプライヤーネットワークは?(グローバル、地域)
- 在庫管理システムは?
- コールドチェーンの能力は?
-
目標・課題
- 主な目標は?(コスト、品質、廃棄物削減)
- 現在の主な問題は?(欠品、廃棄、コスト)
- サステナビリティ目標は?
- 顧客満足度の指標は?
クルーズ船サプライチェーンのフレームワーク
サプライチェーンの構成要素
食品・飲料:
- 生鮮農産物(果物、野菜)
- タンパク質食品(牛肉、鶏肉、魚介類)
- 乳製品
- 乾物・食料品
- 飲料(アルコール飲料、ノンアルコール飲料)
- 特殊食材・原材料
ホテル運営:
- リネン類・タオル
- 客室アメニティ(トイレタリー用品など)
- 清掃用品
- 客室備品
技術・保守:
- 予備部品
- 燃料・潤滑油
- 技術用品
- 安全装備
エンターテインメント・レクリエーション:
- 寄港地観光ツアー用物資
- エンターテインメント機器
- 小売商品
物資補給計画・最適化
複数寄港地での物資補給戦略
import numpy as np
import pandas as pd
from pulp import *
class CruiseProvisioningOptimizer:
"""
Optimize cruise ship provisioning across multiple ports
Balance costs, storage capacity, and quality
"""
def __init__(self, vessel_capacity, itinerary):
self.vessel_capacity = vessel_capacity # storage capacity by type
self.itinerary = itinerary # list of port calls
def optimize_provisioning_schedule(self, item_requirements, port_costs,
port_availability):
"""
Determine what to purchase at each port to minimize total cost
Parameters:
- item_requirements: dict of {item: daily_consumption}
- port_costs: dict of {(port, item): cost_per_unit}
- port_availability: dict of {(port, item): available_quantity}
"""
prob = LpProblem("Cruise_Provisioning", LpMinimize)
items = list(item_requirements.keys())
ports = [port['name'] for port in self.itinerary]
# Variables: quantity of item i purchased at port p
purchase = {}
for port in ports:
for item in items:
if (port, item) in port_costs:
purchase[port, item] = LpVariable(
f"Purchase_{port}_{item}",
lowBound=0
)
# Objective: minimize total procurement cost
total_cost = lpSum([purchase[port, item] * port_costs.get((port, item), 999999)
for port in ports
for item in items
if (port, item) in purchase])
prob += total_cost
# Constraints
# Meet demand for full voyage
voyage_days = sum([port['days_until_next'] for port in self.itinerary])
for item in items:
total_required = item_requirements[item] * voyage_days
total_purchased = lpSum([purchase.get((port, item), 0)
for port in ports])
prob += total_purchased >= total_required
# Storage capacity constraints at each port
for p, port in enumerate(self.itinerary):
# Remaining voyage days from this port
remaining_days = sum([self.itinerary[i]['days_until_next']
for i in range(p, len(self.itinerary))])
# Storage at this port = purchases at this port + previous inventory
# (Simplified model - actual would track consumption)
for storage_type in ['dry', 'cold', 'frozen']:
items_this_type = [i for i in items
if item_requirements[i].get('storage_type') == storage_type]
# Total storage used
storage_used = lpSum([purchase.get((port['name'], item), 0) *
item_requirements[item].get('volume_per_unit', 1)
for item in items_this_type])
prob += storage_used <= self.vessel_capacity[storage_type]
# Port availability limits
for port in ports:
for item in items:
if (port, item) in port_availability:
if (port, item) in purchase:
prob += purchase[port, item] <= port_availability[port, item]
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract provisioning schedule
schedule = []
for port in ports:
port_orders = []
port_cost = 0
for item in items:
if (port, item) in purchase and purchase[port, item].varValue > 0.1:
quantity = purchase[port, item].varValue
cost = quantity * port_costs.get((port, item), 0)
port_orders.append({
'item': item,
'quantity': quantity,
'unit_cost': port_costs.get((port, item), 0),
'total_cost': cost
})
port_cost += cost
if port_orders:
schedule.append({
'port': port,
'orders': port_orders,
'total_port_cost': port_cost
})
return {
'status': LpStatus[prob.status],
'total_cost': value(prob.objective),
'provisioning_schedule': schedule
}
def calculate_food_requirements(self, passenger_count, crew_count,
voyage_days, menu_plan):
"""
Calculate food and beverage requirements based on passenger load
and menu planning
"""
requirements = {}
# Per-person-per-day consumption rates
consumption_rates = {
'beef': 0.25, # kg
'chicken': 0.20,
'seafood': 0.15,
'vegetables': 0.30,
'fruits': 0.25,
'dairy_milk': 0.15, # liters
'bread': 0.15, # kg
'wine': 0.10, # liters
'beer': 0.20, # liters
'soft_drinks': 0.30 # liters
}
total_pax = passenger_count + crew_count
for item, rate_per_day in consumption_rates.items():
daily_consumption = rate_per_day * total_pax
# Add safety factor
safety_factor = 1.15
requirements[item] = {
'daily_consumption': daily_consumption * safety_factor,
'total_voyage': daily_consumption * safety_factor * voyage_days
}
return requirements
# Example usage
vessel_capacity = {
'dry': 500, # cubic meters
'cold': 300,
'frozen': 200
}
itinerary = [
{'name': 'Miami', 'days_until_next': 3},
{'name': 'Cozumel', 'days_until_next': 2},
{'name': 'Grand Cayman', 'days_until_next': 2},
{'name': 'Miami', 'days_until_next': 0}
]
optimizer = CruiseProvisioningOptimizer(vessel_capacity, itinerary)
item_requirements = {
'beef': {'daily_consumption': 500, 'storage_type': 'frozen', 'volume_per_unit': 0.001},
'chicken': {'daily_consumption': 400, 'storage_type': 'frozen', 'volume_per_unit': 0.001},
'vegetables': {'daily_consumption': 600, 'storage_type': 'cold', 'volume_per_unit': 0.0015},
'wine': {'daily_consumption': 200, 'storage_type': 'dry', 'volume_per_unit': 0.001},
}
port_costs = {
('Miami', 'beef'): 12.00,
('Miami', 'chicken'): 6.00,
('Miami', 'vegetables'): 3.00,
('Miami', 'wine'): 8.00,
('Cozumel', 'beef'): 14.00,
('Cozumel', 'vegetables'): 2.50,
('Grand Cayman', 'beef'): 15.00,
}
port_availability = {
('Miami', 'beef'): 10000,
('Miami', 'chicken'): 10000,
('Miami', 'vegetables'): 10000,
('Miami', 'wine'): 5000,
('Cozumel', 'beef'): 2000,
('Cozumel', 'vegetables'): 3000,
}
result = optimizer.optimize_provisioning_schedule(item_requirements,
port_costs,
port_availability)
print(f"Total provisioning cost: ${result['total_cost']:,.2f}")
クルーズ船の在庫管理
適正在庫レベルの最適化
def calculate_par_levels(item, consumption_rate, lead_time_days,
service_level=0.95, storage_cost_per_unit=1.0):
"""
Calculate optimal par stock levels for cruise ship inventory
Parameters:
- item: item details
- consumption_rate: average daily consumption
- lead_time_days: days between ports (resupply time)
- service_level: target service level (stockout probability)
- storage_cost_per_unit: cost to hold inventory
"""
from scipy.stats import norm
# Demand during lead time
avg_demand = consumption_rate * lead_time_days
# Variability (assume coefficient of variation)
cv = 0.20 # 20% variability
std_demand = avg_demand * cv
# Safety stock
z_score = norm.ppf(service_level)
safety_stock = z_score * std_demand
# Reorder point (par level)
par_level = avg_demand + safety_stock
# Maximum stock level (par level + one order quantity)
max_level = par_level * 1.5
return {
'par_level': par_level,
'max_level': max_level,
'safety_stock': safety_stock,
'avg_inventory': (par_level + max_level) / 2,
'holding_cost': ((par_level + max_level) / 2) * storage_cost_per_unit
}
# Example
beef_par = calculate_par_levels(
item='beef',
consumption_rate=500, # kg/day
lead_time_days=7, # 1 week between ports
service_level=0.98 # High service level for critical item
)
print(f"Beef par level: {beef_par['par_level']:.0f} kg")
print(f"Safety stock: {beef_par['safety_stock']:.0f} kg")
廃棄物削減・サステナビリティ
食品廃棄物の最適化
class CruiseFoodWasteOptimizer:
"""
Optimize food ordering and preparation to minimize waste
"""
def __init__(self, historical_consumption):
self.historical_consumption = historical_consumption
def predict_actual_consumption(self, planned_menu, passenger_count,
day_of_cruise):
"""
Predict actual consumption to reduce overproduction
Factors:
- Port days vs. sea days (different consumption patterns)
- Day of cruise (higher consumption early in cruise)
- Menu popularity
- Passenger demographics
"""
from sklearn.ensemble import RandomForestRegressor
# Features for prediction
features = {
'passenger_count': passenger_count,
'day_of_cruise': day_of_cruise,
'is_sea_day': 1 if planned_menu['is_sea_day'] else 0,
'menu_popularity_score': planned_menu.get('popularity', 0.7)
}
# Simple model (would be trained on historical data)
# Predicted consumption factor vs. standard portion
consumption_factor = 0.85 # Typically 85% of planned is consumed
predicted_consumption = {}
for item, planned_quantity in planned_menu['items'].items():
# Adjust based on patterns
if features['is_sea_day']:
adjustment = 1.1 # Higher consumption on sea days
else:
adjustment = 0.9 # Lower on port days
predicted = planned_quantity * consumption_factor * adjustment
predicted_consumption[item] = {
'planned': planned_quantity,
'predicted_actual': predicted,
'recommended_prep': predicted * 1.05 # Small buffer
}
return predicted_consumption
def optimize_buffet_replenishment(self, current_inventory, consumption_rate,
time_remaining_hours):
"""
Optimize buffet replenishment to minimize waste at end of service
"""
# Calculate expected consumption in remaining time
expected_consumption = consumption_rate * time_remaining_hours
# Replenishment decision
if current_inventory < expected_consumption * 0.5:
# Replenish
replenish_quantity = expected_consumption - current_inventory
# Don't overproduce near end of service
if time_remaining_hours < 1:
replenish_quantity *= 0.7 # Conservative
return {
'action': 'replenish',
'quantity': replenish_quantity,
'reason': 'Current inventory below threshold'
}
else:
return {
'action': 'hold',
'quantity': 0,
'reason': 'Sufficient inventory for remaining service'
}
def donation_optimization(self, excess_inventory, port_donations):
"""
Optimize food donation to reduce waste and support communities
Match excess inventory with port-based donation opportunities
"""
donation_plan = []
for item, quantity in excess_inventory.items():
if quantity > 0:
# Find suitable donation partners
eligible_partners = [
p for p in port_donations
if item in p['accepted_items']
]
if eligible_partners:
# Allocate to highest-impact partner
best_partner = max(eligible_partners,
key=lambda x: x['impact_score'])
donation_plan.append({
'item': item,
'quantity': quantity,
'partner': best_partner['name'],
'estimated_impact': quantity * best_partner['meals_per_kg']
})
return donation_plan
コールドチェーン管理
温度管理された在庫
def optimize_cold_chain_storage(items, storage_zones, temperature_requirements):
"""
Optimize placement of items in cold storage zones
Parameters:
- items: list of items with temp requirements
- storage_zones: available cold storage with temp ranges
- temperature_requirements: optimal temps for each item
"""
from pulp import *
prob = LpProblem("Cold_Storage", LpMinimize)
# Variables: assign item i to zone z
x = {}
for i, item in enumerate(items):
for z, zone in enumerate(storage_zones):
# Check if zone can handle item's temp requirement
if (zone['temp_min'] <= temperature_requirements[item['name']]['optimal'] <= zone['temp_max']):
x[i, z] = LpVariable(f"Assign_{i}_{z}", cat='Binary')
# Objective: minimize energy cost (colder zones cost more)
energy_cost = lpSum([x[i, z] * storage_zones[z]['energy_cost_per_unit'] *
items[i]['volume']
for (i, z) in x])
prob += energy_cost
# Constraints
# Each item assigned to exactly one zone
for i in range(len(items)):
zones_for_item = [x[i, z] for z in range(len(storage_zones))
if (i, z) in x]
if zones_for_item:
prob += lpSum(zones_for_item) == 1
# Zone capacity
for z, zone in enumerate(storage_zones):
zone_volume = lpSum([items[i]['volume'] * x[i, z]
for i in range(len(items))
if (i, z) in x])
prob += zone_volume <= zone['capacity']
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract assignments
assignments = []
for (i, z) in x:
if x[i, z].varValue > 0.5:
assignments.append({
'item': items[i]['name'],
'zone': storage_zones[z]['name'],
'temperature': storage_zones[z]['temp_min'],
'volume': items[i]['volume']
})
return {
'total_energy_cost': value(prob.objective),
'assignments': pd.DataFrame(assignments)
}
# Example
items = [
{'name': 'Ice Cream', 'volume': 50},
{'name': 'Frozen Fish', 'volume': 100},
{'name': 'Fresh Vegetables', 'volume': 150},
{'name': 'Dairy Products', 'volume': 80},
]
storage_zones = [
{'name': 'Deep Freeze', 'temp_min': -25, 'temp_max': -18,
'capacity': 200, 'energy_cost_per_unit': 3.0},
{'name': 'Freezer', 'temp_min': -18, 'temp_max': -12,
'capacity': 250, 'energy_cost_per_unit': 2.0},
{'name': 'Cold Storage', 'temp_min': 0, 'temp_max': 4,
'capacity': 300, 'energy_cost_per_unit': 1.0},
]
temperature_requirements = {
'Ice Cream': {'optimal': -20},
'Frozen Fish': {'optimal': -15},
'Fresh Vegetables': {'optimal': 2},
'Dairy Products': {'optimal': 3},
}
result = optimize_cold_chain_storage(items, storage_zones, temperature_requirements)
港湾物流・業務
陸上側との連携
def optimize_port_loading_schedule(deliveries, loading_bays, port_time_window):
"""
Optimize scheduling of supplier deliveries during port call
Constraints:
- Limited port time (6-10 hours typically)
- Limited loading bays
- Crew availability
- Customs clearance
"""
from pulp import *
prob = LpProblem("Port_Loading", LpMinimize)
n_deliveries = len(deliveries)
n_bays = loading_bays
time_slots = range(port_time_window) # hours
# Variables: assign delivery d to bay b in time slot t
x = {}
for d in range(n_deliveries):
for b in range(n_bays):
for t in time_slots:
x[d, b, t] = LpVariable(f"Assign_{d}_{b}_{t}", cat='Binary')
# Objective: minimize total makespan + priority penalties
makespan = LpVariable("Makespan", lowBound=0)
# Completion time of last delivery
prob += makespan
# Each delivery assigned once
for d in range(n_deliveries):
prob += lpSum([x[d, b, t]
for b in range(n_bays)
for t in time_slots]) == 1
# Bay can handle one delivery at a time
for b in range(n_bays):
for t in time_slots:
prob += lpSum([x[d, b, t] for d in range(n_deliveries)]) <= 1
# Makespan constraint
for d, delivery in enumerate(deliveries):
for b in range(n_bays):
for t in time_slots:
# If delivery starts at time t, it completes at t + duration
prob += makespan >= (t + delivery['duration_hours']) * x[d, b, t]
# Priority deliveries (perishables) should be early
for d, delivery in enumerate(deliveries):
if delivery.get('priority') == 'high':
for b in range(n_bays):
for t in time_slots:
if t > port_time_window // 2:
# Penalize late loading of priority items
prob += x[d, b, t] == 0
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract schedule
schedule = []
for d in range(n_deliveries):
for b in range(n_bays):
for t in time_slots:
if x[d, b, t].varValue > 0.5:
schedule.append({
'delivery': deliveries[d]['supplier'],
'items': deliveries[d]['items'],
'bay': b + 1,
'start_time': t,
'duration': deliveries[d]['duration_hours'],
'priority': deliveries[d].get('priority', 'normal')
})
return {
'makespan': makespan.varValue,
'schedule': pd.DataFrame(schedule).sort_values('start_time')
}
ツール・ライブラリ
Python ライブラリ
最適化:
PuLP:線形計画法scipy.optimize:一般的な最適化OR-Tools:Google の最適化ツール
予測:
scikit-learn:機械学習prophet:時系列予測
データ分析:
pandas、numpy:データ操作matplotlib:可視化
商用ソフトウェア
クルーズ運航:
- ShipServ:海事調達プラットフォーム
- MarineCFO:クルーズ船の財務管理
- Adonis:ホスピタリティ管理システム
- ORIS:船舶の運航・報告
在庫管理:
- Visual Computers:クルーズ船の在庫システム
- Compeat:レストラン・ホスピタリティ業界向け在庫管理
- MarketMan:飲食サービス向け在庫管理
物資補給:
- Navtor:海事航海計画
- Martek Marine:船舶管理ソフトウェア
- Danaos:船舶管理システム
サステナビリティ:
- Cleantech:環境規制への適合
- OCEANOS:環境モニタリング
よくある課題と解決策
課題:寄港時間の制約
問題:
- 寄港時間が限られている(4~10時間)
- 複数のサプライヤーと納品
- 税関・検査による遅延
解決策:
- 事前の計画と調整
- 集約業者からの一括納品
- 保税倉庫の手配
- 並行して行う積み込み作業
- 事前承認済みのサプライヤー
課題:保管スペースの制限
問題:
- 冷蔵保管容量の制限
- 部門間でのスペースの競合
- 季節による需要の変動
解決策:
- 適正在庫レベルの最適化
- 可能な場合はジャストインタイムでの物資補給
- 複数温度帯の保管スペースの最適化
- 省スペース型の保管ソリューション
- 物資補給に適した寄港地の戦略的な選定
課題:品質と鮮度
問題:
- 補給なしで長期間航海する
- 食材の品質を維持する
- ゲストが求める鮮度に応える
解決策:
- CA貯蔵
- 船内の水耕栽培ガーデン
- 複数の寄港地で戦略的に調達する
- 食材の保存期間に合わせてメニューを計画する
- 品質検査の手順を確立する
課題:廃棄物管理
問題:
- 食品廃棄物(仕込み時と食べ残し)
- 環境規制
- 海上での廃棄方法が限られている
解決策:
- 予測に基づく生産計画
- ポーション管理の最適化
- 寄港地での寄付プログラム
- 堆肥化とバイオダイジェスター
- 廃棄物発電システム
出力形式
クルーズ・サプライチェーンレポート
エグゼクティブサマリー:
- 船舶への物資補給の実績
- コスト指標と傾向
- 廃棄物削減の実績
- 主な機会
物資補給の実績:
| 寄港地 | 積載品目数 | 金額 | リードタイム | 定時率 | 品質上の問題 |
|---|---|---|---|---|---|
| Miami | 1,250 | $185,000 | 4.5 hrs | 98% | 2 |
| Cozumel | 320 | $28,000 | 2.8 hrs | 100% | 0 |
| Grand Cayman | 180 | $15,000 | 3.2 hrs | 95% | 1 |
在庫指標:
| カテゴリー | 現在庫 | 基準在庫 | 在庫日数 | 回転率 | 廃棄率 |
|---|---|---|---|---|---|
| タンパク質(冷凍) | 3,200 kg | 3,500 kg | 6.4 | 45x/yr | 2.1% |
| 生鮮青果 | 1,800 kg | 2,000 kg | 3.0 | 120x/yr | 5.8% |
| 乳製品 | 1,200 L | 1,400 L | 4.0 | 90x/yr | 3.2% |
| 乾物 | 5,500 kg | 6,000 kg | 18.0 | 20x/yr | 1.5% |
コスト分析:
| カテゴリー | 合計コスト | 乗客1人・1日あたりのコスト | 合計に占める割合 | 予算比 |
|---|---|---|---|---|
| タンパク質 | $125,000 | $8.50 | 35% | -2% |
| 青果 | $85,000 | $5.80 | 24% | +1% |
| 乳製品 | $45,000 | $3.06 | 13% | 0% |
| 飲料 | $70,000 | $4.76 | 20% | -3% |
| その他 | $30,000 | $2.04 | 8% | +2% |
| 合計 | $355,000 | $24.16 | 100% | -1% |
廃棄物削減:
| 指標 | 今回の航海 | 前回の航海 | 年初来平均 | 目標 |
|---|---|---|---|---|
| 食品廃棄物(kg/乗客・日) | 0.45 | 0.52 | 0.48 | < 0.40 |
| 廃棄物削減率 | 13% | - | 8% | 15% |
| 寄付(食数) | 1,250 | 980 | 1,100 | 1,000 |
推奨事項:
- 物資補給の多くをMiamiに切り替える(カリブ海の寄港地と比べて15%のコスト削減)
- 青果の基準在庫を10%削減する(廃棄物削減の機会)
- 予測型ビュッフェ補充システムを導入する
- 寄付プログラムをすべての寄港地に拡大する
- ハーブとレタス用の水耕栽培ガーデンを設置する(コストを35%削減)
質問事項
さらに詳しい情報が必要な場合:
- 船舶の種類と定員は?(メガシップ、ラグジュアリー、探検型)
- 旅程と航路は?
- 物資補給の頻度と主な寄港地は?
- 現在の廃棄物とコストの指標は?
- どのようなシステムを導入していますか?(在庫、調達)
- 主な課題は何ですか?(コスト、品質、廃棄物)
- サステナビリティに関する目標はありますか?
関連スキル
- hotel-inventory-management:ホスピタリティ業界の在庫管理の概念
- hospitality-procurement:購買とサプライヤー管理
- tour-operations:乗客の運航業務
- inventory-optimization:在庫管理戦略
- demand-forecasting:消費量の予測
- route-optimization:旅程の最適化
- cold-chain-logistics:温度管理が必要なサプライチェーン
- food-beverage-supply-chain:飲食業務
コメント
Markdown 対応