Markovi kett on lihtne: vaatame põhimõtet üksikasjalikult. Sõnavarabaasi laiendamine

Veebiehituses ja SEO-s kasutatakse Markovi ahelaid lähtetekstide põhjal pseudotähenduslike tekstide genereerimiseks. Seda kasutatakse kindlaksmääratud ukseavade tembeldamiseks märksõnad, sisuteksti massi ja sarnaste “mustade” trikkide sisestamiseks. Õnneks on otsingumootorid õppinud Markovi kettide põhjal loodud sisu tõhusalt tuvastama ja sellised nutikad inimesed ära keelama. Ma ei hakka teile selliseid tehnoloogiaid õpetama, selleks on spetsiaalsed nõmedad saidid, mind huvitab ainult algoritmi tarkvara rakendamine.


Markovi ahel on testide jada, millest igaühes esineb ainult üks k-st. kokkusobimatud sündmused Ai pärit täisgrupp. Kus tingimuslik tõenäosus pij(s) asjaolust, et sündmus Aj toimub s-s katses, eeldusel, et sündmus Ai leiab aset (s - 1)-ndas katses, ei sõltu eelmiste katsete tulemustest.

Need, kes tahavad ajudele puhuda, saavad lugeda matemaatiline mudel. Inimkeeles taanduvad kõik need valemid järgmisele. Lähtetekstis defineeritakse sõnad ja jäetakse järjekord, mille järel sõnad tulevad. Seejärel luuakse see nende andmete põhjal uus tekst, milles sõnad ise on valitud juhuslikult, kuid nendevahelised seosed säilivad. Võtame näitena lastelaulu:

Metsa pärast, mägede pärast
Vanaisa Egor tuleb:
ma ise hobuse seljas,
naine lehmal,
lapsed vasikatel,
lapselapsed kitsepoegadel.

Parsisime teksti linkideks ja linkideks

Sest [mets, mäed]
metsad [tänu]
mäed [sõidud]
[vanaisa] tuleb
vanaisa [Egor]
Egor [ise]
mina [on]
[hobune, lehm, vasikad, lapsed]
hobune [naine]
naine [on]
lehm [lapsed]
lapsed [peal]
vasikad [lapselapsed]
lapselapsed [on]

Selle loendi lingid esindavad ainulaadseid sõnu tekstist ja sees nurksulud seosed on loetletud - sõnade loend, mis võivad esineda pärast seda sõna.

Linkide loendist teksti genereerimisel valitakse esimesel iteratsioonil juhuslik link, määratakse selle ühendused, valitakse linkide loendist juhuslik link ja võetakse see vastu uue lingina. Seejärel korratakse toimingut kuni jõudmiseni õige suurus tekst. Tulemuseks võib olla näiteks midagi sellist:

