基于 Python 的马尔科夫模型: 创建用于存储字母过渡的多个词典

69 阅读2分钟

在文本文件中,我们试图创建一个马尔科夫模型来查找字母过渡的概率。但是,我们在将字母过渡放入单独的词典时遇到了困难。例如,所有以 "e" 开头的过渡都应该被放入一个词典中,而所有以 "t"、"s"、"a" 和 "m" 开头的过渡应该被放入其他词典中。

huake_00183_.jpg 2. 解决方案: 为了解决这个问题,我们可以创建一个名为 Markov 的类,它包含一个 lookup 词典来存储字母过渡。这个词典的键是字母的组合,而值是字母的列表。我们可以通过使用 nwise 函数将文本中的字母分组为组合来填充这个词典。然后,我们就可以使用 gen_text 函数来生成基于这些字母过渡的随机文本。

from random import choice
import re
from collections import defaultdict
from itertools import chain, tee, izip

def strip_non_alpha(text, reg=re.compile('[^a-z']+', re.IGNORECASE)):
    return reg.sub(' ', text.strip())

def nwise(iterable, n):
    "s -> (s0,s1, ... sn-1), (s1,s2, ... sn), (s2, s3, ... sn+1), ..."
    args = tee(iterable, n)
    for i,t in enumerate(args):
        for j in range(i):
            next(t, None)
    return izip(*args)

class Markov:
    CHAINLEN = 3
    PRE = ' '*(CHAINLEN - 1)

    @classmethod
    def from_file(cls, fname):
        with open(fname) as inf:
            return Markov(inf)

    def __init__(self, text):
        """
        Create a new Markov chain model

            text
                Either a string or a sequence of strings
        """
        self.lookup = defaultdict(list)
        self.words = 0
        self.strings = 0

        if hasattr(text, '__iter__'):
            for s in text:
                self.add_text(s)
        else:
            self.add_text(text)

    def add_text(self, text):
        """
        Add a string to the lookup table

            text
                string to add
        """
        text = strip_non_alpha(text).lower()
        self.words += len(text.split())
        self.strings += 1
        for chars in nwise(chain(Markov.PRE, text, Markov.PRE), Markov.CHAINLEN):
            stem = ''.join(chars[:-1])
            self.lookup[stem].append(chars[-1])

    def gen_text(self, upto=200):
        """
        Generate a string

            upto
                maximum length of string to be generated
        """
        s = Markov.PRE
        res = []
        for i in range(upto + Markov.CHAINLEN):
            ch = choice(self.lookup[s])
            res.append(ch)
            s = s[1:] + ch
            if s == Markov.PRE:    # terminal string
                break
        return ''.join(res[:-(Markov.CHAINLEN - 1)])

    def __str__(self):
        return '\n'.join("'{}': {}".format(k, self.lookup[k]) for k in sorted(self.lookup))

def main():
    # mc = Markov.from_file('markov.txt')
    mc = Markov('Steam,Teams,Meets,Teems,Eat,Ate,State,Tease,Test,Mast,Mates'.split(','))

    print mc.strings, mc.words
    print mc

    for i in range(10):
        print(mc.gen_text())

if __name__=="__main__":
    main()

通过使用这个解决方案,我们可以将字母过渡放入单独的词典中,并使用它们来生成随机文本。