forked from pms/uczenie-maszynowe
1329 lines
107 KiB
Plaintext
1329 lines
107 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Uczenie maszynowe\n",
|
||
"# 5. Metody ewaluacji"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 5.1. Metodologia testowania"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"W uczeniu maszynowym bardzo ważna jest ewaluacja budowanego modelu. Dlatego dobrze jest podzielić posiadane dane na odrębne zbiory – osobny zbiór danych do uczenia i osobny do testowania. W niektórych przypadkach potrzeba będzie dodatkowo wyodrębnić tzw. zbiór walidacyjny."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Zbiór uczący a zbiór testowy"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"* Na zbiorze uczącym uczymy algorytmy, a na zbiorze testowym sprawdzamy ich poprawność.\n",
|
||
"* Zbiór uczący powinien być kilkukrotnie większy od testowego (np. 4:1, 9:1 itp.).\n",
|
||
"* Zbiór testowy często jest nieznany.\n",
|
||
"* Należy unikać mieszania danych testowych i uczących – nie wolno „zanieczyszczać” danych uczących danymi testowymi!"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Czasami potrzebujemy dobrać (hiper-)parametry modelu, np. $\\alpha$ – który zbiór wykorzystać do tego celu?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Zbiór walidacyjny"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"Do doboru parametrów najlepiej użyć jeszcze innego zbioru – jest to tzw. **zbiór walidacyjny**."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
" * Zbiór walidacyjny powinien mieć wielkość zbliżoną do wielkości zbioru testowego, czyli np. dane można podzielić na te trzy zbiory w proporcjach 3:1:1, 8:1:1 itp."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Walidacja krzyżowa"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"Którą część danych wydzielić jako zbiór walidacyjny tak, żeby było „najlepiej”?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
" * Niech każda partia danych pełni tę rolę naprzemiennie!"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"<img src=\"cv.png\" alt=\"Rys. 5.1. Walidacja krzyżowa\" style=\"width: 70%\"/>"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Walidacja krzyżowa\n",
|
||
"\n",
|
||
"* Podziel dane $D = \\left\\{ (x^{(1)}, y^{(1)}), \\ldots, (x^{(m)}, y^{(m)})\\right\\} $ na $N$ rozłącznych zbiorów $T_1,\\ldots,T_N$\n",
|
||
"* Dla $i=1,\\ldots,N$, wykonaj:\n",
|
||
" * Użyj $T_i$ do walidacji i zbiór $S_i$ do uczenia, gdzie $S_i = D \\smallsetminus T_i$. \n",
|
||
" * Zapisz model $\\theta_i$.\n",
|
||
"* Akumuluj wyniki dla modeli $\\theta_i$ dla zbiorów $T_i$.\n",
|
||
"* Ustalaj parametry uczenia na akumulowanych wynikach."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Walidacja krzyżowa – wskazówki\n",
|
||
"\n",
|
||
"* Zazwyczaj ustala się $N$ w przedziale od $4$ do $10$, tzw. $N$-krotna walidacja krzyżowa (*$N$-fold cross validation*). \n",
|
||
"* Zbiór $D$ warto zrandomizować przed podziałem.\n",
|
||
"* W jaki sposób akumulować wyniki dla wszystkich zbiórow $T_i$?\n",
|
||
"* Po ustaleniu parametrów dla każdego $T_i$, uczymy model na całych danych uczących z ustalonymi parametrami.\n",
|
||
"* Testujemy na zbiorze testowym (jeśli nim dysponujemy)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### _Leave-one-out_\n",
|
||
"\n",
|
||
"Jest to szczególny przypadek walidacji krzyżowej, w której $N = m$."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"* Jaki jest rozmiar pojedynczego zbioru $T_i$?\n",
|
||
"* Jakie są zalety i wady tej metody?\n",
|
||
"* Kiedy może być przydatna?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Metoda *leave-one-out* może się przydać w dwóch przypadkach:\n",
|
||
" * kiedy zbiór danych jest mały\n",
|
||
" * kiedy dokładność ewaluacji jest dla nas ważniejsza niż szybkość"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Zbiór walidujący a algorytmy optymalizacji\n",
|
||
"\n",
|
||
"* Gdy błąd rośnie na zbiorze uczącym, mamy źle dobrany parametr $\\alpha$. Należy go wtedy zmniejszyć.\n",
|
||
"* Gdy błąd zmniejsza się na zbiorze uczącym, ale rośnie na zbiorze walidującym, mamy do czynienia ze zjawiskiem **nadmiernego dopasowania** (*overfitting*).\n",
|
||
"* Należy wtedy przerwać optymalizację. Automatyzacja tego procesu to _early stopping_."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 5.2. Miary jakości"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Aby przeprowadzić ewaluację modelu, musimy wybrać **miarę** (**metrykę**), jakiej będziemy używać.\n",
|
||
"\n",
|
||
"Jakiej miary użyc najlepiej?\n",
|
||
" * To zależy od rodzaju zadania.\n",
|
||
" * Innych metryk używa się do regresji, a innych do klasyfikacji"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Metryki dla zadań regresji\n",
|
||
"\n",
|
||
"Dla zadań regresji możemy zastosować np.:\n",
|
||
" * błąd średniokwadratowy (*mean-square error*, MSE):\n",
|
||
" $$ \\mathrm{MSE} \\, = \\, \\frac{1}{m} \\sum_{i=1}^{m} \\left( \\hat{y}^{(i)} - y^{(i)} \\right)^2 $$\n",
|
||
" * pierwiastek z błędu średniokwadratowego (*root-mean-square error*, RMSE):\n",
|
||
" $$ \\mathrm{RMSE} \\, = \\, \\sqrt{ \\frac{1}{m} \\sum_{i=1}^{m} \\left( \\hat{y}^{(i)} - y^{(i)} \\right)^2 } $$\n",
|
||
" * średni błąd bezwzględny (*mean absolute error*, MAE):\n",
|
||
" $$ \\mathrm{MAE} \\, = \\, \\frac{1}{m} \\sum_{i=1}^{m} \\left| \\hat{y}^{(i)} - y^{(i)} \\right| $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"W powyższych wzorach $y^{(i)}$ oznacza **oczekiwaną** wartości zmiennej $y$ w $i$-tym przykładzie, a $\\hat{y}^{(i)}$ oznacza wartość zmiennej $y$ w $i$-tym przykładzie wyliczoną (**przewidzianą**) przez nasz model."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Metryki dla zadań klasyfikacji\n",
|
||
"\n",
|
||
"Aby przedstawić kilka najpopularniejszych metryk stosowanych dla zadań klasyfikacyjnych, posłużmy się następującym przykładem:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Przydatne importy\n",
|
||
"\n",
|
||
"import ipywidgets as widgets\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"import pandas\n",
|
||
"import random\n",
|
||
"import seaborn\n",
|
||
"\n",
|
||
"%matplotlib inline"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def powerme(x1,x2,n):\n",
|
||
" \"\"\"Funkcja, która generuje n potęg dla zmiennych x1 i x2 oraz ich iloczynów\"\"\"\n",
|
||
" X = []\n",
|
||
" for m in range(n+1):\n",
|
||
" for i in range(m+1):\n",
|
||
" X.append(np.multiply(np.power(x1,i),np.power(x2,(m-i))))\n",
|
||
" return np.hstack(X)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def plot_data_for_classification(X, Y, xlabel=None, ylabel=None, Y_predicted=[], highlight=None):\n",
|
||
" \"\"\"Wykres danych dla zadania klasyfikacji\"\"\"\n",
|
||
" fig = plt.figure(figsize=(16*.6, 9*.6))\n",
|
||
" ax = fig.add_subplot(111)\n",
|
||
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
|
||
" X = X.tolist()\n",
|
||
" Y = Y.tolist()\n",
|
||
" X1n = [x[1] for x, y in zip(X, Y) if y[0] == 0]\n",
|
||
" X1p = [x[1] for x, y in zip(X, Y) if y[0] == 1]\n",
|
||
" X2n = [x[2] for x, y in zip(X, Y) if y[0] == 0]\n",
|
||
" X2p = [x[2] for x, y in zip(X, Y) if y[0] == 1]\n",
|
||
" \n",
|
||
" if len(Y_predicted) > 0:\n",
|
||
" Y_predicted = Y_predicted.tolist()\n",
|
||
" X1tn = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 0]\n",
|
||
" X1fn = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 0]\n",
|
||
" X1tp = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 1]\n",
|
||
" X1fp = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 1]\n",
|
||
" X2tn = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 0]\n",
|
||
" X2fn = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 0]\n",
|
||
" X2tp = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 1]\n",
|
||
" X2fp = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 1]\n",
|
||
" \n",
|
||
" if highlight == 'tn':\n",
|
||
" ax.scatter(X1tn, X2tn, c='red', marker='x', s=100, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='gray', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='gray', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='gray', marker='x', s=50, label='Dane')\n",
|
||
" elif highlight == 'fn':\n",
|
||
" ax.scatter(X1tn, X2tn, c='gray', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='green', marker='o', s=100, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='gray', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='gray', marker='x', s=50, label='Dane')\n",
|
||
" elif highlight == 'tp':\n",
|
||
" ax.scatter(X1tn, X2tn, c='gray', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='gray', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='green', marker='o', s=100, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='gray', marker='x', s=50, label='Dane')\n",
|
||
" elif highlight == 'fp':\n",
|
||
" ax.scatter(X1tn, X2tn, c='gray', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='gray', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='gray', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='red', marker='x', s=100, label='Dane')\n",
|
||
" else:\n",
|
||
" ax.scatter(X1tn, X2tn, c='red', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='green', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='green', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='red', marker='x', s=50, label='Dane')\n",
|
||
"\n",
|
||
" else:\n",
|
||
" ax.scatter(X1n, X2n, c='r', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1p, X2p, c='g', marker='o', s=50, label='Dane')\n",
|
||
" \n",
|
||
" if xlabel:\n",
|
||
" ax.set_xlabel(xlabel)\n",
|
||
" if ylabel:\n",
|
||
" ax.set_ylabel(ylabel)\n",
|
||
" \n",
|
||
" ax.margins(.05, .05)\n",
|
||
" return fig"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Wczytanie danych\n",
|
||
"import pandas\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"alldata = pandas.read_csv('data-metrics.tsv', sep='\\t')\n",
|
||
"data = np.matrix(alldata)\n",
|
||
"\n",
|
||
"m, n_plus_1 = data.shape\n",
|
||
"n = n_plus_1 - 1\n",
|
||
"\n",
|
||
"X2 = powerme(data[:, 1], data[:, 2], n)\n",
|
||
"Y2 = np.matrix(data[:, 0]).reshape(m, 1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "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tUpr1qxRz549/dunT5+uyy+/XBkZGbriiiv06quvauvWrSotLQ16nAULFqimpsb/cPHhE7GueXGNsrLgRTgAAADQqqgKX/3791dCQoKqq6sDtldXVystLa3N5z700EO6//779eabb+qcc85ps+3QoUPVv39/7d27N+j+pKQk2e32gAcQs5oHr9JSaezYlkU4CGAAAABtiqrwZbPZNGrUKK1fv96/zev1av369crKymr1eQ888IDuvfdeFRcXa/To0e3+nC+++EIHDx7UoEGDuqXf6GbtrSXFWlPdx+ORnM7gVQ2bV0F0Ojn3AAAAbYiq8CVJ8+bN01NPPaVnnnlGu3bt0vXXX69jx45p5syZkqQZM2ZowYIF/va///3vdffdd2vFihU67bTTVFVVpaqqKh09elSSdPToUd1+++1699139dlnn2n9+vXKycnRGWecoUmTJoXlNaINRUVSRkbroywul29/UZG5/YpVNptUUCClpwevatgUwNLTfe1Y5wsAAHSnGPvSPerCV25urh566CHl5+dr5MiR2rFjh4qLi/1FOCorK3XgwAF/+8cff1wej0f/8R//oUGDBvkfDz30kCQpISFBH3zwgS6//HKlp6dr1qxZGjVqlDZs2KCkpKSwvEa0wuOR8vOliorgt7k13R5XUeFrF2W/jBErN1faubP1qoYOh29/bq65/QIAALEtBr90j7p1viIR63yZKNj8I4ej9e0AAACIPh6PL1hVVAT/bHf8Z7/0dN8XwSbegRMX63wBLeYZTZggbdpE8AIAAIglNptUUhK8uFfzL91LSqJm6gPhC9GneQDLziZ4ATBVbX2tqo9Wq7a+NtxdAYDYFYNfuhO+EJ0cDqmwMHBbYWFU/fIBiD4bKzdqWtE09V7UW2l/SFPvRb01rWiayirLwt01AIhNMfalO+EL0cnlkvLyArfl5bHWFICQeXzr4xq/crzWVayT1/BKkryGV+sq1umilRdp2XvLwtxDAIhRMfSlO+EL0af5fb5lZSz2CyCkNlZu1NzX58qQoQZvQ8C+Bm+DDBm64bUbGAEDgFCIoS/dCV+ILsGqGo4d2/J+4Cj8ZQQQuRaXL1aCNaHNNgnWBD387sMm9QgA4kSMfelO+EL08HgkpzP4fb7N7wd2OlnnC0C3qK2v1do9a1uMeDXX4G3Qmt1rKMIBAN0lBr90J3wheths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xw7NmjWrxb65c+eqf//+GjNmjFasWKG2BgTr6urkdrsDHgAAAIApcnN9I1qtVTV0OHz7c3PN7RfaFTUjX1VVVRo4cGDAtsTERPXr109VVVUdOsby5ct11llnaezYsQHbCwoK9K//+q/q1auX3nzzTd1www06evSofv3rXwc9zqJFi3TPPfd07YUA6ByPp+1v7drbDwBNeD9BLGnvWuVajkhhH/maP39+q0Uxmh67d+8+4Z9TW1ur559/Puio1913363s7Gydd955uvPOO3XHHXfowQcfbPVYCxYsUE1Njf/hYjIjEBpFRb772lv7HXO5fPuLisztF4Dow/sJgAgQ9oIb33zzjQ4ePNhmm6FDh+pPf/qTbr31Vv3jH//wb29oaFDPnj21evVqTZ06tc1jFBYWatasWfryyy81YMCANtu+9tpr+ulPf6rvv/9eSUlJ7b4GCm4AIcCEYgDdwePx/dna+4nHI1VX834CoFOituDGgAED2g1DkpSVlaXDhw9r27ZtGjVqlCTp7bffltfrVWZmZrvPX758uS6//PIO/awdO3aob9++HQpeAELEZvNNJG76QDRhwg8fmJqX2C0p4YMSgJaKin4oShDs/UTy/ffRo9LXX/N+AiDkwn7bYUedddZZmjx5smbPnq0tW7aorKxMN954o6ZPn+6vdPjll19q+PDh2rJlS8Bz9+7dq3feeUe/+tWvWhx33bp1+p//+R99+OGH2rt3rx5//HH993//t2666SZTXheANjRVbDp+zZJNm1qubdLahGMA8cvj8QWvigrfe4YU+H4ybpx04YW+//76a+n003k/ARByURO+JOm5557T8OHDNXHiRF122WUaN26cnnzySf/++vp67dmzR999913A81asWKFTTjlFl1xySYtj9ujRQ0uWLFFWVpZGjhypJ554QosXL9bChQtD/noAdEDzAJadTfAC0L6m0fPjv7yRfO8bQ4ZIlZXSV1/5tg0ZIv3tb7yfAAi5sM/5igXM+QJMsGmTL3g1KSuTmlUuBYAWmt+mXFgo/exnPwQvifcTAJ3W1c//UTXyBSBOuVxSXl7gtry81quWAUCTYKPnxwcvifcTAKYhfAGIbM2/tS4rC7yNiA9MANrjcPhGvI43eDDvJwBMR/gCELmaB6/SUt+tQc2LcPCBCUBbXC7pqqsCtyUmBi/qw/sJgBAifAGITB6P5HQGL67R/AOT0/nDWj4AcDyXS7r4Yl+BDck34tVUcCNYFUTeTwCEEOELQGSy2aSCAt+Cp8GqGjYFsPR0XzvW5QHQXNPo+f790sCBvnLy774rbdwYvAoi7ycAQoxqh92AaodACHk8bX8Qam8/gPjk8UgZGb51vppGz1NTf3i/OP625vR0aedO33beTwB0ANUOAcSm9j4I8UEJQDDBRs+Pf78INnrO+wmAEGPkqxsw8gUAQIRi9BxACDDyBQAA0Byj5wAiCOELAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAEKtvUV7WdQXAOIC4QsAgFAqKvKtN+VyBd/vcvn2FxWZ2y8AgOkIXwAAhIrHI+Xn+xb6nTChZQBrWui3osLXjhEwAIhphC8AAELFZpNKSqShQ6V9+wIDWFPw2rfPt7+khLLnABDjCF8AAISSwyGVlgYGsE2bAoNXaamvHQAgpiWGuwMAAMS8pgDWFLiys33bCV4AEFcY+QIAwAwOh1RYGLitsDC+ghdVHwHEOcIXAABmcLmkvLzAbXl5rVdBjDVUfQQAwhcAACHXvLhGWVnwIhyxiqqPACCJ8AUAQGg1D16lpdLYsS2LcMRyAKPqIwBIInwBABA6Ho/kdAavati8CqLTGdsjPlR9BADCFwAAIWOzSQUFUnp68GDRFEjS033tYn3Ep3kAy84meCE+UGwG/0T4AgAglHJzpZ07Ww8WDodvf26uuf0KF6o+It5QbAbHIXwBABBq7Y1oxfqI1/Hiveoj4kskFJth1C2iEL4AAIA54r3qI+JPuIvNMOoWcQhfAAAg9Kj6iHgVrmIzkTDqhhYIXwAAILSo+oh4F45iM+EedUNQhC8AABBaVH0EwlNshiUeIo7FMAwj3J2Idm63WykpKaqpqZHdbg93dwAAiEweT9vBqr39QDQ7frSpiVnhJ5w/O0Z19fM/I18AAKBzulo9jaqPiFfhLjbDEg8Rg/AFAAA6juppQOdEQrEZlniIGIQvAADQMVRPAzonEorNhHvUDQEIXwAAoGOongZ0TriLzUTCqBsCUHCjG1BwAwAQV5p/oCss9N3CRPU0ILhwFJvxeHy3AFdUBP+9PP73OD1d2rmTL0w6gYIbAADAHOFYswiIZuEoNhPuUTcExchXN2DkCwBgikgr1b5pky94NSkr893SBCByRNr7Roxg5AsAgFgWaVUGqZ4GRAeWeIgohC8AACJdpFUZpHoaAHRJ1ISv3/3udxo7dqx69eqlPn36dOg5hmEoPz9fgwYNUnJyspxOpz755JOANocOHdLVV18tu92uPn36aNasWTp69GgIXgEAAF0USVUGqZ4GAF0WNeHL4/HoZz/7ma6//voOP+eBBx7Qo48+qmXLlmnz5s066aSTNGnSJH3//ff+NldffbU++ugjvfXWW3r11Vf1zjvv6LrrrgvFSwAAoOuaF7mYMME356p5EAplsYtIWLMIAKJY1BXcePrpp3XzzTfr8OHDbbYzDEODBw/Wrbfeqttuu02SVFNTo9TUVD399NOaPn26du3apREjRmjr1q0aPXq0JKm4uFiXXXaZvvjiCw0ePDjosevq6lRXV+f/u9vtlsPhoOAGACD0jh95amJmlcGiIt+tjSUlwX+ey+ULXgUFUm5u6PsDAGFAwY1m9u/fr6qqKjmdTv+2lJQUZWZmqry8XJJUXl6uPn36+IOXJDmdTlmtVm3evLnVYy9atEgpKSn+h4OSugAAszgcvnW1jldYaF5599xc33pArf08h8O3n+AFAC3EbPiqqqqSJKWmpgZsT01N9e+rqqrSwIEDA/YnJiaqX79+/jbBLFiwQDU1Nf6Hi/vaAQBmiYQqg1RPA4AuCWv4mj9/viwWS5uP3bt3h7OLQSUlJclutwc8AAAIOaoMAkBUSwznD7/11lt17bXXttlm6NChXTp2WlqaJKm6ulqDBg3yb6+urtbIkSP9bb7++uuA5zU0NOjQoUP+5wMAEBGCVRlsKnLRtH3CBPPmfgEAOi2s4WvAgAEaMGBASI59+umnKy0tTevXr/eHLbfbrc2bN/srJmZlZenw4cPatm2bRo0aJUl6++235fV6lZmZGZJ+AQDQaR2pMtgUwJxO35wrbv0DgIgTNXO+KisrtWPHDlVWVqqxsVE7duzQjh07AtbkGj58uNasWSNJslgsuvnmm3XffffplVde0c6dOzVjxgwNHjxYV1xxhSTprLPO0uTJkzV79mxt2bJFZWVluvHGGzV9+vRWKx0CAGA6m81XPTA9PfjIVlMAS0/3tSN4AUBECuvIV2fk5+frmWee8f/9vPPOkyT99a9/1YQJEyRJe/bsUU1Njb/NHXfcoWPHjum6667T4cOHNW7cOBUXF6tnz57+Ns8995xuvPFGTZw4UVarVVdeeaUeffRRc14UAAAdlZsrTZ3aerBqqjJI8AKAiBV163xFoq7W+QcAAAAQfVjnCwAAAAAiGOELAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAAAAMAHhCwAAAABMQPgCAAAAABMQvgAAAADABIQvAAAAADAB4QsAAAAATJAY7g7EAsMwJElutzvMPQEAAAAQak2f+5tyQEcRvrrBkSNHJEkOhyPMPQEAAABgliNHjiglJaXD7S1GZ+MaWvB6vfrqq6908skny2KxhPRnud1uORwOuVwu2e32kP6seMe5Ng/n2jyca/Nwrs3F+TYP59o8nGvzdPZcG4ahI0eOaPDgwbJaOz6Ti5GvbmC1WnXKKaeY+jPtdju/hCbhXJuHc20ezrV5ONfm4nybh3NtHs61eTpzrjsz4tWEghsAAAAAYALCFwAAAACYgPAVZZKSkrRw4UIlJSWFuysxj3NtHs61eTjX5uFcm4vzbR7OtXk41+Yx61xTcAMAAAAATMDIFwAAAACYgPAFAAAAACYgfAEAAACACQhfAAAAAGACwhcAAAAAmIDwFWF+97vfaezYserVq5f69OnToecYhqH8/HwNGjRIycnJcjqd+uSTTwLaHDp0SFdffbXsdrv69OmjWbNm6ejRoyF4BdGls+fls88+k8ViCfpYvXq1v12w/atWrTLjJUWsrlyDEyZMaHEe58yZE9CmsrJSU6ZMUa9evTRw4EDdfvvtamhoCOVLiXidPdeHDh3STTfdpGHDhik5OVlDhgzRr3/9a9XU1AS047qWlixZotNOO009e/ZUZmamtmzZ0mb71atXa/jw4erZs6cyMjL0+uuvB+zvyPt3vOrMuX7qqad00UUXqW/fvurbt6+cTmeL9tdee22L63fy5MmhfhlRoTPn+umnn25xHnv27BnQhuu6dZ0518H+DbRYLJoyZYq/Ddd1cO+8847+/d//XYMHD5bFYtHLL7/c7nNKS0t1/vnnKykpSWeccYaefvrpFm06+29AUAYiSn5+vrF48WJj3rx5RkpKSoeec//99xspKSnGyy+/bPz97383Lr/8cuP00083amtr/W0mT55snHvuuca7775rbNiwwTjjjDOMq666KkSvInp09rw0NDQYBw4cCHjcc889Ru/evY0jR47420kyVq5cGdDu+P8f8agr1+DFF19szJ49O+A81tTU+Pc3NDQYZ599tuF0Oo3333/feP31143+/fsbCxYsCPXLiWidPdc7d+40pk2bZrzyyivG3r17jfXr1xtnnnmmceWVVwa0i/fretWqVYbNZjNWrFhhfPTRR8bs2bONPn36GNXV1UHbl5WVGQkJCcYDDzxgfPzxx8Zdd91l9OjRw9i5c6e/TUfev+NRZ8/1L37xC2PJkiXG+++/b+zatcu49tprjZSUFOOLL77wt7nmmmuMyZMnB1y/hw4dMuslRazOnuuVK1cadrs94DxWVVUFtOG6Dq6z5/rgwYMB5/nDDz80EhISjJUrV/rbcF0H9/rrrxv/+Z//abz00kuGJGPNmjVttt+3b5/Rq1cvY968ecbHH39sPPbYY0ZCQoJRXFzsb9PZ/3+tIXxFqJUrV3YofHm9XiMtLc148MEH/dsOHz5sJCUlGX/+858NwzCMjz/+2JBkbN261d/mjTfeMCwWi/Hll192e9+jRXedl5EjRxr/+3//74BtHflFjyddPdcXX3yx8Zvf/KbV/a+//rphtVoD/uF//PHHDbvdbtTV1XVL36NNd13XL7zwgmGz2Yz6+nr/tni/rseMGWPMnTvX//fGxkZj8ODBxqJFi4K2//nPf25MmTIlYFtmZqbxf/7P/zEMo2Pv3/Gqs+e6uYaGBuPkk082nnnmGf+2a665xsjJyenurka9zp7r9j6fcF237kSv64cfftg4+eSTjaNHj/q3cV23ryP/dt1xxx3GT37yk4Btubm5xqRJk/x/P9H/f0247TDK7d+/X1VVVXI6nf5tKSkpyszMVHl5uSSpvLxcffr00ejRo/1tnE6nrFarNm/ebHqfI0V3nJdt27Zpx44dmjVrVot9c+fOVf/+/TVmzBitWLFCRhyvZ34i5/q5555T//79dfbZZ2vBggX67rvvAo6bkZGh1NRU/7ZJkybJ7Xbro48+6v4XEgW66/e9pqZGdrtdiYmJAdvj9br2eDzatm1bwHut1WqV0+n0v9c2V15eHtBe8l2fTe078v4dj7pyrpv77rvvVF9fr379+gVsLy0t1cCBAzVs2DBdf/31OnjwYLf2Pdp09VwfPXpUp556qhwOh3JycgLeb7mug+uO63r58uWaPn26TjrppIDtXNcnrr336+74/9cksf0miGRVVVWSFPDhs+nvTfuqqqo0cODAgP2JiYnq16+fv0086o7zsnz5cp111lkaO3ZswPaCggL967/+q3r16qU333xTN9xwg44ePapf//rX3db/aNLVc/2LX/xCp556qgYPHqwPPvhAd955p/bs2aOXXnrJf9xg137TvnjUHdf1t99+q3vvvVfXXXddwPZ4vq6//fZbNTY2Br3edu/eHfQ5rV2fx783N21rrU086sq5bu7OO+/U4MGDAz4oTZ48WdOmTdPpp5+uTz/9VL/97W916aWXqry8XAkJCd36GqJFV871sGHDtGLFCp1zzjmqqanRQw89pLFjx+qjjz7SKaecwnXdihO9rrds2aIPP/xQy5cvD9jOdd09Wnu/drvdqq2t1T/+8Y8Tfl9qQvgywfz58/X73/++zTa7du3S8OHDTepRbOvo+T5RtbW1ev7553X33Xe32Hf8tvPOO0/Hjh3Tgw8+GHMfUkN9ro//8J+RkaFBgwZp4sSJ+vTTT/XjH/+4y8eNRmZd1263W1OmTNGIESP0X//1XwH74uW6RnS7//77tWrVKpWWlgYUgpg+fbr/vzMyMnTOOefoxz/+sUpLSzVx4sRwdDUqZWVlKSsry//3sWPH6qyzztITTzyhe++9N4w9i23Lly9XRkaGxowZE7Cd6zr6EL5McOutt+raa69ts83QoUO7dOy0tDRJUnV1tQYNGuTfXl1drZEjR/rbfP311wHPa2ho0KFDh/zPjyUdPd8nel5efPFFfffdd5oxY0a7bTMzM3Xvvfeqrq5OSUlJ7baPFmad6yaZmZmSpL179+rHP/6x0tLSWlQaqq6ulqSYu7bNONdHjhzR5MmTdfLJJ2vNmjXq0aNHm+1j9boOpn///kpISPBfX02qq6tbPa9paWlttu/I+3c86sq5bvLQQw/p/vvvV0lJic4555w22w4dOlT9+/fX3r174/ZD6omc6yY9evTQeeedp71790rium7NiZzrY8eOadWqVSooKGj353Bdd01r79d2u13JyclKSEg44d+VJsz5MsGAAQM0fPjwNh82m61Lxz799NOVlpam9evX+7e53W5t3rzZ/81UVlaWDh8+rG3btvnbvP322/J6vf4Ps7Gko+f7RM/L8uXLdfnll2vAgAHttt2xY4f69u0bcx9QzTrXTXbs2CFJ/n/Qs7KytHPnzoCw8dZbb8lut2vEiBHd8yIjRKjPtdvt1iWXXCKbzaZXXnmlRenoYGL1ug7GZrNp1KhRAe+1Xq9X69evDxgFOF5WVlZAe8l3fTa178j7dzzqyrmWpAceeED33nuviouLA+Y8tuaLL77QwYMHAwJCvOnquT5eY2Ojdu7c6T+PXNfBnci5Xr16terq6vTLX/6y3Z/Ddd017b1fd8fvil+nynMg5D7//HPj/fff95cvf//99433338/oIz5sGHDjJdeesn/9/vvv9/o06ePsXbtWuODDz4wcnJygpaaP++884zNmzcbGzduNM4880xKzRvtn5cvvvjCGDZsmLF58+aA533yySeGxWIx3njjjRbHfOWVV4ynnnrK2Llzp/HJJ58YS5cuNXr16mXk5+eH/PVEss6e67179xoFBQXGe++9Z+zfv99Yu3atMXToUGP8+PH+5zSVmr/kkkuMHTt2GMXFxcaAAQMoNd/Jc11TU2NkZmYaGRkZxt69ewNKFjc0NBiGwXVtGL4yw0lJScbTTz9tfPzxx8Z1111n9OnTx19tMy8vz5g/f76/fVlZmZGYmGg89NBDxq5du4yFCxcGLTXf3vt3POrsub7//vsNm81mvPjiiwHXb9O/nUeOHDFuu+02o7y83Ni/f79RUlJinH/++caZZ55pfP/992F5jZGis+f6nnvuMf7yl78Yn376qbFt2zZj+vTpRs+ePY2PPvrI34brOrjOnusm48aNM3Jzc1ts57pu3ZEjR/yfoSUZixcvNt5//33j888/NwzDMObPn2/k5eX52zeVmr/99tuNXbt2GUuWLAlaar6t/38dRfiKMNdcc40hqcXjr3/9q7+N/rnWThOv12vcfffdRmpqqpGUlGRMnDjR2LNnT8BxDx48aFx11VVG7969DbvdbsycOTMg0MWr9s7L/v37W5x/wzCMBQsWGA6Hw2hsbGxxzDfeeMMYOXKk0bt3b+Okk04yzj33XGPZsmVB28aTzp7ryspKY/z48Ua/fv2MpKQk44wzzjBuv/32gHW+DMMwPvvsM+PSSy81kpOTjf79+xu33nprQHn0eNTZc/3Xv/416PuOJGP//v2GYXBdN3nssceMIUOGGDabzRgzZozx7rvv+vddfPHFxjXXXBPQ/oUXXjDS09MNm81m/OQnPzFee+21gP0def+OV50516eeemrQ63fhwoWGYRjGd999Z1xyySXGgAEDjB49ehinnnqqMXv27E5/aIpVnTnXN998s79tamqqcdlllxnbt28POB7Xdes6+x6ye/duQ5Lx5ptvtjgW13XrWvt3ren8XnPNNcbFF1/c4jkjR440bDabMXTo0IDP2k3a+v/XURbDiJM6wQAAAAAQRsz5AgAAAAATEL4AAAAAwASELwAAAAAwAeELAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAAAAMAHhCwAAAABMQPgCAAAAABMQvgAA6IA///nPSk5O1oEDB/zbZs6cqXPOOUc1NTVh7BkAIFpYDMMwwt0JAAAinWEYGjlypMaPH6/HHntMCxcu1IoVK/Tuu+/qRz/6Ubi7BwCIAonh7gAAANHAYrHod7/7nf7jP/5DaWlpeuyxx7RhwwZ/8Jo6dapKS0s1ceJEvfjii2HuLQAgEjHyBQBAJ5x//vn66KOP9Oabb+riiy/2by8tLdWRI0f0zDPPEL4AAEEx5wsAgA4qLi7W7t271djYqNTU1IB9EyZM0MknnxymngEAogHhCwCADti+fbt+/vOfa/ny5Zo4caLuvvvucHcJABBlmPMFAEA7PvvsM02ZMkW//e1vddVVV2no0KHKysrS9u3bdf7554e7ewCAKMHIFwAAbTh06JAmT56snJwczZ8/X5KUmZmpSy+9VL/97W/D3DsAQDRh5AsAgDb069dPu3fvbrH9tddeC0NvAADRjGqHAAB0A6fTqb///e86duyY+vXrp9WrVysrKyvc3QIARBDCFwAAAACYgDlfAAAAAGACwhcAAAAAmIDwBQAAAAAmIHwBAAAAgAkIXwAAAABgAsIXAAAAAJiA8AUAAAAAJiB8AQAAAIAJCF8AAAAAYALCFwAAAACYgPAFAAAAACb4/xm/7/XuDz1BAAAAAElFTkSuQmCC",
|
||
"text/plain": [
|
||
"<Figure size 960x540 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"fig = plot_data_for_classification(X2, Y2, xlabel=r'$x_1$', ylabel=r'$x_2$')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def safeSigmoid(x, eps=0):\n",
|
||
" \"\"\"Funkcja sigmoidalna zmodyfikowana w taki sposób, \n",
|
||
" żeby wartości zawsze były odległe od asymptot o co najmniej eps\n",
|
||
" \"\"\"\n",
|
||
" y = 1.0/(1.0 + np.exp(-x))\n",
|
||
" if eps > 0:\n",
|
||
" y[y < eps] = eps\n",
|
||
" y[y > 1 - eps] = 1 - eps\n",
|
||
" return y\n",
|
||
"\n",
|
||
"def h(theta, X, eps=0.0):\n",
|
||
" \"\"\"Funkcja hipotezy (regresja logistyczna)\"\"\"\n",
|
||
" return safeSigmoid(X*theta, eps)\n",
|
||
"\n",
|
||
"def J(h,theta,X,y, lamb=0):\n",
|
||
" \"\"\"Funkcja kosztu dla regresji logistycznej\"\"\"\n",
|
||
" m = len(y)\n",
|
||
" f = h(theta, X, eps=10**-7)\n",
|
||
" j = -np.sum(np.multiply(y, np.log(f)) + \n",
|
||
" np.multiply(1 - y, np.log(1 - f)), axis=0)/m\n",
|
||
" if lamb > 0:\n",
|
||
" j += lamb/(2*m) * np.sum(np.power(theta[1:],2))\n",
|
||
" return j\n",
|
||
"\n",
|
||
"def dJ(h,theta,X,y,lamb=0):\n",
|
||
" \"\"\"Gradient funkcji kosztu\"\"\"\n",
|
||
" g = 1.0/y.shape[0]*(X.T*(h(theta,X)-y))\n",
|
||
" if lamb > 0:\n",
|
||
" g[1:] += lamb/float(y.shape[0]) * theta[1:] \n",
|
||
" return g\n",
|
||
"\n",
|
||
"def classifyBi(theta, X):\n",
|
||
" \"\"\"Funkcja predykcji - klasyfikacja dwuklasowa\"\"\"\n",
|
||
" prob = h(theta, X)\n",
|
||
" return prob"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def GD(h, fJ, fdJ, theta, X, y, alpha=0.01, eps=10**-3, maxSteps=10000):\n",
|
||
" \"\"\"Metoda gradientu prostego dla regresji logistycznej\"\"\"\n",
|
||
" errorCurr = fJ(h, theta, X, y)\n",
|
||
" errors = [[errorCurr, theta]]\n",
|
||
" while True:\n",
|
||
" # oblicz nowe theta\n",
|
||
" theta = theta - alpha * fdJ(h, theta, X, y)\n",
|
||
" # raportuj poziom błędu\n",
|
||
" errorCurr, errorPrev = fJ(h, theta, X, y), errorCurr\n",
|
||
" # kryteria stopu\n",
|
||
" if abs(errorPrev - errorCurr) <= eps:\n",
|
||
" break\n",
|
||
" if len(errors) > maxSteps:\n",
|
||
" break\n",
|
||
" errors.append([errorCurr, theta]) \n",
|
||
" return theta, errors"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"theta = [[ 1.37136167]\n",
|
||
" [ 0.90128948]\n",
|
||
" [ 0.54708112]\n",
|
||
" [-5.9929264 ]\n",
|
||
" [ 2.64435168]\n",
|
||
" [-4.27978238]]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Uruchomienie metody gradientu prostego dla regresji logistycznej\n",
|
||
"theta_start = np.matrix(np.zeros(X2.shape[1])).reshape(X2.shape[1],1)\n",
|
||
"theta, errors = GD(h, J, dJ, theta_start, X2, Y2, \n",
|
||
" alpha=0.1, eps=10**-7, maxSteps=10000)\n",
|
||
"print('theta = {}'.format(theta))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def plot_decision_boundary(fig, theta, X):\n",
|
||
" \"\"\"Wykres granicy klas\"\"\"\n",
|
||
" ax = fig.axes[0]\n",
|
||
" xx, yy = np.meshgrid(np.arange(-1.0, 1.0, 0.02),\n",
|
||
" np.arange(-1.0, 1.0, 0.02))\n",
|
||
" l = len(xx.ravel())\n",
|
||
" C = powerme(xx.reshape(l, 1), yy.reshape(l, 1), n)\n",
|
||
" z = classifyBi(theta, C).reshape(int(np.sqrt(l)), int(np.sqrt(l)))\n",
|
||
"\n",
|
||
" plt.contour(xx, yy, z, levels=[0.5], lw=3);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"Y_expected = Y2.astype(int)\n",
|
||
"Y_predicted = (classifyBi(theta, X2) > 0.5).astype(int)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Przygotowanie interaktywnego wykresu\n",
|
||
"\n",
|
||
"dropdown_highlight = widgets.Dropdown(options=['all', 'tp', 'fp', 'tn', 'fn'], value='all', description='highlight')\n",
|
||
"\n",
|
||
"def interactive_classification(highlight):\n",
|
||
" fig = plot_data_for_classification(X2, Y2, xlabel=r'$x_1$', ylabel=r'$x_2$',\n",
|
||
" Y_predicted=Y_predicted, highlight=highlight)\n",
|
||
" plot_decision_boundary(fig, theta, X2)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {
|
||
"scrolled": true,
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.jupyter.widget-view+json": {
|
||
"model_id": "3223b3857c254355a1e9900f24e0b07c",
|
||
"version_major": 2,
|
||
"version_minor": 0
|
||
},
|
||
"text/plain": [
|
||
"interactive(children=(Dropdown(description='highlight', options=('all', 'tp', 'fp', 'tn', 'fn'), value='all'),…"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<function __main__.interactive_classification(highlight)>"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"widgets.interact(interactive_classification, highlight=dropdown_highlight)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Zadanie klasyfikacyjne z powyższego przykładu polega na przypisaniu punktów do jednej z dwóch kategorii:\n",
|
||
"\n",
|
||
" 0. <font color=\"red\">czerwone krzyżyki</font>\n",
|
||
" 1. <font color=\"green\">zielone kółka</font>\n",
|
||
"\n",
|
||
"W tym celu zastosowano regresję logistyczną."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"W rezultacie otrzymano model, który dzieli płaszczyznę na dwa obszary:\n",
|
||
"\n",
|
||
" 0. <font color=\"red\">na zewnątrz granatowej krzywej</font>\n",
|
||
" 1. <font color=\"green\">wewnątrz granatowej krzywej</font>\n",
|
||
" \n",
|
||
"Model przewiduje klasę <font color=\"red\">0 („czerwoną”)</font> dla punktów znajdujący się w obszarze na zewnątrz krzywej, natomiast klasę <font color=\"green\">1 („zieloną”)</font> dla punktów znajdujących sie w obszarze wewnąrz krzywej."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Wszysktie obserwacje możemy podzielić zatem na cztery grupy:\n",
|
||
" * **true positives (TP)** – prawidłowo sklasyfikowane pozytywne przykłady (<font color=\"green\">zielone kółka</font> w <font color=\"green\">wewnętrznym obszarze</font>)\n",
|
||
" * **true negatives (TN)** – prawidłowo sklasyfikowane negatywne przykłady (<font color=\"red\">czerwone krzyżyki</font> w <font color=\"red\">zewnętrznym obszarze</font>)\n",
|
||
" * **false positives (FP)** – negatywne przykłady sklasyfikowane jako pozytywne (<font color=\"red\">czerwone krzyżyki</font> w <font color=\"green\">wewnętrznym obszarze</font>)\n",
|
||
" * **false negatives (FN)** – pozytywne przykłady sklasyfikowane jako negatywne (<font color=\"green\">zielone kółka</font> w <font color=\"red\">zewnętrznym obszarze</font>)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Innymi słowy:\n",
|
||
"\n",
|
||
"<img width=\"50%\" src=\"https://blog.aimultiple.com/wp-content/uploads/2019/07/positive-negative-true-false-matrix.png\">"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "skip"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"TP = 5\n",
|
||
"TN = 35\n",
|
||
"FP = 3\n",
|
||
"FN = 6\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Obliczmy TP, TN, FP i FN\n",
|
||
"\n",
|
||
"tp = 0\n",
|
||
"tn = 0\n",
|
||
"fp = 0\n",
|
||
"fn = 0\n",
|
||
"\n",
|
||
"for i in range(len(Y_expected)):\n",
|
||
" if Y_expected[i] == 1 and Y_predicted[i] == 1:\n",
|
||
" tp += 1\n",
|
||
" elif Y_expected[i] == 0 and Y_predicted[i] == 0:\n",
|
||
" tn += 1\n",
|
||
" elif Y_expected[i] == 0 and Y_predicted[i] == 1:\n",
|
||
" fp += 1\n",
|
||
" elif Y_expected[i] == 1 and Y_predicted[i] == 0:\n",
|
||
" fn += 1\n",
|
||
" \n",
|
||
"print('TP =', tp)\n",
|
||
"print('TN =', tn)\n",
|
||
"print('FP =', fp)\n",
|
||
"print('FN =', fn)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "skip"
|
||
}
|
||
},
|
||
"source": [
|
||
"Możemy teraz zdefiniować następujące metryki:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Dokładność (*accuracy*)\n",
|
||
"$$ \\mbox{accuracy} = \\frac{\\mbox{przypadki poprawnie sklasyfikowane}}{\\mbox{wszystkie przypadki}} \\\\ = \\frac{TP + TN}{TP + TN + FP + FN} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Dokładność otrzymujemy przez podzielenie liczby przypadków poprawnie sklasyfikowanych przez liczbę wszystkich przypadków:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Accuracy: 0.8163265306122449\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"accuracy = (tp + tn) / (tp + tn + fp + fn)\n",
|
||
"print('Accuracy:', accuracy)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"**Uwaga:** Nie zawsze dokładność będzie dobrą miarą, zwłaszcza gdy klasy są bardzo asymetryczne!\n",
|
||
"\n",
|
||
"*Przykład:* Wyobraźmy sobie test na koronawirusa, który **zawsze** zwraca wynik negatywny. Jaką przydatność będzie miał taki test w praktyce? Żadną. A jaka będzie jego *dokładność*? Policzmy:\n",
|
||
"$$ \\mbox{accuracy} \\, = \\, \\frac{\\mbox{szacowana liczba osób zdrowych na świecie}}{\\mbox{populacja Ziemi}} \\, \\approx \\, \\frac{7\\,700\\,000\\,000 - 600\\,000}{7\\,700\\,000\\,000} \\, \\approx \\, 0.99992 $$\n",
|
||
"(zaokrąglone dane z 27 marca 2020)\n",
|
||
"\n",
|
||
"Powyższy wynik jest tak wysoki, ponieważ zdecydowana większość osób na świecie nie jest zakażona, więc biorąc losowego Ziemianina możemy w ciemno strzelać, że nie ma koronawirusa.\n",
|
||
"\n",
|
||
"W tym przypadku duża różnica w liczności obu zbiorów (zakażeni/niezakażeni) powoduje, że *accuracy* nie jest dobrą metryką.\n",
|
||
"\n",
|
||
"Dlatego dysponujemy również innymi metrykami:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Precyzja (*precision*)\n",
|
||
"$$ \\mbox{precision} = \\frac{TP}{TP + FP} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Precision: 0.625\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"precision = tp / (tp + fp)\n",
|
||
"print('Precision:', precision)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Precyzja określa, jaka część przykładów sklasyfikowanych jako pozytywne to faktycznie przykłady pozytywne."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Pokrycie (czułość, *recall*)\n",
|
||
"$$ \\mbox{recall} = \\frac{TP}{TP + FN} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Recall: 0.45454545454545453\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"recall = tp / (tp + fn)\n",
|
||
"print('Recall:', recall)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Pokrycie mówi nam, jaka część przykładów pozytywnych została poprawnie sklasyfikowana."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### *$F$-measure* (*$F$-score*)\n",
|
||
"$$ F = \\frac{2 \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{\\mbox{precision} + \\mbox{recall}} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"F-score: 0.5263157894736842\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fscore = (2 * precision * recall) / (precision + recall)\n",
|
||
"print('F-score:', fscore)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"$F$-_measure_ jest kompromisem między precyzją a pokryciem (a ściślej: jest średnią harmoniczną precyzji i pokrycia)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"$F$-_measure_ jest szczególnym przypadkiem ogólniejszej miary:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"*$F_\\beta$-measure*:\n",
|
||
"$$ F_\\beta = \\frac{(1 + \\beta^2) \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{\\beta^2 \\cdot \\mbox{precision} + \\mbox{recall}} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"Dla $\\beta = 1$ otrzymujemy:\n",
|
||
"$$ F_1 \\, = \\, \\frac{(1 + 1^2) \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{1^2 \\cdot \\mbox{precision} + \\mbox{recall}} \\, = \\, \\frac{2 \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{\\mbox{precision} + \\mbox{recall}} \\, = \\, F $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 5.3. Obserwacje odstające"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"**Obserwacje odstające** (*outliers*) – to wszelkie obserwacje posiadające nietypową wartość.\n",
|
||
"\n",
|
||
"Mogą być na przykład rezultatem błędnego pomiaru albo pomyłki przy wprowadzaniu danych do bazy, ale nie tylko.\n",
|
||
"\n",
|
||
"Obserwacje odstające mogą niekiedy znacząco wpłynąć na parametry modelu, dlatego ważne jest, żeby takie obserwacje odrzucić zanim przystąpi się do tworzenia modelu."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"W poniższym przykładzie można zobaczyć wpływ obserwacji odstających na wynik modelowania na przykładzie danych dotyczących cen mieszkań zebranych z ogłoszeń na portalu Gratka.pl: tutaj przykładem obserwacji odstającej może być ogłoszenie, w którym podano cenę w tys. zł zamiast ceny w zł."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Przydatne funkcje\n",
|
||
"\n",
|
||
"def h_linear(Theta, x):\n",
|
||
" \"\"\"Funkcja regresji liniowej\"\"\"\n",
|
||
" return x * Theta\n",
|
||
"\n",
|
||
"def linear_regression(theta):\n",
|
||
" \"\"\"Ta funkcja zwraca funkcję regresji liniowej dla danego wektora parametrów theta\"\"\"\n",
|
||
" return lambda x: h_linear(theta, x)\n",
|
||
"\n",
|
||
"def cost(theta, X, y):\n",
|
||
" \"\"\"Wersja macierzowa funkcji kosztu\"\"\"\n",
|
||
" m = len(y)\n",
|
||
" J = 1.0 / (2.0 * m) * ((X * theta - y).T * (X * theta - y))\n",
|
||
" return J.item()\n",
|
||
"\n",
|
||
"def gradient(theta, X, y):\n",
|
||
" \"\"\"Wersja macierzowa gradientu funkcji kosztu\"\"\"\n",
|
||
" return 1.0 / len(y) * (X.T * (X * theta - y)) \n",
|
||
"\n",
|
||
"def gradient_descent(fJ, fdJ, theta, X, y, alpha=0.1, eps=10**-5):\n",
|
||
" \"\"\"Algorytm gradientu prostego (wersja macierzowa)\"\"\"\n",
|
||
" current_cost = fJ(theta, X, y)\n",
|
||
" logs = [[current_cost, theta]]\n",
|
||
" while True:\n",
|
||
" theta = theta - alpha * fdJ(theta, X, y)\n",
|
||
" current_cost, prev_cost = fJ(theta, X, y), current_cost\n",
|
||
" if abs(prev_cost - current_cost) > 10**15:\n",
|
||
" print('Algorithm does not converge!')\n",
|
||
" break\n",
|
||
" if abs(prev_cost - current_cost) <= eps:\n",
|
||
" break\n",
|
||
" logs.append([current_cost, theta]) \n",
|
||
" return theta, logs\n",
|
||
"\n",
|
||
"def plot_data(X, y, xlabel, ylabel):\n",
|
||
" \"\"\"Wykres danych (wersja macierzowa)\"\"\"\n",
|
||
" fig = plt.figure(figsize=(16*.6, 9*.6))\n",
|
||
" ax = fig.add_subplot(111)\n",
|
||
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
|
||
" ax.scatter([X[:, 1]], [y], c='r', s=50, label='Dane')\n",
|
||
" \n",
|
||
" ax.set_xlabel(xlabel)\n",
|
||
" ax.set_ylabel(ylabel)\n",
|
||
" ax.margins(.05, .05)\n",
|
||
" plt.ylim(y.min() - 1, y.max() + 1)\n",
|
||
" plt.xlim(np.min(X[:, 1]) - 1, np.max(X[:, 1]) + 1)\n",
|
||
" return fig\n",
|
||
"\n",
|
||
"def plot_regression(fig, fun, theta, X):\n",
|
||
" \"\"\"Wykres krzywej regresji (wersja macierzowa)\"\"\"\n",
|
||
" ax = fig.axes[0]\n",
|
||
" x0 = np.min(X[:, 1]) - 1.0\n",
|
||
" x1 = np.max(X[:, 1]) + 1.0\n",
|
||
" L = [x0, x1]\n",
|
||
" LX = np.matrix([1, x0, 1, x1]).reshape(2, 2)\n",
|
||
" ax.plot(L, fun(theta, LX), linewidth='2',\n",
|
||
" label=(r'$y={theta0:.2}{op}{theta1:.2}x$'.format(\n",
|
||
" theta0=float(theta[0][0]),\n",
|
||
" theta1=(float(theta[1][0]) if theta[1][0] >= 0 else float(-theta[1][0])),\n",
|
||
" op='+' if theta[1][0] >= 0 else '-')))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Wczytanie danych (mieszkania) przy pomocy biblioteki pandas\n",
|
||
"\n",
|
||
"alldata = pandas.read_csv('data_flats_with_outliers.tsv', sep='\\t',\n",
|
||
" names=['price', 'isNew', 'rooms', 'floor', 'location', 'sqrMetres'])\n",
|
||
"data = np.matrix(alldata[['price', 'sqrMetres']])\n",
|
||
"\n",
|
||
"m, n_plus_1 = data.shape\n",
|
||
"n = n_plus_1 - 1\n",
|
||
"Xn = data[:, 0:n]\n",
|
||
"\n",
|
||
"Xo = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n + 1)\n",
|
||
"yo = np.matrix(data[:, -1]).reshape(m, 1)\n",
|
||
"\n",
|
||
"Xo /= np.amax(Xo, axis=0)\n",
|
||
"yo /= np.amax(yo, axis=0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/tmp/ipykernel_1240/3692702518.py:59: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" theta0=float(theta[0][0]),\n",
|
||
"/tmp/ipykernel_1240/3692702518.py:60: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" theta1=(float(theta[1][0]) if theta[1][0] >= 0 else float(-theta[1][0])),\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "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ANCrtCt0XXnllfnud7+bCkx82Gbvv/9+Hn/88UyaNKl5XXV1dSZNmpTly5dvdbu1a9dm7733zujRozNlypQ888wz23ycDRs2pKGhocUCsM3rtnaEWVABoNdp1+mFS5cuze9+97vcc889Ofjgg7PLLru0uP+OO+6oSHGbe/PNN9PY2LjFSNXw4cPz3HPPtbrNgQcemB/84Ac59NBDU19fn+uuuy4TJkzIM888k0984hOtbjNnzpx861vfqnj9QA+36bqtjgQuAKBXalfoGjJkSM4+++xK11Jx48ePz/jx45tvT5gwIQcddFBuueWWfOc732l1m9mzZ2fWrFnNtxsaGjJ69OjCawW6sfXrP7yGq6MaGlzTBQC9TLtC1w9/+MNK17Fde+yxR/r06ZM1a9a0WL9mzZqMGDGiTX3ssssuOfzww/P8889vtU1NTU1qamo6VCuwk2loqEzgqq52eiEA9ELt/nLkjRs35v77788tt9ySd999N0ny2muvZe3atRUrbnP9+vXLkUcemUWLFjWva2pqyqJFi1qMZm1LY2Nj/vjHP2bkyJGF1AjspGpry4GpI/r2Tc4+2ygXAPRC7Rrpevnll3Paaadl1apV2bBhQ0455ZQMGjQo1157bTZs2JD58+dXus4kyaxZs/LlL385Rx11VI455pjceOONWbduXaZNm5YkOf/88/Pxj388c+bMSZJ8+9vfzmc+85nsv//+eeedd/J//s//ycsvv5yvfOUrhdQH7KQGDEimTEkWLNix2Qo319iYXHFFRcsCAHqGdoWuGTNm5KijjspTTz2V3XffvXn92WefnYsuuqhixX3UF77whbzxxhv55je/mbq6uhx22GG59957myfXWLVqVao3+9/ov/zlL7noootSV1eX3XbbLUceeWQefvjhfPrTny6sRmAnNWlS+Xu2dlTfvuXANW9ectxxla8LAOj2qkrtmPd99913z8MPP5wDDzwwgwYNylNPPZX99tsvL730Uj796U/nvffeK6LWLtHQ0JDBgwenvr4+ta7FgN7rxBOTJUt2bJuqquScc8ojXAIXAPQIRRz/t+sihaampjQ2Nm6x/s9//nMGDRrU4aIAupXvfnfHA1dSPhVx0iSBCwB6uXaFrlNPPTU33nhj8+2qqqqsXbs211xzTc4444xK1QbQ9ZYu7di1WJdemixbVrl6AIAep12n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KJDQBQAAUCChCwAAoEBCFwAAQIGELgAAgAIJXQAAAAUSugAAAAokdAEAABSox4Sut99+O+edd15qa2szZMiQXHjhhVm7du02t5k4cWKqqqpaLJdcckknVQwAAJD07eoC2uq8887L6tWrs3DhwnzwwQeZNm1aLr744tx2223b3O6iiy7Kt7/97ebbu+66a9GlAgAANOsRoevZZ5/Nvffemz/84Q856qijkiR///d/nzPOOCPXXXddRo0atdVtd91114wYMaKzSgUAAGihR5xeuHz58gwZMqQ5cCXJpEmTUl1dnUceeWSb2/7kJz/JHnvskUMOOSSzZ8/Oe++9t832GzZsSENDQ4sFAACgvXrESFddXV2GDRvWYl3fvn0zdOjQ1NXVbXW7L37xi9l7770zatSo/Mu//Eu+8Y1vZOXKlbnjjju2us2cOXPyrW99q2K1AwAAvVuXhq6rr74611577TbbPPvss+3u/+KLL27+99ixYzNy5Mh89rOfzQsvvJBPfvKTrW4ze/bszJo1q/l2Q0NDRo8e3e4aAACA3q1LQ9eVV16ZCy64YJtt9ttvv4wYMSKvv/56i/UbN27M22+/vUPXax177LFJkueff36roaumpiY1NTVt7hMAAGBbujR07bnnntlzzz232278+PF555138vjjj+fII49MkixevDhNTU3NQaotVqxYkSQZOXJku+oFAADYUT1iIo2DDjoop512Wi666KI8+uijWbZsWS6//PL89V//dfPMha+++mrGjBmTRx99NEnywgsv5Dvf+U4ef/zxvPTSS/nVr36V888/PyeeeGIOPfTQrnw6AABAL9IjQldSnoVwzJgx+exnP5szzjgjxx9/fL73ve813//BBx9k5cqVzbMT9uvXL/fff39OPfXUjBkzJldeeWU+97nP5e677+6qpwAAAPRCVaVSqdTVRXRnDQ0NGTx4cOrr61NbW9vV5QAAAAUq4vi/x4x0AQAA9ERCFwAAQIGELgAAgAIJXQAAAAUSugAAAAokdAEAABRI6AIAACiQ0AUAAFAgoQsAAKBAQhcAAECBhC4AAIACCV0AAAAFEroAAAAKJHQBAAAUSOgCAAAokNAFAABQIKELAACgQEIXAABAgYQuAACAAgldAAAABRK6AAAACiR0AQAAFEjoAgAAKJDQBQAAUCChCwAAoEBCFwAAQIGELgAA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8ePHt2ifJAsXLtxqe7qv9uz/j2psbMwf//hHr/VewGufj1qxYoXXfg9VKpVy+eWX584778zixYuz7777bnebirwHtHemD9gZnXbaaaXDDz+89Mgjj5SWLl1aOuCAA0rnnntu8/1//vOfSwceeGDpkUceKZVKpdLzzz9f+va3v1167LHHSi+++GLprrvuKu23336lE088saueAjvgpz/9aammpqZ06623lv71X/+1dPHFF5eGDBlSqqurK5VKpdKXvvSl0tVXX93cftmyZaW+ffuWrrvuutKzzz5buuaaa0q77LJL6Y9//GNXPQU6YEf3/7e+9a3SfffdV3rhhRdKjz/+eOmv//qvS/379y8988wzXfUUaKd333239OSTT5aefPLJUpLS3LlzS08++WTp5ZdfLpVKpdLVV19d+tKXvtTc/t/+7d9Ku+66a+nrX/966dlnny3ddNNNpT59+pTuvffernoKdMCO7v8bbrihtGDBgtKf/vSn0h//+MfSjBkzStXV1aX777+/q54CHXDppZeWBg8eXHrggQdKq1evbl7ee++95jZFfP4LXbCZt956q3TuueeWBg4cWKqtrS1Nmzat9O677zbf/+KLL5aSlH73u9+VSqVSadWqVaUTTzyxNHTo0FJNTU1p//33L339618v1dfXd9EzYEf9/d//fWmvvfYq9evXr3TMMceUfv/73zffd9JJJ5W+/OUvt2j/s5/9rPSpT32q1K9fv9LBBx9c+s1vftPJFVNJO7L/Z86c2dx2+PDhpTPOOKP0xBNPdEHVdNSmKcA/umza31/+8pdLJ5100hbbHHbYYaV+/fqV9ttvv9IPf/jDTq+bytjR/X/ttdeWPvnJT5b69+9fGjp0aGnixImlxYsXd03xdFhr+z5Ji9d0EZ//Vf/x4AAAABTANV0AAAAFEroAAAAKJHQBAAAUSOgCAAAokNAFAABQIKELAACgQEIXAABAgYQuAACAAgldAFCwl156KVVVVVmxYkVXlwJAF6gqlUqlri4CALqLiRMn5rDDDsuNN95YsT4bGxvzxhtvZI899kjfvn0r1i8APYN3fgDYQaVSKY2NjW0OUH369MmIESMKrgqA7srphQD0WBMnTsxXv/rVzJw5M7vttluGDx+ef/zHf8y6desybdq0DBo0KPvvv3/uueee5m2efvrpnH766Rk4cGCGDx+eL33pS3nzzTeTJBdccEEefPDBfPe7301VVVWqqqry0ksv5YEHHkhVVVXuueeeHHnkkampqcnSpUvzwgsvZMqUKRk+fHgGDhyYo48+Ovfff3/zY23a7qPLBRdc0Nm/KgC6kNAFQI/2ox/9KHvssUceffTRfPWrX82ll16a//yf/3MmTJiQJ554Iqeeemq+9KUv5b333ss777yTv/qrv8rhhx+exx57LPfee2/WrFmTz3/+80mS7373uxk/fnwuuuiirF69OqtXr87o0aObH+vqq6/O//pf/yvPPvtsDj300KxduzZnnHFGFi1alCeffDKnnXZazjrrrKxatSpJMmHChOZ+Vq9encWLF6d///458cQTu+R3BUDXcE0XAD3WxIkT09jYmCVLliQpXzs1ePDgnHPOOfnxj3+cJKmrq8vIkSOzfPny3H///VmyZEnuu+++5j7+/Oc/Z/To0Vm5cmU+9alPtXpN1wMPPJCTTz45CxYsyJQpU7ZZ0yGHHJJLLrkkl19+eYv1b731Vo455picfvrp+Yd/+IcK/QYA6Alc0wVAj3booYc2/7tPnz7ZfffdM3bs2OZ1w4cPT5K8/vrreeqpp/K73/0uAwcO3KKfF154IZ/61Ke2+VhHHXVUi9tr167N3/7t3+Y3v/lNVq9enY0bN2b9+vXNI12bfPDBB/nc5z6X/fbbr6ITdADQMwhdAPRou+yyS4vbVVVVLdZVVVUlSZqamrJ27dqcddZZufbaa7foZ+TIkdt9rI997GMtbn/ta1/LwoULc91112X//ffPgAED8p/+03/K+++/36LdpZdemldffTWPPvqo2QsBeiHv/AD0GkcccUR++ctfZp999tlq+OnXr18aGxvb1N+yZctywQUX5Oyzz05SHvl66aWXWrSZO3dufvGLX+T3v/99dttttw7VD0DPZCINAHqN6dOn5+233865556bP/zhD3nhhRdy3333Zdq0ac1Ba5999skjjzySl156KW+++Waampq22t8BBxyQO+64IytWrMhTTz2VL37xiy3a33///bnqqqty4403ZsiQIamrq0tdXV3q6+sLf64AdB9CFwC9xqhRo7Js2bI0Njbm1FNPzdixYzNz5swMGTIk1dXlj8Svfe1r6dOnTz796U9nzz333OL6rM3NnTs3u+22WyZMmJCzzjorkydPzhFHHNF8/9KlS9PY2Jhp06Zl5MiRzcuMGTMKf64AdB9mLwQAACiQkS4AAIACCV0AAAAFEroAAAAKJHQBAAAUSOgCAAAokNAFAABQIKELAACgQEIXAABAgYQuAACAAgldAAAABRK6AAAACvT/AUJCS8PN32+JAAAAAElFTkSuQmCC",
|
||
"text/plain": [
|
||
"<Figure size 960x540 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"fig = plot_data(Xo, yo, xlabel=u'metraż', ylabel=u'cena')\n",
|
||
"theta_start = np.matrix([0.0, 0.0]).reshape(2, 1)\n",
|
||
"theta, logs = gradient_descent(cost, gradient, theta_start, Xo, yo, alpha=0.01)\n",
|
||
"plot_regression(fig, h_linear, theta, Xo)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Na powyższym przykładzie obserwacja odstająca jawi sie jako pojedynczy punkt po prawej stronie wykresu. Widzimy, że otrzymana krzywa regresji zamiast odwzorowywać ogólny trend, próbuje „dopasować się” do tej pojedynczej obserwacji.\n",
|
||
"\n",
|
||
"Dlatego taką obserwację należy usunąć ze zbioru danych (zobacz ponizej)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Odrzućmy obserwacje odstające\n",
|
||
"alldata_no_outliers = [\n",
|
||
" (index, item) for index, item in alldata.iterrows() \n",
|
||
" if item.price > 100 and item.sqrMetres > 10]\n",
|
||
"\n",
|
||
"alldata_no_outliers = alldata.loc[(alldata['price'] > 100) & (alldata['sqrMetres'] > 100)]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"data = np.matrix(alldata_no_outliers[['price', 'sqrMetres']])\n",
|
||
"\n",
|
||
"m, n_plus_1 = data.shape\n",
|
||
"n = n_plus_1 - 1\n",
|
||
"Xn = data[:, 0:n]\n",
|
||
"\n",
|
||
"Xo = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n + 1)\n",
|
||
"yo = np.matrix(data[:, -1]).reshape(m, 1)\n",
|
||
"\n",
|
||
"Xo /= np.amax(Xo, axis=0)\n",
|
||
"yo /= np.amax(yo, axis=0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/tmp/ipykernel_1240/3692702518.py:59: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" theta0=float(theta[0][0]),\n",
|
||
"/tmp/ipykernel_1240/3692702518.py:60: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)\n",
|
||
" theta1=(float(theta[1][0]) if theta[1][0] >= 0 else float(-theta[1][0])),\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "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uzbS4wQAAJ1NQYG0YUPoc+rrpQceiMpwAMCUds10LVy4UMOGDdNXX32ltEb/8zR9+nQVFRVFbHAAAKATGz3a3ofL4Wg+4+Vy2cdXr2aDZAAJr12ha/v27XrkkUeUkpIScPyyyy7TsWPHIjIwAADQBcybJ23fbi81dJ57W+J02ve3b2djZACdQruWF/p8PtXX1zc7/tlnnykjI6PDgwIAAF3IqFH2rbra7lLo8VDDBaBTaddM1y233KKVK1f67zscDlVWVmrp0qWaNGlSpMYGAAC6krQ0KSuLwAWg02nX5sifffaZJkyYIMuy9OGHH2rYsGH68MMPddFFF2n79u3q1auXibHGBJsjAwAAAF2Hiff/7Qpdkt0y/sUXX9R7772nyspKDR06VLNmzQporNEZELoAAACArsPE+/921XQVFhYqKytL//iP/6hZs2b5jz/zzDM6ceKEHnrooYgMDgAAdDHUdQHohNpV0/XUU0+pf//+zY5fffXV7NEFAADarrhYmjFDSk+XsrPtjzNmSDt2xHpkANBh7QpdZWVlysnJaXb84osvVmlpaYcHBQAAupA1a6QxY6Q//Uny+exjPp99/4YbJP5DF0CCa1foysvL044W/udpx44dys3N7fCgAABAF1FcLM2fL1mWVFcX+FhdnX38vvuY8QKQ0NpV0zV37lwtWrRItbW1+va3vy1JKioq0oMPPqjFixdHdIAAAKATW75cSkpqHrgaS0qSVqyw9/ICgATUrpmuH/7wh7r77rt13333qU+fPurTp4/uv/9+/fM//7OWLFkS6TEGWLVqlS677DKlpqZqxIgR2r17d9Bz161bJ4fDEXBLTU01Oj4AQBRUV0vl5fZHJK7qamnjxtCBS7IfX7+eP28ACatdocvhcGjZsmU6ceKE3nnnHb333ns6efKkHn300UiPL8CLL76ogoICLV26VPv27dOgQYM0YcIEHT9+POg1Ho9HpaWl/tunn35qdIwAAINottC5eL3na7ha4/PZ5wNAAmpX6GqQnp6u6667TgMGDJDb7Y7UmIJavny55s6dqzlz5uhb3/qW1q5dq27duumZZ54Jeo3D4VB2drb/lpWVZXycAAAD4qHZwsmT0sGD9kd0nMcjOcN8K+J02ucDQALqUOiKprNnz2rv3r0aP368/5jT6dT48eO1c+fOoNdVVlbq0ksvVV5enqZO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QYQuAAAAADCI0AUAAAAABhG6AAAAAMAgQhcAAAAAGEToAgAAAACDCF0AAAAAYBChCwAAAAAMSpjQdfLkSc2aNUsej0fdu3fX3XffrcrKypDXjBs3Tg6HI+A2b968KI0YAAAAACRXrAcQrlmzZqm0tFSbNm1SbW2t5syZo3vuuUfPP/98yOvmzp2rH/3oR/773bp1Mz1UAAAAAPBLiND1wQcf6PXXX9e7776rYcOGSZJ+9rOfadKkSXriiSeUm5sb9Npu3bopOzs7WkMFAAAAgAAJsbxw586d6t69uz9wSdL48ePldDq1a9eukNf++te/Vs+ePTVgwAAtWbJEp0+fDnl+TU2NvF5vwA0AAAAA2ishZrrKysrUq1evgGMul0s9evRQWVlZ0Otuv/12XXrppcrNzdWf//xnPfTQQzp06JBeeumloNcUFhbqsccei9jYAQAAAHRtMQ1dDz/8sJYtWxbynA8++KDdz3/PPff4Px84cKBycnJ000036fDhw7riiitavGbJkiUqKCjw3/d6vcrLy2v3GAAAAAB0bTENXYsXL9Zdd90V8pw+ffooOztbx48fDzheV1enkydPtqlea8SIEZKkjz76KGjocrvdcrvdYT8nAAAAAIQS09B18cUX6+KLL271vPz8fH399dfau3evrr32WknSli1b5PP5/EEqHCUlJZKknJycdo0XAAAAANoqIRppXHXVVbr11ls1d+5c7d69Wzt27NCCBQv0ve99z9+58NixY+rfv792794tSTp8+LAef/xx7d27V5988on++Mc/avbs2RozZoyuueaaWH47AAAAALqQhAhdkt2FsH///rrppps0adIkjR49Wk8//bT/8draWh06dMjfnTAlJUWbN2/WLbfcov79+2vx4sX6zne+oz/96U+x+hYAAAAAdEEOy7KsWA8innm9XmVmZqqiokIejyfWwwEAAABgkIn3/wkz0wUAAAAAiYjQBQAAAAAGEboAAAAAwCBCFwAAAAAYROgCAAAAAIMIXQAAAABgEKELAAAAAAwidAEAAACAQYQuAAAAADCI0AUAAAAABhG6AAAAAMAgQhcAAAAAGEToAgAAAACDCF0AAAAAYBChCwAAAAAMInQBAAAAgEGELgAAAAAwiNAFAAAAAAYRugAAAADAIEIXAAAAABhE6AIAAAAAgwhdAAAAAGAQoQsAAAAADCJ0AQAAAIBBhC4AAAAAMIjQBQAAAAAGEboAAAAAwCBCFwAAAAAYROgCAAAAAIMIXQAAAABgEKELAAAAAAxyxXoA8c6yLEmS1+uN8UgAAAAAmNbwvr8hB0QCoasVp06dkiTl5eXFeCQAAAAAouXLL79UZmZmRJ7LYUUywnVCPp9Pn3/+uTIyMuRwOGI9nE7L6/UqLy9PR48elcfjifVwEGd4fSAYXhsIhdcHguG1gVAqKirUu3dvffXVV+revXtEnpOZrlY4nU594xvfiPUwugyPx8MvPwTF6wPB8NpAKLw+EAyvDYTidEau/QWNNAAAAADAIEIXAAAAABhE6EJccLvdWrp0qdxud6yHgjjE6wPB8NpAKLw+EAyvDYRi4vVBIw0AAAAAMIiZLgAAAAAwiNAFAAAAAAYRugAAAADAIEIXAAAAABhE6ELMnDx5UrNmzZLH41H37t119913q7KyMuQ148aNk8PhCLjNmzcvSiOGSatWrdJll12m1NRUjRgxQrt37w55/u9+9zv1799fqampGjhwoF599dUojRTR1pbXxrp165r9jkhNTY3iaBEtb731lqZMmaLc3Fw5HA5t2LCh1Wu2bt2qoUOHyu12q2/fvlq3bp3xcSI22vr62Lp1a7PfHQ6HQ2VlZdEZMKKmsLBQ1113nTIyMtSrVy9NmzZNhw4davW6jr7vIHQhZmbNmqX3339fmzZt0ssvv6y33npL99xzT6vXzZ07V6Wlpf7bf/7nf0ZhtDDpxRdfVEFBgZYuXap9+/Zp0KBBmjBhgo4fP97i+W+//bZmzpypu+++W/v379e0adM0bdo0HTx4MMojh2ltfW1IksfjCfgd8emnn0ZxxIiWqqoqDRo0SKtWrQrr/I8//liTJ0/WjTfeqJKSEi1atEjf//739cYbbxgeKWKhra+PBocOHQr4/dGrVy9DI0SsbNu2TfPnz9c777yjTZs2qba2VrfccouqqqqCXhOR9x0WEAN/+ctfLEnWu+++6z/22muvWQ6Hwzp27FjQ68aOHWstXLgwCiNENA0fPtyaP3++/359fb2Vm5trFRYWtnj+d7/7XWvy5MkBx0aMGGH90z/9k9FxIvra+tp49tlnrczMzCiNDvFCkrV+/fqQ5zz44IPW1VdfHXDstttusyZMmGBwZIgH4bw+3nzzTUuS9dVXX0VlTIgfx48ftyRZ27ZtC3pOJN53MNOFmNi5c6e6d++uYcOG+Y+NHz9eTqdTu3btCnntr3/9a/Xs2VMDBgzQkiVLdPr0adPDhUFnz57V3r17NX78eP8xp9Op8ePHa+fOnS1es3PnzoDzJWnChAlBz0dias9rQ5IqKyt16aWXKi8vT1OnTtX7778fjeEizvF7A+EYPHiwcnJydPPNN2vHjh2xHg6ioKKiQpLUo0ePoOdE4veHq33DAzqmrKys2ZS9y+VSjx49Qq6fvv3223XppZcqNzdXf/7zn/XQQw/p0KFDeumll0wPGYZ88cUXqq+vV1ZWVsDxrKws/fWvf23xmrKyshbPZ+1959Ke10a/fv30zDPP6JprrlFFRYWeeOIJjRw5Uu+//76+8Y1vRGPYiFPBfm94vV5VV1crLS0tRiNDPMjJydHatWs1bNgw1dTU6Be/+IXGjRunXbt2aejQobEeHgzx+XxatGiRRo0apQEDBgQ9LxLvOwhdiKiHH35Yy5YtC3nOBx980O7nb1zzNXDgQOXk5Oimm27S4cOHdcUVV7T7eQF0Dvn5+crPz/ffHzlypK666io99dRTevzxx2M4MgDxrF+/furXr5///siRI3X48GGtWLFCv/rVr2I4Mpg0f/58HTx4UMXFxca/FqELEbV48WLdddddIc/p06ePsrOzmxXC19XV6eTJk8rOzg77640YMUKS9NFHHxG6ElTPnj2VlJSk8vLygOPl5eVBXwvZ2dltOh+JqT2vjaaSk5M1ZMgQffTRRyaGiAQS7PeGx+NhlgstGj58eFTejCM2FixY4G/k1tpKiEi876CmCxF18cUXq3///iFvKSkpys/P19dff629e/f6r92yZYt8Pp8/SIWjpKREkr0sAIkpJSVF1157rYqKivzHfD6fioqKAmYsGsvPzw84X5I2bdoU9Hwkpva8Npqqr6/XgQMH+B0Bfm+gzUpKSvjd0QlZlqUFCxZo/fr12rJliy6//PJWr4nI74/2dvoAOurWW2+1hgwZYu3atcsqLi62rrzySmvmzJn+xz/77DOrX79+1q5duyzLsqyPPvrI+tGPfmTt2bPH+vjjj62NGzdaffr0scaMGROrbwER8sILL1hut9tat26d9Ze//MW65557rO7du1tlZWWWZVnWHXfcYT388MP+83fs2GG5XC7riSeesD744ANr6dKlVnJysnXgwIFYfQswpK2vjccee8x64403rMOHD1t79+61vve971mpqanW+++/H6tvAYacOnXK2r9/v7V//35LkrV8+XJr//791qeffmpZlmU9/PDD1h133OE//29/+5vVrVs364c//KH1wQcfWKtWrbKSkpKs119/PVbfAgxq6+tjxYoV1oYNG6wPP/zQOnDggLVw4ULL6XRamzdvjtW3AEPuvfdeKzMz09q6datVWlrqv50+fdp/jon3HYQuxMyXX35pzZw500pPT7c8Ho81Z84c69SpU/7HP/74Y0uS9eabb1qWZVlHjhyxxowZY/Xo0cNyu91W3759rR/+8IdWRUVFjL4DRNLPfvYzq3fv3lZKSoo1fPhw65133vE/NnbsWOvOO+8MOP+3v/2t9c1vftNKSUmxrr76auuVV16J8ogRLW15bSxatMh/blZWljVp0iRr3759MRg1TGto8d301vB6uPPOO62xY8c2u2bw4MFWSkqK1adPH+vZZ5+N+rgRHW19fSxbtsy64oorrNTUVKtHjx7WuHHjrC1btsRm8DCqpdeFpIDfBybedzjOfXEAAAAAgAHUdAEAAACAQYQuAAAAADCI0AUAAAAABhG6AAAAAMAgQhcAAAAAGEToAgAAAACDCF0AAAAAYBChCwAAAAAMInQBAGDYJ598IofDoZKSklgPBQAQAw7LsqxYDwIAgHgxbtw4DR48WCtXrozYc9bX1+vEiRPq2bOnXC5XxJ4XAJAY+M0PAEAbWZal+vr6sANUUlKSsrOzDY8KABCvWF4IAEhY48aN0/33369FixbpwgsvVFZWlv7nf/5HVVVVmjNnjjIyMtS3b1+99tpr/msOHjyoiRMnKj09XVlZWbrjjjv0xRdfSJLuuusubdu2TT/96U/lcDjkcDj0ySefaOvWrXI4HHrttdd07bXXyu12q7i4WIcPH9bUqVOVlZWl9PR0XXfdddq8ebP/azVc1/R21113RftHBQCIIUIXACCh/fKXv1TPnj21e/du3X///br33nv1D//wDxo5cqT27dunW265RXfccYdOnz6tr7/+Wt/+9rc1ZMgQ7dmzR6+//rrKy8v13e9+V5L005/+VPn5+Zo7d65KS0tVWlqqvLw8/9d6+OGH9ZOf/EQffPCBrrnmGlVWVmrSpEkqKirS/v37deutt2rKlCk6cuSIJGnkyJH+5yktLdWWLVuUmpqqMWPGxORnBQCIDWq6AAAJa9y4caqvr9f27dsl2bVTmZmZmjFjhp577jlJUllZmXJycrRz505t3rxZ27dv1xtvvOF/js8++0x5eXk6dOiQvvnNb7ZY07V161bdeOON2rBhg6ZOnRpyTAMGDNC8efO0YMGCgONffvmlhg8frokTJ+rnP/95hH4CAIBEQE0XACChXXPNNf7Pk5KSdNFFF2ngwIH+Y1lZWZKk48eP67333tObb76p9PT0Zs9z+PBhffOb3wz5tYYNGxZwv7KyUv/2b/+mV155RaWlpaqrq1N1dbV/pqtBbW2tvvOd76hPnz4RbdABAEgMhC4AQEJLTk4OuO9wOAKOORwOSZLP51NlZaWmTJmiZcuWNXuenJycVr/WBRdcEHD/Bz/4gTZt2qQnnnhCffv2VVpamv7+7/9eZ8+eDTjv3nvv1bFjx7R79266FwJAF8RvfgBAlzF06FD94Q9/0GWXXRY0/KSkpKi+vj6s59uxY4fuuusuTZ8+XZI98/XJJ58EnLN8+XL9/ve/1zvvvKMLL7ywQ+MHACQmGmkAALqM+fPn6+TJk5o5c6beffddHT58WG+88YbmzJnjD1qXXXaZdu3apU8++URffPGFfD5f0Oe78sor9dJLL6mkpETvvfeebr/99oDzN2/erAcffFArV65U9+7dVVZWprKyMlVUVBj/XgEA8YPQBQDoMnJzc7Vjxw7V19frlltu0cCBA7Vo0SJ1795dTqf9T+IPfvADJSUl6Vvf+pYuvvjiZvVZjS1fvlwXXnihRo4cqSlTpmjChAkaOnSo//Hi4mLV19drzpw5ysnJ8d8WLlxo/HsFAMQPuhcCAAAAgEHMdAEAAACAQYQuAAAAADCI0AUAAAAABhG6AAAAAMAgQhcAAAAAGEToAgAAAACDCF0AAAAAYBChCwAAAAAMInQBAAAAgEGELgAAAAAwiNAFAAAAAAb9f3ntuvpIGYyMAAAAAElFTkSuQmCC",
|
||
"text/plain": [
|
||
"<Figure size 960x540 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"fig = plot_data(Xo, yo, xlabel=u'metraż', ylabel=u'cena')\n",
|
||
"theta_start = np.matrix([0.0, 0.0]).reshape(2, 1)\n",
|
||
"theta, logs = gradient_descent(cost, gradient, theta_start, Xo, yo, alpha=0.01)\n",
|
||
"plot_regression(fig, h_linear, theta, Xo)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Na powyższym wykresie widać, że po odrzuceniu obserwacji odstających otrzymujemy dużo bardziej „wiarygodną” krzywą regresji."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"celltoolbar": "Slideshow",
|
||
"kernelspec": {
|
||
"display_name": "Python 3 (ipykernel)",
|
||
"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.10.12"
|
||
},
|
||
"livereveal": {
|
||
"start_slideshow_at": "selected",
|
||
"theme": "white"
|
||
},
|
||
"vscode": {
|
||
"interpreter": {
|
||
"hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
|
||
}
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|