石油タンクデータで原油価格予測する機械学習|在庫分析AI手法

 

概要

原油価格は世界経済に大きな影響を与える重要な指標です。従来の価格予測手法に加えて、石油タンクの在庫データを機械学習で分析することで、より精度の高い価格予測が可能になります。本記事では、石油タンクの減り具合から原油価格を予測する機械学習手法について詳しく解説します。

石油在庫データが価格に与える影響

需給関係と価格メカニズム

石油在庫データは価格形成において重要な役割を果たします:

  • 供給過剰時: 在庫増加により価格下落圧力
  • 需要増加時: 在庫減少により価格上昇圧力
  • 季節変動: 暖房需要期や夏場のガソリン需要
  • 地政学リスク: 供給不安による在庫積み増し

分析対象データ

  1. 在庫データ

    • 石油タンク貯蔵量の日次変化
    • 地域別在庫分布
    • 製品別在庫(原油、ガソリン、軽油等)
  2. 市場データ

    • WTI原油価格
    • ブレント原油価格
    • 為替レート(USD/JPY)
  3. 経済指標

    • GDP成長率
    • 製造業PMI
    • エネルギー消費量

価格予測モデルの実装

データ準備と前処理

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error, r2_score

# サンプルデータの生成
def create_oil_data():
    np.random.seed(42)
    dates = pd.date_range('2020-01-01', '2023-12-31', freq='D')
    n_days = len(dates)
    
    # 基準価格(トレンド)
    base_price = 60 + np.linspace(0, 20, n_days) + \
                 10 * np.sin(2 * np.pi * np.arange(n_days) / 365.25)
    
    data = {
        'date': dates,
        'tank_level': 50 + 20 * np.sin(2 * np.pi * np.arange(n_days) / 180) + \
                     np.random.normal(0, 5, n_days),
        'tank_change': np.random.normal(0, 2, n_days),
        'usd_jpy': 110 + np.random.normal(0, 5, n_days),
        'pmi': 50 + np.random.normal(0, 3, n_days),
        'oil_price': base_price + np.random.normal(0, 3, n_days)
    }
    
    df = pd.DataFrame(data)
    
    # 在庫レベルと価格の逆相関を強化
    df['oil_price'] = df['oil_price'] - 0.3 * (df['tank_level'] - 50)
    
    return df

# 特徴量エンジニアリング
def create_features(df):
    df = df.copy()
    
    # 移動平均
    df['tank_level_ma7'] = df['tank_level'].rolling(7).mean()
    df['tank_level_ma30'] = df['tank_level'].rolling(30).mean()
    
    # 変化率
    df['tank_change_rate'] = df['tank_level'].pct_change()
    
    # ラグ特徴量
    df['oil_price_lag1'] = df['oil_price'].shift(1)
    df['tank_level_lag1'] = df['tank_level'].shift(1)
    
    # 季節性
    df['month'] = df['date'].dt.month
    df['day_of_year'] = df['date'].dt.dayofyear
    df['season_sin'] = np.sin(2 * np.pi * df['day_of_year'] / 365.25)
    df['season_cos'] = np.cos(2 * np.pi * df['day_of_year'] / 365.25)
    
    return df.dropna()

df = create_oil_data()
df = create_features(df)

予測モデルの構築

# 特徴量とターゲットの分離
feature_cols = ['tank_level', 'tank_change', 'tank_level_ma7', 'tank_level_ma30',
                'tank_change_rate', 'oil_price_lag1', 'tank_level_lag1',
                'usd_jpy', 'pmi', 'season_sin', 'season_cos']

X = df[feature_cols]
y = df['oil_price']

# 訓練・テストデータの分割
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, shuffle=False
)

# 特徴量の標準化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 勾配ブースティングモデル
model = GradientBoostingRegressor(
    n_estimators=200,
    learning_rate=0.1,
    max_depth=5,
    random_state=42
)

model.fit(X_train_scaled, y_train)

# 予測と評価
y_pred = model.predict(X_test_scaled)

mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print(f"平均絶対誤差 (MAE): ${mae:.2f}")
print(f"決定係数 (R²): {r2:.3f}")

時系列予測の実装

def predict_oil_price_sequence(model, scaler, last_data, days_ahead=30):
    """
    将来の原油価格を連続的に予測
    """
    predictions = []
    current_data = last_data.copy()
    
    for day in range(days_ahead):
        # 現在のデータで予測
        X_current = current_data[feature_cols].values.reshape(1, -1)
        X_scaled = scaler.transform(X_current)
        pred = model.predict(X_scaled)[0]
        
        predictions.append(pred)
        
        # 次の日のデータを更新(簡略化)
        current_data['oil_price_lag1'] = pred
        current_data['tank_level'] += np.random.normal(0, 1)  # 在庫変動のシミュレーション
        current_data['tank_change'] = np.random.normal(0, 2)
        
        # 移動平均の更新(簡略版)
        current_data['tank_level_ma7'] = current_data['tank_level']
        current_data['tank_level_ma30'] = current_data['tank_level']
    
    return predictions

