Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
Loeng 6
Loomuliku keele töötlus Pythonis
Eelmisel korral
Keeleandmete kogumine veebist
Kus me oleme?
läbitud
tehniline
keeleline
andmeteaduslik
Selles loengus
● Keeleandmete lingvistiline eeltöötlus● EstNLTK
Sissejuhatavat
• Keeleandmete efektiivseks analüüsiks on tarvis neid eelnevalt töödelda
• Eeltöötluse võib üldjoontes jagada kaheks:– tehniline eeltöötlus (sh andmete parsimine)– lingvistiline eeltöötlus
Lingvistiline eeltöötlus
- Teksti segmenteerimine (sõnedeks ja (osa)lauseteks)
Ta ei soovinud kolida San Franciscosse ega New Yorki.
Nendel, kes minu ja Oudekki kaotusele loodavad, on ettekujutus, et rahval polegi hääli.
Sel aastal toimus 35. Tartu Rattaralli.
Lingvistiline eeltöötlus
- Lemmatiseerimine
Mida ubadest teha? Oad võib salatisse panna.
Lingvistiline eeltöötlus
- Morfoloogiline analüüs
Prae võis muna ja sai.
Prae praad+0 //_S_ sg g, // praadi+0 //_V_ o, //võis või+s //_S_ sg in, // või+s //_V_ s, //muna muna+0 //_S_ sg g, sg n, sg p, //ja ja+0 //_J_ //sai saa+i //_V_ s, // sai+0 //_S_ sg n, //
Lingvistiline eeltöötlus
- Morfoloogiline ühestamine
Mees oli kärbes.
Süntaktiline analüüs
Pindsüntaks: sõnade funktsioonid lausetes
Väiksed lapsed sõid matsutades kala.@AN> @SUBJ @FMV @ADVL @OBJtäiend alus öeldis määrus sihitis
Süntaktiline analüüs
Sõltuvussüntaks: sõnadevahelised seosed lauses
lapsed
väiksed
matsutades kala
Sõid
Kana munes muna. Muna munes kana.@SUBJ @OBJ @OBJ @SUBJ
Ema lõi isa. - Kes ema lõi? Keda ema lõi? [Kelle ema lõi?]@? @?
Lingvistiline eeltöötlus
• Lingvistilise eeltöötluse hulka kuulub:– teksti segmenteerimine (sõnedeks ja (osa)lauseteks)– lemmatiseerimine– sõnaliikide määramine / morfoloogiline analüüs– süntaktiline analüüs– sünonüümia lahendamine (nt Wordneti abil)– anafooride lahendamine– ...
– Eeltöötluse täpne töövoog sõltub lahendatavast ülesandest või tehtavast analüüsist
Selles aines kasutame lingvistiliseks eeltöötluseks EstNLTK projekti raames loodud ressursse
EstNLTK
● Kogumik Pythoni teeke eestikeelsete tekstide töötluseks
● Loodud TÜ-s, projektijuht Sven Laur
● Olemasolevate tööriistade omavaheline liidestamine,
kättesaadavaks muutmine + uute loomine
● http://estnltk.github.io/estnltk/1.4/
● https://github.com/estnltk/estnltk
EstNLTK ja Text klass
• Põhiline klass, millega teksti töödelda, on Text.
• Klassil on hulk meetodeid, mille abil teksti analüüsida
• Põhimõtteliselt on tegemist Pythoni sõnaraamatuga (dict):
• Sõnaraamatu põhielementideks on märgenduskihid
• Nt toorteksti kuvamiseks tuleb pöörduda sõnaraamatu poole klassimuutujaga “text”:
>>> from estnltk import Text>>> text = Text('Tere maailm!')>>> text{'text': 'Tere maailm!'}
>>> text.text'Tere maailm!'
EstNLTK märgenduskihtidest
• Märgenduskiht kannab informatsiooni tekstis leiduvate olemite kohta:– olemi tüüp (nt sõna, lause, ajaväljend, kohanimi jne)– olemi positsioon (ehk asukoht algses tekstis)
• Märgenduskihtide arv ei ole piiratud – põhimõtteliselt võib märgendada kõike, mis pähe tuleb
• Märgenduskihid on antud Text klassis võti-väärtus paaridena, kus väärtuseks on märgendatud olemite järjend
EstNLTK märgenduskihtidest (2)
• Märgenduskihtide sõnaraamat on jooksvalt uuendatav• Seega saab märgenduskihte alati lisada või neid kustutada:
>>> text = Text('Tere maailm!')>>> text{'text': 'Tere maailm!'}
>>> text.text'Tere maailm!‘
>>> text.sentences[{'start': 0, 'end': 12}]
>>> text{'text': 'Tere maailm!', 'sentences': [{'start': 0, 'end': 12}], 'paragraphs': [{'start': 0, 'end': 12}]}
>>> del text['sentences']>>> text{'text': 'Tere maailm!', 'paragraphs': [{'start': 0, 'end': 12}]}
EstNLTK märgenduskihtidest (3)
• Märgenduskihid on itereeritavad – nt saab itereerida üle tekstist tuvastatud lausete, sõnade, ajaväljendite jne:
>>> text = Text('Tere maailm!')>>> text.words[{'start': 0, 'end': 4, 'text': 'Tere'}, {'start': 5, 'end': 11, 'text': 'maailm'}, {'start': 11, 'end': 12, 'text': '!'}]
>>> for word in text.words:print word
{'start': 0, 'end': 4, 'text': 'Tere'}{'start': 5, 'end': 11, 'text': 'maailm'}{'start': 11, 'end': 12, 'text': '!'}
Teksti segmenteerimine
Lausestamine
• Lausestamine ehk lausepiiride tuvastamine• Oluline, sest teksti on mõistlik analüüsida ühe lause piires• Näiteks informatsiooni ekstraheerimisel:
– President Meri keskendus oma kõnes päevapoliitilistele sündmustele. – Eestit külastas USA president. Meri on tänavu jäävaba.
• Iga punkt ei ole lausepiir (nt järgarvud), mistõttu tuleb taas analüüsida lokaalset konteksti
Lausestamine EstNLTKs>>> from pprint import pprint>>> text = Text('Tere maailm!')>>> text.sentences...>>> pprint(text){'paragraphs': [{'end': 12, 'start': 0}], 'sentences': [{'end': 12, 'start': 0}], 'text': 'Tere maailm!'}
Üksustamine
• Ingl k tokenisation• A token is an instance of a sequence of characters in some
particular document that are grouped together as a useful semantic unit for processing.1
• Üksus on enamasti:– sõna (kollane, Jeltsin)– arv (42, 3,14, 666., ¼)– kirjavahemärk ( – , :)– erisümbolid (€, ¥)
1 http://nlp.stanford.edu/IR-book/html/htmledition/tokenization-1.html
Üksustamine
• Praktiline probleem – kirjavahemärgid on “kleepunud” sõnade külge
• Sisend:Meremees Jack ja veel üheksa meest, kes tema sõnade järgi olid ettevõtlikud sellid, vehkisid sisse korraliku paadi ning asusid mööda jõge allapoole teele.
• Väljund:Meremees Jack ja veel üheksa meest , kes tema sõnade järgi olid ettevõtlikud sellid , vehkisid sisse korraliku paadi ning asusid mööda jõge allapoole teele .
Üksustamine
• Iga punkt ja koma ei pruugi olla kirjavahemärk:– järgarvud– kümnendmurrud– ...
• Seega tuleb analüüsida lokaalset konteksti – millised sõnad ja muud märgid on konkreetse juhtumi ümbruses
• EstNLTK raames rakendatakse selleks regulaaravaldisi
Üksustamine EstNLTKs>>> from pprint import pprint>>> text = Text('Tere maailm!')>>> text.words{'text': 'Tere maailm!', 'sentences': [{'start': 0, 'end': 12}], 'paragraphs': [{'start': 0, 'end': 12}]}
>>> pprint(text){'paragraphs': [{'end': 12, 'start': 0}], 'sentences': [{'end': 12, 'start': 0}], 'text': 'Tere maailm!', 'words': [{'end': 4, 'start': 0, 'text': 'Tere'}, {'end': 11, 'start': 5, 'text': 'maailm'}, {'end': 12, 'start': 11, 'text': '!'}]}
Osalausestamine
• Osalausestamise käigus tuvastatakse liitlauses osalausete piirid:– Kell sai kaks ja ma hakkasin minema.– Linn, mille poole me liikusime, oli parajasti leekides.
• Osalausete vahel eristatakse kaht tüüpi seoseid:– rinnastusseos– alistusseos
• Oluliselt keerulisem probleem kui lausestamine, kuna lausestruktuuri varieeruvus on suur
Osalausestamine>>> text = Text("Kell sai kaks ja ma hakkasin minema.")>>> text.clause_texts['Kell sai kaks ja', 'ma hakkasin minema.']
>>> text.clauses[{'start': [0], 'end': [16]}, {'start': [17], 'end': [36]}]
>>> text = Text("Linn, mille poole me liikusime, oli parajasti leekides.")>>> text.clause_texts['Linn oli parajasti leekides.', ', mille poole me liikusime,']
>>> text.clauses[{'start': [0, 32], 'end': [4, 55]}, {'start': [4], 'end': [31]}]
Morfoloogiline informatsioon
Meeldetuletus arvutimorfoloogiast
• Eesti keele muuteparadigmad on mahukad – leidub väga palju käändelisi ja pöördelisi vorme
• Samuti palju mitmetähenduslikkust, nt:– kallas
• ainsuse nimetav substantiivist kallas• lihtmineviku 3. isiku ainsuse vorm verbist kallama
– kastis• ainsuse seesütlev substantiivist kast• lihtmineviku 3. isiku ainsuse vorm verbist kastma
– jne
Meeldetuletus arvutimorfoloogiast
• Eesti keele morfoloogiline analüüs:– ainult konkreetset sõnavormi vaadeldes võib sellel olla mitu analüüsi– kasutatakse reeglipõhist lähenemist, mille käigus määratakse kõik
võimalikud analüüsid
Meeldetuletus arvutimorfoloogiast
• Eesti keele morfoloogiline ühestamine:– eesmärk on käia üle morfoloogilise analüsaatori väljund ning valida
vorm, mis on antud kontekstis korrektne– kasutatakse statistilist keelemudelit (Markovi peitmudel)– mõnedel juhtudel jäävad mitmesused siiski alles
Meeldetuletus arvutimorfoloogiast
● Lauset ei vaadelda kui sõnade järjestust, vaid kui märgendite (M) järjestust. ● Kuna sõnal võib olla mitu M, siis konkreetsele lausele võib vastata mitu
võimalikku Mide järjestust, aga ainult üks neist on õige.● Mõned järjestused on antud keeles tüüpilised, mõned mitte.● Võimalikest järjestustest tuleb valida kõige tüüpilisem, s.o. kõige tõenäolisem. See
ongi antud lause puhul õige.● Iga konkreetse sõna puhul lauses tuleb tema võimalike Mide hulgast valida selline
M, et lause Mide järjestus oleks kõige tõenäolisem.● Terve lause Mide järjestuse arvutamisel lähtutakse üksikute Mide tõenäosustest.● Üksiku sõna tõenäosus antud lauses ei sõltu kõigist teistest selle lause sõnadest,
vaid ainult ühest (harvem kahest) eelnevast Mist. Seda nimetatakse Markovi sõltumatuse eelduseks.
Lemmatiseerimine
• Lemmatiseerimine ehk sõnade algvormide määramine• Eesti keele muuteparadigmad on mahukad – leidub palju käändelisi ja
pöördelisi vorme• Tekstist informatsiooni tuvastamiseks on mõistlik sõnad nende
algvormideks teisendada• Tulemuseks oluliselt väiksem leksikon (sõnavara tähenduses)
• Näiteks eestikeelse vikipeedia artikkel Eestist (https://et.wikipedia.org/wiki/Eesti):– lemmatiseerimata kujul 3560 unikaalset sõnet– lemmatiseeritud kujul 2647 unikaalset sõnet (seega ~25% väiksem leksikon)
Lemmatiseerimine EstNLTK’s
• Lemmade leidmine klassimuutujaga “lemmas”:
• Lemmad pärinevad morfoloogilise analüsaatori ja ühestaja väljundist
• Informatsioon lisatakse teksti kirjeldavasse sõnaraamatusse
>>> text = Text('Mis kell sa tulema hakkad?')>>> text.lemmas['mis', 'kell', 'sina', 'tulema', 'hakkama', '?']
Sõnaliikide määramine EstNLTKs
• Sõnaliikide määramine klassimuutujaga “postags”:
• Väljastatakse järjend sõnaliikide märgenditega:– ühestamata juhtudel on märgendid eraldatud püstkriipsuga– informatsioon lisatakse teksti kirjeldavasse sõnaraamatusse
>>> text = Text('Ibumetin on levinud valuvaigisti.')>>> text.postags['H', 'V', 'A|V', 'S', 'Z']
POS Seletus Näide
A omadussõna - algvõrre (adjektiiv - positiiv), nii käänduvad kui käändumatud kallis või eht
C omadussõna - keskvõrre (adjektiiv - komparatiiv) laiem
D määrsõna (adverb) kõrvuti
G genitiivatribuut (käändumatu omadussõna) balti
H pärisnimi Edgar
I hüüdsõna (interjektsioon) tere
J sidesõna (konjunktsioon) ja
K kaassõna (pre/postpositsioon) kaudu
N põhiarvsõna (kardinaalnumeraal) kaks
O järgarvsõna (ordinaalnumeraal) teine
P asesõna (pronoomen) see
S nimisõna (substantiiv) asi
U omadussõna - ülivõrre (adjektiiv - superlatiiv) pikim
V tegusõna (verb) lugema
X verbi juurde kuuluv sõna, millel eraldi sõnaliigi tähistus puudub plehku
Y lühend USA
Z lausemärk -, /, ...
Morfoloogiline informatsioon
• Lisaks lemmadele ja sõnaliikidele saab leida ka muud informatsiooni sõnade koostise kohta
• Informatsioon on esitatud märgenditena
• Kasutatavad märgendid:– http://estnltk.github.io/estnltk/1.4/tutorials/morf_tables.html
>>> text = Text(‘Tere maailm!').analysis>>> pprint(text){'paragraphs': [{'end': 12, 'start': 0}], 'sentences': [{'end': 12, 'start': 0}], 'text': 'Tere maailm!', 'words': [{'analysis': [{'clitic': '', 'ending': '0', 'form': '', 'lemma': 'tere', 'partofspeech': 'I', 'root': 'tere', 'root_tokens': ['tere']}], 'end': 4, 'start': 0, 'text': 'Tere'}, {'analysis': [{'clitic': '', 'ending': '0', 'form': 'sg n', 'lemma': 'maailm', 'partofspeech': 'S', 'root': 'maa_ilm', 'root_tokens': ['maa', 'ilm']}], 'end': 11, 'start': 5, 'text': 'maailm'}, {'analysis': [{'clitic': '', 'ending': '', 'form': '', 'lemma': '!', 'partofspeech': 'Z', 'root': '!', 'root_tokens': ['!']}], 'end': 12, 'start': 11, 'text': '!'}]}
EstNLTK ilma morfoloogilise ühestajata
• EstNLTK võimaldab statistilist ühestamist välja lülitada
• Selleks tuleb Text objekti loomisel varustada see disambiguate=False argumendiga
>>> text = Text("Reis kuule.")>>> pprint(text.analysis)[[{'clitic': '', 'ending': '0', 'form': 'sg n', 'lemma': 'reis', 'partofspeech': 'S', 'root': 'reis', 'root_tokens': ['reis']}], [{'clitic': '', 'ending': 'le', 'form': 'sg all', 'lemma': 'kuu', 'partofspeech': 'S', 'root': 'kuu', 'root_tokens': ['kuu']}], [{'clitic': '', 'ending': '', 'form': '', 'lemma': '.', 'partofspeech': 'Z', 'root': '.', 'root_tokens': ['.']}]]
>>> text = Text("Reis kuule.",disambiguate=False)>>> pprint(text.analysis)[[{'clitic': '', 'ending': '0', 'form': 'sg n', 'lemma': 'Reis', 'partofspeech': 'H', 'root': 'Reis', 'root_tokens': ['Reis']}, {'clitic': '', 'ending': 's', 'form': 'sg in', 'lemma': 'Rei', 'partofspeech': 'H', 'root': 'Rei', 'root_tokens': ['Rei']}, {'clitic': '', 'ending': '0', 'form': 'sg n', 'lemma': 'Reis', 'partofspeech': 'H', 'root': 'Reis', 'root_tokens': ['Reis']}, {'clitic': '', 'ending': '0', 'form': 'sg n', 'lemma': 'reis', 'partofspeech': 'S', 'root': 'reis', 'root_tokens': ['reis']}], [{'clitic': '', 'ending': 'le', 'form': 'sg all', 'lemma': 'kuu', 'partofspeech': 'S', 'root': 'kuu', 'root_tokens': ['kuu']}, {'clitic': '', 'ending': '0', 'form': 'o', 'lemma': 'kuulma', 'partofspeech': 'V', 'root': 'kuul', 'root_tokens': ['kuul']}, {u'clitic': u'', u'ending': u'e', u'form': u'pl p', u'lemma': u'kuul', u'partofspeech': u'S', u'root': u'kuul', u'root_tokens': [u'kuul']}, {u'clitic': u'', u'ending': u'0', u'form': u'sg n', u'lemma': u'kuule', u'partofspeech': u'S', u'root': u'kuule', u'root_tokens': [u'kuule']}], [{u'clitic': u'', u'ending': u'', u'form': u'', u'lemma': u'.', u'partofspeech': u'Z', u'root': u'.', u'root_tokens': [u'.']}]]
Informatsiooni ekstraheerimine
Ajaväljendite tuvastamine
• Eesmärk on tuvastada tekstist fragmendid, mis viitavad ajale:– aastaarvud– kuupäevad– nädalapäevad– jne
• Ajaväljendite tuvastamiseks EstNLTKs on klassil Text meetod timexes
Ajaväljendite tuvastamine EstNLTKs
>>> text = Text('Konspiraatorid kogunesid reedel Narva kohvikus, et arutada komandanditunni kehtestamist.')>>> pprint(text.timexes)[{'end': 31, 'id': 0, 'start': 25, 'temporal_function': True, 'text': 'reedel', 'tid': 't1', 'type': 'DATE', 'value': '2016-10-07'}]
Nimega üksuste tuvastamine
• Nimega üksuste tuvastamise (ingl k named-entity recognition) eesmärk on tuvastada ja kategoriseerida tekstifragmente, mis viitavad:– isikutele– kohtadele– organisatsioonidele– jne
Nimega üksuste tuvastamine EstNLTK’s
>>> text = Text("Osvald soovib sõita Tallinnast Tartusse. Tallinna ja Tartu vahel opereerivad lisaks AS Sebele ka AS Taisto Reiside ja teiste ettevõtete bussid.")
>>> text.named_entities['Osvald', 'Tallinn', 'Tartu', 'Tallinn', 'Tartu', 'AS Sebele', 'AS Taisto Reiside']
>>> pprint(text['named_entities'])[{u'end': 6, u'label': 'PER', u'start': 0}, {u'end': 30, u'label': 'LOC', u'start': 20}, {u'end': 39, u'label': 'LOC', u'start': 31}, {u'end': 49, u'label': 'LOC', u'start': 41}, {u'end': 58, u'label': 'LOC', u'start': 53}, {u'end': 93, u'label': 'ORG', u'start': 84}, {u'end': 114, u'label': 'ORG', u'start': 97}]
Semantilised suhted
WordNet
• Wordnet on teatud tüüpi leksikaal-semantiline andmebaas, mis sisaldab informatsiooni mõistete ja nendevaheliste semantiliste suhete kohta
• Wordneti tüüpi tesauruse põhiühik on sünonüümihulk (ka sünohulk)• Sünohulk koosneb kõigist ühte ja sama mõistet väljendavatest sõnadest
(või sõnaühenditest)
• Sünohulgad on ühendatud viidetega, mis vastavad mõistetevahelistele semantilistele või leksikaalsetele suhetele
• Kõige olulisemad suhted on hüponüümia ja hüperonüümia, kuid sageli on märgitud ka meronüümia, antonüümia jne
Wordneti struktuur
• Wordnet on struktuurilt graaf, kus tippudeks on sünuhulgad ja kaarteks nendevahelised relatsioonid
• Eesti WN sisaldab umbes:– 65 000 sünohulka (u 100 000 sõna)– 200 000 relatsiooni
EstNLTK ja WordNet
• Otsing Wordnetist, tulemus esitatakse järjendina:
• Otsingut saab kitsendada sõnaliigi alusel:
>>> from estnltk.wordnet import wn>>> wn.synsets("kohvik")["Synset('kohvik.n.01')"]
>>> wn.synsets("selg")["Synset('selg.n.02')", "Synset('selg.n.01')"]
>>> wn.synsets("selg",pos=wn.VERB)[]
• Vastavad tähendused on nummerdatud:
>>> synsets = wn.synsets("selg")>>> synsets["Synset('selg.n.02')", "Synset('selg.n.01')"]
>>> for synset in synsets:print synset.definition()
kuju, asendi v. ülesande poolest selga meenutav osa esemel, kehaosal v. loodusobjektilinimese v. looma keha tagumine külg kaelast kuni selgroo lõpuni
• Sünohulga sõnaliik: >>> synsets = wn.synsets("selg")>>> synsets[0].pos'n'
EstNLTK ja WordNet
• Hüpero- ja hüponüümide (ülem- ja alammõistete) leidmine:
>>> wn.synsets("kohvik")["Synset('kohvik.n.01')"]
>>> wn.synsets("kohvik")[0].hypernyms()["Synset('toitlustusettevõte.n.01')"]
>>> wn.synsets("kohvik")[0].hyponyms()["Synset('suvekohvik.n.01')", "Synset('vabaõhukohvik.n.01')", "Synset('internetikohvik.n.01')", "Synset('esinduskohvik.n.01')", "Synset('noortekohvik.n.01')", "Synset('rannakohvik.n.01')", "Synset('tantsukohvik.n.01')", "Synset('üliõpilaskohvik.n.01')", "Synset('jäätisekohvik.n.01')", "Synset('lastekohvik.n.01')", "Synset('keldrikohvik.n.01')"]
EstNLTK ja WordNet
• Ühise hüperonüümi (ülemmõiste) leidmine:
>>> wn.synsets("kohvik")["Synset('kohvik.n.01')"]
>>> wn.synsets("baar")["Synset('baar.n.01')", u"Synset('õllebaar.n.01')"]
>>> wn.synsets("kohvik")[0].lowest_common_hypernyms(wn.synsets("baar")[0])["Synset('toitlustusettevõte.n.01')"]
>>> wn.synset("kohvik.n.01").lowest_common_hypernyms(wn.synset("baar.n.01"))["Synset('toitlustusettevõte.n.01')"]
Kokkuvõtteks
● Eeltöötlus on oluline (ja aeganõudev)
● Ei õnnestu kunagi 100% (nagu pole 100% korrektsed ka
andmed)