Egor ise vasikal, lapselapsed hobusel, naine lehmal, lapsed lehmal
Selles näites erineb saadud tekst algsest tekstist vähe, kuna originaaltekst väga lühike. Kui võtta esialgne mitme kilobaidi või isegi megabaidine sõnastik, on väljundiks täiesti ühtne tekst, kuigi sellel pole mõtet.

  1. // Loe läbi lähtetekst, mille põhjal genereeritakse uus
  2. $str = file_get_contents("markov.txt");
  3. // Süsteemi kodeeringu määramine
  4. setlocale(LC_ALL, "ru_RU.CP1251");
  5. // Eemaldage tekstist tähemärgid, välja arvatud numbrid, tähed ja mõned kirjavahemärgid
  6. $str = eregi_replace ("[^-a-zа-я0-9 !\?\.\,]" , " " , $str );
  7. // Puhastage tühikud enne lausete lõpetamist
  8. $str = eregi_asendamine (" (1,)([!\?\.\,])" , "\\1" , $str );
  9. // Jaga tekst sõnadeks
  10. $tmp = preg_split ("/[[:space:]]+/is" , $str );
  11. // "Linkide" massiiv
  12. $sõnad =Massiiv();
  13. // Täida lingid
  14. for($i = 0 ; $i< count ($tmp ); $i ++) {
  15. if ($tmp [ $i + 1 ]!= "" ) (
  16. $sõnad [ $tmp [ $i ]]= $tmp [ $i + 1 ];
  17. $sõnad = massiivi_kaart("massiivi_unikaalne" , ​​$sõnad );
  18. // Algsõnade massiiv lausetes
  19. $start =Massiiv();
  20. foreach($words as $word => $lings ) (
  21. if (ereg ("^[A-Z][a-Z]+" , $word )) (
  22. $algus = $sõna ;
  23. // Loo lähteteksti põhjal 100 lauset
  24. jaoks ($i = 0; $i< 100 ; $i ++) {
  25. samas (tõsi) (
  26. $w = $start [ rand (0 ,(count ($start )- 1 ))];
  27. if (ereg ("[\.!\?]$" , $w )) ( jätka; )
  28. $lause = $w . "" ;
  29. // Sõnade arv lauses
  30. $cnt = 1 ;
  31. // Loo pakkumine
  32. kuigi (tõsi) (
  33. $lingid = $sõnad [ $w ];
  34. // Lüliti kett
  35. $w = $sõnad [ $w ][ rand (0 ,(loend ($sõnad [ $w ])- 1 ))];
  36. $lause .= $w . "" ;
  37. // Kui sõna oli lause lõpus
  38. if (ereg ("[\.!\?]$" , $w )) ( break; )
  39. $cnt++;
  40. // Kui generaator on ahelas, siis sund välju
  41. if ($cnt > 19) ( break; )
  42. // Edukaks loetakse lause pikkusega 5-20 sõna
  43. if ($cnt > 5 && $cnt< 20 ) { break; }
  44. // Loodud pakkumine
  45. kaja $lause ;

Väike selgitus, kuidas see kõik töötab. Esiteks laaditakse fail "markov.txt", see peab olema win-1251 kodeeringus. Seejärel eemaldatakse sellelt kõik märgid, välja arvatud tähed ja mõned kirjavahemärgid, ning seejärel lõigatakse välja mittevajalikud tühikud. Selgub selge tekst, mis seejärel jaguneb üksikud sõnad. See on kõik, meil on ahelas üksikud lülid. Nüüd tuleb määrata sõnadevahelised seosed ehk millised sõnad milliste taga võivad asuda. See on kõige ressursimahukam protsess, nii et suurte failide puhul peate olema kannatlik. Kui genereerimist nõutakse sageli, on tõenäoliselt mõistlik salvestada mõnda andmebaasi linkide massiivi, et sellele kiirelt juurde pääseda. Järgmine samm- sõnade tuvastamine, millega laused algavad. Ma nõustusin tingimusega, et selliste sõnade esimene täht peaks olema suur, saate rohkem täpne määratlus. Teksti genereerimine toimub ülalkirjeldatud algoritmi järgi, lisasin sellele lihtsalt mitu kontrolli silmuste vastu.

Näete Markovi ahelate ja ülaltoodud skripti põhjal töötavat tekstigeneraatori näidet

See artikkel annab üldine idee selle kohta, kuidas Markovi protsessi modelleerimist kasutades tekste genereerida. Eelkõige tutvustame Markovi ahelaid ja praktikana rakendame Pythonis väikese tekstigeneraatori.

Alustuseks kirjutame Vikipeedia lehelt üles vajalikud, kuid veel mitte väga selged määratlused, et vähemalt ligikaudselt mõista, millega tegu:

Markovi protsess t t

Markovi kett

Mida see kõik tähendab? Selgitame välja.

Põhitõed

Esimene näide on äärmiselt lihtne. Kasutades lauset lasteraamatust, me meisterdame põhikontseptsioon Markovi ahelaid ja määratleda ka, mis need meie kontekstis on keha, lingid, tõenäosusjaotus ja histogrammid. Kuigi ettepanek antakse edasi inglise keel, on teooria olemust lihtne mõista.

See ettepanek on raami, ehk siis alus, mille alusel edaspidi tekst genereeritakse. See koosneb kaheksast sõnast, kuid samal ajal ainulaadsed sõnad ainult viis on lingid(me räägime Markovianist ketid). Selguse huvides värvime iga lingi oma värviga:

Ja kirjutame tekstis üles iga lingi ilmumiste arvu:

Ülaltoodud pildil näete seda sõna "kala" esineb tekstis 4 korda sagedamini kui iga teine ​​sõna ( "Üks", "kaks", "punane", "sinine"). See tähendab tõenäosust kohata sõna meie korpuses "kala" 4 korda suurem kui joonisel näidatud iga teise sõna kohtumise tõenäosus. Rääkides matemaatika keeles, saame määrata juhusliku suuruse jaotusseaduse ja arvutada, millise tõenäosusega ilmub üks sõnadest tekstis pärast praegust. Tõenäosus arvutatakse järgmiselt: peame jagama meile vajaliku sõna esinemiste arvu korpuses koguarv kõik sõnad selles. Sõna pärast "kala" see tõenäosus on 50%, kuna see esineb 4 korda 8-sõnalises lauses. Iga ülejäänud lingi puhul on see tõenäosus 12,5% (1/8).

Esitage jaotust graafiliselt juhuslikud muutujad võimalik kasutada histogrammid. IN sel juhul, on lause iga lingi esinemissagedus selgelt nähtav:

Niisiis koosneb meie tekst sõnadest ja ainulaadsetest linkidest ning me kuvasime histogrammil iga lingi ilmumise tõenäosusjaotuse lauses. Kui arvad, et statistikaga ei tasu vaeva näha, siis loe edasi. Ja võib-olla päästab see teie elu.

Määratluse olemus

Nüüd lisame oma tekstile elemendid, mis on alati vihjatud, kuid mida igapäevases kõnes ei esitata - lause algus ja lõpp:

Iga lause sisaldab neid nähtamatuid "algusi" ja "lõppusid" lisame need meie distributsiooni linkidena:

Tuleme tagasi artikli alguses antud määratluse juurde:

Markovi protsess - juhuslik protsess, mille evolutsioon pärast mis tahes seatud väärtus aja parameeter t ei sõltu eelnevast arengust t, eeldusel, et protsessi väärtus sel hetkel on fikseeritud.

Markovi kett - erijuhtum Markovi protsess, kui selle olekute ruum on diskreetne (st mitte rohkem kui loendatav).

Mida see siis tähendab? Jämedalt öeldes modelleerime protsessi, kus süsteemi olek järgmisel ajahetkel sõltub ainult selle olekust Sel hetkel, ja ei sõltu mingil viisil kõigist eelnevatest olekutest.

Kujutage ette, mis on teie ees aken, mis kuvab ainult süsteemi hetkeseisu (meie puhul on see üks sõna) ja peate määrama, mis see on järgmine sõna, põhineb ainult selles aknas esitatud andmetel. Meie korpuses järgivad sõnad üksteist järgmise mustri järgi:

Seega moodustuvad sõnapaarid (isegi lause lõpus on oma paar - tühi tähendus):

Rühmitame need paarid esimese sõna järgi. Näeme, et igal sõnal on oma lingid, mis meie lause kontekstis saab järgne talle:

Esitame selle teabe muul viisil - iga lingi jaoks määrame massiivi kõigist sõnadest, mis võivad pärast seda linki tekstis ilmuda:

Vaatame lähemalt. Näeme, et igal lingil on sõnad, mis saab tulge sellele lausega järele. Kui peaksime ülaltoodud diagrammi kellelegi teisele näitama, saaks see inimene suure tõenäosusega meie rekonstrueerida esialgne pakkumine, see tähendab keha.

Näide. Alustame sõnast "Alusta". Järgmisena valige sõna "Üks", kuna meie skeemi järgi on see ainus sõna, mis võib järgneda lause algusele. Sõna taga "Üks" samuti võib järgneda ainult üks sõna - "kala". Nüüd näeb uus ettepanek vahepealses versioonis välja selline "Üks kala". Edasi muutub olukord keerulisemaks - jaoks "kala" võib olla sõnu võrdse tõenäosusega 25% "kaks", "punane", "sinine" ja lause lõpp "Lõpp". Kui eeldame, et järgmine sõna on "kaks", rekonstrueerimine jätkub. Kuid me saame valida lingi "Lõpp". Sel juhul genereeritakse meie skeemi alusel juhuslikult lause, mis on korpusest väga erinev - "Üks kala".

Simuleerisime just Markovi protsessi – iga järgmise sõna määrasime ainult praeguse sõna teadmiste põhjal. Materjali täielikuks mõistmiseks koostame diagrammid, mis näitavad meie korpuses olevate elementide vahelisi sõltuvusi. Ovaalid tähistavad linke. Nooled viivad potentsiaalsete linkideni, mis võivad ovaalis olevale sõnale järgneda. Iga noole kõrval on tõenäosus, millega järgmine link praeguse lingi järel ilmub:

Suurepärane! Oleme õppinud vajalikku teavet liikuda edasi ja analüüsida keerukamaid mudeleid.

Sõnavarabaasi laiendamine

Artikli selles osas koostame mudeli sama põhimõtte järgi nagu varem, kuid kirjelduses jätame mõned sammud välja. Kui teil on raskusi, pöörduge tagasi esimese ploki teooria juurde.

Võtame veel neli tsitaati samalt autorilt (ka inglise keeles, see ei tee meile haiget):

"Täna sina Kas sa oled. See on tõest tõesem. Pole elus kedagi, kes oleks sina - kui sina.

« Sul on ajud peas. Sul on jalad kingades. Saate end juhtida mis tahes valitud suunas. Sa oled omaette."

"Mida rohkem loed, seda rohkem asju saate teada." Mida rohkem õpid, seda rohkematesse kohtadesse sa lähed.

"Mõtle vasakule ja mõtleõige ja mõtle madalalt ja mõtle kõrgelt. Oh, mõtteid sa saad mõelge järele, kui ainult proovite."

Korpuse keerukus on suurenenud, kuid meie puhul on see ainult pluss - nüüd saab tekstigeneraator toota sisukamaid lauseid. Fakt on see, et igas keeles on sõnu, mis esinevad kõnes sagedamini kui teised (näiteks kasutame eessõna "in" palju sagedamini kui sõna "krüogeenne"). Kuidas rohkem sõnu meie korpuses (ja seega ka nendevahelistes sõltuvustes), seda rohkem on generaatoril infot selle kohta, milline sõna esineb tekstis kõige tõenäolisemalt pärast praegust sõna.

Lihtsaim viis seda selgitada programmi vaatenurgast. Teame, et iga lingi jaoks on sõnad, mis võivad sellele järgneda. Ja ka iga sõna iseloomustab selle esinemiste arv tekstis. Meil on vaja mingit viisi kogu selle teabe ühte kohta kogumiseks; Selleks sobib kõige paremini sõnaraamat, mis salvestab paare “(võti, väärtus)”. Sõnastikuvõti salvestab süsteemi hetkeseisu, st ühe keha lingi (näiteks "te" alloleval pildil); ja sõnastiku väärtusesse salvestatakse teine ​​sõnastik. Pesastatud sõnastikus on võtmeteks sõnad, mis võivad esineda tekstis pärast korpuse aktiivset linki ( "mõtleb" Ja "rohkem" võib tekstis järele minna "te") ja väärtused on nende sõnade esinemiste arv tekstis pärast meie linki (sõna "mõtleb" ilmub tekstis sõna järel "te" 1 kord, sõna "rohkem" pärast sõna "te"- 4 korda):

Lugege ülaltoodud lõik mitu korda uuesti läbi, et veenduda, et saate sellest täpselt aru. Pange tähele, et pesastatud sõnastik on sel juhul sama histogramm, mis aitab meil jälgida linke ja nende esinemise sagedust tekstis võrreldes teiste sõnadega. Tuleb märkida, et isegi selline sõnavarabaas on tekstide õigeks genereerimiseks väga väike loomulik keel- see peaks sisaldama rohkem kui 20 000 sõna või veelgi parem, rohkem kui 500 000 sõna.

Markovi ahel on sel juhul konstrueeritud sarnaselt esimesele näitele - iga järgmine sõna valitakse ainult praeguse sõna teadmiste põhjal, kõiki teisi sõnu ei võeta arvesse. Kuid tänu sellele, et sõnaraamatus on salvestatud andmed selle kohta, millised sõnad ilmuvad teistest sagedamini, võime valimisel nõustuda teadlik otsus. Vaatame konkreetset näidet:

Veel:

See tähendab, kui praegune sõna on sõna "rohkem", pärast seda võivad olla sõnad võrdse tõenäosusega 25% "asjad" Ja "kohad", ja 50% tõenäosusega - sõna "see". Kuid tõenäosused võivad kõik olla võrdsed:

Mõtle:

Windowsiga töötamine

Siiani oleme akendega arvestanud vaid ühe sõna suurust. Saate akna suurust suurendada, nii et tekstigeneraator toodab rohkem "kontrollitud" lauseid. See tähendab, et mida suurem on aken, seda väiksemad on genereerimisel kerest kõrvalekalded. Akna suuruse suurendamine vastab Markovi ahela üleminekule rohkemale kõrge järjekord. Varem ehitasime akna jaoks esimest järku vooluringi, kaks sõna tekitavad teist järku ahela, kolm kolmandat järku vooluringi ja nii edasi.

Aken- need on andmed praegune olek süsteemid, mida kasutatakse otsuste tegemiseks. Kui sobime suur aken ja väike kogum andmeid, siis suure tõenäosusega saame iga kord sama lause. Võtame sõnavarabaasi meie esimesest näitest ja laiendame akent suurusele 2:

Laiendus on tähendanud, et igal aknal on nüüd ainult üks võimalus süsteemi järgmise oleku jaoks – ükskõik, mida me teeme, saame alati sama lause, mis on identne meie juhtumiga. Seetõttu varuge akendega katsetamiseks ja tekstigeneraatori ainulaadse sisu tagastamiseks sõnavarabaasi vähemalt 500 000 sõna.

Rakendamine Pythonis

Diktogrammi andmestruktuur

Diktogramm (dict on Pythonis sisseehitatud sõnastiku andmetüüp) kuvab linkide vahelise seose ja nende esinemissageduse tekstis, st nende leviku. Kuid samal ajal on sellel sõnastiku omadus, mida me vajame – programmi täitmisaeg ei sõltu sisendandmete hulgast, mis tähendab, et loome tõhusa algoritmi.

Impordi juhuslik klass Diktogramm(dict): def __init__(self, iterable=None): # Initsialiseeri meie distributsioon uus objekt klass, # lisa olemasolevad elemendid super(diktogramm, ise).__init__() self.types = 0 # unikaalsete võtmete arv distributsioonis self.tokens = 0 # kõigi jaotuse sõnade koguarv, kui itereeritav: self.update( itereeritav) def update (self, iterable): # Värskenda jaotust olemasoleva # itereeritava andmekogumi elementidega iterable: if item in self: self += 1 self.tokens += 1 else: self = 1 self. tüübid += 1 self.tokens += 1 def count(self, item): # Tagastab üksuse loenduri väärtuse või 0, kui üksus ise: return self return 0 def return_random_word(self): random_key = random.sample(self, 1) # Teine võimalus: # juhuslik .valik(histogramm.võtmed()) return random_key def return_weighted_random_word(self): # Genereeri pseudojuhuslik arv vahemikus 0 kuni (n-1), # kus n on sõnade koguarv random_int = random.randint(0, self.tokens-1 ) index = 0 list_of_keys = self.keys() # print "juhuslik indeks:", random_int for i in range(0, self.types): index += ise] # prindi indeks if(indeks > juhuslik_int): # prindi_võtmete_loend [i] return_of_keys[i]

Diktogrammi struktuuri konstruktorit saab edasi anda mis tahes objektist, mida saab itereerida. Selle objekti elementideks on sõnad diktogrammi lähtestamiseks, näiteks kõik sõnad raamatust. Sel juhul loendame elemente nii, et ühelegi neist juurde pääsemiseks ei pea me iga kord kogu andmestikku läbima.

Samuti tegime juhusliku sõna tagastamiseks kaks funktsiooni. Üks funktsioon valib sõnastikus juhusliku võtme ja teine, võttes arvesse iga sõna esinemiste arvu tekstis, tagastab meile vajaliku sõna.

Markovi ahela struktuur

histogrammidest import Diktogramm def make_markov_model(data): markov_model = dict() for i in range(0, len(data)-1): if data[i] in markov_model: # Lihtsalt lisa olemasolevale distributsioonile markov_model].update( ]) else: markovi_mudel] = Diktogramm() tagastab markovi_mudel

Ülaltoodud teostuses on meil sõnastik, mis salvestab aknad võtmena paaris „(võti, väärtus)” ja jaotused selle paari väärtustena.

N-ndat järku Markovi ahela struktuur

histogrammidest import Diktogramm def make_higher_order_markov_model(order, data): markov_model = dict() for i in range(0, len(data)-order): # Loo akna aken = korteež(andmed) # Lisa sõnaraamatusse if window in markov_model: # Lisa olemasolevale distributsioonile markov_model.update() else: markov_model = Dictogram() return markov_model

Väga sarnane esimese järjekorra Markovi ketiga, kuid sel juhul laos autokolonn võtmena sõnaraamatu paaris “(võti, väärtus)”. Kasutame seda loendi asemel, kuna korteež on muudatuste eest kaitstud ja see on meie jaoks oluline - lõppude lõpuks ei tohiks sõnaraamatu võtmed muutuda.

Mudeli parsimine

Suurepärane, oleme sõnastiku kasutusele võtnud. Aga kuidas saaksime luua sisu, mis põhineb praegusel olekul ja sammul järgmisse olekusse? Vaatame läbi oma mudeli:

Histogrammide import Diktogrammide import juhuslikult kogumitest import deque import re def gener_random_start(modell): # Mis tahes algussõna genereerimiseks tühjendage rida: # return random.choice(model.keys()) # "Õige" algussõna genereerimiseks , kasutage allolevat koodi: # Õige algussõnad- need on need, mis olid korpuse lausete alguseks, kui "END" mudelis: seed_word = "END" while seed_word == "END": seed_word = model["END"].return_weighted_random_word() return seed_word return juhuslik. valik(mudel .keys()) def genereeri_juhuslik_lause(pikkus, markovi_mudel): praegune_sõna = genereeri_juhuslik_algus(markovi_mudel) lause = i jaoks vahemikus(0, pikkus): praegune_diktogramm = markovi_mudel juhuslik_kaalutud_sõna = praegune_diktogramm.tagasi_kaalutud_juhuslik_sõna. (praegune_sõna) lause = lause.suurtäht() return " ".join(lause) + "." tagasilause

Mis järgmiseks?

Proovige välja mõelda, kus saate ise Markovi ahelatel põhinevat tekstigeneraatorit kasutada. Lihtsalt ärge unustage, et kõige olulisem on see, kuidas te mudelit sõelute ja millised eripiirangud genereerimisele seate. Selle artikli autor kasutas näiteks säutsu generaatorit luues suurt akent, piiras genereeritava sisu 140 tähemärgini ja kasutas lausete alustamiseks ainult “õigeid” sõnu, st neid, mis olid lausete alguseks. korpus.

Kirjeldati, kuidas treenida neutronite võrku nii, et see mängiks Mariot või juhiks robotit. Aga saab närvivõrk teksti genereerida? Markovi ketid võivad selles aidata.

Seetõttu "armastan" venekeelset Vikipeediat, sest igasugust lihtsat nähtust/võrrandit/reeglit, eriti matemaatikast, kirjeldatakse kohe nii üldsõnaliselt, nii mõistusevastaste valemitega, et ilma selleta ei saagi aru. pool liitrit. Pealegi ei vaevu artiklite autorid andma lihtsat kirjeldust (vähemalt paar lauset) inimkeel ja minge otse valemite juurde.

Kui keegi tahab teada, mis on Markovi ketid, siis esimeses tõlkes saab ta teada, et:
"Markovi kett on jada juhuslikud sündmused Lõpliku või loendatava arvu tulemustega, mida iseloomustab omadus, et fikseeritud olevikuga on tulevik minevikust sõltumatu. Nimetatud A. A. Markovi (vanem) auks."

Ja seda hoolimata asjaolust, et Markovi kettide põhiidee on väga lihtne, kuid ilma matemaatilise hariduseta on seda Wikipediast lihtsalt võimatu mõista.

Markovi ahelad on vaid süsteemi ühest olekust teise ülemineku tõenäosuse kirjeldus. Kõiki olekuid saab kirjeldada graafiku tippudega. Näiteks võivad sellised tipud olla inimese asendid: [lamamine], [istumine], [seismine], [kõndimine]

Siin on näha, et graafik on suunatud, mis tähendab, et igast olekust teise ei ole võimalik jõuda. Näiteks kui oled pikali, siis on võimatu kohe kõndida. Kõigepealt tuleb istuda, siis püsti tõusta ja alles siis kõndida. Kuid võite kukkuda ja lõpuks pikali jääda igast asendist))
Igal ühendusel on teatud tõenäosus. Nii on näiteks seisvast asendist kukkumise tõenäosus väga väike; Kõigi tõenäosuste summa on 1.

Markovi ketid võimaldavad muu hulgas genereerida sündmusi. Nii või teisiti on enamik tekstigeneraatoreid üles ehitatud Markovi ahelatele.

Proovime kirjutada pirukate generaatori.

Pirukad

Pirukad – neljavärsked ilma riimita, kirjavahemärkideta, numbriteta, ilma suured tähed. Silpide arv peaks olema 9-8-9-8.


Enamik tekstigeneraatoreid kasutab morfoloogilisi analüsaatoreid. Aga me teeme selle lihtsamaks. Jagame lihtsalt sõnad silpideks ja arvutame välja tõenäosuse, et üks silp tuleb teise silbi järel. See tähendab, et graafiku sõlmedeks on silbid, servad ja nende kaalud - esimesele järgneva teise silbi sagedus.
Järgmisena toidame programmi viiskümmend pirukat.

Näiteks pärast silpi “pri” võivad olla järgmised silbid (ääred ja nende kaalud):
"chem" (1) "ho" (4) "mina" (1) "du" (2) "chi" (4) "yatel" (4) "läks" (5) "ku" (1) " " (9) "su"(1) "vych"(3) "mi"(1) "kos"(1) "ob"(1) "det"(2) "sõitis"(1) "uchi"(1) ) "mu"(1) "bi"(1) "tse"(1) "int"(2) "tom"(1) "ko"(1) "võll"(1) "nes"(1) " det"(1) "aga"(1) "vez"(1) "meth"(1) "veterinaar"(1) "dia"(1) "teie"(1)

Nüüd pole vaja teha muud, kui võtta juhuslik silp (näiteks "at"). Kõigi pärast seda tulevate silpide summa on 58. Nüüd peate võtma järgmise silbi, võttes arvesse nende silpide sagedust (arvu):

suurus_t nth = rand() % count;

suurus_kõik = 0 ;

jaoks (const auto &n: next) (

Kõik += n.count;

kui (kõik >= n-s)

tagasi n.sõna;

Seega genereerime read nii, et esimesel real on 9 silpi, teisel - 8, seejärel 9 ja 8, saame:

Kunagi oli nali äratuskella üle
ta rööviti selle ajal
teie ülemus on siin jah
Onegini efektiga diivan

Siiani ei tundu see eriti sidusa tekstina. Sageli kohtab olematuid sõnu (“poku”). Nüüd on võtmena ainult üks silp. Kuid ühe silbi põhjal lauset on raske koostada. Suurendame silpide arvu, mille alusel genereerime järgmise silbi, vähemalt 3-ni:

Asfalti mõistusele piisavalt
kell on seitse jagatud
laud on välja võetud, must kast on
ta kasvas üles, maksis kätte, leidis
Siin on esimene pirukas, mida võib enam-vähem ekslikult pidada inimese kirjutatud.
Teksti sisukamaks muutmiseks peate kasutama morfoloogilisi analüsaatoreid ja siis pole sõlmedeks silbid, vaid sõnade metakirjeldused (näiteks "verb, mitmuses, minevikuvorm").

Sellised programmid võimaldavad teil juba "sisukamat" teksti kirjutada. Näiteks rooter on teadusteksti generaatori kirjutatud artikkel, mis on läbi vaadatud ja isegi teadusajakirjas avaldatud.

Markovi kett on sündmuste jada, milles iga järgnev sündmus sõltub eelmisest. Selles artiklis käsitleme seda kontseptsiooni üksikasjalikumalt.

Markovi kett on levinud ja üsna lihtne viis juhuslike sündmuste modelleerimiseks. Kasutatud enamikus erinevad valdkonnad, teksti genereerimisest finantsmodelleerimiseni. Kõige kuulus näide on SubredditSimulator. Sel juhul kasutatakse Markovi ahelat sisu loomise automatiseerimiseks kogu subredditi ulatuses.

Markovi kett on selge ja hõlpsasti kasutatav, kuna seda saab rakendada ilma statistilisi või matemaatilisi kontseptsioone kasutamata. Markovi kett sobib ideaalselt tõenäosusliku modelleerimise ja andmeteaduse õppimiseks.

Stsenaarium

Kujutage ette, et neid on ainult kaks ilmastikutingimused: Võib olla päikesepaisteline või pilvine. Saate alati täpselt määrata praeguse hetke ilma. Garanteeritud on selge või pilvine ilm.

Nüüd soovite õppida, kuidas ennustada homset ilma. Intuitiivselt mõistate, et ilm ei saa ühe päevaga dramaatiliselt muutuda. Seda mõjutavad paljud tegurid. Homne ilm sõltub otseselt praegusest jne. Seega kogutakse ilma ennustamiseks andmeid mitme aasta kohta ja jõutakse järeldusele, et pärast pilvist päeva on päikesepaistelise päeva tõenäosus 0,25. Loogiline on eeldada, et kahe järjestikuse pilvise päeva tõenäosus on 0,75, kuna meil on ainult kaks võimalikku ilmastikuolukorda.

Nüüd saate praeguse ilma põhjal ilma ennustada mitu päeva ette.

See näide näitab võtmemõisteid Markovi ketid. Markovi ahel koosneb üleminekute komplektist, mis on määratud tõenäosusjaotusega, mis omakorda rahuldavad Markovi omadust.

Pange tähele, et näites sõltub tõenäosusjaotus ainult üleminekutest praegune päev järgmisele. See ainulaadne vara Markovi protsess– teeb seda ilma mälu kasutamata. Tavaliselt ei suuda see lähenemine luua järjestust, milles suundumusi täheldatakse. Näiteks kui Markovi kett võib sõna kasutamise sageduse põhjal simuleerida kirjutamisstiili, ei saa see luua tekste sügav tähendus, kuna see töötab ainult suurte tekstidega. Seetõttu ei saa Markovi kett toota kontekstist sõltuvat sisu.

Mudel

Formaalselt on Markovi ahel tõenäosuslik automaat. Ülemineku tõenäosusjaotust esitatakse tavaliselt maatriksina. Kui Markovi ketil on N võimalikud olekud, siis saab maatriks kuju N x N, milles kirje (I, J) on olekust I olekusse J ülemineku tõenäosus. Lisaks peab selline maatriks olema stohhastiline, see tähendab, et read või veergude summa peab olema üks. Sellises maatriksis on igal real oma tõenäosusjaotus.

Markovi ahela üldvaade, mille olekud on ringidena ja servad üleminekutena.

Kolme võimaliku olekuga siirdemaatriksi näide.

Markovi kett on algvektor olekud, mis on esitatud N x 1 maatriksina. See kirjeldab alguse tõenäosusjaotust igas N võimalikus olekus. Kirje I kirjeldab tõenäosust, et ahel algab olekus I.

Need kaks struktuuri on Markovi ahela esindamiseks täiesti piisavad.

Oleme juba arutanud, kuidas saada ühest olekust teise ülemineku tõenäosust, aga kuidas oleks selle tõenäosuse saamisega mõne sammuga? Selleks peame määrama M-sammuga olekust I olekusse J ülemineku tõenäosuse. See on tegelikult väga lihtne. Üleminekumaatriksi P saab määrata arvutamise (I, J) abil, tõstes P võimsusele M. Väikeste M väärtuste korral saab seda teha käsitsi korduva korrutamise teel. Aga selleks suured väärtused M kui oled tuttav Lineaaralgebra, rohkem tõhus viis maatriksi tõstmine astmeni diagonaliseerib selle maatriksi esmalt.

Markovi kett: järeldus

Nüüd, teades, mis on Markovi kett, saate seda hõlpsasti ühes programmeerimiskeeles rakendada. Lihtsad ketid Markov on aluseks, et rohkem õppida keerulised meetodid modelleerimine.