[PYTHON] Mit maschinellem Lernen spielen: Kann Q-Learning bestimmen, ob marketingbezogene Maßnahmen ergriffen werden sollten?

Einführung

Zuvor Können Sie Zusatzspiele mit erweitertem Lernen lernen? wurde ausprobiert und ich konnte ohne Probleme lernen.

Dieses Mal gehe ich von einem realistischeren Problem aus.

Es gibt ein Problem. Nun, es gibt eine Geschichte, die Sie an alle senden sollten, wenn es um E-Mails geht, aber wenn Sie zu viel senden, führt dies zu einer Auszahlung, und Gutscheine sind teuer, sodass ich nicht zu viel herausplatzen möchte.

Die Frage ist diesmal, was passieren würde, wenn dieses Problem in einem Q-Learning-Framework gelöst würde. Mit Q-Learning ist es ein guter Ort, um mehrere Aktionen ausführen zu können. Stellen Sie sich dies jedoch als eine einfache, vollständig virtuelle Situation vor.

Thema: Können Sie entscheiden, ob Sie mit Q-Learning marketingbezogene Maßnahmen ergreifen möchten? Spiel

Spiel

Um es einfach zu schreiben

Es ist wie es ist.

Warum hast du an so ein Spiel gedacht?

Bei diesem Spiel war ich besorgt, dass es schwierig sein könnte zu sagen, dass es eine Pause zwischen der besten Aktion und der Belohnung gibt. Es scheint, dass das Lernen schnell sein wird, wenn Sie unmittelbar nach der optimalen Aktion eine Belohnung erhalten, aber der größte Punkt ist, dass dies nicht der Fall ist. Ich denke, es ist schwierig, "Strafe" zu definieren, aber jetzt gebe ich es nur für Aktionen, die falsch zu sein scheinen. (Ist das zu einfach für das Problem ...?).

Wie Sie jedoch in Erkundung des Labyrinths mit erweitertem Lernen sehen können, können Sie rückwirkend lernen, sodass ich mich frage, ob Sie dies tun können. Ich wollte es nur überprüfen.

Ergebnis

Sie erhalten nur Belohnungen, wenn U = 2 auftritt. Erhöhen Sie also die Wahrscheinlichkeitszahl, wenn U = 2 auftritt. Die maximale Belohnung, die Sie über einen bestimmten Zeitraum erhalten können, ist "Chance_Count". Daher sei "hit_rate" die erhaltene "Belohnung / Chance_Count". Die folgende Abbildung zeigt, wie es sich nach 10.000 Lern- / Evaluierungsarbeiten geändert hat.

スクリーンショット_2015_12_31_11_50.png

Ich habe es ungefähr 50 Millionen Mal versucht, aber nach ungefähr 30 Millionen Mal hatte ich das Gefühl, dass das Lernen seinen Höhepunkt erreicht hatte, und es ging um hit_rate = 0,9.

Erwägung

schließlich

Q Lernen macht Spaß, weil es in gewissem Sinne wie eine einfache KI aussieht. Ich hoffe es kann für etwas verwendet werden.

Code

Ich werde es als Referenz posten.

#!/usr/bin/env python
# coding: utf-8

import numpy as np
from random import random, choice


class Game(object):
    state = None
    actions = None
    game_over = False

    def __init__(self, player):
        self.player = player
        self.turn = 0
        self.last_reward = 0
        self.total_reward = 0
        self.init_state()

    def player_action(self):
        action = self.player.action(self.state, self.last_reward)
        if action not in self.actions:
            raise Exception("Invalid Action: '%s'" % action)
        self.state, self.last_reward = self.get_next_state_and_reward(self.state, action)

    def play(self):
        yield(self)
        while not self.game_over:
            self.player_action()
            self.turn += 1
            self.total_reward += self.last_reward
            yield(self)

    def init_state(self):
        raise NotImplemented()

    def get_next_state_and_reward(self, state, action):
        raise NotImplemented()


class UserAndPushEventGame(Game):
    """
    State           :S : list of (U, A)
    UserActivity    :U : int of 0~3
    Action          :A : int of 0 or 1

    Next-State(S, A):S':
        S[-1][1] = A
        S.append((Next-U, None))
        S = S[-5:]
    Next-U          :  :
        if S[-4] == (2, 1) then 3
        else 10% -> 2, 10% -> 1, 80% -> 0
    Reward(S, A)    :R :
        if S[-1] == (3, *) then R += 1
        wrong_action_count := Number of ({0,1,3}, 1) in S
        R -= wrong_action_count * 0.3
    """

    STATE_HISTORY_SIZE = 5

    def init_state(self):
        self.actions = [0, 1]
        self.state = [(0, None)]
        self.chance_count = 0

    def get_next_state_and_reward(self, state, action):
        next_state = (state + [(self.next_user_action(state), None)])[-self.STATE_HISTORY_SIZE:]
        next_state[-2] = (next_state[-2][0], action)
        reward = 0
        if len(state) > 0 and state[-1][0] == 3:
            reward += 1
        action_count = reduce(lambda t, x: t+(x[1] or 0), state, 0)
        correct_action_count = len([0 for x in state if x == (2, 1)])
        wrong_action_count = action_count - correct_action_count
        reward -= wrong_action_count * 0.3
        return next_state, reward

    def next_user_action(self, state):
        if len(state) > 4 and state[-4] == (2, 1):
            return 3
        else:
            rnd = np.random.random()
            if rnd < 0.8:
                return 0
            elif rnd < 0.9:
                return 1
            else:
                self.chance_count += 1
                return 2


