Понимание кода Coffee - Перевод его на Python - PullRequest
0 голосов
/ 25 октября 2018

В настоящее время я пытаюсь реализовать Markov Word Generator Я нашел в интернете в Python (потому что я не знаю Coffee), чтобы я мог добавить к нему больше функциональности.Однако у меня возникают проблемы с пониманием того, что делает код Coffee, и я немного сбит с толку.Код, который я пытаюсь «перевести», можно найти здесь .

Пока у меня есть методы generate() и ngrams().Я также теоретически получил continuation() (моя версия continue(), поскольку это было бы ключевое слово в Python), но, поскольку оно зависит от реализации узлов в tree(), оно, вероятно, не является окончательным.

Часть, с которой я больше всего борюсь, это метод tree().Я понимаю, что он должен делать, но я не знаю, как это реализовать.Вот что у меня так далеко.Многое из этого, вероятно, глупо, и я думаю о том, чтобы пересмотреть все, как только переведу его, чтобы посмотреть, смогу ли я улучшить свою реализацию.

import random
from functools import reduce

class MarkovNode:
    def __init__(self, name = "", count = 0, frequency = 0.0, continuations = dict()):
        self.continuations = continuations
        self.count = count
        self.frequency = frequency
        self.name = name

class Markov:
    # Creates a new Markov chain from the given array of sequences
    # (to collectively use as a corpus) and value for n (to use as the Markov order).
    # sequences may be empty. n must be an integer no lower than 0.
    # Feel free to directly access and modify an object's .sequences and .n.
    def __init__(self, corpus="", n=2, maxLength=20):
        self.sequences = corpus
        self.n = n
        self.maxLength = maxLength

    # Generates a new pseudorandom sequence generated by the Markov chain and
    # returns it as an array.  Its length will be truncated to @maxLength if necessary.
    def generate(self):
        result = ""
        def currentState():
            # Returns at most the last n elements of result.
            return result[max(0, len(result)-self.n):len(result)]
        def nextElement():
            element = self.continuation(currentState())
            print("Added {} to chain".format(element))
            return element
        #print(type(nextElement))
        while len(result) < self.maxLength and nextElement != None:
            result = "{}{}".format(result, nextElement)
        return result

    # Returns in a list the n-grams that went into making the Markov chain
    # Note that the size of the n-grams will always be one greater than the
    # Markov order - if a Markov chain was created with n=2, this method
    # will return an array of 3-grams.
    def ngrams(self):
        def ngramsFromSequence(word, n):
            if n < 1 or n > len(word):
                return []
            else:
                return [word[i:i+n] for i in range(len(word)-n)]

        ngrams = []
        for word in self.sequences:
            ngrams.append(ngramsFromSequence(word, self.n+1))
        return ngrams

    # Builds a probability tree and returns the node of the given sequence, or
    # the root node if no sequence is specified.  Returns null if the given
    # sequence is not represented in the tree.
    #
    # Each node has a "count", "frequency" and "continuations" property.
    # For example:
    #   node = myMarkov.tree("abc")
    #   c = node.continuations["d"].count
    #   f = node.continuations["d"].frequency
    # c would be the number of times that "d" came after "abc" in the original corpus.
    # f would be the probability that the letter to follow "abc" is "d."
    def tree(self, sequence = ""):
        n_grams = self.ngrams()
        root = MarkovNode(count = len(n_grams), frequency = 1.0)

        # Build the tree and supply each node with its count property.
        for n_gram in n_grams:
            node = root
            for element in n_gram:
                    # If we need to create a new node, do so.
                    if element not in node.continuations:
                        node.continuations[element] = MarkovNode(name = element)
                    node = node.continuations[element]
                    node.count += 1

        # Recursively descend through the tree we just built and give each node its
        # frequency property.
        def normalize(node):
            for child in node.continuations:
                child.frequency = child.count/node.count
                normalize(child)

        normalize(root)

        if type(sequence) is str:
            for sym in ",.!#;:":
                sequence.replace(sym, '')
            seq = sequence.split()

        # Navigate to the desired sequence.
        def find(root, sequence):
            print("Looking for: {}".format(sequence))
            if root is not None:
                if root.name is sequence:
                    print("Returned: {}".format(root.name))
                    return root
                for child in root.continuations:
                    print(child.name)
                    node = find(child, sequence)
                    if node is not None:
                        return node
            return None

        find(root, sequence)


    # Uses the Markov chain to pick the next element to come after sequence.
    # Returns null if there are no possible continuations.
    def continuation(self, sequence):
        node = self.tree(sequence)
        if node:
            target = random()
            sum = 0
            for child in node.continuations:
                sum += child.frequency
                if sum >= target:
                    print("Chose {}".format(child.name))
                    return child.name
        else:
            print(node)
        return None
        # Either the node was None or it had no continuations.

РЕДАКТИРОВАТЬ: Обновлен код Этореализация в настоящее время не работает, как следует.Я мог бы упустить что-то очевидное здесь.

...