Проблемы с кодированием Марковского процесса принятия решений

Я пытаюсь закодировать Markov-Decision Process (MDP) и столкнулся с некоторой проблемой. Не могли бы вы проверить мой код и выяснить, почему он не работает

Я попытался сделать это с некоторыми небольшими данными, и это работает и дает мне необходимые результаты, которые я считаю правильными. Но моя проблема заключается в обобщении этого кода. Да, я знаю о библиотеке MDP, но мне нужно закодировать эту. Этот код работает, и я хочу получить такой же результат в классе:

import pandas as pd
data = [['3 0', 'UP', 0.6, '3 1', 5, 'YES'], ['3 0', 'UP', 0.4, '3 2', -10, 'YES'], \
    ['3 0', 'RIGHT', 1, '3 3', 10, 'YES'], ['3 1', 'RIGHT', 1, '3 3', 4, 'NO'], \
    ['3 2', 'DOWN', 0.6, '3 3', 3, 'NO'], ['3 2', 'DOWN', 0.4, '3 1', 5, 'NO'], \
    ['3 3', 'RIGHT', 1, 'EXIT', 7, 'NO'], ['EXIT', 'NO', 1, 'EXIT', 0, 'NO']]

df = pd.DataFrame(data, columns = ['Start', 'Action', 'Probability', 'End', 'Reward', 'Policy'], \
                  dtype = float) #initial matrix

point_3_0, point_3_1, point_3_2, point_3_3, point_EXIT = 0, 0, 0, 0, 0

gamma = 0.9 #it is a discount factor

for i in range(100): 
    point_3_0 = gamma * max(0.6 * (point_3_1 + 5) + 0.4 * (point_3_2 - 10), point_3_3 + 10)
    point_3_1 = gamma * (point_3_3 + 4)
    point_3_2 = gamma * (0.6 * (point_3_3 + 3) + 0.4 * (point_3_1 + 5))
    point_3_3 = gamma * (point_EXIT + 7)


print(point_3_0, point_3_1, point_3_2, point_3_3, point_EXIT)

Но здесь у меня где-то ошибка и это выглядит слишком сложно? Не могли бы вы помочь мне с этим вопросом?!

gamma = 0.9

class MDP:

    def __init__(self, gamma, table):
        self.gamma = gamma
        self.table = table

    def Action(self, state):
        return self.table[self.table.Start == state].Action.values

    def Probability(self, state):
        return self.table[self.table.Start == state].Probability.values

    def End(self, state):
        return self.table[self.table.Start == state].End.values

    def Reward(self, state):
        return self.table[self.table.Start == state].Reward.values

    def Policy(self, state):
        return self.table[self.table.Start == state].Policy.values

mdp = MDP(gamma = gamma, table = df)

def value_iteration():
    states = mdp.table.Start.values
    actions = mdp.Action
    probabilities = mdp.Probability
    ends = mdp.End
    rewards = mdp.Reward
    policies = mdp.Policy

    V1 = {s: 0 for s in states}
    for i in range(100):
        V = V1.copy()
        for s in states:
            if policies(s) == 'YES':
                V1[s] = gamma * max(rewards(s) + [sum([p * V[s1] for (p, s1) \
                in zip(probabilities(s), ends(s))][actions(s)==a]) for a in set(actions(s))])
            else: 
                sum(probabilities[s] * ends(s))

    return V

value_iteration()

Я ожидаю значения в каждой точке, но получаю: ValueError: Значение истинности массива с более чем одним элементом неоднозначно. Используйте a.any() или a.all()


person David    schedule 23.06.2019    source источник
comment
Не могли бы вы приложить полную трассировку исключения, чтобы мы знали, какая строка спровоцировала исключение? Я ставлю на if policies(s) == 'YES', вы можете заменить его на if (policies(s) == 'YES').any() или if (policies(s) == 'YES').all() в зависимости от ваших потребностей, это происходит потому, что policies(s) - это массив (логических значений)   -  person rotem tal    schedule 23.06.2019
comment
Я добавил: if (policies(s) == 'YES').any(). Но тут я получаю другую ошибку — TypeError: только целочисленные скалярные массивы могут быть преобразованы в скалярный индекс. В 15-й строке есть проблема: ---> 15 в zip(вероятности(и), концы(и))][действия(я)==a]) для a в наборе(действия(я))]) - --> 16 else: ---> 17 sum(вероятности[s] * end(s)) TypeError: только целочисленные скалярные массивы могут быть преобразованы в скалярный индекс. Извините, я не могу добавить полный журнал ошибок из-за ограничения количества символов   -  person David    schedule 23.06.2019


Ответы (2)


Вы получаете сообщение об ошибке, потому что политика(и) = ['YES' 'YES' 'YES'], поэтому она содержит 'YES' три раза. Если вы хотите проверить, все ли элементы в политиках имеют значение «ДА», просто замените policies(s) == 'YES' на all(x=='YES' for x in policies(s)).

Если вы хотите проверить только первый элемент, измените на policies(s)[0] == 'YES'

См. Сообщение проверить, идентичны ли все элементы в списке для разных подходов.

person TheJed    schedule 23.06.2019
comment
Да, я вижу это. Итак, я хочу найти максимум именно для тех строк, где Policy == YES. Для других строк нужно просто умножить вероятность на значение. Итак, вы можете видеть в первом коде. Итак, где Policy == YES, я хочу найти максимум значений, где Policy != YES, просто умножение - person David; 23.06.2019
comment
Итак, я попытался отказаться от оператора if, но проблема все равно остается. - person David; 23.06.2019

Для второй описанной проблемы (при условии, что (policies(s) == YES).any() устранена 1-я проблема) обратите внимание, что вы инициализируете обычный список python с этим выражением

[sum([p * V[s1] for (p, s1) in zip(probabilities(s), ends(s))]

к которому вы затем пытаетесь получить доступ с помощью индексов [actions(s)==a] списки python не поддерживают множественную индексацию, и это вызывает ошибку TypeError, с которой вы столкнулись

person rotem tal    schedule 23.06.2019
comment
Я понимаю, что вы имеете в виду, так как вы думаете, стоит решить эту проблему? - person David; 23.06.2019
comment
Я не уверен на 100%, чего вы пытаетесь достичь, я думаю, вы могли бы изменить внутри почтового индекса на этот zip(probabilities(s)[actions(s)==a], ends(s)[actions(s)==a]), если это было вашим намерением, иначе вы могли бы прояснить, какова была цель этих индексов. - person rotem tal; 23.06.2019
comment
Я просто хочу, чтобы он прошел этот цикл в зависимости от количества уникальных действий. Например, для первого State = 3 0. Есть три действия: ВВЕРХ, ВВЕРХ, ВПРАВО (согласно таблице). Таким образом, использование для in set(actions(s)) дает мне набор из ДВУХ уникальных значений, т.е. ВВЕРХ, ВПРАВО - person David; 23.06.2019
comment
Хорошо, кажется, я понимаю, для любого действия, которое вы хотите просуммировать по всем вероятностям и значениям, вам нужно уменьшить probabilities(s) и ends(s), чтобы они содержали только значения, соответствующие какому-то действию, проблема в том, что вы возвращаете их в виде массивов np (при вызове .values ​​во фрейме данных) вы теряете эту информацию, то есть, какая вероятность соответствует какому действию, если бы вы вернули их как серию pandas (просто удалите .values ​​в методах класса), вы могли бы сохранить эту информацию, тогда мой предыдущий исправление будет работать (2-й комментарий) - person rotem tal; 24.06.2019