airline-cargo-optimization について
airline-cargo-optimizationは、航空貨物チーム向けの計画スキルです。収益、輸送能力、経路、取扱上の制約を考慮し、旅客便のベリー貨物と貨物便を対象に、容量配分、ULD積載、価格設定、複数区間の経路計画を扱います。
主な機能
- 01貨物容量の割り当て
- 02ULD積載の最適化
- 03需要と容量に基づく価格設定
- 04複数区間の貨物経路計画
- 05特殊貨物の取扱に関する考慮事項
活用シーン
- 01旅客手荷物と併せたベリー容量の配分
- 02貨物のULD積載計画
- 03出発時期と残容量に応じた価格調整
- 04乗り継ぎ便を使った貨物経路の計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill airline-cargo-optimizationインストール後、Claude Code で/airline-cargo-optimizationを入力して読み込まれたか確認します。
詳細
航空貨物の最適化
航空貨物の運航と航空貨物輸送の最適化に精通しています。旅客運航と運航上の制約とのバランスを取りながら、容量配分、価格設定、経路選定、取り扱いを最適化し、貨物収入の最大化を支援します。
初期評価
航空貨物を最適化する前に、以下を把握します。
-
貨物運航の種類
- 貨物運航の形態は何ですか?(貨物専用、旅客便のベリー搭載、コンビ、貨物専用機)
- ネットワーク構造はどのようなものですか?(ハブ・アンド・スポーク、ポイント・ツー・ポイント、地域型)
- 主な輸送路線と市場はどこですか?
- フォワーダーとの関係はどうなっていますか?
-
容量とリソース
- 機材構成と貨物搭載容量はどうなっていますか?
- ULD(ユニット・ロード・デバイス)の在庫はどれくらいですか?
- 貨物取扱施設はありますか?
- 倉庫と保管の容量はどれくらいですか?
-
貨物の構成
- 貨物の種類は何ですか?(一般貨物、エクスプレス、特殊貨物)
- 種類別の収入貢献はどれくらいですか?
- 特別な取扱要件はありますか?(生鮮品、医薬品、危険物)
- Eコマースと従来型貨物の割合はどうなっていますか?
-
目標と課題
- 主な目標は何ですか?(収入、イールド、搭載率)
- 現在の課題は何ですか?(容量利用率、価格設定、運航)
- 旅客と貨物のどちらを優先しますか?
- どのような技術システムを利用していますか?(CMS、レベニューマネジメント)
航空貨物のフレームワーク
貨物カテゴリー
一般貨物:
- 標準的な貨物
- 特別な要件なし
- 容量計画において最も柔軟
エクスプレスとEコマース:
- 時間的制約のある貨物
- 優先的な取扱い
- 高いイールドが期待できる
特殊貨物:
- 生鮮品(花、魚介類、青果物)
- 医薬品(温度管理が必要)
- 危険物(IATA 規制)
- 生きた動物
- 高価値貨物(宝飾品、電子機器)
寸法超過・重量物貨物:
- 規格外の貨物
- 特殊な ULD または床面への積載が必要
- 航空機との適合性に関する制約あり
貨物容量管理
ベリー搭載容量の配分
import numpy as np
import pandas as pd
from pulp import *
def optimize_cargo_capacity_allocation(flight, cargo_bookings, passenger_bags,
available_capacity):
"""
Optimize cargo allocation for passenger flight belly capacity
Parameters:
- flight: flight details (route, aircraft type, departure time)
- cargo_bookings: list of cargo booking requests with rates
- passenger_bags: expected passenger baggage (priority)
- available_capacity: total cargo hold capacity (weight and volume)
"""
prob = LpProblem("Cargo_Allocation", LpMaximize)
# Variables: accept booking b (binary) and quantity
accept = {}
quantity = {}
for b, booking in enumerate(cargo_bookings):
accept[b] = LpVariable(f"Accept_{b}", cat='Binary')
quantity[b] = LpVariable(f"Quantity_{b}",
lowBound=0,
upBound=booking['pieces'])
# Objective: maximize cargo revenue
revenue = lpSum([booking['rate_per_kg'] * booking['weight_per_piece'] *
quantity[b]
for b, booking in enumerate(cargo_bookings)])
prob += revenue
# Constraints
# Weight capacity
total_weight = (
passenger_bags['weight'] +
lpSum([booking['weight_per_piece'] * quantity[b]
for b, booking in enumerate(cargo_bookings)])
)
prob += total_weight <= available_capacity['weight_kg']
# Volume capacity
total_volume = (
passenger_bags['volume'] +
lpSum([booking['volume_per_piece'] * quantity[b]
for b, booking in enumerate(cargo_bookings)])
)
prob += total_volume <= available_capacity['volume_m3']
# All-or-nothing bookings (some cargo must be accepted completely)
for b, booking in enumerate(cargo_bookings):
if booking.get('all_or_nothing', False):
# If accepted, must take all pieces
prob += quantity[b] == booking['pieces'] * accept[b]
else:
# Partial acceptance allowed
prob += quantity[b] <= booking['pieces'] * accept[b]
# Priority rules (express cargo over general cargo if capacity tight)
# Implemented via revenue rates in objective
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract results
accepted_bookings = []
total_revenue = 0
total_cargo_weight = 0
for b, booking in enumerate(cargo_bookings):
if quantity[b].varValue > 0.1:
pieces_accepted = quantity[b].varValue
weight = booking['weight_per_piece'] * pieces_accepted
revenue_booking = booking['rate_per_kg'] * weight
accepted_bookings.append({
'booking_id': booking['id'],
'commodity': booking['commodity'],
'pieces_requested': booking['pieces'],
'pieces_accepted': pieces_accepted,
'weight_kg': weight,
'revenue': revenue_booking,
'rate_per_kg': booking['rate_per_kg']
})
total_revenue += revenue_booking
total_cargo_weight += weight
return {
'status': LpStatus[prob.status],
'total_revenue': value(prob.objective),
'accepted_bookings': pd.DataFrame(accepted_bookings),
'cargo_weight_kg': total_cargo_weight,
'passenger_bag_weight_kg': passenger_bags['weight'],
'total_weight_kg': total_cargo_weight + passenger_bags['weight'],
'capacity_utilization': (total_cargo_weight + passenger_bags['weight']) /
available_capacity['weight_kg']
}
# Example usage
flight = {'flight_number': 'AA100', 'route': 'JFK-LAX', 'aircraft': 'B777'}
cargo_bookings = [
{'id': 'CG001', 'commodity': 'Electronics', 'pieces': 10,
'weight_per_piece': 50, 'volume_per_piece': 0.2,
'rate_per_kg': 3.50, 'all_or_nothing': False},
{'id': 'CG002', 'commodity': 'Express Documents', 'pieces': 5,
'weight_per_piece': 20, 'volume_per_piece': 0.1,
'rate_per_kg': 8.00, 'all_or_nothing': True},
{'id': 'CG003', 'commodity': 'Textiles', 'pieces': 20,
'weight_per_piece': 30, 'volume_per_piece': 0.3,
'rate_per_kg': 2.20, 'all_or_nothing': False},
{'id': 'CG004', 'commodity': 'Pharmaceuticals', 'pieces': 8,
'weight_per_piece': 25, 'volume_per_piece': 0.15,
'rate_per_kg': 6.50, 'all_or_nothing': True},
]
passenger_bags = {
'weight': 3000, # kg
'volume': 15 # m3
}
available_capacity = {
'weight_kg': 5000,
'volume_m3': 35
}
result = optimize_cargo_capacity_allocation(flight, cargo_bookings,
passenger_bags, available_capacity)
print(f"Total cargo revenue: ${result['total_revenue']:,.2f}")
print(f"Capacity utilization: {result['capacity_utilization']:.1%}")
print(result['accepted_bookings'])
ULD(ユニット・ロード・デバイス)の最適化
ULD の組み付け最適化
class ULDOptimizer:
"""
Optimize packing of cargo into ULDs (containers and pallets)
"""
def __init__(self, uld_types):
self.uld_types = uld_types # dict of ULD specs
def optimize_uld_assignment(self, cargo_pieces, available_ulds):
"""
Assign cargo to ULDs to minimize ULD usage and maximize weight
3D bin packing problem
"""
from pulp import *
prob = LpProblem("ULD_Assignment", LpMinimize)
# Variables
# x[p, u]: assign piece p to ULD u
x = {}
for p, piece in enumerate(cargo_pieces):
for u, uld in enumerate(available_ulds):
x[p, u] = LpVariable(f"Assign_{p}_{u}", cat='Binary')
# y[u]: use ULD u
y = {}
for u, uld in enumerate(available_ulds):
y[u] = LpVariable(f"Use_ULD_{u}", cat='Binary')
# Objective: minimize number of ULDs used
prob += lpSum([y[u] for u in range(len(available_ulds))])
# Constraints
# Each piece assigned to exactly one ULD
for p in range(len(cargo_pieces)):
prob += lpSum([x[p, u] for u in range(len(available_ulds))]) == 1
# ULD weight capacity
for u, uld in enumerate(available_ulds):
total_weight = lpSum([cargo_pieces[p]['weight'] * x[p, u]
for p in range(len(cargo_pieces))])
prob += total_weight <= uld['max_weight_kg'] * y[u]
# ULD volume capacity (simplified - actual 3D packing is NP-hard)
for u, uld in enumerate(available_ulds):
total_volume = lpSum([cargo_pieces[p]['volume'] * x[p, u]
for p in range(len(cargo_pieces))])
prob += total_volume <= uld['max_volume_m3'] * y[u]
# If piece assigned to ULD, ULD must be used
for p in range(len(cargo_pieces)):
for u in range(len(available_ulds)):
prob += x[p, u] <= y[u]
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract results
assignments = []
for p, piece in enumerate(cargo_pieces):
for u, uld in enumerate(available_ulds):
if x[p, u].varValue > 0.5:
assignments.append({
'piece_id': piece['id'],
'uld_id': uld['id'],
'weight': piece['weight'],
'volume': piece['volume']
})
ulds_used = [uld['id'] for u, uld in enumerate(available_ulds)
if y[u].varValue > 0.5]
return {
'ulds_used': len(ulds_used),
'uld_list': ulds_used,
'assignments': pd.DataFrame(assignments),
'status': LpStatus[prob.status]
}
def calculate_uld_utilization(self, assignments, uld):
"""Calculate weight and volume utilization for ULD"""
uld_pieces = assignments[assignments['uld_id'] == uld['id']]
total_weight = uld_pieces['weight'].sum()
total_volume = uld_pieces['volume'].sum()
return {
'weight_utilization': total_weight / uld['max_weight_kg'],
'volume_utilization': total_volume / uld['max_volume_m3'],
'pieces_count': len(uld_pieces)
}
# Example
cargo_pieces = [
{'id': 'P001', 'weight': 150, 'volume': 0.8},
{'id': 'P002', 'weight': 200, 'volume': 1.2},
{'id': 'P003', 'weight': 180, 'volume': 0.9},
{'id': 'P004', 'weight': 120, 'volume': 0.6},
{'id': 'P005', 'weight': 250, 'volume': 1.5},
]
available_ulds = [
{'id': 'ULD_1', 'type': 'AKE', 'max_weight_kg': 1588, 'max_volume_m3': 4.0},
{'id': 'ULD_2', 'type': 'AKE', 'max_weight_kg': 1588, 'max_volume_m3': 4.0},
{'id': 'ULD_3', 'type': 'PMC', 'max_weight_kg': 6033, 'max_volume_m3': 16.0},
]
optimizer = ULDOptimizer(uld_types={})
result = optimizer.optimize_uld_assignment(cargo_pieces, available_ulds)
print(f"ULDs used: {result['ulds_used']}")
print(f"ULD list: {result['uld_list']}")
貨物レベニューマネジメント
貨物の動的価格設定
def optimize_cargo_pricing(flight, capacity_remaining, days_to_departure,
historical_demand, competitor_rates):
"""
Dynamic pricing for air cargo based on demand and capacity
Similar to passenger yield management but with cargo-specific factors
Parameters:
- flight: flight details
- capacity_remaining: available cargo capacity (kg and m3)
- days_to_departure: booking window remaining
- historical_demand: historical booking patterns
- competitor_rates: market rates
"""
# Calculate recommended rates by commodity type
rates = {}
for commodity in ['general', 'express', 'pharma', 'perishable']:
# Base rate from market
base_rate = competitor_rates.get(commodity, 2.50)
# Demand factor
if days_to_departure <= 3:
# Close to departure - increase rates if capacity limited
if capacity_remaining['weight_kg'] < 1000:
demand_factor = 1.5 # High demand, low capacity
else:
demand_factor = 0.8 # Need to fill capacity
elif days_to_departure <= 7:
demand_factor = 1.1
else:
demand_factor = 1.0
# Commodity premium
commodity_premium = {
'general': 1.0,
'express': 2.5,
'pharma': 3.0,
'perishable': 2.0
}.get(commodity, 1.0)
# Calculate rate
recommended_rate = base_rate * demand_factor * commodity_premium
# Floor and ceiling
min_rate = base_rate * 0.8
max_rate = base_rate * 3.0
recommended_rate = max(min_rate, min(recommended_rate, max_rate))
rates[commodity] = {
'rate_per_kg': recommended_rate,
'base_rate': base_rate,
'demand_factor': demand_factor,
'commodity_premium': commodity_premium
}
return rates
# Example
flight = {'flight_number': 'AA200', 'route': 'LAX-NRT', 'aircraft': 'B777'}
capacity_remaining = {
'weight_kg': 1500,
'volume_m3': 12
}
competitor_rates = {
'general': 2.50,
'express': 6.00,
'pharma': 8.00,
'perishable': 5.00
}
rates = optimize_cargo_pricing(flight, capacity_remaining, days_to_departure=5,
historical_demand={}, competitor_rates=competitor_rates)
for commodity, rate_info in rates.items():
print(f"{commodity}: ${rate_info['rate_per_kg']:.2f}/kg "
f"(demand factor: {rate_info['demand_factor']:.2f})")
貨物ネットワークの最適化
複数区間の貨物経路設定
def optimize_cargo_routing(shipments, flight_network, connecting_times):
"""
Optimize routing of cargo shipments through flight network
Parameters:
- shipments: list of cargo shipments with origin/destination
- flight_network: available flights with capacity and timing
- connecting_times: minimum connection times at each airport
"""
from pulp import *
import networkx as nx
prob = LpProblem("Cargo_Routing", LpMaximize)
# Build network graph
G = nx.DiGraph()
for flight in flight_network:
G.add_edge(flight['origin'], flight['destination'],
flight_id=flight['id'],
capacity=flight['cargo_capacity_kg'],
departure_time=flight['departure_time'],
arrival_time=flight['arrival_time'])
# Variables: route shipment s on flight f
x = {}
for s, shipment in enumerate(shipments):
# Find all possible paths from origin to destination
try:
paths = list(nx.all_simple_paths(G, shipment['origin'],
shipment['destination'],
cutoff=3)) # Max 3 legs
for path_idx, path in enumerate(paths):
# Check if path is feasible (timing)
feasible = True
# Would need to check connection times here
if feasible:
x[s, path_idx] = LpVariable(f"Route_{s}_{path_idx}",
cat='Binary')
except:
pass # No path exists
# Objective: maximize revenue (shipments delivered × rate)
revenue = []
for (s, path_idx), var in x.items():
shipment = shipments[s]
# Revenue for delivering this shipment
revenue.append(shipment['revenue'] * var)
prob += lpSum(revenue)
# Constraints
# Each shipment routed at most once
for s in range(len(shipments)):
routes = [x[s, p] for (s_, p) in x.keys() if s_ == s]
if routes:
prob += lpSum(routes) <= 1
# Flight capacity constraints
# (Simplified - would need to map paths to flights)
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract routes
selected_routes = []
for (s, path_idx), var in x.items():
if var.varValue > 0.5:
shipment = shipments[s]
selected_routes.append({
'shipment_id': shipment['id'],
'origin': shipment['origin'],
'destination': shipment['destination'],
'weight_kg': shipment['weight_kg'],
'revenue': shipment['revenue']
})
return {
'total_revenue': value(prob.objective),
'routes': selected_routes
}
特殊貨物の取扱い
温度管理が必要な貨物
class TemperatureControlledCargo:
"""
Manage pharmaceutical and perishable cargo requiring temp control
"""
def __init__(self, aircraft_cool_chain_capacity):
self.cool_chain_capacity = aircraft_cool_chain_capacity
def validate_pharma_shipment(self, shipment):
"""
Validate pharmaceutical shipment meets requirements
- Temperature range
- Packaging qualification
- Lane approval
- Handling certification
"""
requirements = {
'temp_range': shipment.get('required_temp_range', (2, 8)), # °C
'packaging': shipment.get('packaging_type'),
'lane_approved': shipment.get('lane_approved', False),
'gdp_certified': shipment.get('gdp_certified', False) # Good Distribution Practice
}
validation_result = {
'approved': True,
'issues': []
}
# Check temperature capability
temp_min, temp_max = requirements['temp_range']
if temp_min < 2 or temp_max > 8:
if not self.cool_chain_capacity.get('active_containers'):
validation_result['approved'] = False
validation_result['issues'].append(
'Temperature range requires active containers'
)
# Check packaging
if requirements['packaging'] not in ['qualified_passive', 'active_container']:
validation_result['approved'] = False
validation_result['issues'].append('Invalid packaging type')
# Check lane approval
if not requirements['lane_approved']:
validation_result['approved'] = False
validation_result['issues'].append('Lane not approved for pharma')
return validation_result
def allocate_cool_chain_capacity(self, pharma_shipments):
"""
Allocate limited cool chain capacity across shipments
Prioritize by:
- Value
- Urgency
- Contracted customers
"""
# Sort by priority score
for shipment in pharma_shipments:
shipment['priority_score'] = (
shipment.get('value_usd', 0) * 0.5 +
shipment.get('urgency_score', 0) * 0.3 +
shipment.get('customer_tier', 1) * 0.2
)
sorted_shipments = sorted(pharma_shipments,
key=lambda x: x['priority_score'],
reverse=True)
allocated = []
capacity_used = 0
for shipment in sorted_shipments:
if capacity_used + shipment['weight_kg'] <= self.cool_chain_capacity['weight_kg']:
allocated.append(shipment)
capacity_used += shipment['weight_kg']
return {
'allocated_shipments': allocated,
'capacity_utilization': capacity_used / self.cool_chain_capacity['weight_kg']
}
ツールとライブラリ
Python ライブラリ
最適化:
PuLP:線形計画法OR-Tools:Google の最適化ツールnetworkx:ネットワークの経路設定とフロー
3D パッキング:
py3dbp:3D ビンパッキング- ULD 最適化向けのカスタムアルゴリズム
データ分析:
pandas、numpy:データ操作matplotlib:可視化
商用ソフトウェア
貨物管理システム(CMS):
- IBS iCargo:包括的な貨物管理
- Mercator:貨物レベニューマネジメント
- Champ Cargosystems:貨物 IT ソリューション
- Smartkargo:クラウドベースの貨物プラットフォーム
レベニューマネジメント:
- Pros Revenue Management:価格設定の最適化
- Accelya:貨物収入の最適化
運航:
- SITA:貨物運航と追跡
- Descartes:貨物フォワーディングソフトウェア
- CargoWise:貨物フォワーディングプラットフォーム
ULD 管理:
- Unilode:ULD のプーリングと管理
- Nordisk Aviation Products:ULD の追跡
- Jettainer:ULD ソリューション
よくある課題と解決策
課題:容量予測
問題:
- 旅客手荷物の量が不確定
- 直前の貨物予約
- 予約客の未搭乗やキャンセル
解決策:
- 旅客手荷物の過去データ分析
- 季節調整係数
- 動的な容量開放
- オーバーブッキング戦略
- リアルタイムの容量更新
課題:ベリー搭載と貨物専用機の採算性
問題:
- 貨物専用機の運航にかかる固定費
- 副産物としてのベリー搭載容量
- 市場運賃の圧力
解決策:
- ネットワークの最適化(ベリー搭載+貨物専用機)
- 貨物専用機の稼働率目標(>80%)
- トラック輸送から貨物専用機への切り替え分析
- ウェットリースの柔軟な活用
- アセットライトモデル(チャーター)
課題:ULDの配置
問題:
- ULDの配置場所が適切でない
- 再配置コストが高い
- 主要拠点でULDが不足している
解決策:
- ULDフロー最適化モデル
- 空のULDの再配置計画
- ULDプーリング契約
- ULD在庫の戦略的配置
- 代替梱包ソリューション
課題:Eコマースとの統合
問題:
- 小口貨物で、取扱量が多い
- スピードが求められる
- 混載貨物の仕分けが必要
解決策:
- Eコマース専用商品
- ハブでの混載貨物仕分け施設
- エクスプレス取扱手順
- インテグレーターとの連携
- スピードに応じたプレミアム価格設定
出力形式
航空会社の貨物業績レポート
エグゼクティブサマリー:
- ネットワーク全体の貨物業績
- 収益とイールドの傾向
- 搭載容量の利用状況
- 主な機会
フライト業績:
| フライト | 路線 | 機材 | 搭載容量(kg) | 搭載貨物 | PAX手荷物 | 利用率 | 収益 | イールド($/kg) |
|---|---|---|---|---|---|---|---|---|
| AA100 | JFK-LAX | B777 | 5,000 | 3,200 | 1,200 | 88% | $8,960 | $2.80 |
| AA200 | LAX-NRT | B777 | 5,000 | 4,100 | 800 | 98% | $18,450 | $4.50 |
| AA300 | ORD-LHR | B787 | 3,500 | 2,400 | 900 | 94% | $9,600 | $4.00 |
貨物構成:
| 品目 | 重量(トン) | 収益 | イールド($/kg) | 収益に占める割合 |
|---|---|---|---|---|
| 一般貨物 | 450 | $1,125,000 | $2.50 | 42% |
| エクスプレス | 120 | $960,000 | $8.00 | 36% |
| 医薬品 | 45 | $360,000 | $8.00 | 13% |
| 生鮮品 | 80 | $240,000 | $3.00 | 9% |
| 合計 | 695 | $2,685,000 | $3.86 | 100% |
ULDの利用状況:
| ULDタイプ | 数量 | 平均重量利用率 | 平均容積利用率 | 月間回転数 |
|---|---|---|---|---|
| AKE | 250 | 82% | 68% | 12 |
| PMC | 150 | 88% | 75% | 10 |
| PGA | 80 | 79% | 71% | 8 |
推奨事項:
- LAX-NRT便(イールドの高い路線)の医薬品搭載容量を増やす
- より適切な積載計画により、ULDの容積利用率を改善する
- JFK-LAX向けのEコマース・エクスプレス商品を開始する
- 上位3社のフォワーダーと料金を再交渉する
- ORD-PVG便に貨物専用便を追加する(需要が旺盛)
確認事項
より詳しい情報が必要な場合:
- どのような貨物運航形態ですか?(貨物専用、ベリー、コンビ)
- ネットワーク構成と主要路線はどのようなものですか?
- 貨物構成と品目の種類はどのようなものですか?
- 現在のイールドと搭載率の指標はどのようなものですか?
- どのようなシステムを導入していますか?(CMS、レベニューマネジメント)
- 主な課題は何ですか?(容量、価格設定、運航)
- どのような特殊貨物の取扱能力がありますか?(医薬品、生鮮品など)
関連スキル
- network-design:貨物ネットワークの最適化
- route-optimization:貨物のルート設定
- inventory-optimization:ULD在庫の管理
- hotel-inventory-management:レベニューマネジメントの概念
- 3d-bin-packing:ULD積載の最適化
- container-loading-optimization:貨物の積み付け
- demand-forecasting:貨物需要の予測
- fleet-management:貨物専用機材の管理
コメント
Markdown 対応