🔥

バンディットアルゴリズムを用いたダイナミックプライシングの実装

2025/02/27に公開

📌 目的:
本記事では、バンディットアルゴリズム(Multi-Armed Bandit, MAB) を用いたダイナミックプライシングの実装を行います。
また、実装の難しい点や苦労した点についても解説します。


📌 1. バンディットアルゴリズムとは?

バンディットアルゴリズム(MAB)は、探索(Exploration)と活用(Exploitation)のバランスを取りながら、最適な選択肢を見つける手法です。

ダイナミックプライシングでは、「どの価格が最も収益を最大化するか?」 を探索しつつ、効果の高い価格を優先して適用することが重要になります。

🔹 バンディットアルゴリズムの種類

アルゴリズム 説明 特徴
ε-Greedy 一定確率(ε)でランダムに探索し、それ以外は最も良いアクションを選択 シンプルで計算が軽い
UCB1(Upper Confidence Bound) 信頼区間を考慮し、試行回数が少ないアクションを優先 探索と活用のバランスが良い
Thompson Sampling ベイズ推論を用いて、確率的に最適なアクションを選択 収束が早く、理論的に優れた結果が得られやすい

今回は、最も一般的な ε-Greedy法 を実装します。


📌 2. ε-Greedy を用いたダイナミックプライシングの実装

価格の候補をいくつか設定し、最適な価格を探索しながら収益を最大化する戦略をとります。

🔹 ① 実装の流れ

  1. 複数の価格候補を設定(例: [90, 100, 110, 120, 130]
  2. 各価格に対する報酬(売上)を記録
  3. ε-Greedyアルゴリズムで価格を選択
  4. 実際の売上をシミュレーション
  5. 最適な価格を学習しながら適用

🔹 ② 実装コード

import numpy as np
import random

# 価格候補(複数の価格帯を設定)
price_options = [90, 100, 110, 120, 130]

# 各価格に対する累積報酬(売上)
price_rewards = {price: 0 for price in price_options}
price_counts = {price: 0 for price in price_options}

# ε-Greedyのパラメータ
epsilon = 0.1  # 探索の確率(10%の確率でランダムに価格を選択)
total_trials = 1000  # シミュレーション回数

# 需要関数(価格が高いほど需要が減るシミュレーション)
def simulate_demand(price):
    base_demand = 1000  # 基本需要
    price_sensitivity = 5  # 価格変化による需要の減少
    return max(base_demand - price_sensitivity * price + np.random.randint(-50, 50), 0)

# ε-Greedy アルゴリズムの実行
for t in range(total_trials):
    if random.uniform(0, 1) < epsilon:
        # 探索: ランダムな価格を選択
        selected_price = random.choice(price_options)
    else:
        # 活用: 最も平均報酬の高い価格を選択
        avg_rewards = {price: price_rewards[price] / (price_counts[price] + 1) for price in price_options}
        selected_price = max(avg_rewards, key=avg_rewards.get)

    # 価格に対する実際の需要をシミュレーション
    demand = simulate_demand(selected_price)
    revenue = selected_price * demand  # 収益 = 価格 × 需要

    # 報酬(売上)を記録
    price_rewards[selected_price] += revenue
    price_counts[selected_price] += 1

# 最適な価格の決定
optimal_price = max(price_rewards, key=lambda p: price_rewards[p] / (price_counts[p] + 1))
print(f"最適な価格: {optimal_price}")

📌 3. 実装の難しい点・苦労した点

🔹 ① 価格と需要の関係を正しくモデル化するのが難しい

  • 需要関数 を正しく設計しないと、価格が高すぎても低すぎても需要が極端に変化する 可能性がある。
  • 例えば、需要関数が単純な線形減少だけではなく、季節性やトレンドを考慮しなければ、実際のデータとは異なる結果になる。

💡 改善策

  • 過去の販売データを基に、統計モデル(ARIMA, Prophet) で需要予測を組み合わせる。
  • より現実的な需要モデル(ロジスティック回帰など)を構築する。

🔹 ② 探索と活用のバランスが難しい

  • εの設定が難しい
    • εを大きくすると「探索が多くなりすぎて収束しない」
    • εを小さくすると「最適価格が見つかる前に局所最適解にハマる」

💡 改善策

  • 減衰型ε-Greedy(εを徐々に減少させる)
epsilon = max(0.01, 1.0 - (t / total_trials))

🔹 ③ 競合の影響を考慮するのが難しい

  • 競合の価格変動に応じて最適価格が変わるため、単独のMAB(バンディット)では適応しにくい。
  • 例えば、Amazonでは同じ商品を他の販売者が出品しているため、競合価格を考慮しないと不適切な価格設定になる

💡 改善策

  • コンテクスチュアルバンディット(Contextual Bandit) を用いる
    • 競合の価格・在庫・市場動向を入力として、適切な価格を探索
    • 需要予測を組み込んで、複数の価格帯を同時に学習する

📌 4. まとめ

バンディットアルゴリズム(ε-Greedy)を用いて、探索と活用をバランスよく調整する
価格と需要の関係を適切にモデル化し、最適な価格を決定する
シンプルなMABでは競合の影響を考慮しにくいため、コンテクスチュアルバンディットなどの高度な手法を検討する

🚀 次のステップ

  • UCB1, Thompson Sampling を試す
  • 時系列予測(Prophet)と組み合わせて価格設定を最適化
  • 競合の価格を考慮した価格戦略の導入

この手法を活用すれば、ECサイトやサブスクリプションビジネスの収益最大化 に貢献できます! 💰✨

Discussion