class HumanPlayer(object):
    training = False

    def action(self, state, last_reward):
        print "LastReward=%s, CurrentState: %s" % (last_reward, state)
        while True:
            action_input = raw_input("Enter 0~1: ")
            if int(action_input) in [0, 1]:
                return int(action_input)


class QLearnPlayer(object):
    ALPHA = 0.1
    GAMMA = 0.99
    E_GREEDY = 0.05

    def __init__(self):
        self.actions = [0, 1]
        self.q_table = {}
        self.last_state = self.last_action = None
        self.training = True

    def get_q_value(self, state, action):
        return self.q_table.get(state, {}).get(action, (np.random.random() - 0.5)/1000)  #Undefiniert gibt eine kleine Zufallszahl zurück

    def get_all_q_values(self, state):
        return [self.get_q_value(state, act) for act in self.actions]

    def set_q_value(self, state, action, val):
        if state in self.q_table:
            self.q_table[state][action] = val
        else:
            self.q_table[state] = {action: val}

    def action(self, state, last_reward):
        state = tuple(state)
        next_action = self.select_action(state)
        if self.last_state is not None:
            self.update_q_table(self.last_state, self.last_action, state, last_reward)
        self.last_state = state
        self.last_action = next_action
        return next_action

    def select_action(self, state):
        if self.training and random() < self.E_GREEDY:
            return choice(self.actions)
        else:
            return np.argmax(self.get_all_q_values(state))

    def update_q_table(self, last_state, last_action, cur_state, last_reward):
        if self.training:
            d = last_reward + np.max(self.get_all_q_values(cur_state)) * self.GAMMA - self.get_q_value(last_state, last_action)
            self.set_q_value(last_state, last_action, self.get_q_value(last_state, last_action) + self.ALPHA * d)


if __name__ == '__main__':
    SWITCH_MODE_TURN_NUM = 10000
    fp = file("result.txt", "w")
    dt = file("detail.txt", "w")
    player = QLearnPlayer()
    # player = HumanPlayer()
    game = UserAndPushEventGame(player)
    last_chance_count = last_score = 0
    for g in game.play():
        # dt.write("%s: isT?=%s LastReward=%s TotalReward=%s S=%s\n" %
        #          (g.turn, player.training, g.last_reward, g.total_reward, g.state))
        if g.turn % SWITCH_MODE_TURN_NUM == 0:
            if not player.training:
                this_term_score = game.total_reward - last_score
                this_term_chance = game.chance_count - last_chance_count
                if this_term_chance > 0:
                    hit_rate = 100.0*this_term_score/this_term_chance
                else:
                    hit_rate = 0
                # print "Turn=%d: This 100 turn score=%2.2f chance=%02d: HitRate=%.1f%% %s" % \
                #       (g.turn, this_term_score, this_term_chance, hit_rate, '*' * int(hit_rate/2))
                fp.write("%d\t%.2f\t%d\t%f\n" % (g.turn, this_term_score, this_term_chance, hit_rate))
            last_score = game.total_reward
            last_chance_count = game.chance_count
            player.training = not player.training
        if g.turn % 10000 == 0:
            fp.flush()

Recommended Posts

Mit maschinellem Lernen spielen: Kann Q-Learning bestimmen, ob marketingbezogene Maßnahmen ergriffen werden sollten?
Kann maschinelles Lernen parallele Vierecke vorhersagen? (1) Kann es extern eingefügt werden?
pd.tseries.offsets.DateOffset kann sehr langsam sein, wenn es nicht mit Vorsicht verwendet wird
Stellen Sie fest, ob die Zeichenfolge formatierbar ist
Stellen Sie sicher, dass Python eine Zeichenfolge in int konvertieren / konvertieren kann
[Python] Runden Sie nur mit dem Operator ab
Mit maschinellem Lernen spielen: Kann Q-Learning bestimmen, ob marketingbezogene Maßnahmen ergriffen werden sollten?
Wie man Kaldi mit JUST Corpus trainiert
Ändern Sie die zu ersetzende Zeichenfolge entsprechend der übereinstimmenden Zeichenfolge, indem Sie sie durch den regulären Python-Ausdruck ersetzen
So löschen Sie die angegebene Zeichenfolge mit dem Befehl sed! !! !!
Fügen Sie einfach den Treiber mit dem Mixer zum Formschlüssel hinzu