スピーチの記事を書いた男。お役に立ててうれしいです!さて、マルコフ連鎖の私の最初の実装は実際にはPythonで行われたので、この答えはよりPython的な方法でそれを書く方法に焦点を当てます。話しやすいので、注文2マルコフ連鎖を作成する方法を示しますが、もちろん、いくつかの変更を加えて注文Nにすることもできます。
データ構造
jsでは、2つの顕著なデータ構造は、汎用オブジェクトと配列(汎用オブジェクトの拡張)です。ただし、Pythonでは、よりきめ細かい制御を行うための他のオプションがあります。2つの実装の主な違いは次のとおりです。
したがって、from collections import defaultdict
上部にを貼り付けて、markov.memory
定義方法を変更します。
memory = defaultdict(list)
ここでmarkov.getInitial
、タプルを返すように変更します(これは、順序2のチェーンを説明していることを思い出してください)。
def getInitial(self):
return ('', '')
(さらに拡張したい場合は、非常に優れたPythonトリックを使用できますtuple([''] * 2)
。同じものが返されます。空の文字列の代わりに、を使用できますNone
)
使用するものをgenInitial
少し変更します。
歩留まりと反復
jsには(まだ)存在しないがPythonには存在する強力な概念は、yield
演算子です(詳細な説明については、この質問を参照してください)。
Pythonのもう1つの機能は、その汎用for
ループです。ジェネレーター(を使用する関数)を含め、ほとんどすべてのものを非常に簡単に調べることができますyield
。2つを組み合わせると、次のように再定義できますbreakText
。
def breakText(self, txt):
#our very own (ε,ε)
prev = self.getInitial()
for word in txt.split(self.separator):
yield prev, word
#will be explained in the next paragraph
prev = (prev[1], word)
#end-of-sentence, prev->ε
yield prev, ''
上記の魔法の部分は、prev = (prev[1], word)
例によって最もよく説明できます。
>>> a = (0, 1)
>>> a
(0, 1)
>>> a = (a[1], 2)
>>> a
(1, 2)
それが私たちが単語リストを進める方法です。そして今、私たちは、を使用するものに移り、 :breakText
の再定義に移ります。markov.learn
def learn(self, txt):
for part in self.breakText(txt):
key = part[0]
value = part[1]
self.memory[key].append(value)
私たちの記憶はであるためdefaultdict
、キーが存在しないことを心配する必要はありません。
道路脇のおしっこ休憩
OK、チェーンの半分が実装されました。実際に動作するのを見てみましょう。これまでのところ:
from collections import defaultdict
class Markov:
memory = defaultdict(list)
separator = ' '
def learn(self, txt):
for part in self.breakText(txt):
key = part[0]
value = part[1]
self.memory[key].append(value)
def breakText(self, txt):
#our very own (ε,ε)
prev = self.getInitial()
for word in txt.split(self.separator):
yield prev, word
prev = (prev[1], word)
#end-of-sentence, prev->ε
yield (prev, '')
def getInitial(self):
return ('', '')
(クラスが小文字で始まるたびにうずくまるので、クラス名をからに変更しましたmarkov
) 。Markov
私はそれをとして保存し、brain.py
Pythonをロードしました。
>>> import brain
>>> bob = brain.Markov()
>>> bob.learn('Mary had a little lamb')
>>> bob.memory
defaultdict(<class 'list'>, {('had', 'a'): ['little'], ('Mary', 'had'): ['a'], ('', ''): ['Mary'], ('little', 'lamb'): [''], ('a', 'little'): ['lamb'], ('', 'Mary'): ['had']})
成功!結果をもっと注意深く見て、正しい結果が得られたことを確認しましょう。
{ ('', ''): ['Mary'],
('', 'Mary'): ['had'],
('Mary', 'had'): ['a'],
('a', 'little'): ['lamb'],
('had', 'a'): ['little'],
('little', 'lamb'): ['']}
ジップアップ運転する準備はできましたか?私たちはまだこのチェーンを使わなければなりません!
step
機能の変更
リメイクに必要なものはすでに満たされていstep
ます。defaultdictがあるので、random.choice
すぐに使用できます。チェーンの順序がわかっているので、少しごまかすことができます。再帰を(いくらかの悲しみを伴って)連鎖をたどる単一のステップを踏む関数として見れば、再帰を取り除くこともできます(元の記事では私の悪い-悪い名前の関数)。
def step(self, state):
choice = random.choice(self.memory[state] or [''])
if not choice:
return None
nextState = (state[1], choice)
return choice, nextState
空のリストについてうめき声を上げるor ['']
ので、残念ながら追加しました。random.choice
最後に、ロジックの大部分をask
(文の実際の構成)に移動します。
def ask(self, seed=False):
ret = []
if not seed:
seed = self.getInitial()
while True:
link = self.step(seed)
if link is None:
break
ret.append(link[0])
seed = link[1]
return self.separator.join(ret)
はい、少し厄介です。もっといい名前を付けstep
て発電機にすることもできたのですが、けん引されている車の中でストーブに火をつけたまま出産しようとしている妊娠中の妻との面会に遅れました!急いだほうがいい!
グランドフィナーレ
しかし、最初に、ボブとの話:
from collections import defaultdict
import random
class Markov:
memory = defaultdict(list)
separator = ' '
def learn(self, txt):
for part in self.breakText(txt):
key = part[0]
value = part[1]
self.memory[key].append(value)
def ask(self, seed=False):
ret = []
if not seed:
seed = self.getInitial()
while True:
link = self.step(seed)
if link is None:
break
ret.append(link[0])
seed = link[1]
return self.separator.join(ret)
def breakText(self, txt):
#our very own (ε,ε)
prev = self.getInitial()
for word in txt.split(self.separator):
yield prev, word
prev = (prev[1], word)
#end-of-sentence, prev->ε
yield (prev, '')
def step(self, state):
choice = random.choice(self.memory[state] or [''])
if not choice:
return None
nextState = (state[1], choice)
return choice, nextState
def getInitial(self):
return ('', '')
そしてそれをロードします:
>>> import brain
>>> bob = brain.Markov()
>>> bob.learn('Mary had a little lamb')
>>> bob.ask()
'Mary had a little lamb'
>>> bob.learn('Mary had a giant crab')
>>> bob.ask(('Mary', 'had'))
'a giant crab'
もちろん、このコンセプトには改善と拡張の余地があります。しかし、私があなたに答えを与えただけでは、それは楽しいことではありません。
うまくいけば、これは4か月後も役立つでしょう。