はじめに
今回は、前回の記事の続きになります。
前回の記事↓
やること
前回は、モンテカルロ法を用いてブラックジャックの最適戦略を作らせてみました。
そこで今回は、Q学習を用いてブラックジャックの最適戦略を作らせてみようと思います。
使用コード・結果
import gym
import numpy as np
import pandas as pd
from collections import defaultdict
def q_learning_blackjack(n_episodes=500000, alpha=0.1, gamma=1.0, epsilon=0.1):
env = gym.make('Blackjack-v1', natural=True, sab=True)
Q = defaultdict(lambda: np.zeros(env.action_space.n)) # Qテーブル
for episode in range(n_episodes):
state, _ = env.reset()
done = False
while not done:
# ε-グリーディー方策による行動選択
if np.random.rand() < epsilon:
action = env.action_space.sample() # ランダム行動
else:
action = np.argmax(Q[state]) # 最良行動
next_state, reward, done, _, _ = env.step(action)
# Q値の更新 (Q学習の更新式)
best_next_action = np.argmax(Q[next_state])
Q[state][action] += alpha * (reward + gamma * Q[next_state][best_next_action] - Q[state][action])
state = next_state # 状態を更新
return Q
# Q学習で戦略を学習
Q_table = q_learning_blackjack()
# 学習した戦略を評価
def evaluate_policy(Q, n_episodes=10000):
env = gym.make('Blackjack-v1', natural=True, sab=True)
wins, draws, losses = 0, 0, 0
for _ in range(n_episodes):
state, _ = env.reset()
done = False
while not done:
action = np.argmax(Q[state]) if state in Q else env.action_space.sample()
state, reward, done, _, _ = env.step(action)
if reward == 1:
wins += 1
elif reward == 0:
draws += 1
else:
losses += 1
win_rate = wins / n_episodes
print(f"勝率: {win_rate:.3f}, 引き分け: {draws/n_episodes:.3f}, 負け: {losses/n_episodes:.3f}")
evaluate_policy(Q_table)
勝率: 0.390, 引き分け: 0.068, 負け: 0.542
# 学習した戦略を表形式で表示
policy_df = pd.DataFrame({(player, dealer): 'スタンド' if np.argmax(Q_table[(player, dealer, False)]) == 0 else 'ヒット'
for player in range(12, 22) for dealer in range(1, 11)},
index=["推奨行動"]).T
プレイヤーの合計 | ディーラーのアップカード | 推奨行動 | プレイヤーの合計(後半) | ディーラーのアップカード(後半) | 推奨行動(後半) |
---|---|---|---|---|---|
12 | 1 | ヒット | 17 | 1 | ヒット |
12 | 2 | ヒット | 17 | 2 | スタンド |
12 | 3 | ヒット | 17 | 3 | スタンド |
12 | 4 | ヒット | 17 | 4 | スタンド |
12 | 5 | ヒット | 17 | 5 | スタンド |
12 | 6 | ヒット | 17 | 6 | スタンド |
12 | 7 | スタンド | 17 | 7 | スタンド |
12 | 8 | ヒット | 17 | 8 | ヒット |
12 | 9 | スタンド | 17 | 9 | ヒット |
12 | 10 | ヒット | 17 | 10 | スタンド |
13 | 1 | スタンド | 18 | 1 | スタンド |
13 | 2 | スタンド | 18 | 2 | スタンド |
13 | 3 | スタンド | 18 | 3 | スタンド |
13 | 4 | スタンド | 18 | 4 | スタンド |
13 | 5 | ヒット | 18 | 5 | スタンド |
13 | 6 | ヒット | 18 | 6 | スタンド |
13 | 7 | スタンド | 18 | 7 | スタンド |
13 | 8 | ヒット | 18 | 8 | スタンド |
13 | 9 | ヒット | 18 | 9 | ヒット |
13 | 10 | スタンド | 18 | 10 | スタンド |
14 | 1 | ヒット | 19 | 1 | スタンド |
14 | 2 | ヒット | 19 | 2 | スタンド |
14 | 3 | スタンド | 19 | 3 | スタンド |
14 | 4 | ヒット | 19 | 4 | スタンド |
14 | 5 | スタンド | 19 | 5 | スタンド |
14 | 6 | ヒット | 19 | 6 | スタンド |
14 | 7 | スタンド | 19 | 7 | スタンド |
14 | 8 | スタンド | 19 | 8 | スタンド |
14 | 9 | スタンド | 19 | 9 | スタンド |
14 | 10 | ヒット | 19 | 10 | スタンド |
15 | 1 | スタンド | 20 | 1 | スタンド |
15 | 2 | ヒット | 20 | 2 | スタンド |
15 | 3 | ヒット | 20 | 3 | スタンド |
15 | 4 | スタンド | 20 | 4 | スタンド |
15 | 5 | スタンド | 20 | 5 | スタンド |
15 | 6 | スタンド | 20 | 6 | スタンド |
15 | 7 | スタンド | 20 | 7 | スタンド |
15 | 8 | スタンド | 20 | 8 | スタンド |
15 | 9 | ヒット | 20 | 9 | スタンド |
15 | 10 | ヒット | 20 | 10 | スタンド |
16 | 1 | ヒット | 21 | 1 | スタンド |
16 | 2 | スタンド | 21 | 2 | スタンド |
16 | 3 | スタンド | 21 | 3 | スタンド |
16 | 4 | スタンド | 21 | 4 | スタンド |
16 | 5 | ヒット | 21 | 5 | スタンド |
16 | 6 | スタンド | 21 | 6 | スタンド |
16 | 7 | ヒット | 21 | 7 | スタンド |
16 | 8 | ヒット | 21 | 8 | スタンド |
16 | 9 | スタンド | 21 | 9 | スタンド |
16 | 10 | スタンド | 21 | 10 | スタンド |
おわりに
前回のモンテカルロ法での勝率が43.1%だったことを考慮すると、今回のQ学習の方が勝率が低い。ただ、Q学習に関してはもう少し改善できるポイントがあると思うので、もう少し改善してから比較していこうと思います。