aitech-eks-pub/wyk/07_Naiwny_klasyfikator_bayesowski.ipynb
2021-09-27 07:57:37 +02:00

392 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"id": "45264aad",
"metadata": {},
"source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Ekstrakcja informacji </h1>\n",
"<h2> 7. <i>Naiwny klasyfikator bayesowski w ekstrakcji informacji</i> [wykład]</h2> \n",
"<h3> Filip Graliński (2021)</h3>\n",
"</div>\n",
"\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
]
},
{
"cell_type": "markdown",
"id": "moderate-array",
"metadata": {},
"source": [
"# Klasyfikacja binarna dla tekstu\n",
"\n",
"Zakładamy, że mamy dwie klasy: $c$ i jej dopełnienie ($\\bar{c}$).\n",
"\n",
"Typowym przykładem jest zadanie klasyfikacji mejla, czy należy do spamu, czy nie (_spam_ vs _ham_), czyli innymi słowy filtr antyspamowy."
]
},
{
"cell_type": "markdown",
"id": "correct-victory",
"metadata": {},
"source": [
"**Pytanie**: Czy można wyobrazić sobie zadanie klasyfikacji mejli, niebędące zadaniem klasyfikacji binarnej?"
]
},
{
"cell_type": "markdown",
"id": "spiritual-diploma",
"metadata": {},
"source": [
"Zakładamy paradygmat uczenia nadzorowanego, tzn. dysponujemy zbiorem uczącym.\n",
"\n",
"**Pytanie**: Czym jest i w jaki sposób powstaje zbiór uczący dla filtru antyspamowego?"
]
},
{
"cell_type": "markdown",
"id": "secure-performance",
"metadata": {},
"source": [
"## Klasyfikacja regułowa\n",
"\n",
"Filtr anyspamowe _można_ zrealizować za pomocą metod innych niż opartych na uczeniu maszynowym. Można np. tworzyć reguły (np. wyrażenia regularne). Przykładem są (barokowe...) reguły w programie SpamAssassin, zob. fragment [pliku reguł](https://github.com/apache/spamassassin/blob/trunk/rules/20_advance_fee.cf):\n",
"\n",
"```\n",
"header __FRAUD_VQE\tSubject =~ /^(?:Re:|\\[.{1,10}\\])?\\s*(?:very )?urgent\\s+(?:(?:and|&)\\s+)?(?:confidential|assistance|business|attention|reply|response|help)\\b/i\n",
"\n",
"body __FRAUD_DBI\t/(?:\\bdollars?\\b|\\busd(?:ollars)?(?:[0-9]|\\b)|\\bus\\$|\\$[0-9,.]{6,}|\\$[0-9].{0,8}[mb]illion|\\$[0-9.,]{2,10} ?m|\\beuros?\\b|u[.]?s[.]? [0-9.]+ m)/i\n",
"body __FRAUD_KJV\t/(?:claim|concerning) (?:the|this) money/i\n",
"body __FRAUD_IRJ\t/(?:finance|holding|securit(?:ies|y)) (?:company|firm|storage house)/i\n",
"body __FRAUD_NEB\t/(?:government|bank) of nigeria/i\n",
"body __FRAUD_XJR\t/(?:who was a|as a|an? honest|you being a|to any) foreigner/i\n",
"```\n",
"\n",
"**Pytanie:** Jakie są wady i zalety regułowych filtrów antyspamowych?\n",
"\n",
"Współcześnie zdecydowanie dominuje użycie metod statystycznych (opartych na nadzorowanym uczeniu maszynowym). Do popularności tych metod przyczynił się artykuł [Plan for spam](http://www.paulgraham.com/spam.html) autorstwa Paula Grahama."
]
},
{
"cell_type": "markdown",
"id": "indoor-ending",
"metadata": {},
"source": [
"## Podejście generatywne i dyskryminatywne\n",
"\n",
"W klasyfikacji (i w ogóle w uczeniu nadzorowanym) można wskazać dwa podejścia:\n",
"\n",
"* generatywne - wymyślamy pewną \"historyjkę\", w jaki sposób powstaje tekst, \"historyjka\" powinna mieć miejsca do wypełnienia (parametry), np. częstości wyrazów, na podstawie zbioru uczącego dobieramy wartości parametrów (przez rachunki wprost); \"historyjka\" nie musi być prawdziwa, wystarczy, że jakoś przybliża rzeczywistość\n",
"\n",
"* dyskryminatywne - nie zastanawiamy się, w jaki sposób powstają teksty, po prostu \"na siłę\" dobieramy wartości parametrów (wag) modelu, tak aby uzyskać jak najmniejszą wartość funkcji kosztu na zbiorze uczącym; zwykle odbywa się to w iteracyjnym procesie (tak jak przedstawiono na schemacie na poprzednim wykładzie).\n",
"\n",
"**Pytanie**: Jakie są wady i zalety obu podejść?"
]
},
{
"cell_type": "markdown",
"id": "pleased-clinic",
"metadata": {},
"source": [
"## Nasz \"dyżurny\" przykład\n",
"\n",
"Zakładamy, że nasz zbiór uczący ($X$) składa się z 4 dokumentów:\n",
"\n",
"* $x_1=\\mathit{kup\\ pan\\ Viagrę}$\n",
"* $x_2=\\mathit{tanie\\ miejsce\\ dla\\ pana}$\n",
"* $x_3=\\mathit{viagra\\ viagra\\ viagra}$\n",
"* $x_4=\\mathit{kup\\ tanie\\ cartridge'e}$\n",
"\n",
"z następującymi etykietami:\n",
"\n",
"* $y_1=c$ (spam)\n",
"* $y_2=\\bar{c}$ (nie-spam)\n",
"* $y_3=c$\n",
"* $y_4=c$\n",
"\n",
"Zakładamy, że dokumenty podlegają lematyzacji i sprowadzeniu do mały liter, więc ostatecznie będziemy mieli następujące ciąg termów:\n",
"\n",
"* $x_1=(\\mathit{kupić}, \\mathit{pan}, \\mathit{viagra})$\n",
"* $x_2=(\\mathit{tani}, \\mathit{miejsce}, \\mathit{dla}, \\mathit{pan})$\n",
"* $x_3=(\\mathit{viagra}, \\mathit{viagra}, \\mathit{viagra})$\n",
"* $x_4=(\\mathit{kupić}, \\mathit{tani}, \\mathit{cartridge})$\n",
"\n",
"$P(tani|c) = (1+1)/(9+7) = 2/16 = 0.125$\n",
"$P(viagra|c) = \\frac{4+1}{9 + 7} = 5/16 = 0.3125 $\n",
"$P(dla|c) = \\frac{0+1}{9+7} = 1/16 = 0.0625$\n",
"$P(pan|c) = (1+1)/(9+7) = 2/16 = 0.125 $\n",
"$P(c) = 0.75$\n",
"\n",
"w wersji wielomianowej: $P(c)P(tani|c)P(tani|c)P(viagra|c)P(dla|c)P(pan|c) = 0.75 * 0.125 * 0.125 * 0.3125 * 0.0625 * 0.125= 0.0002861$\n",
"\n",
"w werjis Bernoulliego: $P(c)P(U_{dla}=1|c)P(U_{cartridge}=0|c)P(U_{viagra}=1|c)P(U_{pan}=1|c)P(U_{tani}=1|c)P(U_{miejsce}=0|c)P(U_{kup}=0|c)$\n",
"\n",
"$P(tani|\\bar{c}) = (1+1)/(4+7) = 2/11 =0.182 $\n",
"$P(viagra|\\bar{c}) = 1/11 = 0.091 $\n",
"$P(dla|\\bar{c}) = 2/11 = 0.182 $\n",
"$P(pan|\\bar{c}) = 2/11 = 0.182 $\n",
"$P(\\bar{c}) = 0.25$\n",
"\n",
"$P(\\bar{c})P(tani|\\bar{c})P(tani|\\bar{c})P(dla|\\bar{c})P(pan|\\bar{c}) = 0.25 * 0.182 * 0.182 * 0.091 * 0.182 * 0.182 = 0.00002496$\n",
"\n",
"\n",
"\n",
"Uczymy na tym zbiorze klasyfikator, który będziemy testować na dokumencie $d=\\mathit{tania\\ tania\\ viagra\\ dla\\ pana}$, tj. po normalizacji\n",
"$d=(\\mathit{tani}, \\mathit{tani}, \\mathit{viagra}, \\mathit{dla}, \\mathit{pan})$.\n",
"\n",
"**Uwaga:** Przykład jest oczywiście nierealistyczny i trudno będzie nam ocenić sensowność odpowiedzi. Za to będziemy w stanie policzyć ręcznie wynik.\n"
]
},
{
"cell_type": "markdown",
"id": "partial-military",
"metadata": {},
"source": [
"## Naiwny klasyfikator bayesowski\n",
"\n",
"* _naiwny_ - niekoniecznie oznacza, że to \"głupi\", bezużyteczny klasyfikator\n",
"* _klasyfikator_ \n",
"* _bayesowski_ - będzie odwoływać się do wzoru Bayesa.\n",
"\n",
"Naiwny klasyfikator bayesowski raczej nie powinien być stosowany \"produkcyjnie\" (są lepsze metody). Natomiast jest to metoda bardzo prosta w implementacji dająca przyzwoity _baseline_.\n",
"\n",
"Naiwny klasyfikator bayesowski ma dwie odmiany:\n",
"\n",
"* wielomianową,\n",
"* Bernoulliego.\n",
"\n",
"Wielomianowy naiwny klasyfikator bayesowski jest częściej spotykany i od niego zaczniemy."
]
},
{
"cell_type": "markdown",
"id": "colonial-creature",
"metadata": {},
"source": [
"Mamy dokument $d$ i dwie klasy $c$ i $\\bar{c}$. Policzymy prawdopodobieństwa $P(c|d)$ (mamy dokument $d$, jakie jest prawdopodobieństwo, że to klasa $c$) i $P(\\bar{c}|d)$. A właściwie będziemy te prawdopodobieństwa porównywać.\n",
"\n",
"**Uwaga**: nasz zapis to skrót notacyjny, właściwie powinniśmy podać zmienne losowe $P(C=c|D=d)$, ale zazwyczaj będziemy je pomijać. \n",
"\n",
"**Pytanie**: kiedy ostatecznie nasz klasyfikator zwróci informację, że klasa $c$, a kiedy że $\\bar{c}$? czy użytkownika interesują prawdopodobieństwa $P(c|d)$ i $P(\\bar{c}|d)$?"
]
},
{
"cell_type": "markdown",
"id": "governing-fiction",
"metadata": {},
"source": [
"Zastosujmy najpierw wzór Bayesa.\n",
"\n",
"$P(c|d) = \\frac{P(d|c) P(c)}{P(d)}$"
]
},
{
"cell_type": "markdown",
"id": "northern-spine",
"metadata": {},
"source": [
"$P(\\bar{c}|d) = \\frac{P(d|\\bar{c}) P(\\bar{c})}{P(d)}$"
]
},
{
"cell_type": "markdown",
"id": "utility-induction",
"metadata": {},
"source": [
"(Oczywiście skądinąd $P(\\bar{c}|d) = 1 - P(c|d)$, ale nie będziemy teraz tego wykorzystywali.)"
]
},
{
"cell_type": "markdown",
"id": "timely-force",
"metadata": {},
"source": [
"Co możemy pominąć, jeśli tylko porównujemy $P(c|d)$ i $P(\\bar{c}|d)$?\n",
"\n",
"Użyjmy znaku proporcjonalności $\\propto$:\n",
"\n",
"$P(c|d) = \\frac{P(d|c) P(c)}{P(d)} \\propto P(d|c) P(c)$\n",
"\n",
"$P(\\bar{c}|d) = \\frac{P(d|\\bar{c}) P(\\bar{c})}{P(d)} \\propto P(d|\\bar{c}) P(\\bar{c})$\n",
"\n",
"**Pytanie:** czy iloczyn $P(d|c)P(c)$ można interpretować jako prawdopodobieństwo?"
]
},
{
"cell_type": "markdown",
"id": "embedded-involvement",
"metadata": {},
"source": [
"#### Prawdopodobieństwo _a priori_\n",
"\n",
"$P(c)$ - prawdopodobieństwo a priori klasy $c$\n",
"\n",
"$\\hat{P}(c) = \\frac{N_c}{N}$\n",
"\n",
"gdzie\n",
"\n",
"* N - liczba wszystkich dokumentów w zbiorze uczącym\n",
"* N_c - liczba dokumentow w zbiorze uczącym z klasą $c$\n",
"\n",
"$\\hat{P}(c) = 0,75$\n",
"\n",
"$\\hat{P}(\\bar{c}) = 0,25$\n"
]
},
{
"cell_type": "markdown",
"id": "virgin-premiere",
"metadata": {},
"source": [
"#### Prawdopodobieństwo _a posteriori_\n",
"\n",
"Jak interpretować $P(d|c)$?\n",
"\n",
"Wymyślmy sobie model generatywny, $P(d|c)$ będzie prawdopodobieństwem, że spamer (jeśli $c$ to spam) wygeneruje tekst.\n",
"\n",
"Załóżmy, że dokument $d$ to ciąg $n$ termów, $d = (t_1\\dots t_n)$. Na razie niewiele z tego wynika."
]
},
{
"cell_type": "markdown",
"id": "acting-zimbabwe",
"metadata": {},
"source": [
"$P(d|c) = P(t_1\\dots t_n|c)$\n",
"\n",
"Żeby pójść dalej musimy doszczegółowić nasz model generatywny. Przyjmijmy bardzo naiwny i niezgodny z rzeczywistością model spamera (i nie-spamera): spamer wyciąga wyrazy z worka i wrzuca je z powrotem (losowanie ze zwracaniem). Jedyne co odróżnia spamera i nie-spamera, to **prawdopodobieństwo wylosowania wyrazu** (np. spamer wylosuje słowo _Viagra_ z dość dużym prawdopodobieństwem, nie-spamer - z bardzo niskim).\n",
"\n",
"**Pytanie:** Ile może wynosić $P(\\mathit{Viagra}|c)$?\n",
"\n",
"Po przyjęciu takich \"naiwnych założeń\":\n",
"\n",
"$$P(d|c) = P(t_1\\dots t_n|c) \\approx P(t_1|c)\\dots P(t_n|c) = \\prod_i^n P(t_i|c)$$"
]
},
{
"cell_type": "markdown",
"id": "adjustable-disney",
"metadata": {},
"source": [
"Jak oszacować $\\hat{P}(t|c)$?\n",
"\n",
"$$\\hat{P}(t|c) = \\frac{\\#(t,c)}{\\sum_i^{|V|} \\#(t_i,c)} = \\frac{\\mathit{ile\\ razy\\ term\\ t\\ pojawił\\ się\\ w\\ dokumentach\\ klasy\\ c}}{liczba\\ wyrazów\\ w\\ klasie\\ c}$$"
]
},
{
"cell_type": "markdown",
"id": "associate-variance",
"metadata": {},
"source": [
"### Wygładzanie\n",
"\n",
"Mamy problem z zerowymi prawdopodobieństwami.\n",
"\n",
"Czy jeśli w naszym zbiorze uczącym spamerzy ani razu nie użyli słowa _wykładzina_, to $P(\\mathit{wykładzina}|c) = 0$?.\n",
"\n",
"Musimy zastosować wygładzanie (_smoothing_). Spróbujmy wymyślić wygładzanie wychodząc od zdroworozsądkowych aksjomatów.\n",
"\n",
"#### Aksjomaty wygładzania.\n",
"\n",
"Założmy, że mamy dyskretną przestrzeń probabilistyczną $\\Omega = \\{\\omega_1,\\dots,\\omega_m\\}$, zdarzenie $\\omega_i$ w naszym zbiorze uczącym wystąpiło $k_i$ razy. Wprost prawdopodobieństwa byśmy oszacowali tak: $P(\\omega_i) = \\frac{k_i}{\\sum_j^m k_j}$.\n",
"Szukamy zamiast tego funkcji wygładzającej $f(m, k, T)$ (innej niż $f(m, k, T) = \\frac{k}{T}$), która spełniałaby następujące aksjomaty:\n",
"\n",
"1. $f(m, k, T) \\in [0, 1]$\n",
"2. $f(m, k, T) \\in (0, 1)$ jeśli $m > 1$\n",
"3. $\\sum_i f(m, k_i, T) = 1$, jeśli $\\sum_i k_i = T$\n",
"4. $f(m, 0, 0) = \\frac{1}{m}$\n",
"5. $\\lim_{T \\to \\inf} f(m, k, T) = \\frac{k}{T}$\n",
"\n",
"\n",
"m=2, k1=2, k2=4, T=6, 2/6 => f(2, 2, 6) > 0.333, f(2, 4, 6) < 0.666 \n",
"\n",
"Jaka funkcja spełnia te aksjomaty?\n",
"\n",
"$$f(m, k, T) = \\frac{k+1}{T+m}$$\n",
"\n",
"Jest to wygładzanie +1, albo wygładzanie Laplace'a.\n",
"\n",
"**Pytanie:** Wymyślić jakiś inny przykład funkcji, która będzie spełniała aksjomaty.\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "complimentary-airplane",
"metadata": {},
"source": [
"Po zastosowaniu do naszego naiwnego klasyfikatora otrzymamy:\n",
" \n",
"$$\\hat{P}(t|c) = \\frac{\\#(t,c) + 1}{\\sum_i^{|V|} \\#(t_i,c) + |V|}$$"
]
},
{
"cell_type": "markdown",
"id": "comprehensive-junior",
"metadata": {},
"source": [
"### Metoda Bernoulliego"
]
},
{
"cell_type": "markdown",
"id": "vocational-spanish",
"metadata": {},
"source": [
"$$P(𝑑|𝑐) \\approx P(U=u_1|c)\\dots P(U=u_{|v|})$$, gdzie $u_i = 1$, $t_i$ pojawił się w dokumencie $d$, 0 - w przeciwnym razie\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "enabling-manitoba",
"metadata": {},
"source": [
"$\\hat{P}(U_{viagra}=1|c) = \\frac{\\#(viagra,N_c) + 1}{N_c + 2}$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bearing-execution",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"author": "Filip Graliński",
"email": "filipg@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"lang": "pl",
"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.9.6"
},
"subtitle": "7.Naiwny klasyfikator bayesowski w ekstrakcji informacji[wykład]",
"title": "Ekstrakcja informacji",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}