Epsilon-Greedy 법으로 만족도가 높은 레스토랑을 찾는 방법을 생각해 보았습니다.

목적


  • 파이썬에서 배우는 강화 학습의 3.1에서 강화 학습의 하나의 방법인 Epsilon-Greedy법의 해설 중에 「표가 나올 확률이 다른 복수장의 동전을 던져 표가 나오기 쉬운 동전을 탐구하고, 그 결과를 활용하면서 보상을 극대화한다는 게임이 샘플 코드와 함께 소개되었습니다.
  • 그 코인 던지기 게임을 응용하여 "평상시의 외식에서 이용하는 레스토랑의 탐색과 활용의 비율 의 가게에 가는 것 같은 비율)로 몇 할 정도가 좋은 것인가?

  • 모델


  • 선택한 레스토랑의 평가는 해당 레스토랑의 리뷰 평가를 평균, 분산 $σ = 0.5 $로 정규 분포에 따라 난수로 나타냅니다
  • 선택한 레스토랑에 만족했는지의 여부는 "가는 것을 검토 한 여러 가게의 리뷰 평가의 평균보다 높은 평가가 그 회의 레스토랑 선택에 대해 얻어 졌는지"그렇게합니다.
  • 특히, 이번에 실제로 회사 근처 점심 가게를 10 점포 조사하고 Google 리뷰 리뷰 평가의 값으로 ]라는 값을 사용했습니다.

  • 선택한 레스토랑에 만족하면 보상은 1이고 만족하지 않은 경우 보상은 0입니다

  • 평소 외식에서 이용하는 레스토랑의 탐색과 활용 비율은 Epsilon-Greedy법의 $\epsilon$ 에 해당하는 파라미터로 이번 [0.0, 0.1, 0.2, 0.3, 0.8] (0% or 10% or 20% or 30% or 80%)의 비율에 대해 결과를 확인했습니다.

  • 결과


  • 아래 그림의 가로축은 레스토랑 선택 횟수, 세로축은 1회의 레스토랑 선택당 보수(0 이상 1 이하의 범위를 취할 수 있다)입니다.

  • 평상시의 외식으로 이용하는 레스토랑의 탐색과 활용의 비율로서 좋은 분으로부터 차례로 10% > 20% > 30% > 80% > 0% 라고 하는 결과가 되었습니다.
  • 즉, "10 회 외식하는 중 1 회 정도는 익숙한 가게뿐만 아니라 무작위로 가게를 선택하는 것이 긴 눈으로 보면 만족도가 높은 레스토랑을 찾아 활용하는 것이 할 수 있게 된다」라고 하는 것을 시사하고 있을 것 같습니다(어디까지나 상기 모델 위에서의 이야기).



  • 코드


  • 파이썬에서 배우는 강화 학습 의 3.1 의 Epsilon-Greedy법의 샘플 코드 을 적당히 상기 모델에 맞추어 재기록한 것이 아래와 같습니다.
  • 계산 실행은 Google 공동체에서 Python3에서 수행되었습니다. 계산 시간으로서는 수 10초 or 1분 정도였습니다.

  • ChoiceRestaurant 클래스 (상기 간이 모델 포함)
    import random
    import numpy as np
    
    class ChoiceRestaurant():
    
      def __init__(self, online_reviews, max_episode_steps=30):
        self.online_reviews = online_reviews
        self.max_episode_steps = max_episode_steps
        self.toss_count = 0
    
      def __len__(self):
        return len(self.online_reviews)
    
      def reset(self):
        self.toss_count = 0
    
      def step(self, action):
        final = self.max_episode_steps - 1
        if self.toss_count > final:
          raise Exception("The step count exceeded maximum. Please reset env.")
        else:
          done = True if self.toss_count == final else False
    
        if action >= len(self.online_reviews):
          raise Exception("The No.{} restaurant doesn't exitst.".format(action))
        else:
          average_online_reviews = sum(self.online_reviews)/len(self.online_reviews)
          online_review = self.online_reviews[action]
          sigma = 0.5
          if average_online_reviews < random.gauss(online_review, sigma):
            reward = 1.0
          else:
            reward = 0.0
          self.toss_count += 1
          return reward, done
    

    Epsilon-Greedy 방법의 계산 실행 클래스
    class EpsilonGreedyAgent():
    
      def __init__(self, epsilon):
        self.epsilon = epsilon
        self.V = []
    
      def policy(self):
        restaurants = range(len(self.V))
        if random.random() < self.epsilon:
          return random.choice(restaurants)
        else:
          return np.argmax(self.V)
    
      def play(self, env):
        # Initialize estimation.
        N = [0] * len(env)
        self.V = [0] * len(env)
        env.reset()
        done = False
        rewards = []
        while not done:
          selected_restaurant = self.policy()
          reward, done = env.step(selected_restaurant)
          rewards.append(reward)
    
          n = N[selected_restaurant]
          restaurant_average = self.V[selected_restaurant]
          new_average = (restaurant_average * n + reward) / (n+1)
          N[selected_restaurant] += 1
          self.V[selected_restaurant] = new_average
    
        return rewards
    

    구체적인 평가 리뷰/epsilon 값을 넣어 계산 실행 그래프 그리기
    if __name__ == "__main__":
      import pandas as pd
      import matplotlib.pyplot as plt
    
      def main():
        env = ChoiceRestaurant([2.8, 4.1, 3.5, 4.1, 3.7, 3.9, 3.6, 3.4, 4.0, 3.6])
        epsilons = [0.0, 0.1, 0.2, 0.3, 0.8]
        game_steps = list(range(10, 3010, 10))
        result = {}
        for e in epsilons:
          agent = EpsilonGreedyAgent(epsilon=e)
          means = []
          for s in game_steps:
            env.max_episode_steps = s
            rewards = agent.play(env)
            means.append(np.mean(rewards))
          result["epsilon={}".format(e)] = means
        result["restaurant choice count"] = game_steps
        result = pd.DataFrame(result)
        result.set_index("restaurant choice count", drop=True, inplace=True)
        result.plot.line(figsize=(10,5))
        plt.show()
    
      main()
    

    참고


  • 파이썬에서 배우는 강화 학습의 3.1 절

  • Epsilon-Greedy 방법의 샘플 코드
  • 좋은 웹페이지 즐겨찾기