{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "<h1 style=\"color:blue\"> Praktikum 6.</h1>\n", "<h3 style=\"color:blue\">JSON andmeformaat, märgendatud tekstide salvestamine ja taastamine, <br> ajaväljendite tuvastamine ja visualiseerimine</h3>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Käesolevas praktikumis tutvume JSON andmeformaadiga ja vaatame, kuidas selles formaadis andmeid (sh EstNLTK märgendustega tekste) salvestada/taastada, keeletöötluse poolel aga tegeleme ajaväljendite tuvastamisega ning joonistame ajaväljenditele vastavate kuupäevade kohta tulpdiagramme." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## JSON andmeformaat" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Neljandas praktikumis tutvusime CSV andmeformaadiga. CSV sobib hästi tabelkujul andmete salvestamiseks, aga pole just kuigi mugav kasutada, kui meie andmed on hierarhilise struktuuriga. \n", "\n", "Näiteks, milline tabel tuleks teha, kui eesmärk oleks salvestada tabelisse EstNLTK `Text` ning selle märgenduskihid: lausepiirid, sõnapiirid, sõnade morfoloogilised analüüsid ja tekstist tuvastatud nimeüksuste fraasid?\n", "Selleks, et kogu see informatsioon ilma kadudeta tabelisse salvestada, tuleks luua võrdlemisi keerukas andmete teisendamise süsteem ja võimalik, et ei piisakski ühest tabelist, vaid tuleks teha mitu. Märksa parem oleks aga, kui saaksime keeruka süsteemi loomise asemel lihtsalt kasutada sama sõnastik-andmestruktuuri, mida kasutab EstNLTK `Text`. Ja seda võimaldabki JSON.\n", "\n", "JSON sai algselt populaarseks veebis andmete vahetamise formaadina, hiljem aga muutus tavaliseks ka andmete lokaalsel talletamisel. Tänu tekstilisele vormingule on JSON hõlpsalt loetav ja kirjutatav nii arvutite kui ka inimeste poolt. Nii nagu CSV, nii on ka JSON formaat täielikult platvormist sõltumatu, seega võib andmed kirjutada näiteks Windows-is ja hiljem lugeda Linux-is.\n", "\n", "JSON-is esitatakse andmed objektidena, mis pannakse kokku kaht liiki struktuuridest:\n", "\n", " * _Võti-väärtus_ paarid, kus võti on alati sõne ja väärtus võib olla sõne, arv, tõeväärtus (`true/false`), järjend või mõni JSON objekt. Süntaksi poolest on see väga sarnane Pythoni sõnastikule. Näide:\n", " {\n", " \"nimi\": \"Juku\",\n", " \"vanus\": 15\n", " }\n", " * _Järjendid_, mille elementideks võivad olla sõned, arvud, tõeväärtused või JSON objektid. Jällegi, süntaksilt sarnane Pythoni listile. Näide: \n", " {\n", " \"nimi\": \"Juku\",\n", " \"vanus\": 15,\n", " \"vanemad\" : [\n", " { \n", " \"nimi\": \"Juhan\",\n", " \"vanus\": 40\n", " },\n", " { \n", " \"nimi\": \"Pille\",\n", " \"vanus\": 37\n", " }\n", " ]\n", " }\n", " Eelmises näites: võtmele `\"vanemad\"` vastavaks väärtuseks on järjend (`[]`-vahel), mis koosneb omakorda JSON objektidest.\n", "\n", "Neid kaht liiki struktuuriliiki kombineerides võib moodustada kuitahes keerukaid või sügavaid andmestruktuure, mingit otsest piirangut siin ei ole (v.a loomulikud piirangud, mis tulenevad arvuti mälu- / kõvakettamahust)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Muide, ka _Jupyter Notebook_-i `.ipynb` failid on JSON formaadis, seega saate neid avada ka täiesti tavalise tekstiredaktoriga ning vajadusel teha kiireid parandusi ilma, et peaksite _Notebook_-i käivitama. **(!)** Siiski ka hoiatus: kui muudate `.ipynb` faili käsitsi, peate olema väga tähelepanelik selle suhtes, et säiliks algne faili formaat -- kui teete formaadi katki, ei lähe märkmikufail enam _Notebook_-is käima..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Python ja JSON\n", "\n", "Praktiliselt iga Pythoni sõnastiku, mille võtmeteks on sõned ning väärtused on sõned, arvud, tõeväärtused, järjendid või sõnastikud, võib teisendada JSON kujule. Seda saab teha teegi `json` abil:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\"lemmikloomad\": [{\"liik\": \"koer\", \"nimi\": \"Pontu\"}, {\"liik\": \"k\\u00fc\\u00fclik\", \"nimi\": \"J\\u00f5nksu\"}], \"nimi\": \"Elvis\"}\n" ] } ], "source": [ "import json\n", "\n", "my_hierarchical_data = {'nimi':'Elvis','lemmikloomad':[{'nimi':'Pontu','liik':'koer'},{'nimi':'Jõnksu','liik':'küülik'}]}\n", "\n", "# Teisendame sõnastiku JSON kujul sõneks\n", "json_string = json.dumps( my_hierarchical_data )\n", "\n", "print(json_string)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mis muutus pärast JSON-iks konverteerimist? Esiteks, kõik sõned on nüüd `\"`-sümbolite, mitte enam `'`-sümbolite vahel. Erinevalt Pythonist lubataksegi JSON-is ainult jutumärkide vahel olevaid sõnesid. Teiseks, täpitähtede asemele ilmusid sõnedesse veidrad sümbolite jadad. Põhjus selles, et vaikimisi lubab meetod `dumps` sõnede sees kasutada ainult [ASCII sümboleid](http://ascii-table.com) ning kõik muud sümbolid kodeeritakse. Seda sätet saab siiski ka muuta -- kui käivitate meetodi lipuga `ensure_ascii=False`, siis jäävad _Unicode_ sümbolid alles nende algsel kujul.\n", "\n", "Andmete tagasiteisendamiseks sõne kujult Pythoni andmestruktuuriks saame kasutada meetodit `json.loads`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'lemmikloomad': [{'liik': 'koer', 'nimi': 'Pontu'}, {'liik': 'küülik', 'nimi': 'Jõnksu'}], 'nimi': 'Elvis'}\n" ] } ], "source": [ "# Teisendame JSON kujul andmed tagasi Pythoni sõnastikuks\n", "my_new_hierarchical_data = json.loads(json_string)\n", "\n", "print(my_new_hierarchical_data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### JSON andmete \"kaunistrükk\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hierarhilist struktuuri võib olla keerukas jälgida, kui kogu andmestruktuur on surutud kokku ühele reale. Et andmete struktuur oleks kergemini jälgitav, selleks trükitakse andmed sageli välja nii, et iga element on eraldi real ning hierarhia järgmise taseme liikmed on eelmise taseme liikmetest eristatud taanete abil. Ka JSON sõnede loomisel võib nõuda, et erinevate tasemete liikmed oleksid eristatud taanete abil:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\n", " \"lemmikloomad\": [\n", " {\n", " \"liik\": \"koer\",\n", " \"nimi\": \"Pontu\"\n", " },\n", " {\n", " \"liik\": \"k\\u00fc\\u00fclik\",\n", " \"nimi\": \"J\\u00f5nksu\"\n", " }\n", " ],\n", " \"nimi\": \"Elvis\"\n", "}\n" ] } ], "source": [ "# Teisendame sõnastiku JSON kujul sõneks ning nõuame, et taane oleks 3 tühikut\n", "json_string = json.dumps( my_hierarchical_data, indent = 3 )\n", "\n", "print(json_string)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Andmete sisselugemise seisukohalt vahet pole, kas andmed on taandega või ilma -- meetod `loads` oskab lugeda mõlemal kujul andmeid. Küll aga on taandega JSON-andmete miinuseks see, et need võtavad (mälus / kõvakettal) rohkem ruumi ja seega praktikas (andmete vahetamisel / salvestamisel) kasutatakse taanetega kuju harvem." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ka Pythoni enda andmestruktuure võib väljastada ekraanile taanetega. Selle jaoks on standardteegis nn \"kaunistrüki\" (ingl _pretty-printing_) meetod [`pprint`](https://docs.python.org/3.5/library/pprint.html):" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'lemmikloomad': [{'liik': 'koer', 'nimi': 'Pontu'},\n", " {'liik': 'küülik', 'nimi': 'Jõnksu'}],\n", " 'nimi': 'Elvis'}\n" ] } ], "source": [ "from pprint import pprint\n", "\n", "pprint(my_hierarchical_data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lisaks kulub see meetod marjaks ära nt siis, kui tahame printida EstNLTK `Text` objekti sõnastiku-sisu -- vaikimisi prinditakse `Text` objekti puhul ainult ilma märgenduseta tekst, `pprint` abil saab aga väljastada kogu sõnastiku. Mis puutub _Jupyter Notebook_-i, siis siia on juba sisse ehitatud mugavus, et kui kirjutada koodilahtrisse ainult `Text` objekt või seda sisaldava muutuja nimi, siis väljastatakse sõnastiku sisu. \n", "Käsureaprogrammides `Text` objekti printides aga nii ei juhtu ning seal on `pprint` mugavaim viis `Text` objekti taga oleva sõnastiku väljastamiseks/uurimiseks.\n", "\n", "Katsetage: looge üks `Text` objekt, lisage sellele märgendust ja printige selle sisu `pprint` abil." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### JSON andmete salvestamine faili / lugemine failist\n", "\n", "Kui andmed on konverteeritud JSON sõneks, siis võib need salvestada faili samal viisil, nagu salvestatakse tavalisi tekstiandmeid. Analoogselt: JSON failist võib andmed algul lugeda sisse sõnena ning seejärel teisendada `json.loads` abil Pythoni andmeteks. Lisaks sellele on teegis `json` meetodid [`dump`](https://docs.python.org/3.5/library/json.html#json.dump) ja [`load`](https://docs.python.org/3.5/library/json.html#json.load), mida saab kasutada vahetult faili kirjutamiseks / failist lugemiseks. Näide: faili kirjutamine:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "with open('minu_andmed.json', 'w') as f:\n", " # Teisendame andmed JSON kujule ja kirjutame faili f\n", " json.dump( my_hierarchical_data, f )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mis puutub aga EstNLTK `Text` objektidesse, siis nende salvestamiseks kõvakettale on samuti JSON kõige loomulikum kuju, ning EstNLTK sisaldab ka funktsioone, mis teevad failioperatsioonid veelgi mugavamaks. Järgmisena uurimegi neid." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Estnltk ja JSON\n", "\n", "Moodul `estnltk.corpus` sisaldab funktsioone, mis võimaldavad `Text` objekte salvestada \\ laadida JSON failide kujul:\n", "\n", " - `read_document(fnm)` -- loeb tekstifalist nimega `fnm` JSON kujul teksti ning tagastab vastava `Text` objekti. Eeldab, et tekst on kodeeritud baidimassiiviks ning hõlmab kogu tekstifaili (ehk: kogu faili sisu moodustab ühe JSON objekti); \n", "\n", "\n", " - `write_document(doc, fnm)` -- konverteerib `Text` objekti `doc` JSON kujule (sõne kodeeritakse baidimassiiviks), ning kirjutab tekstifaili nimega `fnm`; \n", "\n", "\n", " - `read_json_corpus(fnm)` -- loeb tekstifalist nimega `fnm` JSON kujul tekstide korpuse ning tagastab **`Text` objektide järjendina**. Eeldab, et igal faili real on üks korpuse tekst ja iga tekst on JSON kujul ning baidimassiiviks kodeeritud sõnena; \n", "\n", "\n", " - `write_json_corpus(documents, fnm)` -- konverteerib **`Text` objektid järjendis `documents`** JSON kujule (ja baidimassiivideks kodeeritud sõnedeks) ning kirjutab faili nimega `fnm`, iga tekst eraldi reale;\n", "\n", "Sisuliselt salvestatakse faili kogu `Text` sisu, mida näeb `pprint` abil objekti välja trükkides -- ehk siis tekst koos selle märgendustega. Salvestamata jäävad parameetrid, mis antakse `Text` objektile loomisel kaasa (nt lipud `'disambiguate'` ja `'guess'`), seega, kui on oluline jäädvustada ka parameetrite seis, tuleks need eraldi `Text`-i võtmeteks panna." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ülesanne 1. JSON korpuse lugemine ja kirjutamine (1 p)\n", "\n", "Looge skript, mis teeb järgmist: \n", " 1. loeb kaustast 'aja_json' JSON kujul tekstid (ajaleheartiklid Postimehest ja EPL-ist); \n", " 2. moodustab nende põhjal `Text` objektid ning lisab tekstidele morfoloogilised analüüsid;\n", " 3. salvestab tulemused JSON kujul korpustena, selliselt, et ühel päeval ilmunud artiklid koondatakse salvestatamisel ühte faili;\n", "\n", "Programm peaks ka väljastama igasse faili salvestatud artiklite arvu, et oleks näha, millistel kuupäevadel ilmus kõige rohkem artikleid.\n", "\n", "Detailid / vihjed: \n", " - kasutage funktsiooni `estnltk.corpus.read_document(fnm)` artikli-failide sisselugemiseks;\n", " - _metaandmed_: informatsioon artikli kohta (ilmumiskuupäev, rubriik, aga ka pealkiri ja autor) on talletatud `Text` objekti võtmetes: uurige, millised võtmed/väärtused on sisseloetud `Text` objektidel (Vihje: kasutage meetodit `.keys()` sõnastiku võtmete kättesaamiseks);\n", " - kasutage meetodit `estnltk.corpus.write_json_corpus(documents, fnm)` uue märgendusega tekstide salvestamiseks; uute failide nimedes peaksid kajastuma ka artiklite loomise kuupäevad;\n", " - NB! järgmiste ülesannete lahendamist lihtsustab, kui kasutada failinimedes ühes kindlas formaadis kuupäevi, isegi kui metaandmetes kasutatakse erinevaid kuupäevaformaate (nt `'yyyy.mm.dd'` ja `'dd.mm.yyyy'`);\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Boonusülesanne. Programmi tööaja mõõtmine (0,5 p)\n", "\n", "Kui on tarvis analüüsida suurt korpust, otsida/loendada midagi märgenduse järgi, siis võib märgenduste faili salvestamise taga olla praktiline vajadus: kogu märgendustega korpus ei pruugi lihtsalt korraga mällu ära mahtuda. Lisaks pakub märgenduste faili salvestamine ka ajavõitu: juba märgendatud `Text` objektide failist lugemine ülesande lahendamiseks on enamasti oluliselt kiirem kui märgenduse nö nullist lisamine. Järgnevalt ongi teie ülesandeks uurida, kui suurt ajavõitu pakub juba märgendatud korpuse kasutamine.\n", "\n", "Lahendage lihtne ülesanne -- loendage, kui palju on Postimehe ja EPL korpuses (kaustas 'aja_json') nimeüksuseid -- kahel viisil:\n", " 1. failidest loetakse sisse tavalised tekstid, lisatakse nimeüksuste märgendus (isikud, asukohad, organisatsioonid) ning seejärel loetakse nimeüksused kokku;\n", " 2. failidest loetakse sisse juba nimeüksuste märgendust sisaldavad tekstid (tekitage need ise) ning loetakse nimeüksused kokku;\n", " \n", "Mõõtke, kui palju kulub programmil aega esimesel ja teisel viisil ülesande lahendamiseks.\n", "\n", "Programmi tööaja mõõtmiseks Pythonis on mitmeid viise. Uurige moodulite `timeit` ([viide 1](https://docs.python.org/3.5/library/timeit.html), [viide 2](http://pythoncentral.io/measure-time-in-python-time-time-vs-time-clock/)) ja `datetime/timedelta` ([viide 1](https://stackoverflow.com/a/766382), [viide 2](http://en.proft.me/2014/12/7/measure-time-python)) võimalusi ning leidke antud ülesande jaoks sobivaim tööaja mõõtmise viis." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ajaväljendite tuvastamine\n", "\n", "Loomuliku keele tekstides kasutatakse sageli aja väljendamiseks kalendrilisi termineid ja määranguid (nt _'11. oktoobril'_, _'järgmisel neljapäeval'_, _'eelmisel kuul'_) ning sellistel juhtudel saab ajaväljendeid (ingl _time expression_ ehk _TIMEX_) ja nende semantikat ka suures osas automaatselt analüüsida. Ajaväljendite tuvastaja tegelebki tekstist ajaväljendite otsimisega (ajaväljendifraaside piiritlemisega) ning nende semantika _normaliseerimisega_.\n", "\n", "Ajaväljendite _semantika normaliseerimine_ tähendab seda, et kõigi ajaväljendite semantika esitatakse ühtsel viisil. Näiteks, kuupäeva _'11. oktoober 2020'_ edasiandmiseks võib kasutada ajaväljendeid _'11. okt 2020'_, _'2020.10.11'_ või siis (sõltuvalt kõnehetkest / kirjutamise ajast) _'täna'_, _'pühapäeval'_, _'selle nädala pühapäeval'_, tuvastaja eesmärgiks on aga kõigile neile vastavusse seada üks ajamäärang: `2020-10-11`. \n", "Tuvastaja poolt kasutatav aja esitamise formaat (`yyyy-mm-dd`) tugineb ISO standardile, ajaväljendite normaliseerimise tarbeks on seda aga natukene kohendatud. Näiteks, kui ajaväljendist pole võimalik välja lugeda konkreetset kuupäeva, aga seal on infot (või saab oletada midagi) _kuu_ ja _aasta_ kohta, siis lühendatakse esituskuju paremalt poolt: _'oktoober 2020'_, _'sellel kuul'_, _'tänavu oktoobris'_ => `2020-10`. \n", "Analoogselt saab kuupäeva esituskuju pikendada, kui väljendis on infot ka kellaaja kohta (nt _'11. oktoobril kell 10.00'_ => `2020-10-11T10:00`). Lisaks võimaldab aja esitamise formaat edasi anda kestvuste (nt _'viis aastat'_) ja korduvuste (_'kord nädalas'_) semantikat ning teatud määral ka hägusate ajaväljendite (nagu nt _'hiljuti'_, '_järgmisel suvel_') semantikat, aga käesolevas praktikumis me kõiki neid nüansse uurida ei jõua. Märgendusformaadi detailsema kirjelduse leiab EstNLTK [dokumentatsioonist](https://estnltk.github.io/estnltk/1.4.1/tutorials/text.html#temporal-expression-timex-tagging) ning kõige põhjalikuma käsitluse [sellest dokumendist](https://github.com/soras/Ajavt/blob/master/doc/margendusformaat_et.pdf?raw=true)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Tehniline vahemärkus**: ajaväljendite tuvastaja kasutab `java`-t. Seega, tuvastaja töölesaamiseks tuleb:\n", "\n", " * Installida süsteemi [_Java SE Runtime Environment_](https://www.java.com/en/download/) (versioon >= 1.8);\n", " \n", " * Panna `java` käsk süsteemi keskkonnamuutujasse PATH. Windows-i ja Mac-i puhul tehakse seda tüüpiliselt juba installi käigus, aga kui on siiski tarvis seda käsitsi teha, siis detailsemat abi saab [siit](https://java.com/en/download/help/path.xml);\n", "\n", "Kuidas kontrollida, kas `java` on juba olemas või kas installimine õnnestus? Käsureakäsk `java -version` peaks kuvama infot installitud `java` versiooni kohta, näiteks midagi taolist:\n", "\n", " java version \"1.8.0_171\"\n", " Java(TM) SE Runtime Environment (build 1.8.0_171-b11)\n", " Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)\n", "\n", " * _Lisamärkus_: Kui käivitate EstNLTK-s esmakordselt `java`-t kasutava analüüsi -- ajaväljendite või osalausete tuvastamise -- läheb alguses natukene kauem aega, kuna toimub `java` protsessi initsialiseerimine. Kui see on tehtud, peaks aga järgmiste analüüside tegemine kulgema ilma oluliste viivitusteta." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vaatame nüüd EstNLTK ajaväljendite tuvastaja liidest:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "[{'end': 20,\n", " 'id': 0,\n", " 'start': 16,\n", " 'temporal_function': True,\n", " 'text': 'eile',\n", " 'tid': 't1',\n", " 'type': 'DATE',\n", " 'value': '2020-06-21'},\n", " {'anchor_tid': 't0',\n", " 'end': 38,\n", " 'id': 1,\n", " 'start': 34,\n", " 'temporal_function': True,\n", " 'text': 'nüüd',\n", " 'tid': 't2',\n", " 'type': 'DATE',\n", " 'value': 'PRESENT_REF'},\n", " {'end': 56,\n", " 'id': 2,\n", " 'start': 46,\n", " 'temporal_function': False,\n", " 'text': 'viie aasta',\n", " 'tid': 't3',\n", " 'type': 'DURATION',\n", " 'value': 'P5Y'}]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from estnltk import Text\n", "from pprint import pprint\n", "\n", "text = Text('Potsataja ütles eile, et vaatavad nüüd Genaga viie aasta plaanid uuesti üle.')\n", "\n", "# Lisame tekstile ajaväljendite märgenduskihi\n", "text.tag_timexes()\n", "\n", "# Kuvame leitud ajaväljendid\n", "text['timexes']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nagu teised märgendused, nii koosneb ka ajaväljendite märgendus sõnastikest ja iga sõnastik kirjeldab ühte ajaväljendifraasi. Käesoleva praktikumi seisukohalt on kõige olulisem info võtmetes `type` ja `value`. Võtme `type` all on ajaväljendi liik: `DATE` -- tavaline toimumisaeg, `TIME` -- kellaaeg-täpsusega toimumisaeg, `DURATION` -- kestvus või `SET` -- korduvus. Võtme `value` all on ajaväljendi normaliseeritud semantika. Muude võtmete kohta vt lähemalt EstNLTK [dokumentatsioonist](https://estnltk.github.io/estnltk/1.4.1/tutorials/text.html#temporal-expression-timex-tagging)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Samuti saab ka ajaväljendite puhul kasutada nn mugavusfunktsioone, mis teostavad väljakutsumisel ajaväljendimärgenduse (kutsuvad ise välja meetodi `tag_timexes()`) ning tagastavad mingi alamosa tulemusest. Näited:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "text = Text('Potsataja ütles eile, et vaatavad nüüd Genaga viie aasta plaanid uuesti üle.')" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['eile', 'nüüd', 'viie aasta']" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "text.timex_texts" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['DATE', 'DATE', 'DURATION']" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "text.timex_types" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['2020-06-21', 'PRESENT_REF', 'P5Y']" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "text.timex_values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dokumendi loomise aja täpsustamine\n", "\n", "Ajaväljendite _'2020.10.11'_ ja _'11. oktoobril 2020'_ semantika normaliseerimine on suhteliselt triviaalne: väljend kirjutatakse lihtsalt ümber õigesse kuupäevaformaati, midagi oletama ei pea. Tegemist on nn _absoluutsete ajaväljenditega_: nende fraasides on olemas kogu normaliseerimiseks vajalik kalendriline informatsioon. \n", "\n", "Keerulisem on lugu aga _relatiivsete ajaväljenditega_, mille täpne kalendriline semantika ei peitu fraasis, vaid tuleb leida arvutuslikul teel mingi teise ajapunkti suhtes. Sellised väljendid on näiteks _'eile', 'eelmisel aastal', 'järgmisel kuul'_. Et relatiivsete väljendite semantika normaliseerimine toimuks korrektselt, tuleb `Text` objekti loomisel täpsustada _dokumendi loomise aeg_ ehk ajapunkt, mille suhtes semantika arvutatakse.\n", "\n", "Alljärgnevas näites fikseeritakse dokumendi loomise ajana (parameeter `creation_date`) kuupäev 21.12.1986 ning leitakse relatiivsete väljendite semantika selle kuupäeva suhtes:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[('eile', '1986-12-20'),\n", " ('eelmisel aastal', '1985'),\n", " ('järgmisel kuul', '1987-01')]\n" ] } ], "source": [ "import datetime\n", "\n", "# Loome uue kuupäev-objekti\n", "dct = datetime.datetime(1986, 12, 21)\n", "\n", "# Loome uue teksti kasutades etteantud dokumendi loomise kuupäeva\n", "text = Text('Oli see eile, eelmisel aastal või tuleb see hoopis järgmisel kuul?', \\\n", " creation_date = dct)\n", "\n", "# Väljastame ajaväljendifraasid + nende normaliseeritud väärtused\n", "pprint( list(zip(text.timex_texts,text.timex_values)) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " * **NB!** Kui jätate _dokumendi loomise aja_ täpsustamata, kasutatakse selle asemel vaikimisi programmi käivitamise aega, mis ei pruugi aga olla täpne kui analüüsite minevikus kirjutatud tekste;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eesti keele ajaväljendite tuvastajat, selle tööpõhimõtteid ja tuvastamise kvaliteeti kirjeldab detailsemalt [see artikkel](http://arhiiv.rakenduslingvistika.ee/ajakirjad/index.php/aastaraamat/article/view/ERYa8.10)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ülesanne 2. Ajaväljendimärgenduse lisamine korpusele (1,5 p)\n", "\n", "Lisage esimese ülesande käigus tekitatud korpusele (ilmumiskuupäevade järgi JSON failidesse salvestatud artiklid) ajaväljendimärgendus. Seejärel filtreerige ajaväljendimärgendust ning jätke alles vaid kuupäevaks (_yyyy-mm-dd_), kuuks (_yyyy-mm_) ja aastaks (_yyyy_) normaliseeritud väljendid. Salvestage tulemused uuesti JSON kujul korpusefailidena.\n", "\n", "Detaile / soovitusi:\n", " * Ajaväljendite tuvastamine:\n", " - enne ajaväljendite märgendamist tuleb leida iga artikli kirjutamise aeg;\n", " - _artikli kirjutamise aja_ saab kätte faili nimest (kui 1. ülesanne on õigesti lahendatud) või teksti metaandmetest (võtme `'ajalehenumber'` alt);\n", " (kasutage regulaaravaldisi aasta, kuu ja kuupäeva sõnest väljanoppimiseks, moodustage nende põhjal `datetime` objekt ja kasutage seda uue `Text` objekti loomisel);\n", " - kuidas säilitada ajaväljendite märgendamisel sisseloetud `Text` objekti metaandmed? Uut `Text`-i saab luua ka [olemasoleva `Text`-i alusel](https://estnltk.github.io/estnltk/1.4.1/tutorials/text.html#getting-started): kui anda uuele `Text` objektile sisseloetud `Text` parameetriks, siis kopeeritakse sealt kõik andmed, k.a metaandmed:\n", " \n", " new_text_obj = Text( loaded_text_obj, creation_date= ... )\n", " \n", " - igaks juhuks on hea ajaväljendite tuvastamise tulemust pisteliselt käsitsi uurida, et veenduda, et ajaväljendite normaliseerimine toimub korrektselt -- nt kui artikli kirjutamise kuupäev on 12. juuli 1999 a, siis ajaväljend _'mullu detsembris'_ peaks omandama väärtuse `'1998-12'` (mitte `'2020-12'`);\n", " * Ajaväljendite filtreerimine:\n", " - Ajaväljendite normaliseeritud kujusid on üksjagu palju ja kõiki me selles praktikumis uurida ei jõua. Seetõttu lihtsustame ülesannet ja filtreerime välja vaid kuupäevaks, kuuks ja aastaks normaliseeritud väljendid;\n", " - Järjend `text['timexes']` sisaldab kõiki teksti ajaväljendeid. Filtreerige seda ja jätke alles vaid ajaväljendid, mille 'value' vastab mustritele `yyyy-mm-dd` (kuupäev), `yyyy-mm` (kuu) ja `yyyy` (aasta). Filtreerimisel on ilmselt kõige parem kasutada regulaaravaldisi. Alljärgnev tabel toob näiteid väljenditest, mis tuleks alles jätta ja mis mitte:\n", " \n", "Ajaväljendi tekst | Ajaväljendi normaliseeritud väärtus (_value_) | Kas ajaväljend tuleks alles jätta?\n", "--- | --- | ---\n", "`mullu` | `1998` | `jah`\n", "`sellel kuul` | `1999-11` | `jah`\n", "`14. oktoobril` | `1999-10-14` | `jah`\n", "`suvel` | `1999-SU` | `ei`\n", "`hiljuti` | `PAST_REF` | `ei`\n", "`viis aastat` | `P5Y` | `ei`\n", "\n", " \n", " * `Text` objekti muutmine -- tuletage meelde kolmandas praktikumis õpitut: kuidas teha nii, et `Text`-is olev ajaväljendite järjend kirjutatakse üle uue / filtreeritud ajaväljendite järjendiga?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lihtne kronoloogiline järjestus\n", "\n", "ISO standardil põhineva ajaformaadi võluks on lihtne kronoloogiline järjestatavus: kronoloogilise järjekorra taastamiseks piisab, kui sorteerida ajaväljendite normaliseeritud väärtuste sõnesid:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['1918-02-24', '1991-08-20', '2002-10', '2016', '2018-10-13']" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "values = ['2018-10-13', '2002-10', '1991-08-20', '1918-02-24', '2016']\n", "sorted(values)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Semantika seisukohalt on siin on muidugi omad nüansid. Kui ajaväljendite normaliseeritud kujud on erineva detailsusega, aga muidu kattuvad, nt üks on kuu-detailsusega (_'oktoobris'_ => `2018-10`) ja teine kuupäev-detailsusega (_'13. oktoobril'_ => `2018-10-13`), siis sellisel viisil sorteerides tuleb lühem esituskuju alati ettepoole. Tegelikult võib aga väiksema detailsusega väljend tähistada seda, et kirjutaja lihtsalt ei soovinud või ei saanud detailsemat ajalist infot anda, ning tegelik kronoloogiline järjekord nende väljendite vahel peaks olema lahtine / määratlemata (ehk: _\"oktoobris\"_ võib tähendada kuupäeva nii enne kui pärast _\"13. oktoobrit\"_). Selliste semantiliste eristuste tegemine nõuab aga keerukamat analüüsi ning käesolevas praktikumis võime leppida sellega, et lihtne kronoloogiline järjestus on teatud määral ebatäpne." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " ### Ülesanne 3. Tulevikuennustused (1,5 p)\n", "\n", "Looge programm, mis analüüsib ajaväljendimärgendusega korpust ning väljastab 5 kõige kaugemat tulevikku mainivat lauset. Lisaks lausetele peaks skript väljastama ka lausetega seotud artiklite meta-andmed -- ajalehenumbri ja artikli pealkirja -- et oleks selgem, mis kontekstist lause pärineb. \n", "\n", "Ülesande lahendamiseks tuleks koguda kokku kõik ajaleheartiklites olevad ajaväljendid (ja nendega seotud laused ja vastavad metaandmed), sorteerida ajaväljendid _'value'_ järgi ning väljastada 5 kõige hilisema ajamääranguga seotud laused.\n", "\n", "Soovitusi / vihjeid:\n", "\n", " * Sisendkorpusena tuleks jällegi kasutada eelmise ülesande tulemust, ehk siis korpust, kus on märgendatud kuupäevaks (_yyyy-mm-dd_), kuuks (_yyyy-mm_) ja aastaks (_yyyy_) normaliseeritud väljendid;\n", " * Kuidas kätte saada ajaväljendiga seotud lause? Kõige lihtsam lähenemisviis on tükeldada tekst lauseteks (2. praksi teema), koguda kokku lause sees olevad ajaväljendid ja salvestada iga väljend selliselt, et sellega on kaasa pandud ka seda sisaldanud lause (+ meta-andmed);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " ### Ülesanne 4. Kuupäevade tulpdiagrammid (3 p)\n", "\n", "Meie poolt uuritavas korpuses on päevalehed ja võib oletada, et suur osa nendes kajastatavatest sündmustest paigutuvad lehe ilmumisaja suhtes lähipäevadele. Selle oletuse kinnituseks (või ümberlükkamiseks) visualiseerime kuupäevaks normaliseeritud ajaväljendite sagedused _tulpdiagrammide_ abil. \n", "\n", "Konkreetsemalt. Leidke korpusest Postimehe ja Eesti Päevalehe ajalehenumbrid, mis sisaldavad kõige rohkem artikleid, ning joonistage mõlema ajalehenumbri _kuupäevadeks_ normaliseeritud ajaväljendite kohta üks _tulpdiagramm_. \n", "\n", "Diagrammi igas tulbas kajastub üheks konkreetseks kuupäevaks normaliseeritud ajaväljendite arv ning tulba pealkiri ongi vastav kuupäev (nt `1999-11-24`).\n", "\n", "Ühe ajalehenumbri tulpdiagramm peaks andma ülevaate _ilmumiskuupäeva ümbritsevate kuupäevade_ mainimissagedusest. Valige mingi väike ümbritsevate kuupäevade raadius. Näiteks, tulpdiagrammil võib olla statistika viie ajalehenumbri ilmumisele eelneva ja viie järgneva kuupäeva mainimiste kohta, sh ka ajalehenumbri enda ilmumiskuupäeva mainimiste kohta. Nende seas peaksid näha olema ka kuupäevad, mis jäid raadiusesse, aga mida üldse ei mainitud. Ülejäänud kuupäevade mainimissagedused saab koguda kokku ja paigutada tulpadesse diagrammi otstes, nt pealkirjadega \"varasemad\" ja \"hilisemad\";\n", "\n", "Detaile:\n", " * Sisendiks jällegi ülesande 2 väljund. Valige ajaväljendite seast loendamiseks / visualiseerimiseks ainult kuupäevadeks normaliseeritud ajaväljendid -- ehk siis ajaväljendid, mille _'value'_ vastab formaadile _yyyy-mm-dd_;\n", " * Vihjeid kuupäevade loendamise kohta: \n", " * Kuna meid huvitavad *N* ilmumiskuupäevale eelnevat ja järgnevat kuupäeva ning _N_ on eeldatavasti väike arv (valige see ise), siis üsna kasulik oleks lähikuupäevadele vastavad sõned juba enne loendamist valmis genereerida (nt teha nende kohta sõnastik). Mõnda nendest kuupäevadest võib-olla ei mainitagi, aga tulpdiagrammile peaks vastava tulba koht ikkagi tekkima. Kui lähikuupäevad on juba genereeritud, siis loendamisel tuleb iga (kuupäev-)ajaväljendi puhul kontrollida, kas see on artikli lähikuupäevade hulgas, kui on, siis suurendada vastavat sagedust, ja kui pole, siis liigitada see vastavalt kas \"varasemate\" või \"hilisemate\" kuupäevade hulka;\n", " * Kuidas leida artikli/ajalehenumbri ilmumisaja lähikuupäevad? Ilmumisaeg ise on metaandmetes olemas, kalendriaritmeetika vahendite abil saab leida sellele eelnevad/järgnevad kuupäevad. Näide:\n", " \n", " >> from datetime import datetime, timedelta\n", " >> dct = datetime(2017, 10, 1)\n", " >> prev_day = dct - timedelta(days=1)\n", " >> print( 'Eelmine kuupäev:', prev_day )\n", " Eelmine kuupäev: 2017-09-30 00:00:00\n", " \n", " * Visualiseerimiseks võib kasutada teegi `matplotlib` vahendeid (allpool on selle kohta ka näide), aga samas kohustuslik see pole -- kui leiate netist mõne alternatiivse visualiseerimisteegi, siis olete teretulnud seda katsetama; \n", " \n", " ( `matplotlib`-i eeliseks on ilmselt see, et seda ei pea uuesti installima -- peaks olema installitud juba 2. praktikumist )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Tulpdiagrammi joonistamine (`matplotlib`)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", "# Andmed: tulpade nimed ja vastavad arvandmed\n", "labels = ['A', 'B', 'C']\n", "data = [1, 7, 3]\n", "\n", "# tulpade \"koordinaadid\"\n", "# (ehk millises järjekorras tulbad pildile \n", "# paigutatakse)\n", "y_pos = range(len(labels))\n", "# tulpdiagrammi tegemine:\n", "plt.bar(y_pos, data, color='blue', width=0.6)\n", "# tulpade nimed:\n", "plt.xticks(y_pos, labels)\n", "# diagrammi ja selle telgede nimed:\n", "plt.title('minu diagramm')\n", "plt.xlabel('tähed')\n", "plt.ylabel('sagedused')\n", "\n", "# kuvame diagrammi:\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mille kohta veel tasub uurida: \n", " * Funktsiooni bar [dokumentatsioon](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.bar.html);\n", " * X- ja Y-telje nimede vormistuse muutmine, nt [xticks](https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.xticks) ja [selle võimalike parameetrite loend](https://matplotlib.org/api/text_api.html#matplotlib.text.Text);\n", " * Pildi ja fondi suuruse [muutmine](https://matplotlib.org/users/dflt_style_changes.html#figure-size-font-size-and-screen-dpi);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.3" } }, "nbformat": 4, "nbformat_minor": 1 }