From 59edef32fa177ee9e41cbcb1b0d84dfa7107fe09 Mon Sep 17 00:00:00 2001 From: Filip Gralinski Date: Sat, 5 Mar 2022 14:20:23 +0100 Subject: [PATCH] Fix 02 --- wyk/02_Jezyki.org | 69 +++++++++++++------------ wyk/02_Jezyki/communication.drawio | 1 + wyk/02_Jezyki/communication.drawio.png | Bin 0 -> 10221 bytes 3 files changed, 37 insertions(+), 33 deletions(-) create mode 100644 wyk/02_Jezyki/communication.drawio create mode 100644 wyk/02_Jezyki/communication.drawio.png diff --git a/wyk/02_Jezyki.org b/wyk/02_Jezyki.org index 5a5cf76..4f981aa 100644 --- a/wyk/02_Jezyki.org +++ b/wyk/02_Jezyki.org @@ -2,7 +2,7 @@ Jakim rozkładom statystycznym podlegają języki? -** Język naturalny albo „Pan Tedeusz” w liczbach +** Język naturalny albo „Pan Tadeusz” w liczbach Przygotujmy najpierw „infrastrukturę” do /segmentacji/ tekstu na różnego rodzaju jednostki. Używać będziemy generatorów. @@ -58,7 +58,7 @@ Powrót pani Counter({' ': 63444, 'a': 30979, 'i': 29353, 'e': 25343, 'o': 23050, 'z': 22741, 'n': 15505, 'r': 15328, 's': 15255, 'w': 14625, 'c': 14153, 'y': 13732, 'k': 12362, 'd': 11465, '\r': 10851, '\n': 10851, 't': 10757, 'm': 10269, 'ł': 10059, ',': 9130, 'p': 8031, 'u': 7699, 'l': 6677, 'j': 6586, 'b': 5753, 'ę': 5534, 'ą': 4794, 'g': 4775, 'h': 3915, 'ż': 3334, 'ó': 3097, 'ś': 2524, '.': 2380, 'ć': 1956, ';': 1445, 'P': 1265, 'W': 1258, ':': 1152, '!': 1083, 'S': 1045, 'T': 971, 'I': 795, 'N': 793, 'Z': 785, 'J': 729, '—': 720, 'A': 698, 'K': 683, 'ń': 651, 'M': 585, 'B': 567, 'O': 567, 'C': 556, 'D': 552, '«': 540, '»': 538, 'R': 489, '?': 441, 'ź': 414, 'f': 386, 'G': 358, 'L': 316, 'H': 309, 'Ż': 219, 'U': 184, '…': 157, '*': 150, '(': 76, ')': 76, 'Ś': 71, 'F': 47, 'é': 43, '-': 33, 'Ł': 24, 'E': 23, '/': 19, 'Ó': 13, '8': 10, '9': 8, '2': 6, 'v': 5, 'Ź': 4, '1': 4, '3': 3, 'x': 3, 'V': 3, '7': 2, '4': 2, '5': 2, 'q': 2, 'æ': 2, 'à': 1, 'Ć': 1, '6': 1, '0': 1}) :end: -Napiszmy pomocniczą funkcję, która zwraca /listę frekwencyjną/. +Napiszmy pomocniczą funkcję, która zwraca *listę frekwencyjną*. #+RESULTS: :results: @@ -96,6 +96,8 @@ OrderedDict([(' ', 63444), ('a', 30979), ('i', 29353), ('e', 25343), ('o', 23050 freq = freq_list(g, top) plt.figure(figsize=(12, 3)) + plt.ylabel('liczba wystąpień') + plt.bar(freq.keys(), freq.values()) fname = f'{name}.png' @@ -108,11 +110,11 @@ OrderedDict([(' ', 63444), ('a', 30979), ('i', 29353), ('e', 25343), ('o', 23050 #+END_SRC #+RESULTS: -[[file:pt-chars.png]] +[[file:]] *** Słowa -Co rozumiemy pod pojęciem słowa czy wyrazu, nie jest oczywiste. W praktyce zależy to od wyboru /tokenizatora/. +Co rozumiemy pod pojęciem słowa czy wyrazu, nie jest oczywiste. W praktyce zależy to od wyboru *tokenizatora*. Załóżmy, że przez wyraz rozumieć będziemy nieprzerwany ciąg liter bądź cyfr (oraz gwiazdek — to za chwilę ułatwi nam analizę pewnego tekstu…). @@ -198,7 +200,7 @@ najpierw tylko do współrzędnej y. Z poprzedniego wykresu możemy odczytać, że ok. 2/3 wyrazów wystąpiło dokładnie 1 raz. Słowa występujące jeden raz w danym korpusie noszą -nazwę /hapax legomena/ (w liczbie pojedycznej /hapax legomenon/, ἅπαξ +nazwę /hapax legomena/ (w liczbie pojedynczej /hapax legomenon/, ἅπαξ λεγόμενον, „raz powiedziane”, żargonowo: „hapaks”). „Prawdziwe” hapax legomena, słowa, które wystąpiły tylko raz w /całym/ @@ -274,15 +276,16 @@ rozmiarze $n$. Na przykład /digramy/ (/bigramy/) to zbitki dwóch jednostek, np. liter albo wyrazów. -|$n$| | nazwa | -|---+---------+---------------+ +|$n$| $n$-gram| nazwa | +|---+---------+---------------| | 1 | 1-gram | unigram | | 2 | 2-gram | digram/bigram | | 3 | 3-gram | trigram | | 4 | 4-gram | tetragram | | 5 | 5-gram | pentagram | -**Pytanie** Jak nazywa się 6-gram? + +*Pytanie:* Jak nazywa się 6-gram? Jak widać, dla symetrii mówimy czasami o unigramach, jeśli operujemy po prostu na jednostkach, nie na ich podciągach. @@ -310,7 +313,7 @@ Statystyki, które policzyliśmy dla pojedynczych liter czy wyrazów możemy pow Zauważmy, że policzyliśmy wszystkie n-gramy, również częściowo pokrywające się. -Zawsze powinniśmy się upewnić, że jest jasne, czy chodzi o n-gramy znakowe czy wyrazowe +Zawsze powinniśmy się upewnić, czy jest jasne, czy chodzi o n-gramy znakowe czy wyrazowe *** 3-gramy znakowe @@ -341,7 +344,7 @@ jedną z największych zagadek historii (i lingwistyki). Sami zbadajmy statystyczne własności tekstu manuskryptu. Użyjmy transkrypcji Vnow, gdzie poszczególne znaki tajemniczego alfabetu zamienione na litery alfabetu łacińskiego, cyfry i gwiazdkę. Jak -transkrybować Manuskrypt, pozostaje sprawą dyskusyjną, natomiast wybór +transkrybować manuskrypt, pozostaje sprawą dyskusyjną, natomiast wybór takiego czy innego systemu transkrypcji nie powinien wpływać dramatycznie na analizę statystyczną. @@ -495,7 +498,7 @@ trypletu STOP (_ powyżej). Taka sekwencja to /gen/. *Entropia* ($E$) to miara nieuporządkowania, niepewności, niewiedzy. Im większa entropia, tym mniej wiemy. Pojęcie to pierwotnie wywodzi się z -termodynamiki, później znaleziono wiele zaskakujących zastosowań w +termodynamiki, później znaleziono wiele zaskakujących analogii i zastosowań w innych dyscyplinach nauki. *** Entropia w fizyce @@ -511,7 +514,7 @@ a uporządkowanie się zmniejszy. [[./02_Jezyki/gas-high-entropy.drawio.png]] -Innymi słowy, zwiększy się stopień uporządkowania układu, czyli właśnie entropia. +Innymi słowy, zwiększy się stopień nieuporządkowania układu, czyli właśnie entropia. *** II prawo termodynamiki @@ -539,6 +542,8 @@ losowania do odbiorcy $O$ używając zer i jedynek (bitów). Teorioinformacyjną entropię można zdefiniować jako średnią liczbę bitów wymaganych do przesłania komunikatu. +[[./02_Jezyki/communication.drawio.png]] + *** Obliczanie entropii — proste przykłady Załóżmy, że nadawca chce przekazać odbiorcy informację o wyniku rzutu monetą. @@ -546,13 +551,12 @@ Entropia wynosi wówczas rzecz jasna 1 — na jedno losowanie wystarczy jeden bi (informację o tym, że wypadł orzeł, możemy zakodować na przykład za pomocą zera, zaś to, że wypadła reszka — za pomocą jedynki). -Rozpatrzmy przypadek, gdy nadawca ośmiościenną kością. Aby przekazać +Rozpatrzmy przypadek, gdy nadawca rzuca ośmiościenną kością. Aby przekazać wynik, potrzebuje wówczas 3 bity (a więc entropia ośmiościennej kości -wynosi 3 bity). Przykładowe kodowanie może mieć następującą postać. +wynosi 3 bity). Przykładowe kodowanie może mieć następującą postać: -+-------+-----------+ | Wynik | Kodowanie | -+-------+-----------+ +|-------+-----------| | 1 | 001 | | 2 | 010 | | 3 | 011 | @@ -561,38 +565,34 @@ wynosi 3 bity). Przykładowe kodowanie może mieć następującą postać. | 6 | 110 | | 7 | 111 | | 8 | 000 | -+-------+-----------+ *** Obliczenie entropii — trudniejszy przykład Załóżmy, że $\Sigma = \{A, B, C, D\}$, natomiast poszczególne komunikaty -są losowane zgodnie z następujących rozkładem prawdopodobieństwa: +są losowane zgodnie z następującym rozkładem prawdopodobieństwa: $P(A)=1/2$, $P(B)=1/4$, $P(C)=1/8$, $P(D)=1/8$. Ile wynosi entropia w takim przypadku? Można by sądzić, że 2, skoro wystarczą 2 bity do przekazania wyniku losowania przy zastosowaniu następującego kodowania: -+-------+-----------+ | Wynik | Kodowanie | -+-------+-----------+ +|-------+-----------| | A | 00 | | B | 01 | | C | 10 | | D | 11 | -+-------+-----------+ Problem w tym, że w rzeczywistości nie jest to /optymalne/ kodowanie. Możemy sprytnie zmniejszyć średnią liczbę bitów wymaganych do przekazania losowego wyniku przypisując częstszym wynikom krótsze kody, rzadszym zaś — dłuższe. Oto takie optymalne kodowanie: -+-------+-----------+ | Wynik | Kodowanie | -+-------+-----------+ +|-------+-----------| | A | 0 | | B | 10 | | C | 110 | | D | 111 | -+-------+-----------+ + Używając takiego kodowanie średnio potrzebujemy: @@ -604,14 +604,12 @@ bita. Innymi słowy, entropia takiego źródła wynosi 1,75 bita. Można by sądzić, że da się stworzyć jeszcze krótsze kodowanie dla omawianego rozkładu nierównomiernego: -+-------+-----------+ | Wynik | Kodowanie | -+-------+-----------+ +|-------+-----------| | A | 0 | | B | 1 | | C | 01 | | D | 11 | -+-------+-----------+ Niestety, nie jest to właściwe rozwiązanie — kodowanie musi być jednoznaczne nie tylko dla pojedynczego komunikatu, lecz dla całej sekwencji. @@ -626,7 +624,7 @@ Na podstawie poprzedniego przykładu można dojść do intuicyjnego wniosku, że optymalny kod dla wyniku o prawdopodobieństwie $p$ ma długość $-\log_2(p)$, a zatem ogólnie entropia źródła o rozkładzie prawdopodobieństwa $\{p_1,\ldots,p_|\Sigma|\}$ wynosi: -$$E = -\Sum_{i=1}^{|\Sigma|} p_i\log_2(p_i)$$. +$$E = -\sum_{i=1}^{|\Sigma|} p_i\log_2(p_i)$$. Zauważmy, że jest to jeden z nielicznych przypadków, gdy w nauce naturalną podstawą logarytmu jest 2 zamiast… podstawy logarytmu naturalnego ($e$). @@ -636,7 +634,7 @@ Teoretycznie można mierzyć entropię używając logarytmu naturalnego niewiele to jednak zmienia i jest mniej poręczne i trudniejsze do interpretacji (przynajmniej w kontekście informatyki) niż operowanie na bitach. -**Pytanie** Ile wynosi entropia sześciennej kostki? Jak wygląda +**Pytanie** Ile wynosi entropia zwykłej sześciennej kostki? Jak wygląda optymalne kodowanie wyników rzutu taką kostką? *** Entropia dla próby Bernoulliego @@ -654,6 +652,8 @@ Wiemy już, że entropia dla rzutu monetą wynosi 1 bit. A jaki będzie wynik dl x = list(np.arange(0.001,1,0.001)) y = [binomial_entropy(x) for x in x] plt.figure().clear() + plt.xlabel('prawdopodobieństwo wylosowania orła') + plt.ylabel('entropia') plt.plot(x, y) fname = f'binomial-entropy.png' @@ -711,7 +711,7 @@ by policzyć liczbę wszystkich znaków… Przypomnijmy sobie jednak, że rozkład jednostek języka jest zawsze skrajnie nierównomierny! Jeśli uwzględnić ten nierównomierny rozkład znaków, można opracować o wiele efektywniejszy sposób zakodowania znaków składających się na „Pana Tadeusza” -(częste litery, np. „a” i „e” powinny mieć krótkie kody, a rzadkie, np. „ź” — dłuższe kody). +(częste litery, np. „a” i „e” powinny mieć krótkie kody, a rzadkie, np. „ź” — dłuższe). Policzmy entropię przy takim założeniu: @@ -733,6 +733,8 @@ Policzmy entropię przy takim założeniu: 4.938605272823633 :end: +(Jak dowiemy się na kolejnym wykładzie, zastosowaliśmy tutaj *unigramowy model języka*). + *** Ile wynosi entropia rękopisu Wojnicza? #+BEGIN_SRC python :session mysession :exports both :results raw drawer @@ -753,15 +755,16 @@ generowany przecież według rozkładu wielomianowego. Istnieją rzecz jasna pewne zależności między znakami, np. niemożliwe, żeby po „ń” wystąpiły litera „a” czy „e”. Na poziomie wyrazów zależności mogę mieć jeszcze bardziej skrajny charakter, np. po wyrazie „przede” prawie na -pewno wystąpi „wszystkim”, co oznacza w takiej sytuacji słowo +pewno wystąpi „wszystkim”, co oznacza, że w takiej sytuacji słowo „wszystkim” może zostać zakodowane za pomocą 0 (!) bitów. Można uwzględnić takie zależności i uzyskać jeszcze lepsze kodowanie, -a co za tym idzie lepsze oszacowanie entropii. +a co za tym idzie lepsze oszacowanie entropii. (Jak wkrótce się +dowiemy, oznacza to użycie digramowego, trigramowego, etc. modelu języka). *** Rozmiar skompresowanego pliku jako przybliżenie entropii -Cele algorytmów kompresji jest właściwie wyznaczanie efektywnych +Celem algorytmów kompresji jest właściwie wyznaczanie efektywnych sposobów kodowania danych. Możemy więc użyć rozmiaru skompresowanego pliku w bitach (po podzieleniu przez oryginalną długość) jako dobrego przybliżenia entropii. diff --git a/wyk/02_Jezyki/communication.drawio b/wyk/02_Jezyki/communication.drawio new file mode 100644 index 0000000..13aa4d0 --- /dev/null +++ b/wyk/02_Jezyki/communication.drawio @@ -0,0 +1 @@ +1VbbcpswEP0aHpMxEGznMbFzmTZtPc1Dk0cZrUGJ0LpC2JCvrwTC3OzcO9P6waM9klbsObtaOf4sya8kWcffkAJ3vBHNHX/ueN7piav/DVBUQOAFFRBJRivIbYBb9gQWHFk0YxTSzkKFyBVbd8EQhYBQdTAiJW67y1bIu6euSQQD4DYkfIj+YlTFFTr1Jg1+DSyK65Pd8Wk1k5B6sY0kjQnFbQvyLxx/JhFVNUryGXDDXc1Lte/ywOzuwyQI9ZoNX6X3O78fXS/phv3kIss2X7wj62VDeGYD/k4o2YbEfrMqaiL056/NMEv4WahQOv75BqRimqobsgS+wJQphkIvWaJSmLQWnHEWmQmFa43GKuHacPUQM8WZgNlOvJEG7SfpvZAfjNXdMagzDzABJQu9xG7wTizpRc/eNhr6Fopb8o0tRmzWRDvPDbF6YLl9A88nA55/0CVD+b8THfj/GNHBgOiDBK845GfmitBUgKB2OA85SVMWdvmTmAkKtEMc0MHV8SJtLVqCPbTUmAROFNt03e/jyp6wQKYPbtJ/2lNl0qM7xUyGYHe174yeo8B7wZEiMgI1cFRKtwv7/WqOB2o+EkGcWeBMDf6ISSbYIwkf2EBlo05ZL10hia2QUCsFck/pJIxS4+NcQsqeyLL0Z0RfmyDLsINzJ5g/Vz+2GdnNTQtoJ8jh7D1YbEejY7dun+/NkHoJrlYp/BXNpnuluLUmShVjhILwiwbtlVez5gbNRVYK9wBKFfZ9QDKFXVkhZ+rObD8OrHXfmpnn1nNpFLUhdKB3beO+9OD3fvVs46W0Om4WIJkmzmTUm24IzVNZis/waV8aVaW91MqHufPqRPnQtTsZFOoVCJDE9C8dY5EskQ9r9ON9rb7LdTov9FPM9reyaXZzKq0yp8qPT2h8bu+F4U6GjW/8OY1Pm80rsarS5qntX/wB \ No newline at end of file diff --git a/wyk/02_Jezyki/communication.drawio.png b/wyk/02_Jezyki/communication.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..3338d9e21e8a3af286b8805d603e331abd27dfcb GIT binary patch literal 10221 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