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