# 30日先までの価格予測
last_data = df.iloc[-1:].copy()
future_prices = predict_oil_price_sequence(model, scaler, last_data, 30)

# 結果の可視化
import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))
plt.plot(range(1, 31), future_prices, 'o-', label='予測価格')
plt.xlabel('日数')
plt.ylabel('原油価格 ($)')
plt.title('石油タンクデータに基づく30日間の原油価格予測')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

リアルタイム価格監視システム

class OilPriceMonitor:
    def __init__(self, model, scaler, threshold=5.0):
        self.model = model
        self.scaler = scaler
        self.threshold = threshold  # 価格変動アラートの閾値
    
    def analyze_tank_impact(self, tank_data):
        """
        タンクデータの変化が価格に与える影響を分析
        """
        # 現在の予測
        current_pred = self.predict_price(tank_data)
        
        # タンクレベルを±10%変化させた場合の影響
        tank_data_high = tank_data.copy()
        tank_data_low = tank_data.copy()
        
        tank_data_high['tank_level'] *= 1.1
        tank_data_low['tank_level'] *= 0.9
        
        pred_high = self.predict_price(tank_data_high)
        pred_low = self.predict_price(tank_data_low)
        
        sensitivity = {
            'current_price': current_pred,
            'high_inventory_price': pred_high,
            'low_inventory_price': pred_low,
            'sensitivity': (pred_low - pred_high) / 0.2  # 20%在庫変化に対する価格感応度
        }
        
        return sensitivity
    
    def predict_price(self, data):
        """
        単一データポイントの価格予測
        """
        X = data[feature_cols].values.reshape(1, -1)
        X_scaled = self.scaler.transform(X)
        return self.model.predict(X_scaled)[0]
    
    def generate_alert(self, current_data, previous_data):
        """
        価格変動アラートの生成
        """
        current_pred = self.predict_price(current_data)
        previous_pred = self.predict_price(previous_data)
        
        price_change = abs(current_pred - previous_pred)
        
        if price_change > self.threshold:
            return {
                'alert': True,
                'message': f"大幅な価格変動予測: ${price_change:.2f}",
                'previous_price': previous_pred,
                'current_price': current_pred
            }
        
        return {'alert': False}

# 監視システムの使用例
monitor = OilPriceMonitor(model, scaler)

# 在庫変化の影響分析
sample_data = df.iloc[-1:].copy()
impact_analysis = monitor.analyze_tank_impact(sample_data)

print("在庫レベル変化の価格への影響:")
print(f"現在予測価格: ${impact_analysis['current_price']:.2f}")
print(f"高在庫時価格: ${impact_analysis['high_inventory_price']:.2f}")
print(f"低在庫時価格: ${impact_analysis['low_inventory_price']:.2f}")
print(f"価格感応度: ${impact_analysis['sensitivity']:.2f}/在庫10%変化")

モデル改善のポイント

より高度な特徴量エンジニアリング

  1. 在庫回転率: 在庫の効率性指標
  2. 地域別在庫格差: 地理的な供給バランス
  3. 精製マージン: 原油と製品価格の差

アンサンブル手法の活用

from sklearn.ensemble import VotingRegressor
from sklearn.linear_model import ElasticNet
from xgboost import XGBRegressor

# 複数モデルのアンサンブル
ensemble_model = VotingRegressor([
    ('gb', GradientBoostingRegressor(n_estimators=200)),
    ('elastic', ElasticNet(alpha=0.1)),
    ('xgb', XGBRegressor(n_estimators=200))
])

ensemble_model.fit(X_train_scaled, y_train)
ensemble_pred = ensemble_model.predict(X_test_scaled)

ensemble_mae = mean_absolute_error(y_test, ensemble_pred)
print(f"アンサンブル模型 MAE: ${ensemble_mae:.2f}")

まとめ

石油タンクデータを活用した原油価格予測は、従来の経済指標だけでは捉えきれない需給バランスの変化を定量的に分析できる有効な手法です。リアルタイムの在庫監視と機械学習を組み合わせることで、価格変動の早期警告システムの構築が可能になります。

継続的なデータ収集とモデル改善により、エネルギー市場の動向をより正確に予測し、投資判断やリスク管理に活用できます。

■テックジム「AIエンジニア養成コース」

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座