diff --git a/cw/02_wyszukiwarki_roboty.ipynb b/cw/02_wyszukiwarki_roboty.ipynb index 7037db8..d5ddced 100644 --- a/cw/02_wyszukiwarki_roboty.ipynb +++ b/cw/02_wyszukiwarki_roboty.ipynb @@ -244,8 +244,31 @@ "49. [Zeszyty Formacyjne Katolickiego Stowarzyszenia „Civitas Christania”](http://podkarpacki.civitaschristiana.pl/formacja/zeszyty-formacyjne/), tylko niektóre pliki można zdatować\n", "50. [Józef Piłsudski Institute of America](https://archiwa.pilsudski.org/) - **220 punktów**\n", "51. [Prasa podziemna — Częstochowa](http://www.podziemie.com.pl), również ulotki i inne materiały skanowane - **180 punktów**\n", - "52. [Tajemnica Atari](http://krap.pl/mirrorz/atari/horror.mirage.com.pl/pixel/), plik ZIP z DjVu\n" + "52. [Tajemnica Atari](http://krap.pl/mirrorz/atari/horror.mirage.com.pl/pixel/), plik ZIP z DjVu\n", + "53. [Gorzowskie Wiadomości Samorządowe](http://www.gorzow.pl/archiwum/przystan/media-strona-glowna/gorzowskie-wiadomosci-samorzadowe)\n", + "54. [Gazeta Rodnia - Bieruń](https://www.bierun.pl/mieszkancy/archiwum)\n", + "55. [Parafia Śrem](https://sremfara.pl/miesiecznik_30.html)\n", + "56. [BIP Gdynia](https://bip.um.gdynia.pl/wyszukiwarka-uchwal-rady-miasta,7485/wyszukiwarka-uchwal,504923) do roku 1990!, **120 punktów**\n", + "57. [BIP Żyrardów](https://www.bip.zyrardow.pl/4945,uchwaly-rady-miejskiej-zyrardowa?tresc=46185) do roku 1990!, **120 punktów**\n", + "58. [Biuletyn Polarny](http://www.geol.agh.edu.pl/~bipo/index.php?menu=BiPo_0021)\n", + "59. [Otwarte czasopisma Wydawnictwa UAM](https://pressto.amu.edu.pl), **140 punktów**\n", + "60. [Wycinki o kolei gondolowej](http://kolej-szyndzielnia.pl/kolej-gondolowa/) — zob. \"Napisali o Szyndzielni\" na tej stronie\n", + "61. [Instytut Radioelektroniki PW](https://www.ire.pw.edu.pl/o-instytucie/raporty-roczne/)\n", + "62. [Zagadnienia Ekonomiki Rolnej](http://www.zer.waw.pl/Archive), **100 punktów**\n", + "63. [Rozkazy Komendanta Chorągwi Wielkopolskiej ZHP](http://dokumenty.zhp.wlkp.pl/rozkazy.htm), **130 punktów**\n", + "64. [Sulimczyk - pismo harcerskie](http://www.16wdh.pl/s28,Sulimczyk)\n", + "65. [Archiwum Harcerskie](https://archiwumharcerskie.pl/index.php?title=Strona_g%C5%82%C3%B3wna), **170 punktów**\n", + "66. [Cyfrowe Archiwa Tarnowskie](https://www.agora.tarnow.pl/viewforum.php?f=30), **100 punktów**\n", + "67. [Instytut Techniki Górniczej - wycinki](http://www.komag.gliwice.pl/archiwum/historia-komag)\n", + "\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -264,7 +287,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.9.1" } }, "nbformat": 4, diff --git a/wyk/01_Wyszukiwarki-wprowadzenie.ipynb b/wyk/01_Wyszukiwarki-wprowadzenie.ipynb index 6015e5f..dba39ef 100644 --- a/wyk/01_Wyszukiwarki-wprowadzenie.ipynb +++ b/wyk/01_Wyszukiwarki-wprowadzenie.ipynb @@ -289,7 +289,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -314,55 +314,51 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQmhMwC3oECAwQDg&usg=AOvVaw0u-zPrcoqssLDbeZ31b45n',\n", + "[('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQmhMwC3oECA0QDg&usg=AOvVaw0GUY96bFEsdrfOb9_ME9qP',\n", " 'Wikipedia'),\n", - " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAQegQICBAB&usg=AOvVaw1-g3udljATwOyLar27GcFL',\n", + " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjASegQIDBAB&usg=AOvVaw3LMsdCuK3PBSunL8shYp-S',\n", " 'Wielka Stopa (zwierzę) – Wikipedia, wolna encyklopediapl.wikipedia.org › wiki › Wielka_Stopa_(zwierzę)'),\n", - " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Opis&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQ0gIwEHoECAgQAg&usg=AOvVaw3m9BrYVkOk8UfzeawG-8hG',\n", + " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Opis&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQ0gIwEnoECAwQAg&usg=AOvVaw02WHiDgMZ18jJGW-y7agVg',\n", " 'Opis'),\n", - " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Historia&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQ0gIwEHoECAgQAw&usg=AOvVaw2wkegIx737ZZ8eHDu-yaBk',\n", + " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Historia&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQ0gIwEnoECAwQAw&usg=AOvVaw10BrulHDJ4WgEOFkd-3-H6',\n", " 'Historia'),\n", - " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Najwa%25C5%25BCniejsze_argumenty_%25E2%2580%259Eza%25E2%2580%259D_i_%25E2%2580%259Eprzeciw%25E2%2580%259D&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQ0gIwEHoECAgQBA&usg=AOvVaw2Aybk94vFA5F8HebOUFjCP',\n", + " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Najwa%25C5%25BCniejsze_argumenty_%25E2%2580%259Eza%25E2%2580%259D_i_%25E2%2580%259Eprzeciw%25E2%2580%259D&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQ0gIwEnoECAwQBA&usg=AOvVaw1nSHJDVeWEJTqpRJOMBcus',\n", " 'Najważniejsze argumenty ...'),\n", - " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Argumenty_%25E2%2580%259Eprzeciw%25E2%2580%259D&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQ0gIwEHoECAgQBQ&usg=AOvVaw13uED0LDtqV7CGICk1AB53',\n", + " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(zwierz%25C4%2599)%23Argumenty_%25E2%2580%259Eprzeciw%25E2%2580%259D&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQ0gIwEnoECAwQBQ&usg=AOvVaw3UqFIOr7y6yxvK-i1su1au',\n", " 'Argumenty „przeciw”'),\n", - " ('https://www.youtube.com/watch%3Fv%3DEPRggWavPX4&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQtwIwEXoECAkQAQ&usg=AOvVaw2C9FR_ka-bwILishacl72z',\n", + " ('https://pl.wikipedia.org/wiki/Wielka_Stopa_(w%25C3%25B3dz_Siuks%25C3%25B3w)&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjATegQICxAB&usg=AOvVaw1lZSYrEp4ez0Kh4o4SXrY1',\n", + " 'Wielka Stopa (wódz Siuksów) – Wikipedia, wolna encyklopediapl.wikipedia.org › wiki › Wielka_Stopa_(wódz_Siuksów)'),\n", + " ('https://www.youtube.com/watch%3Fv%3DEPRggWavPX4&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQtwIwFHoECAQQAQ&usg=AOvVaw2EugGtxH-FfMbNmqhS5py3',\n", " 'Wielka Stopa w Suszu - YouTubewww.youtube.com › watch'),\n", - " ('https://www.youtube.com/watch%3Fv%3DEPRggWavPX4&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQuAIwEXoECAkQAg&usg=AOvVaw2db91ofMFO2lgJy4fWM1r5',\n", + " ('https://www.youtube.com/watch%3Fv%3DEPRggWavPX4&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQuAIwFHoECAQQAg&usg=AOvVaw17g24VY46PboJW54XyZGa1',\n", " '23 cze 2017 · Od niedawna oczy naukowców poszukujących Wielkiej Stopy skierowane są na niewielkie ...Czas trwania: 6:24\\nOpublikowano: 23 cze 2017'),\n", - " ('https://www.youtube.com/watch%3Fv%3DIhS1d56aPOc&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQtwIwEnoECAsQAQ&usg=AOvVaw24XoaMg6h7x2NTyAl26BnK',\n", - " 'MAŁA WIELKA STOPA: W RODZINIE SIŁA - spot 60\" - wkrótce w ...www.youtube.com › watch'),\n", - " ('https://www.youtube.com/watch%3Fv%3DIhS1d56aPOc&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQuAIwEnoECAsQAg&usg=AOvVaw1jnKr1_iwK6wdtnv6On4IS',\n", - " '18 wrz 2020 · MAŁA WIELKA STOPA: W RODZINIE SIŁA - spot 60\" - wkrótce w kinach. 3,215 views3.2K ...Czas trwania: 1:00\\nOpublikowano: 18 wrz 2020'),\n", - " ('https://www.youtube.com/watch%3Fv%3D_r4_GIfTn2o&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQtwIwF3oECAoQAQ&usg=AOvVaw1IdActIEpEOFwmM7o1JJgN',\n", - " 'Mała Wielka Stopa 2 - Zwiastun PL (Official Trailer) - YouTubewww.youtube.com › watch'),\n", - " ('https://www.youtube.com/watch%3Fv%3D_r4_GIfTn2o&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQuAIwF3oECAoQAg&usg=AOvVaw2y2RgIecicP4Elo-FDJzUU',\n", - " '18 sty 2021 · Mała Wielka Stopa 2 - Zwiastun PL (Official Trailer). 3,841 views3.8K views. • Jan 18, 2021 ...Czas trwania: 1:58\\nOpublikowano: 18 sty 2021'),\n", - " ('https://www.ceneo.pl/%3Bszukaj-wielka%2Bstopa&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAYegQIBhAB&usg=AOvVaw3CsIfH1bbl4NuHdhD1HhPh',\n", + " ('https://www.ceneo.pl/%3Bszukaj-wielka%2Bstopa&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAZegQIBhAB&usg=AOvVaw0HUE-TpszLKJjAMsV6lvPU',\n", " 'Wielka Stopa - znaleziono na Ceneo.plwww.ceneo.pl › ...'),\n", - " ('https://www.ceneo.pl/Filmy%3Bszukaj-wielka%2Bstopa&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAZegQIAxAB&usg=AOvVaw337S-gY9rL-W459aGtNIDc',\n", - " 'Wielka stopa Filmy - Ceneo.plwww.ceneo.pl › Filmy'),\n", - " ('https://www.antyradio.pl/News/Kobieta-twierdzi-ze-spotkala-Wielka-Stope-Hustala-sie-na-drzewie-ZDJECIE-43102&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAaegQIBRAB&usg=AOvVaw2OxO4D_gS2oFUPAKLTIwcX',\n", + " ('https://www.antyradio.pl/News/Kobieta-twierdzi-ze-spotkala-Wielka-Stope-Hustala-sie-na-drzewie-ZDJECIE-43102&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAaegQICBAB&usg=AOvVaw1iIlPUpJwldL0MacDY4ebw',\n", " 'Wielka Stopa - kolejny przypadek spotkania z potworem - Antyradiowww.antyradio.pl › News › Kobieta-twierdzi-ze-spotkala-Wielka-Stope-Hu...'),\n", - " ('https://www.empik.com/gra-strategiczna-yeti-wielka-stopa-jawa,p1103341700,zabawki-p&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAbegQIBBAB&usg=AOvVaw3KwX6-C-1IICOuzALNhRGX',\n", - " 'Gra strategiczna Yeti Wielka stopa - | Sklep EMPIK.COMwww.empik.com › Zabawki › Gry › Strategiczne i ekonomiczne'),\n", - " ('https://allegro.pl/kategoria/gry%3Fstring%3DWielka%2520stopa%2520%253A)%2520-&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAcegQIAhAB&usg=AOvVaw2VXMwFFmZ7mQMiBl0i3Jd6',\n", + " ('https://allegro.pl/kategoria/gry%3Fstring%3DWielka%2520stopa%2520%253A)%2520-&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAbegQIABAB&usg=AOvVaw0mgn1YuyE65LFfA54P-gQo',\n", " 'Wielka stopa :) - Gry - Allegro.plallegro.pl › Kultura i rozrywka › Gry'),\n", - " ('https://allegro.pl/listing%3Fstring%3DWielka%2520stopa%2520%253A%2529%2520-&sa=U&ved=2ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQFjAdegQIBxAB&usg=AOvVaw3NufyiyhsTOVf3RzSU42tb',\n", + " ('https://allegro.pl/listing%3Fstring%3DWielka%2520stopa%2520%253A%2529%2520-&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAcegQIAxAB&usg=AOvVaw3dzMG9f8K5w31r30AyxNEz',\n", " 'Wielka stopa :) - Niska cena na Allegro.plallegro.pl › listing'),\n", - " ('https://support.google.com/websearch%3Fp%3Dws_settings_location%26hl%3Dpl&sa=U&ved=0ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQty4Ifg&usg=AOvVaw1DLM5f67WADgR79BH8vXdm',\n", - " 'Stare Miasto, Poznań\\xa0-\\xa0Z Twojego adresu internetowego\\xa0-\\xa0Dowiedz się więcej'),\n", - " ('https://accounts.google.com/ServiceLogin%3Fcontinue%3Dhttps://www.google.com/search%253Fq%253D%252522wielka%252Bstopa%252522%26hl%3Dpl&sa=U&ved=0ahUKEwjx5M-vs6XvAhW0RhUIHVQOAasQxs8CCH8&usg=AOvVaw0fuHSgJA70sVMFF_4YfaI0',\n", + " ('https://www.empik.com/gra-strategiczna-yeti-wielka-stopa-jawa,p1103341700,zabawki-p&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAdegQIBxAB&usg=AOvVaw3xZ_RVxgMxK7vOUPAYO-pe',\n", + " 'Gra strategiczna Yeti Wielka stopa - | Sklep EMPIK.COMwww.empik.com › Zabawki › Gry › Strategiczne i ekonomiczne'),\n", + " ('https://tvn24.pl/tvnmeteo/informacje-pogoda/ciekawostki,49/wielka-stopa-nie-istnieje-naukowcy-to-nie-koniec-nadziei,127328,1,0.html&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAeegQICRAB&usg=AOvVaw3XECuxJKyNK_x4MTREa9Ui',\n", + " 'Wielka Stopa nie istnieje? Naukowcy: to nie koniec nadziei - TVN24tvn24.pl › Informacje pogodowe › Ciekawostki'),\n", + " ('https://www.monolith.pl/filmy/2020/mala-wielka-stopa-2-w-rodzinie-sila/&sa=U&ved=2ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQFjAfegQIChAB&usg=AOvVaw3uFesbmGBr0dDWxK1ej5n_',\n", + " 'Mała Wielka Stopa 2 - Filmy - Monolith Filmswww.monolith.pl › filmy › mala-wielka-stopa-2-w-rodzinie-sila'),\n", + " ('https://support.google.com/websearch%3Fp%3Dws_settings_location%26hl%3Dpl&sa=U&ved=0ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQty4IigE&usg=AOvVaw0fYQ97CWfJ8aCmNBcv3a_d',\n", + " 'Poznań\\xa0-\\xa0Z Twojego adresu internetowego\\xa0-\\xa0Dowiedz się więcej'),\n", + " ('https://accounts.google.com/ServiceLogin%3Fcontinue%3Dhttps://www.google.com/search%253Fq%253D%252522wielka%252Bstopa%252522%26hl%3Dpl&sa=U&ved=0ahUKEwj-ktTzsLfvAhW8ZxUIHQHnB5EQxs8CCIsB&usg=AOvVaw1V17_OrU9CNrErDjbwNZRj',\n", " 'Zaloguj się')]" ] }, - "execution_count": 25, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } diff --git a/wyk/02_Wyszukiwarki-roboty.ipynb b/wyk/02_Wyszukiwarki-roboty.ipynb index 4e207ba..fef3ae0 100644 --- a/wyk/02_Wyszukiwarki-roboty.ipynb +++ b/wyk/02_Wyszukiwarki-roboty.ipynb @@ -396,10 +396,8 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ "## Jak poradzić sobie z dynamicznymi stronami?" ] @@ -434,17 +432,15 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ "## Selenium" ] }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 2, "metadata": {}, "outputs": [ { diff --git a/wyk/03_Tfidf.ipynb b/wyk/03_Tfidf.ipynb new file mode 100644 index 0000000..56b4000 --- /dev/null +++ b/wyk/03_Tfidf.ipynb @@ -0,0 +1,2341 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Wyszukiwarka - szybka i sensowna" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Roboczy przykład\n", + "\n", + "Zakładamy, że mamy pewną kolekcję dokumentów $D = {d_1, \\ldots, d_N}$. ($N$ - liczba dokumentów w kolekcji)." + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Podobno jest kot w butach." + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "{-# LANGUAGE OverloadedStrings #-}\n", + "\n", + "import Data.Text hiding(map, filter, zip)\n", + "import Prelude hiding(words, take)\n", + "\n", + "collectionD :: [Text]\n", + "collectionD = [\"Ala ma kota.\", \"Podobno jest kot w butach.\", \"Ty chyba masz kota!\", \"But chyba zgubiłem.\"]\n", + "\n", + "-- Operator (!!) zwraca element listy o podanym indeksie\n", + "-- (Przy większych listach będzie nieefektywne, ale nie będziemy komplikować)\n", + "collectionD !! 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Wydobycie tekstu\n", + "\n", + "Przykładowe narzędzia:\n", + "\n", + "* pdftotext\n", + "* antiword\n", + "* Tesseract OCR\n", + "* Apache Tika - uniwersalne narzędzie do wydobywania tekstu z różnych formatów\n", + "\n", + "## Normalizacja tekstu\n", + "\n", + "Cokolwiek robimy z tekstem, najpierw musimy go _znormalizować_." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tokenizacja\n", + "\n", + "Po pierwsze musimy podzielić tekst na _tokeny_, czyli wyrazapodobne jednostki.\n", + "Może po prostu podzielić po spacjach?" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Ala" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ma" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kota." + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenizeStupidly :: Text -> [Text]\n", + "-- words to funkcja z Data.Text, która dzieli po spacjach\n", + "tokenizeStupidly = words\n", + "\n", + "tokenizeStupidly $ Prelude.head collectionD" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A, trzeba _chociaż_ odsunąć znaki interpunkcyjne. Najprościej użyć wyrażenia regularnego. Warto użyć [unikodowych własności](https://en.wikipedia.org/wiki/Unicode_character_property) znaków i konstrukcji `\\p{...}`. " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Ala" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ma" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kota" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "." + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "{-# LANGUAGE QuasiQuotes #-}\n", + "\n", + "import Text.Regex.PCRE.Heavy\n", + "\n", + "tokenize :: Text -> [Text]\n", + "tokenize = map fst . scan [re|[\\p{L}0-9]+|\\p{P}|]\n", + "\n", + "tokenize $ Prelude.head collectionD" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cała kolekcja stokenizowana:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Ala" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ma" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kota" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "." + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Podobno" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "jest" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kot" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "w" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "butach" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "." + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Ty" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "chyba" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "masz" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kota" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "!" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "But" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "chyba" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "zgubiłem" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "." + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "map tokenize collectionD" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Problemy z tokenizacją\n", + "\n", + "##### Język angielski" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "I" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "use" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "a" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "data" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "-" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "base" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"I use a data-base\"" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "I" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "use" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "a" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "database" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"I use a database\"" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "I" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "use" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "a" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "data" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "base" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"I use a data base\"" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "I" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "don" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "t" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "like" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Python" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"I don't like Python\"" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0018" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "555" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "555" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "122" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"+0018 555 555 122\"" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0018555555122" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"+0018555555122\"" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Which" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "one" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "is" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "better" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + ":" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "C" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "or" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "C" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "#" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "?" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"Which one is better: C++ or C#?\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Inne języki?" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Rechtsschutzversicherungsgesellschaften" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "wie" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "die" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "HUK" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "-" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Coburg" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "machen" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "es" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "bereits" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "seit" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "geraumer" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Zeit" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "vor" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + ":" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"Rechtsschutzversicherungsgesellschaften wie die HUK-Coburg machen es bereits seit geraumer Zeit vor:\"" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "今日波兹南是贸易" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "、" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "工业及教育的中心" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "。" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "波兹南是波兰第五大的城市及第四大的工业中心" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "," + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "波兹南亦是大波兰省的行政首府" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "。" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "也舉辦有不少展覽會" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "。" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "是波蘭西部重要的交通中心都市" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "。" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"今日波兹南是贸易、工业及教育的中心。波兹南是波兰第五大的城市及第四大的工业中心,波兹南亦是大波兰省的行政首府。也舉辦有不少展覽會。是波蘭西部重要的交通中心都市。\"" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "l" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ordinateur" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tokenize \"l'ordinateur\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lematyzacja" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_Lematyzacja_ to sprowadzenie do formy podstawowej (_lematu_), np. \"krześle\" do \"krzesło\", \"zrobimy\" do \"zrobić\" dla języka polskiego, \"chairs\" do \"chair\", \"made\" do \"make\" dla języka angielskiego." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lematyzacja dla języka polskiego jest bardzo trudna, praktycznie nie sposób wykonać ją regułowo, po prostu musimy się postarać o bardzo obszerny _słownik form fleksyjnych_.\n", + "\n", + "Na potrzeby tego wykładu stwórzmy sobie mały słownik form fleksyjnych w postaci tablicy asocjacyjnej (haszującej)." + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Use head
Found:
collectionD !! 0
Why Not:
head collectionD
" + ], + "text/plain": [ + "Line 22: Use head\n", + "Found:\n", + "collectionD !! 0\n", + "Why not:\n", + "head collectionD" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "but" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "butami" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Ala" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "mieć" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kot" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "." + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import Data.Map as Map hiding(take, map, filter)\n", + "\n", + "mockInflectionDictionary :: Map Text Text\n", + "mockInflectionDictionary = Map.fromList [\n", + " (\"kota\", \"kot\"),\n", + " (\"butach\", \"but\"),\n", + " (\"masz\", \"mieć\"),\n", + " (\"ma\", \"mieć\"),\n", + " (\"buta\", \"but\"),\n", + " (\"zgubiłem\", \"zgubić\")]\n", + "\n", + "lemmatizeWord :: Map Text Text -> Text -> Text\n", + "lemmatizeWord dict w = findWithDefault w w dict\n", + "\n", + "lemmatizeWord mockInflectionDictionary \"butach\"\n", + "-- a tego nie ma w naszym słowniczku, więc zwracamy to samo\n", + "lemmatizeWord mockInflectionDictionary \"butami\"\n", + "\n", + "lemmatize :: Map Text Text -> [Text] -> [Text]\n", + "lemmatize dict = map (lemmatizeWord dict)\n", + "\n", + "lemmatize mockInflectionDictionary $ tokenize $ collectionD !! 0 \n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Pytanie**: Nawet w naszym słowniczku mamy problemy z niejednoznacznością lematyzacji. Jakie?\n", + "\n", + "Obszerny słownik form fleksyjnych dla języka polskiego: http://zil.ipipan.waw.pl/PoliMorf?action=AttachFile&do=view&target=PoliMorf-0.6.7.tab.gz" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stemowanie\n", + "\n", + "Stemowanie (rdzeniowanie) obcina wyraz do _rdzenia_ niekoniecznie będącego sensownym wyrazem, np. \"krześle\" może być rdzeniowane do \"krześl\", \"krześ\" albo \"krzes\", \"zrobimy\" do \"zrobi\".\n", + "\n", + "* stemowanie nie jest tak dobrze określone jak lematyzacja (można robić na wiele sposobów)\n", + "* bardziej podatne na metody regułowe (choć dla polskiego i tak trudno)\n", + "* dla angielskiego istnieją znane algorytmy stemowania, np. [algorytm Portera](https://tartarus.org/martin/PorterStemmer/def.txt)\n", + "* zob. też [program Snowball](https://snowballstem.org/) z regułami dla wielu języków\n", + "\n", + "Prosty stemmer \"dla ubogich\" dla języka polskiego to obcinanie do sześciu znaków." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "zrobim" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "komput" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "butach" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "poorMansStemming :: Text -> Text\n", + "poorMansStemming = take 6\n", + "\n", + "poorMansStemming \"zrobimy\"\n", + "poorMansStemming \"komputerami\"\n", + "poorMansStemming \"butach\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### _Stop words_\n", + "\n", + "Często wyszukiwarki pomijają krótkie, częste i nieniosące znaczenia słowa - _stop words_ (_słowa przestankowe_)." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "isStopWord :: Text -> Bool\n", + "isStopWord \"w\" = True\n", + "isStopWord \"jest\" = True\n", + "isStopWord \"że\" = True\n", + "-- przy okazji możemy pozbyć się znaków interpunkcyjnych\n", + "isStopWord w = w ≈ [re|^\\p{P}+$|]\n", + "\n", + "isStopWord \"kot\"\n", + "isStopWord \"!\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Ala" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ma" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kota" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "removeStopWords :: [Text] -> [Text]\n", + "removeStopWords = filter (not . isStopWord)\n", + "\n", + "removeStopWords $ tokenize $ Prelude.head collectionD " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Pytanie**: Jakim zapytaniom usuwanie _stop words_ może szkodzić? Podać przykłady dla języka polskiego i angielskiego. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Normalizacja - różności\n", + "\n", + "W skład normalizacji może też wchodzić:\n", + "\n", + "* poprawianie błędów literowych\n", + "* sprowadzanie do małych liter (lower-casing czy raczej case-folding)\n", + "* usuwanie znaków diakrytycznych\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "żdźbło" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "toLower \"ŻDŹBŁO\"" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "źdźbło" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "toCaseFold \"ŹDŹBŁO\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Pytanie:** Kiedy _case-folding_ da inny wynik niż _lower-casing_? Jakie to ma praktyczne znaczenie?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Normalizacja jako całościowy proces\n", + "\n", + "Najważniejsza zasada: dokumenty w naszej kolekcji powinny być normalizowane w dokładnie taki sposób, jak zapytania.\n", + "\n", + "Efektem normalizacji jest zamiana dokumentu na ciąg _termów_ (ang. _terms_), czyli znormalizowanych wyrazów.\n", + "\n", + "Innymi słowy po normalizacji dokument $d_i$ traktujemy jako ciąg termów $t_i^1,\\dots,t_i^{|d_i|}$." + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "but" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "chyba" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "zgubić" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "normalize :: Text -> [Text]\n", + "normalize = removeStopWords . map toLower . lemmatize mockInflectionDictionary . tokenize\n", + "\n", + "normalize $ collectionD !! 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Zbiór wszystkich termów w kolekcji dokumentów nazywamy słownikiem (ang. _vocabulary_), nie mylić ze słownikiem jako strukturą danych w Pythonie (_dictionary_).\n", + "\n", + "$$V = \\bigcup_{i=1}^N \\{t_i^1,\\dots,t_i^{|d_i|}\\}$$\n", + "\n", + "(To zbiór, więc liczymy bez powtórzeń!)" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "fromList [\"ala\",\"but\",\"chyba\",\"kot\",\"mie\\263\",\"podobno\",\"ty\",\"zgubi\\263\"]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import Data.Set as Set hiding(map)\n", + "\n", + "getVocabulary :: [Text] -> Set Text \n", + "getVocabulary = Set.unions . map (Set.fromList . normalize) \n", + "\n", + "getVocabulary collectionD" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Jak wyszukiwarka może być szybka?\n", + "\n", + "_Odwrócony indeks_ (ang. _inverted index_) pozwala wyszukiwarce szybko szukać w milionach dokumentów. Odwrócoy indeks to prostu... indeks, jaki znamy z książek (mapowanie słów na numery stron/dokumentów).\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Use tuple-section
Found:
\\ t -> (t, ix)
Why Not:
(, ix)
" + ], + "text/plain": [ + "Line 4: Use tuple-section\n", + "Found:\n", + "\\ t -> (t, ix)\n", + "Why not:\n", + "(, ix)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "fromList [(\"chyba\",2),(\"kot\",2),(\"mie\\263\",2),(\"ty\",2)]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "collectionDNormalized = map normalize collectionD\n", + "\n", + "documentToPostings :: ([Text], Int) -> Set (Text, Int)\n", + "documentToPostings (d, ix) = Set.fromList $ map (\\t -> (t, ix)) d\n", + "\n", + "documentToPostings (collectionDNormalized !! 2, 2) \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Use zipWith
Found:
map documentToPostings $ zip coll [0 .. ]
Why Not:
zipWith (curry documentToPostings) coll [0 .. ]
" + ], + "text/plain": [ + "Line 2: Use zipWith\n", + "Found:\n", + "map documentToPostings $ zip coll [0 .. ]\n", + "Why not:\n", + "zipWith (curry documentToPostings) coll [0 .. ]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "fromList [(\"ala\",0),(\"but\",1),(\"but\",3),(\"chyba\",2),(\"chyba\",3),(\"kot\",0),(\"kot\",1),(\"kot\",2),(\"mie\\263\",0),(\"mie\\263\",2),(\"podobno\",1),(\"ty\",2),(\"zgubi\\263\",3)]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "collectionToPostings :: [[Text]] -> Set (Text, Int)\n", + "collectionToPostings coll = Set.unions $ map documentToPostings $ zip coll [0..]\n", + "\n", + "collectionToPostings collectionDNormalized" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Eta reduce
Found:
updateInvertedIndex (t, ix) invIndex\n", + " = insertWith (++) t [ix] invIndex
Why Not:
updateInvertedIndex (t, ix) = insertWith (++) t [ix]
" + ], + "text/plain": [ + "Line 2: Eta reduce\n", + "Found:\n", + "updateInvertedIndex (t, ix) invIndex\n", + " = insertWith (++) t [ix] invIndex\n", + "Why not:\n", + "updateInvertedIndex (t, ix) = insertWith (++) t [ix]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "fromList [(\"ala\",[0]),(\"but\",[1,3]),(\"chyba\",[2,3]),(\"kot\",[0,1,2]),(\"mie\\263\",[0,2]),(\"podobno\",[1]),(\"ty\",[2]),(\"zgubi\\263\",[3])]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "updateInvertedIndex :: (Text, Int) -> Map Text [Int] -> Map Text [Int]\n", + "updateInvertedIndex (t, ix) invIndex = insertWith (++) t [ix] invIndex\n", + "\n", + "getInvertedIndex :: [[Text]] -> Map Text [Int]\n", + "getInvertedIndex = Prelude.foldr updateInvertedIndex Map.empty . Set.toList . collectionToPostings\n", + "\n", + "getInvertedIndex collectionDNormalized" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Relewantność\n", + "\n", + "Potrafimy szybko przeszukiwać znormalizowane dokumenty, ale które dokumenty są ważne (_relewantne_) względem potrzeby informacyjnej użytkownika?\n", + "\n", + "### Zapytania boole'owskie\n", + "\n", + "* `pizzeria Poznań dowóz` to `pizzeria AND Poznań AND dowóz` czy `pizzera OR POZNAŃ OR dowóz`\n", + "* `(pizzeria OR pizza OR tratoria) AND Poznań AND dowóz\n", + "* `pizzeria AND Poznań AND dowóz AND NOT golonka`\n", + "\n", + "Jak domyślnie interpretować zapytanie?\n", + "\n", + "* jako zapytanie AND -- być może za mało dokumentów\n", + "* rozwiązanie pośrednie?\n", + "* jako zapytanie OR -- być może za dużo dokumentów\n", + "\n", + "Możemy jakieś miary dopasowania dokumentu do zapytania, żeby móc posortować dokumenty...\n", + "\n", + "### Mierzenie dopasowania dokumentu do zapytania\n", + "\n", + "Potrzebujemy jakieś funkcji $\\sigma : Q x D \\rightarrow \\mathbb{R}$. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Musimy jakoś zamienić dokumenty na liczby, tj. dokumenty na wektory liczb, a całą kolekcję na macierz.\n", + "\n", + "Po pierwsze ponumerujmy wszystkie termy ze słownika." + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "fromList [(0,\"ala\"),(1,\"but\"),(2,\"chyba\"),(3,\"kot\"),(4,\"mie\\263\"),(5,\"podobno\"),(6,\"ty\"),(7,\"zgubi\\263\")]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "fromList [(\"ala\",0),(\"but\",1),(\"chyba\",2),(\"kot\",3),(\"mie\\263\",4),(\"podobno\",5),(\"ty\",6),(\"zgubi\\263\",7)]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ala" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "2" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "voc = getVocabulary collectionD\n", + "\n", + "vocD :: Map Int Text\n", + "vocD = Map.fromList $ zip [0..] $ Set.toList voc\n", + "\n", + "invvocD :: Map Text Int\n", + "invvocD = Map.fromList $ zip (Set.toList voc) [0..]\n", + "\n", + "vocD\n", + "\n", + "invvocD\n", + "\n", + "vocD ! 0\n", + "invvocD ! \"chyba\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Napiszmy funkcję, która _wektoryzuje_ znormalizowany dokument.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Redundant $
Found:
map (\\ i -> count (v ! i) doc) $ [0 .. (vecSize - 1)]
Why Not:
map (\\ i -> count (v ! i) doc) [0 .. (vecSize - 1)]
Redundant bracket
Found:
(collectionDNormalized !! 2)
Why Not:
collectionDNormalized !! 2
" + ], + "text/plain": [ + "Line 2: Redundant $\n", + "Found:\n", + "map (\\ i -> count (v ! i) doc) $ [0 .. (vecSize - 1)]\n", + "Why not:\n", + "map (\\ i -> count (v ! i) doc) [0 .. (vecSize - 1)]Line 9: Redundant bracket\n", + "Found:\n", + "(collectionDNormalized !! 2)\n", + "Why not:\n", + "collectionDNormalized !! 2" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "ty" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "chyba" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "mieć" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "kot" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "[0.0,0.0,1.0,1.0,1.0,0.0,1.0,0.0]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "vectorize :: Int -> Map Int Text -> [Text] -> [Double]\n", + "vectorize vecSize v doc = map (\\i -> count (v ! i) doc) $ [0..(vecSize-1)]\n", + " where count t doc \n", + " | t `elem` doc = 1.0\n", + " | otherwise = 0.0\n", + " \n", + "vocSize = Set.size voc\n", + "\n", + "(collectionDNormalized !! 2)\n", + "vectorize vocSize vocD (collectionDNormalized !! 2)\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " ![image](./macierz.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Jak inaczej uwzględnić częstość wyrazów?\n", + "\n", + "
\n", + " $\n", + " \\newcommand{\\idf}{\\mathop{\\rm idf}\\nolimits}\n", + " \\newcommand{\\tf}{\\mathop{\\rm tf}\\nolimits}\n", + " \\newcommand{\\df}{\\mathop{\\rm df}\\nolimits}\n", + " \\newcommand{\\tfidf}{\\mathop{\\rm tfidf}\\nolimits}\n", + " $\n", + "
\n", + "\n", + "* $\\tf_{t,d}$\n", + "\n", + "* $1+\\log(\\tf_{t,d})$\n", + "\n", + "* $0.5 + \\frac{0.5 \\times \\tf_{t,d}}{max_t(\\tf_{t,d})}$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " $\n", + " \\newcommand{\\idf}{\\mathop{\\rm idf}\\nolimits}\n", + " \\newcommand{\\tf}{\\mathop{\\rm tf}\\nolimits}\n", + " \\newcommand{\\df}{\\mathop{\\rm df}\\nolimits}\n", + " \\newcommand{\\tfidf}{\\mathop{\\rm tfidf}\\nolimits}\n", + " $\n", + "
\n", + "\n", + "### Odwrotna częstość dokumentowa\n", + "\n", + "Czy wszystkie wyrazy są tak samo ważne?\n", + "\n", + "**NIE.** Wyrazy pojawiające się w wielu dokumentach są mniej ważne.\n", + "\n", + "Aby to uwzględnić, przemnażamy frekwencję wyrazu przez _odwrotną\n", + " częstość w dokumentach_ (_inverse document frequency_):\n", + "\n", + "$$\\idf_t = \\log \\frac{N}{\\df_t},$$\n", + "\n", + "gdzie:\n", + "\n", + "* $\\idf_t$ - odwrotna częstość wyrazu $t$ w dokumentach\n", + "\n", + "* $N$ - liczba dokumentów w kolekcji\n", + "\n", + "* $\\df_f$ - w ilu dokumentach wystąpił wyraz $t$?\n", + "\n", + "#### Dlaczego idf?\n", + "\n", + "term $t$ wystąpił...\n", + "\n", + "* w 1 dokumencie, $\\idf_t = \\log N/1 = \\log N$\n", + "* 2 razy w kolekcji, $\\idf_t = \\log N/2$ lub $\\log N$\n", + "* 3 razy w kolekcji, $\\idf_t = \\log N/(N/2) = \\log 2$\n", + "* we wszystkich dokumentach, $\\idf_t = \\log N/N = \\log 1 = 0$\n", + "\n", + "#### Co z tego wynika?\n", + "\n", + "Zamiast $\\tf_{t,d}$ będziemy w wektorach rozpatrywać wartości:\n", + "\n", + "$$\\tfidf_{t,d} = \\tf_{t,d} \\times \\idf_{t}$$\n", + "\n", + "Teraz zdefiniujemy _overlap score measure_:\n", + "\n", + "$$\\sigma(q,d) = \\sum_{t \\in q} \\tfidf_{t,d}$$\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Haskell", + "language": "haskell", + "name": "haskell" + }, + "language_info": { + "codemirror_mode": "ihaskell", + "file_extension": ".hs", + "mimetype": "text/x-haskell", + "name": "haskell", + "pygments_lexer": "Haskell", + "version": "8.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/wyk/macierz.png b/wyk/macierz.png new file mode 100644 index 0000000..e0a1012 Binary files /dev/null and b/wyk/macierz.png differ