uczenie-glebokie/w2/.ipynb_checkpoints/04_Metody_ewaluacji-checkpoint.ipynb
2023-05-06 11:28:04 +02:00

1313 lines
102 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Uczenie maszynowe zastosowania\n",
"# 4. Metody ewaluacji"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## 4.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 (treningowym) 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 treningowych nie wolno „zanieczyszczać” danych treningowych danymi testowymi!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Czasami potrzebujemy dobrać 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": "slide"
}
},
"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 width=\"100%\" src=\"https://chrisjmccormick.files.wordpress.com/2013/07/10_fold_cv.png\"/>\n",
"Żródło: https://chrisjmccormick.wordpress.com/2013/07/31/k-fold-cross-validation-with-matlab-code/"
]
},
{
"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 trenowania, 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$, trenujemy model na całych danych treningowych 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": "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 trenują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": [
"## 4.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": "slide"
}
},
"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": "slide"
}
},
"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='r', marker='x', s=100, label='Dane')\n",
" ax.scatter(X1fn, X2fn, c='k', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1tp, X2tp, c='k', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1fp, X2fp, c='k', marker='x', s=50, label='Dane')\n",
" elif highlight == 'fn':\n",
" ax.scatter(X1tn, X2tn, c='k', marker='x', s=50, label='Dane')\n",
" ax.scatter(X1fn, X2fn, c='g', marker='o', s=100, label='Dane')\n",
" ax.scatter(X1tp, X2tp, c='k', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1fp, X2fp, c='k', marker='x', s=50, label='Dane')\n",
" elif highlight == 'tp':\n",
" ax.scatter(X1tn, X2tn, c='k', marker='x', s=50, label='Dane')\n",
" ax.scatter(X1fn, X2fn, c='k', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1tp, X2tp, c='g', marker='o', s=100, label='Dane')\n",
" ax.scatter(X1fp, X2fp, c='k', marker='x', s=50, label='Dane')\n",
" elif highlight == 'fp':\n",
" ax.scatter(X1tn, X2tn, c='k', marker='x', s=50, label='Dane')\n",
" ax.scatter(X1fn, X2fn, c='k', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1tp, X2tp, c='k', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1fp, X2fp, c='r', marker='x', s=100, label='Dane')\n",
" else:\n",
" ax.scatter(X1tn, X2tn, c='r', marker='x', s=50, label='Dane')\n",
" ax.scatter(X1fn, X2fn, c='g', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1tp, X2tp, c='g', marker='o', s=50, label='Dane')\n",
" ax.scatter(X1fp, X2fp, c='r', 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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eqrxwQcfhG1/4MAB45RTTjHuvvtu49133zWeeuopIyUlxXjuuef8berr642kpCTjRz/6kbF3717jRz/6kZGcnGy8/vrrZr2sqDTQc3333XcbjzzyiPHmm28ajY2NxtKlS42UlBRj586d/jZr1qwx0tPTQ97DE91Az/Urr7xiSDL2798fcB67v+dyXYc30HN97NixgHPscrmMM844w/j+97/vb8N1Hd7mzZuNBx980Fi/fr0hyaiqquq1vZnv14SvKLZmzZp+hS+v12tkZWUZP/7xj/3bPvvsM8NutxuPP/64YRi+P+CUlBTj2Wef9bf56KOPDKvVarz00ktD3vdY8O677xqSAv5oGhoaDEnGvn37+n2ckpIS4ytf+UrAtksvvdS4++67h6qrMW+w5/qmm24ySkpKetzPdR1qqK7rN99805AU8KEg0a/riy++2CgrKwvYNmnSJOOBBx4I2/7f/u3fjEmTJgVs+9d//Vdj5syZ/p8XLlxoXHnllQFt5s6dayxatGiIeh2bBnquw5k8ebLx8MMP+3/u77+piWag57orfB09erTHY3Jdh3ey13VVVZVhsViM999/37+N67pv/QlfZr5fc9thHDh48KCam5tVXFzs35aamqpLL71U9fX1kqQdO3aovb09oM3YsWM1ZcoUf5tE09DQILvdrhkzZvi3zZw5U3a7vd/n5PDhw9q0aZNuvfXWkH1PP/20MjIydN555+m+++7T8ePHh6zvseZkznVNTY1Gjx6tnJwc3XbbbTpy5Ih/H9d1qKG4riWppaVFFosl5NbnRL2uPR6PduzYEXCtSVJxcXGP57WhoSGk/dy5c7V9+3a1t7f32iZRr19pcOc6mNfr1fHjx3XGGWcEbD9x4oTGjx+vs88+W9dcc4127do1ZP2ORSdzri+66CKNGTNGl19+uV555ZWAfVzXoYbiul61apWKioo0fvz4gO1c1yfPzPfr5JPrKqJBc3OzJCkzMzNge2Zmpj744AN/G5vNptNPPz2kTdfzE01zc7NGjx4dsn306NH9Pie/+c1vNGrUKC1YsCBg+w033KAJEyYoKytLb7/9tpYuXaq33npLW7ZsGZK+x5rBnuurrrpKX/va1zR+/HgdPHhQ3/ve9/SVr3xFO3bsUGpqKtd1GENxXX/22Wd64IEH9I1vfEPp6en+7Yl8XX/yySfq7OwM+z7b03ltbm4O276jo0OffPKJxowZ02ObRL1+pcGd62CPPvqo/vGPf2jhwoX+bZMmTdLatWs1depUud1u/exnP1NhYaHeeustfelLXxrS1xArBnOux4wZoyeffFJ5eXlqa2tTZWWlLr/8ctXU1Gj27NmSer72ua4Hf10fOnRIL774op555pmA7VzXQ8PM92vCl0keeughPfzww7222bZtm6ZPnz7o32GxWAJ+NgwjZFuw/rSJNf0911LoOZMGdk5Wr16tG264QSNGjAjYftttt/n/95QpU/SlL31J06dP186dOzVt2rR+HTsWDPe5Li0t9f/vKVOmaPr06Ro/frw2bdoUEngHctxYZNZ13d7erkWLFsnr9aqioiJgX6Jc170Z6PtsuPbB2wfz3p0IBnte1q1bp4ceekgbNmwI+CJi5syZAQV7CgsLNW3aNP3iF7/Qz3/+86HreAwayLnOzc1Vbm6u/+f8/Hy5XC7953/+pz98DfSYiWSw52Xt2rU67bTTdP311wds57oeOma9XxO+THLnnXf2WRXsnHPOGdSxs7KyJPlS+5gxY/zbjxw54k/oWVlZ8ng8Onr0aMAowZEjR1RQUDCo3xut+nuu//KXv+jw4cMh+/7+97+HfLMRTm1trfbv3y+n09ln22nTpiklJUXvvfdeXH1INetcdxkzZozGjx+v9957TxLXdbCTPdft7e1auHChDh48qD//+c8Bo17hxOt1HU5GRoaSkpJCvuHs/j4bLCsrK2z75ORknXnmmb22GcjfRbwZzLnu4nQ6deutt+r3v/+9ioqKem1rtVr15S9/2f9+kohO5lx3N3PmTP3ud7/z/8x1HepkzrVhGFq9erUcDodsNluvbbmuB8fM92vmfJkkIyNDkyZN6vURPHrSX123AXW/9cfj8ejVV1/1fwDNy8tTSkpKQJtDhw7p7bffjrsPqf091/n5+WppadGbb77pf+4bb7yhlpaWfp2TVatWKS8vTxdccEGfbd955x21t7cHhON4YNa57vLpp5/K5XL5zyPX9dCd667g9d5776m6utr/j01v4vW6DsdmsykvLy/kFsstW7b0eF7z8/ND2r/88suaPn26UlJSem0Tb9fvQAzmXEu+Ea+bb75ZzzzzjObNm9fn7zEMQ7t3706I67cngz3XwXbt2hVwHrmuQ53MuX711Vf117/+Nez88mBc14Nj6vv1gMpzwBQffPCBsWvXLuPhhx82Ro4caezatcvYtWuXcfz4cX+b3Nxc4/nnn/f//OMf/9iw2+3G888/b+zZs8f4+te/HrbU/Nlnn21UV1cbO3fuNL7yla9QkvvKK43zzz/faGhoMBoaGoypU6eGlOQOPteGYRgtLS3GKaecYqxcuTLkmH/961+Nhx9+2Ni2bZtx8OBBY9OmTcakSZOMiy66iHM9gHN9/Phx49577zXq6+uNgwcPGq+88oqRn59vfOELX+C67sNAz3V7e7tx3XXXGWeffbaxe/fugHLFbW1thmFwXRvG52WiV61aZbz77rvG4sWLjVNPPdVfeeyBBx4wHA6Hv31X6eJ77rnHePfdd41Vq1aFlC6uq6szkpKSjB//+MfG3r17jR//+MeU5DYGfq6feeYZIzk52fjVr37V41IIDz30kPHSSy8Zf/vb34xdu3YZt9xyi5GcnGy88cYbpr++aDLQc/3YY48ZVVVVRmNjo/H2228bDzzwgCHJWL9+vb8N13V4Az3XXb75zW8aM2bMCHtMruvwjh8/7v/8LMlYsWKFsWvXLn8F30i+XxO+otBNN91kSAp5vPLKK/42kow1a9b4f/Z6vcb3v/99Iysry0hNTTVmz55t7NmzJ+C4ra2txp133mmcccYZRlpamnHNNdcYTU1NJr2q6PTpp58aN9xwgzFq1Chj1KhRxg033BBSPjf4XBuGYTzxxBNGWlpa2DWOmpqajNmzZxtnnHGGYbPZjC9+8YvGXXfdFbI+VaIZ6Ln+3//9X6O4uNg466yzjJSUFGPcuHHGTTfdFHLNcl2HGui5PnjwYNj3nO7vO1zXPr/61a+M8ePHGzabzZg2bZrx6quv+vfddNNNxqWXXhrQvqamxrjooosMm81mnHPOOWG/sPn9739v5ObmGikpKcakSZMCPsQmsoGc60svvTTs9XvTTTf52yxevNgYN26cYbPZjLPOOssoLi426uvrTXxF0Wsg5/qRRx4xvvjFLxojRowwTj/9dOOSSy4xNm3aFHJMruvwBvoecuzYMSMtLc148sknwx6P6zq8riURenpPiOT7tcUw/jmbDAAAAAAwbJjzBQAAAAAmIHwBAAAAgAkIXwAAAABgAsIXAAAAAJiA8AUAAAAAJiB8AQAAAIAJCF8AAAAAYALCFwAAAACYgPAFAAAAACYgfAEA0A/r1q3TiBEj9NFHH/m3fetb39L555+vlpaWCPYMABArLIZhGJHuBAAA0c4wDF144YWaNWuWfvnLX+rhhx/Wr3/9a73++uv6whe+EOnuAQBiQHKkOwAAQCywWCz64Q9/qH/5l3/R2LFj9bOf/Uy1tbX+4DV//nzV1NTo8ssv13PPPRfh3gIAohEjXwAADMC0adP0zjvv6OWXX9all17q3/7KK6/oxIkT+s1vfkP4AgCExZwvAAD66Y9//KP27dunzs5OZWZmBuy77LLLNGrUqAj1DAAQCwhfAAD0w86dO/W1r31NTzzxhObOnavvfe97ke4SACDGMOcLAIA+vP/++5o3b54eeOABORwOTZ48WV/+8pe1Y8cO5eXlRbp7AIAYwcgXAAC9+J//+R9dddVVuu666/Td735XkpSXl6drr71WDz74YIR7BwCIJYx8AQDQizPOOEN79+4N2b5hw4YI9AYAEMuodggAwBCYO3eudu7cqX/84x8644wzVFVVpS9/+cuR7hYAIIoQvgAAAADABMz5AgAAAAATEL4AAAAAwASELwAAAAAwAeELAAAAAExA+AIAAAAAExC+AAAAAMAEhC8AAAAAMAHhCwAAAABMQPgCAAAAABMQvgAAAADABIQvAAAAADDB/w8EUR4xgCUl7AAAAABJRU5ErkJggg==\n",
"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 zawsz 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": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "660e6cef0e7c4e8e85052791cceacf7f",
"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",
" 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ą.\n",
"\n",
"W rezultacie otrzymano model, który dzieli płaszczyznę na dwa obszary:\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": "notes"
}
},
"source": [
"Możemy teraz zdefiniować następujące metryki:"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"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": "slide"
}
},
"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": "slide"
}
},
"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": "slide"
}
},
"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) \\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) \\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": [
"## 4.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": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA14AAAH0CAYAAAAtwPxTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAz3ElEQVR4nO3de3RV5Z038N8h4dZCooKE0KJoW6kVrQhWUbG2tiC2LARnen2p2qkzKN6gji3Ou6a1nXex2mVRu1pAZ7Q37VvnLeJlvFSsgqCoxaJOl0idVoVqIoI2EcyASfb7x5lEQwLkcp6Ek3w+a50V9j7Pfs7vZLMP58uz97NzWZZlAQAAQDL9eroAAACA3k7wAgAASEzwAgAASEzwAgAASEzwAgAASEzwAgAASEzwAgAASEzwAgAASEzwAgAASEzwAgAASKxogtfChQvj+OOPj6FDh8aIESPirLPOio0bN+5zu1WrVsWECRNi0KBBcfjhh8fSpUu7oVoAAIB3FE3wWrVqVcydOzcee+yxWLFiRdTX18eUKVNix44de9zmhRdeiDPPPDMmT54c69evjyuvvDIuueSSWLZsWTdWDgAA9HW5LMuyni6iM1577bUYMWJErFq1Kk499dQ223zjG9+IO++8MzZs2NC8bs6cOfH000/H2rVru6tUAACgjyvt6QI6q6amJiIiDjrooD22Wbt2bUyZMqXFuqlTp8aNN94Yb7/9dvTv37/VNjt37oydO3c2Lzc2Nsbrr78ew4YNi1wuV6DqAQCA/VGWZfHmm2/GqFGjol+/wp0gWJTBK8uymD9/fpxyyikxbty4Pbarrq6OioqKFusqKiqivr4+tm7dGpWVla22WbhwYVx11VUFrxkAACgemzdvjve///0F668og9dFF10UzzzzTKxZs2afbXcfpWo6s3JPo1cLFiyI+fPnNy/X1NTEIYccEps3b46ysrIuVA0AAOzvamtrY/To0TF06NCC9lt0weviiy+OO++8Mx5++OF9JtCRI0dGdXV1i3VbtmyJ0tLSGDZsWJvbDBw4MAYOHNhqfVlZmeAFAAB9RKEvMyqaWQ2zLIuLLroobrvttnjwwQfjsMMO2+c2kyZNihUrVrRYd//998fEiRPbvL4LAAAghaIJXnPnzo2bb745fvnLX8bQoUOjuro6qquro66urrnNggUL4itf+Urz8pw5c+Kll16K+fPnx4YNG+Kmm26KG2+8MS6//PKeeAsAAEAfVTTBa8mSJVFTUxOnnXZaVFZWNj9uvfXW5jZVVVWxadOm5uXDDjss7rnnnli5cmUce+yx8d3vfjd++MMfxtlnn90TbwEAAOijivY+Xt2ltrY2ysvLo6amxjVeAADQy6X6/l80I14AAADFSvACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABIrKiC18MPPxzTp0+PUaNGRS6Xi9tvv32v7VeuXBm5XK7V47nnnuueggEAACKitKcL6IgdO3bERz/60TjvvPPi7LPPbvd2GzdujLKysublgw8+OEV5AAAAbSqq4DVt2rSYNm1ah7cbMWJEHHDAAYUvCAAAoB2K6lTDzho/fnxUVlbG6aefHg899NBe2+7cuTNqa2tbPAAAALqiVwevysrKuOGGG2LZsmVx2223xdixY+P000+Phx9+eI/bLFy4MMrLy5sfo0eP7saKAQCA3iiXZVnW00V0Ri6Xi+XLl8dZZ53Voe2mT58euVwu7rzzzjaf37lzZ+zcubN5uba2NkaPHh01NTUtrhMDAAB6n9ra2igvLy/49/9ePeLVlhNPPDGef/75PT4/cODAKCsra/EAAADoij4XvNavXx+VlZU9XQYAANCHFNWshtu3b4//+q//al5+4YUX4qmnnoqDDjooDjnkkFiwYEG8/PLL8fOf/zwiIq699toYM2ZMHHXUUbFr1664+eabY9myZbFs2bKeegsAAEAfVFTBa926dfGJT3yieXn+/PkREXHOOefET3/606iqqopNmzY1P79r1664/PLL4+WXX47BgwfHUUcdFXfffXeceeaZ3V47AADQdxXt5BrdJdXFdQAAwP7H5BoAAABFSvACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPAC6Ki6uohXX83/BABoB8ELoL3WrImYNStiyJCIkSPzP2fNinjkkZ6uDADYzxVV8Hr44Ydj+vTpMWrUqMjlcnH77bfvc5tVq1bFhAkTYtCgQXH44YfH0qVL0xcK9D5LlkScemrEXXdFNDbm1zU25pcnT47w2QIA7EVRBa8dO3bERz/60fjRj37UrvYvvPBCnHnmmTF58uRYv359XHnllXHJJZfEsmXLElcK9Cpr1kTMnRuRZRH19S2fq6/Pr7/wQiNfAMAelfZ0AR0xbdq0mDZtWrvbL126NA455JC49tprIyLiyCOPjHXr1sXVV18dZ599dqIqgV5n0aKIkpLWoevdSkoirrkm4uSTu68uAKBoFNWIV0etXbs2pkyZ0mLd1KlTY926dfH222+3uc3OnTujtra2xQPow+rqIu64Y++hKyL//PLlJtwAANrUq4NXdXV1VFRUtFhXUVER9fX1sXXr1ja3WbhwYZSXlzc/Ro8e3R2lAvur2tp3runal8bGfHsAgN306uAVEZHL5VosZ1nW5vomCxYsiJqamubH5s2bk9cI7MfKyiL6tfOjsl+/fHsAgN306uA1cuTIqK6ubrFuy5YtUVpaGsOGDWtzm4EDB0ZZWVmLB9CHDR4cMWNGROk+LoktLY2YOTPfHgBgN706eE2aNClWrFjRYt39998fEydOjP79+/dQVUDRmT8/oqFh720aGiLmzeueegCAolNUwWv79u3x1FNPxVNPPRUR+enin3rqqdi0aVNE5E8T/MpXvtLcfs6cOfHSSy/F/PnzY8OGDXHTTTfFjTfeGJdffnlPlA8Uq1NOiVi8OCKXaz3yVVqaX794sRkNAYA9KqrgtW7duhg/fnyMHz8+IiLmz58f48ePj3/+53+OiIiqqqrmEBYRcdhhh8U999wTK1eujGOPPTa++93vxg9/+ENTyQMdN2dOxOrV+dMOm6756tcvv7x6df55AIA9yGVNs03Qptra2igvL4+amhrXewF5dXX52QvLylzTBQC9TKrv/0V1A2WA/cLgwQIXANAhRXWqIQAAQDESvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAAAABITvAC6oq4u4tVX8z8BAPZA8ALojDVrImbNihgyJGLkyPzPWbMiHnmkpysDAPZDghdARy1ZEnHqqRF33RXR2Jhf19iYX548OWLp0p6tDwDY7wheAB2xZk3E3LkRWRZRX9/yufr6/PoLLzTyBQC0IHgBdMSiRRElJXtvU1IScc013VMPAFAUBC+A9qqri7jjjtYjXburr49YvtyEGwBAM8ELoL1qa9+5pmtfGhvz7QEAQvACaL+ysoh+7fzY7Ncv3x4AIAQvgPYbPDhixoyI0tK9tystjZg5M98eACAEL4COmT8/oqFh720aGiLmzeueegCAoiB4AXTEKadELF4ckcu1HvkqLc2vX7w44uSTe6Y+AGC/JHgBdNScORGrV+dPO2y65qtfv/zy6tX55wEA3mUfFyoA0KaTT84/6urysxeWlbmmCwDYI8ELoCsGD24duIQxAGA3TjUEKJQ1ayJmzYoYMiRi5Mj8z1mzIh55pKcrAwB6mOAFUAhLlkScemrEXXe9c5Plxsb88uTJEUuX9mx9AECPErwAumrNmoi5cyOyLKK+vuVz9fX59RdeaOQLAPowwQugqxYtiigp2XubkpKIa67pnnoAgP2O4AXQFXV1EXfc0Xqka3f19RHLl+fbAwB9juAF0BW1te9c07UvjY359gBAnyN4AXRFWdk7N1Hel3798u0BgD5H8ALoisGDI2bMiCjdx20RS0sjZs50Xy8A6KO6dAPlt956KzZt2hS7du1qsf6YY47pUlEARWX+/Ijbb997m4aGiHnzuqUcAGD/06ng9dprr8V5550X9957b5vPNzQ0dKkogKJyyikRixfnp4wvKWk50UZpaT50LV4ccfLJPVcjANCjOnWq4WWXXRZvvPFGPPbYYzF48OC477774mc/+1l86EMfijvvvLPQNQLs/+bMiVi9On/aYdM1X/365ZdXr84/DwD0WZ0a8XrwwQfjjjvuiOOPPz769esXhx56aHz605+OsrKyWLhwYXzmM58pdJ0A+7+TT84/6urysxeWlbmmCwCIiE6OeO3YsSNGjBgREREHHXRQvPbaaxERcfTRR8fvf//7wlUHUIwGD46oqBC6AIBmnQpeY8eOjY0bN0ZExLHHHhvXX399vPzyy7F06dKorKwsaIEAAADFrlOnGl522WVRVVUVERHf+ta3YurUqXHLLbfEgAED4qc//Wkh6wMoPk41BAB2k8uyLOtqJ2+99VY899xzccghh8Tw4cMLUdd+o7a2NsrLy6OmpibK3PgU2Js1ayIWLYq4446IxsZ3Jtf4+tfNaAgARSLV9/+C3ED5Pe95Txx33HG9LnQBtNuSJRGnnhpx11350BWR/3nXXRGTJ0csXdqz9QEAPapTpxo2NDTET3/60/jtb38bW7ZsicamLxn/48EHHyxIcQBFYc2aiLlzI7Ks5T28It5ZvvDCiKOPNvIFAH1Up0a8Lr300rj00kujoaEhxo0bFx/96EdbPFJavHhxHHbYYTFo0KCYMGFCrF69eo9tV65cGblcrtXjueeeS1oj0AfU1UW8+mr+56JF+Rsn701JScQ113RPbQDAfqdTI16/+tWv4t///d/jzDPPLHQ9e3XrrbfGZZddFosXL46TTz45rr/++pg2bVo8++yzccghh+xxu40bN7Y4P/Pggw/ujnKB3mj367hyufxI177U10csX54PaibcAIA+p1MjXgMGDIgPfvCDha5lnxYtWhR/93d/F1/7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AABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYoIXAABAYkUTvN54442YPXt2lJeXR3l5ecyePTv++te/7nWbc889N3K5XIvHiSee2D0FAwAA/I/Sni6gvb70pS/FX/7yl7jvvvsiIuLv//7vY/bs2XHXXXftdbszzjgjfvKTnzQvDxgwIGmdAAAAuyuK4LVhw4a477774rHHHosTTjghIiL+9V//NSZNmhQbN26MsWPH7nHbgQMHxsiRI7urVAAAgFaK4lTDtWvXRnl5eXPoiog48cQTo7y8PB599NG9brty5coYMWJEHHHEEXH++efHli1b9tp+586dUVtb2+IBAADQFUURvKqrq2PEiBGt1o8YMSKqq6v3uN20adPilltuiQcffDB+8IMfxO9+97v45Cc/GTt37tzjNgsXLmy+jqy8vDxGjx5dkPcAAAD0XT0avL797W+3mvxi98e6desiIiKXy7XaPsuyNtc3+fznPx+f+cxnYty4cTF9+vS49957449//GPcfffde9xmwYIFUVNT0/zYvHlz198oAADQp/XoNV4XXXRRfOELX9hrmzFjxsQzzzwTr776aqvnXnvttaioqGj361VWVsahhx4azz///B7bDBw4MAYOHNjuPgEAAPalR4PX8OHDY/jw4ftsN2nSpKipqYknnngiPvaxj0VExOOPPx41NTVx0kkntfv1tm3bFps3b47KyspO1wwAANBRRXGN15FHHhlnnHFGnH/++fHYY4/FY489Fueff3589rOfbTGj4Yc//OFYvnx5RERs3749Lr/88li7dm28+OKLsXLlypg+fXoMHz48Zs6c2VNvBQAA6IOKInhFRNxyyy1x9NFHx5QpU2LKlClxzDHHxC9+8YsWbTZu3Bg1NTUREVFSUhL/+Z//GTNmzIgjjjgizjnnnDjiiCNi7dq1MXTo0J54CwAAQB+Vy7Is6+ki9me1tbVRXl4eNTU1UVZW1tPlAAAACaX6/l80I14AAADFSvACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABIrLSnC9jfZVkWERG1tbU9XAkAAJBa0/f+phxQKILXPrz55psRETF69OgergQAAOgu27Zti/Ly8oL1l8sKHeV6mcbGxnjllVdi6NChkcvleroculltbW2MHj06Nm/eHGVlZT1dDt3M/u/b7P++zf7v2+z/vq2mpiYOOeSQeOONN+KAAw4oWL9GvPahX79+8f73v7+ny6CHlZWV+eDtw+z/vs3+79vs/77N/u/b+vUr7HQYJtcAAABITPACAABITPCCvRg4cGB861vfioEDB/Z0KfQA+79vs//7Nvu/b7P/+7ZU+9/kGgAAAIkZ8QIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8ILdvPHGGzF79uwoLy+P8vLymD17dvz1r3/d6zbnnntu5HK5Fo8TTzyxewqmSxYvXhyHHXZYDBo0KCZMmBCrV6/ea/tVq1bFhAkTYtCgQXH44YfH0qVLu6lSUujI/l+5cmWr4zyXy8Vzzz3XjRVTKA8//HBMnz49Ro0aFblcLm6//fZ9buP47z06uv8d/73HwoUL4/jjj4+hQ4fGiBEj4qyzzoqNGzfuc7tCHP+CF+zmS1/6Ujz11FNx3333xX333RdPPfVUzJ49e5/bnXHGGVFVVdX8uOeee7qhWrri1ltvjcsuuyz+6Z/+KdavXx+TJ0+OadOmxaZNm9ps/8ILL8SZZ54ZkydPjvXr18eVV14Zl1xySSxbtqybK6cQOrr/m2zcuLHFsf6hD32omyqmkHbs2BEf/ehH40c/+lG72jv+e5eO7v8mjv/it2rVqpg7d2489thjsWLFiqivr48pU6bEjh079rhNwY7/DGj27LPPZhGRPfbYY83r1q5dm0VE9txzz+1xu3POOSebMWNGN1RIIX3sYx/L5syZ02Ldhz/84eyb3/xmm+2vuOKK7MMf/nCLdf/wD/+QnXjiiclqJJ2O7v+HHnooi4jsjTfe6Ibq6E4RkS1fvnyvbRz/vVd79r/jv/fasmVLFhHZqlWr9timUMe/ES94l7Vr10Z5eXmccMIJzetOPPHEKC8vj0cffXSv265cuTJGjBgRRxxxRJx//vmxZcuW1OXSBbt27Yonn3wypkyZ0mL9lClT9riv165d26r91KlTY926dfH2228nq5XC68z+bzJ+/PiorKyM008/PR566KGUZbIfcfwT4fjvjWpqaiIi4qCDDtpjm0Id/4IXvEt1dXWMGDGi1foRI0ZEdXX1HrebNm1a3HLLLfHggw/GD37wg/jd734Xn/zkJ2Pnzp0py6ULtm7dGg0NDVFRUdFifUVFxR73dXV1dZvt6+vrY+vWrclqpfA6s/8rKyvjhhtuiGXLlsVtt90WY8eOjdNPPz0efvjh7iiZHub479sc/71TlmUxf/78OOWUU2LcuHF7bFeo47+005VCEfn2t78dV1111V7b/O53v4uIiFwu1+q5LMvaXN/k85//fPOfx40bFxMnToxDDz007r777pg1a1Ynq6Y77L5f97Wv22rf1nqKQ0f2/9ixY2Ps2LHNy5MmTYrNmzfH1VdfHaeeemrSOtk/OP77Lsd/73TRRRfFM888E2vWrNln20Ic/4IXfcJFF10UX/jCF/baZsyYMfHMM8/Eq6++2uq51157rdX/dOxNZWVlHHroofH88893uFa6x/Dhw6OkpKTV6MaWLVv2uK9HjhzZZvvS0tIYNmxYslopvM7s/7aceOKJcfPNNxe6PPZDjn925/gvbhdffHHceeed8fDDD8f73//+vbYt1PEveNEnDB8+PIYPH77PdpMmTYqampp44okn4mMf+1hERDz++ONRU1MTJ510Urtfb9u2bbF58+aorKzsdM2kNWDAgJgwYUKsWLEiZs6c2bx+xYoVMWPGjDa3mTRpUtx1110t1t1///0xceLE6N+/f9J6KazO7P+2rF+/3nHeRzj+2Z3jvzhlWRYXX3xxLF++PFauXBmHHXbYPrcp2PHfoak4oA8444wzsmOOOSZbu3Zttnbt2uzoo4/OPvvZz7ZoM3bs2Oy2227LsizL3nzzzezrX/969uijj2YvvPBC9tBDD2WTJk3K3ve+92W1tbU98RZop1/96ldZ//79sxtvvDF79tlns8suuyx773vfm7344otZlmXZN7/5zWz27NnN7f/85z9n73nPe7J58+Zlzz77bHbjjTdm/fv3z37961/31FugCzq6/6+55pps+fLl2R//+MfsD3/4Q/bNb34zi4hs2bJlPfUW6II333wzW79+fbZ+/fosIrJFixZl69evz1566aUsyxz/vV1H97/jv/e44IILsvLy8mzlypVZVVVV8+Ott95qbpPq+Be8YDfbtm3LvvzlL2dDhw7Nhg4dmn35y19uNX1sRGQ/+clPsizLsrfeeiubMmVKdvDBB2f9+/fPDjnkkOycc87JNm3a1P3F02E//vGPs0MPPTQbMGBAdtxxx7WYTvacc87JPv7xj7dov3Llymz8+PHZgAEDsjFjxmRLlizp5ooppI7s/+9973vZBz7wgWzQoEHZgQcemJ1yyinZ3Xff3QNVUwhN04Pv/jjnnHOyLHP893Yd3f+O/96jrf3+7u91WZbu+M/9TwEAAAAkYjp5AACAxAQvAACAxAQvAACAxAQvAACAxAQvAACAxAQvAACAxAQvAACAxAQvAACAxAQvAOgGL774YuRyuXjqqad6uhQAekAuy7Ksp4sAgP3JaaedFscee2xce+21BeuzoaEhXnvttRg+fHiUlpYWrF8AioNPfgDohCzLoqGhod0hqqSkJEaOHJm4KgD2V041BKConXbaaXHxxRfHZZddFgceeGBUVFTEDTfcEDt27Ijzzjsvhg4dGh/4wAfi3nvvbd7m2WefjTPPPDOGDBkSFRUVMXv27Ni6dWtERJx77rmxatWquO666yKXy0Uul4sXX3wxVq5cGblcLn7zm9/ExIkTY+DAgbF69er405/+FDNmzIiKiooYMmRIHH/88fHAAw80v1bTdrs/zj333O7+VQHQgwQvAIrez372sxg+fHg88cQTcfHFF8cFF1wQf/u3fxsnnXRS/P73v4+pU6fG7Nmz46233oqqqqr4+Mc/Hscee2ysW7cu7rvvvnj11Vfjc5/7XEREXHfddTFp0qQ4//zzo6qqKqqqqmL06NHNr3XFFVfEwoULY8OGDXHMMcfE9u3b48wzz4wHHngg1q9fH1OnTo3p06fHpk2bIiLipJNOau6nqqoqHnzwwRg0aFCceuqpPfK7AqBnuMYLgKJ22mmnRUNDQ6xevToi8tdSlZeXx6xZs+LnP/95RERUV1dHZWVlrF27Nu655554/PHH4ze/+U1zH3/5y19i9OjRsXHjxjjiiCPavMZr5cqV8YlPfCJuv/32mDFjxl5rOuqoo+KCCy6Iiy66qMX6bdu2xQknnBBnnHFG/OhHPyrQbwCAYuAaLwCK3jHHHNP855KSkhg2bFgcffTRzesqKioiImLLli3x5JNPxkMPPRRDhgxp1c+f/vSnOOKII/b6WhMnTmyxvGPHjrjqqqviP/7jP+KVV16J+vr6qKurax7xavL222/H2WefHWPGjCnopB0AFAfBC4Ci179//xbLuVyuxbpcLhcREY2NjdHY2BjTp0+P733ve636qays3Odrvfe9722x/I//+I/xm9/8Jq6++ur44Ac/GIMHD46/+Zu/iV27drVod8EFF8TLL78cTzzxhFkNAfogn/wA9CnHHXdcLFu2LMaMGbPHADRgwIBoaGhoV3+rV6+Oc889N2bOnBkREdu3b48XX3yxRZtFixbFr3/963jsscfiwAMP7FL9ABQnk2sA0KfMnTs3Xn/99fjiF78YTzzxRPz5z3+O+++/P7761a82h60xY8bE448/Hi+++GJs3bo1Ghsb99jfBz/4wbjtttviqaeeiqeffjq+9KUvtWj/wAMPxBVXXBHXXnttHHDAAVFdXR3V1dVRU1OT/L0CsP8QvADoU0aNGhWPPPJINDQ0xNSpU2PcuHFx6aWXRnl5efTrl/9n8fLLL4+SkpL4yEc+EgcffHCr67Xe7ZprrokDDzwwTjrppJg+fXpMnTo1jjvuuObn16xZEw0NDXHeeedFZWVl8+PSSy9N/l4B2H+Y1RAAACAxI14AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJCV4AAACJ/X+XlNFNcNa5fAAAAABJRU5ErkJggg==\n",
"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 > 10000 and item.sqrMetres < 1000]\n",
"\n",
"# Alternatywnie można to zrobić w następujący sposób\n",
"alldata_no_outliers = alldata.loc[(alldata['price'] > 10000) & (alldata['sqrMetres'] < 1000)]"
]
},
{
"cell_type": "code",
"execution_count": 22,
"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": 23,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"image/png": "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YECz2/Tu3TvKysqaLEA31rdvxJQpEaX7uCS2tDRi6tR8fwCAXXTp4DV27NhYsmRJk7aHH344Ro8eHT179uygqoCiM3t2RH393vvU10fMmtU+9QAARaeogteWLVviueeei+eeey4i8tPFP/fcc7Fu3bqIyJ8m+OUvf7mx/4wZM+K1116L2bNnx5o1a+L222+P2267La6++uqOKB8oVqedFjF/fkQut/uRr9LSfPv8+WY0BAD2qKiC16pVq+KEE06IE044ISIiZs+eHSeccEJ84xvfiIiIqqqqxhAWETF8+PB44IEHYunSpXH88cfHd77znfj+979vKnlg/82YEbF8ef60w53XfPXokV9fvjz/OADAHuSynbNN0Kza2tooLy+Pmpoa13sBedu25WcvLCtzTRcAdDGpvv8X1Q2UATqFvn0FLgBgvxTVqYYAAADFSPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACAABITPACaItt2yI2bMj/BADYA8ELoDVWrIiYNi2iX7+IwYPzP6dNi3jiiY6uDADohAQvgP21YEHE+PER990X0dCQb2toyK+PGxexcGHH1gcAdDqCF8D+WLEi4tJLI7Isoq6u6WN1dfn2Sy5x5AsAaELwAtgf8+ZFlJTsvU9JScSNN7ZPPQBAURC8AFpq27aIX/1q9yNdu6qri1i82IQbAEAjwQugpWpr37+ma18aGvL9AQBC8AJoubKyiB4t/Njs0SPfHwAgBC+AluvbN2LKlIjS0r33Ky2NmDo13x8AIAQvgP0ze3ZEff3e+9TXR8ya1T71AABFQfAC2B+nnRYxf35ELrf7ka/S0nz7/PkRp57aMfUBAJ2S4AWwv2bMiFi+PH/a4c5rvnr0yK8vX55/HADgA/ZxoQIAzTr11PyybVt+9sKyMtd0AQB7JHgBtEXfvrsHLmEMANiFUw0BCmXFiohp0yL69YsYPDj/c9q0iCee6OjKAIAOJngBFMKCBRHjx0fcd9/7N1luaMivjxsXsXBhx9YHAHQowQugrVasiLj00ogsi6ira/pYXV2+/ZJLHPkCgG5M8AJoq3nzIkpK9t6npCTixhvbpx4AoNMRvADaYtu2iF/9avcjXbuqq4tYvDjfHwDodgQvgLaorX3/mq59aWjI9wcAuh3BC6Atysrev4nyvvToke8PAHQ7ghdAW/TtGzFlSkTpPm6LWFoaMXWq+3oBQDfVphsov/vuu7Fu3brYsWNHk/Zjjz22TUUBFJXZsyPuuWfvferrI2bNapdyAIDOp1XB680334wLL7wwHnzwwWYfr6+vb1NRAEXltNMi5s/PTxlfUtJ0oo3S0nzomj8/4tRTO65GAKBDtepUw5kzZ8bbb78dTz31VPTt2zceeuih+MlPfhIf+9jH4t577y10jQCd34wZEcuX50873HnNV48e+fXly/OPAwDdVquOeD366KPxq1/9Kk466aTo0aNHHHbYYfHZz342ysrKYu7cufG5z32u0HUCdH6nnppftm3Lz15YVuaaLgAgIlp5xGvr1q0xaNCgiIg4+OCD480334yIiGOOOSZ+97vfFa46gGLUt29ERYXQBQA0alXwGjFiRKxduzYiIo4//vi45ZZb4vXXX4+FCxdGZWVlQQsEAAAodq061XDmzJlRVVUVERHf/OY3Y+LEiXHnnXdGr1694sc//nEh6wMoPk41BAB2kcuyLGvrIO+++2689NJLceihh8bAgQMLUVenUVtbG+Xl5VFTUxNlbnwK7M2KFRHz5kX86lcRDQ3vT65x1VVmNASAIpHq+39BbqD8oQ99KE488cQuF7oAWmzBgojx4yPuuy8fuiLyP++7L2LcuIiFCzu2PgCgQ7XqVMP6+vr48Y9/HL/5zW9i48aN0bDzS8ZfPfroowUpDqAorFgRcemlEVnW9B5eEe+vX3JJxDHHOPIFAN1Uq454XXnllXHllVdGfX19jBw5Mo477rgmS0rz58+P4cOHR58+fWLUqFGxfPnyPfZdunRp5HK53ZaXXnopaY1AN7BtW8SGDfmf8+blb5y8NyUlETfe2D61AQCdTquOeP3iF7+I//zP/4yzzjqr0PXs1V133RUzZ86M+fPnx6mnnhq33HJLTJo0KV588cU49NBD97jd2rVrm5yfecghh7RHuUBXtOt1XLlc/kjXvtTVRSxenA9qJtwAgG6nVUe8evXqFR/96EcLXcs+zZs3L/7hH/4hvvrVr8ZRRx0VN910UwwdOjQWLFiw1+0GDRoUgwcPblxK9vUv0wDNae46rv2Zn6ihIT/bIQDQ7bQqeF111VVx8803RwEmRGyxHTt2xLPPPhsTJkxo0j5hwoR48skn97rtCSecEJWVlXHGGWfEY489tte+27dvj9ra2iYLwF6v49ofZkcFgG6pVacarlixIh577LF48MEH4+ijj46ePXs2efzuu+8uSHEftGnTpqivr4+Kioom7RUVFVFdXd3sNpWVlXHrrbfGqFGjYvv27fGzn/0szjjjjFi6dGmMHz++2W3mzp0b119/fcHrB4rczuu42hK6AIBuq1XB68ADD4ypU6cWupYWyeVyTdazLNutbacRI0bEiBEjGtfHjh0b69evjxtuuGGPwWvOnDkxe/bsxvXa2toYOnRoASoHita2be9f09VWtbWu8QKAbqhVwetHP/pRoevYp4EDB0ZJScluR7c2bty421GwvRkzZkzccccde3y8d+/e0bt371bXCXRBtbWFCV09ejjVEAC6qVbfQLmuri4eeeSRuOWWW+Kdd96JiIg33ngjtmzZUrDiPqhXr14xatSoWLJkSZP2JUuWxCmnnNLicVavXh2VlZWFLg/oysrK8qGpLUpLI6ZOdbQLALqpVh3xeu211+LMM8+MdevWxfbt2+Ozn/1s9O/fP/71X/81/vKXv8TChQsLXWdERMyePTumT58eo0ePjrFjx8att94a69atixkzZkRE/jTB119/PX76059GRMRNN90Uw4YNi6OPPjp27NgRd9xxRyxatCgWLVqUpD6gi+rbN2LKlIh77tm/WQw/qL4+YtasgpYFABSPVgWvK6+8MkaPHh3PP/98DBgwoLF96tSp8dWvfrVgxe3q3HPPjc2bN8e3v/3tqKqqipEjR8YDDzwQhx12WEREVFVVxbp16xr779ixI66++up4/fXXo2/fvnH00UfH/fff3+73HwO6gM98Jn8frv1VWpoPXfPnR5x6auHrAgCKQi5rxZzwAwcOjCeeeCJGjBgR/fv3j+effz4OP/zwePXVV+PjH/94vPvuuylq7RC1tbVRXl4eNTU1TW7CDHQz48dHLF++f9vkchHTpuWPdAldAFAUUn3/b9VFCw0NDVFfX79b+5/+9Kfo379/m4sC6FRuvnn/Q1dE/rTEz3xG6AIAWhe8PvvZz8ZNN93UuJ7L5WLL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8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEhM8AIAAEisaILX22+/HdOnT4/y8vIoLy+P6dOnx5///Oe9bnPBBRdELpdrsowZM6Z9CgYAAPir0o4uoKXOO++8+NOf/hQPPfRQRET84z/+Y0yfPj3uu+++vW535plnxo9+9KPG9V69eiWtEwAAYFdFEbzWrFkTDz30UDz11FNx8sknR0TEv/3bv8XYsWNj7dq1MWLEiD1u27t37xg8eHB7lQoAALCbojjVcOXKlVFeXt4YuiIixowZE+Xl5fHkk0/uddulS5fGoEGD4ogjjoiLLrooNm7cuNf+27dvj9ra2iYLAABAWxRF8Kquro5Bgwbt1j5o0KCorq7e43aTJk2KO++8Mx599NH43ve+F7/97W/j05/+dGzfvn2P28ydO7fxOrLy8vIYOnRoQV4DAADQfXVo8PrWt7612+QXuy6rVq2KiIhcLrfb9lmWNdu+07nnnhuf+9znYuTIkTF58uR48MEH4/e//33cf//9e9xmzpw5UVNT07isX7++7S8UAADo1jr0Gq/LLrssvvCFL+y1z7Bhw+KFF16IDRs27PbYm2++GRUVFS1+vsrKyjjssMPi5Zdf3mOf3r17R+/evVs8JgAAwL50aPAaOHBgDBw4cJ/9xo4dGzU1NfHMM8/EJz7xiYiIePrpp6OmpiZOOeWUFj/f5s2bY/369VFZWdnqmgEAAPZXUVzjddRRR8WZZ54ZF110UTz11FPx1FNPxUUXXRSf//znm8xoeOSRR8bixYsjImLLli1x9dVXx8qVK+PVV1+NpUuXxuTJk2PgwIExderUjnopAABAN1QUwSsi4s4774xjjjkmJkyYEBMmTIhjjz02fvaznzXps3bt2qipqYmIiJKSkvjv//7vmDJlShxxxBFx/vnnxxFHHBErV66M/v37d8RLAAAAuqlclmVZRxfRmdXW1kZ5eXnU1NREWVlZR5cDAAAklOr7f9Ec8QIAAChWghcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBighcAAEBipR1dQGeXZVlERNTW1nZwJQAAQGo7v/fvzAGFInjtwzvvvBMREUOHDu3gSgAAgPayefPmKC8vL9h4uazQUa6LaWhoiDfeeCP69+8fuVyuo8uhndXW1sbQoUNj/fr1UVZW1tHl0M7s/+7N/u/e7P/uzf7v3mpqauLQQw+Nt99+Ow488MCCjeuI1z706NEjPvzhD3d0GXSwsrIyH7zdmP3fvdn/3Zv9373Z/91bjx6FnQ7D5BoAAACJCV4AAACJCV6wF717945vfvOb0bt3744uhQ5g/3dv9n/3Zv93b/Z/95Zq/5tcAwAAIDFHvAAAABITvAAAABITvAAAABITvAAAABITvOAD3n777Zg+fXqUl5dHeXl5TJ8+Pf785z/vdZsLLrggcrlck2XMmDHtUzBtNn/+/Bg+fHj06dMnRo0aFcuXL99r/2XLlsWoUaOiT58+cfjhh8fChQvbqVJS2J/9v3Tp0t3e67lcLl566aV2rJhCePzxx2Py5MkxZMiQyOVycc899+xzG+/9rmN/97/3ftcyd+7cOOmkk6J///4xaNCgOPvss2Pt2rX73K4QnwGCF3zAeeedF88991w89NBD8dBDD8Vzzz0X06dP3+d2Z555ZlRVVTUuDzzwQDtUS1vdddddMXPmzPj6178eq1evjnHjxsWkSZNi3bp1zfZ/5ZVX4qyzzopx48bF6tWr47rrrosrrrgiFi1a1M6VUwj7u/93Wrt2bZP3+8c+9rF2qphC2bp1axx33HHxgx/8oEX9vfe7lv3d/zt573cNy5Yti0svvTSeeuqpWLJkSdTV1cWECRNi69ate9ymYJ8BGZBlWZa9+OKLWURk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xo8f3yG/KwA6hmu8AChqp59+etTX18fy5csjIn8tVXl5eUybNi1++tOfRkREdXV1VFZWxsqVK+OBBx6Ip59+On796183jvGnP/0phg4dGmvXro0jjjii2Wu8li5dGp/61KfinnvuiSlTpuy1pqOPPjouvvjiuOyyy5q0b968OU4++eQ488wz4wc/+EGBfgMAFAPXeAFQ9I499tjG/y4pKYkBAwbEMccc09hWUVEREREbN26MZ599Nh577LHo16/fbuP84Q9/iCOOOGKvzzV69Ogm61u3bo3rr78+/uu//iveeOONqKuri23btjUe8drpvffei3POOSeGDRtW0Ek7ACgOghcARa9nz55N1nO5XJO2XC4XERENDQ3R0NAQkydPju9+97u7jVNZWbnP5zrggAOarP/zP/9z/PrXv44bbrghPvrRj0bfvn3jb//2b2PHjh1N+l188cXx+uuvxzPPPGNWQ4BuyCc/AN3KiSeeGIsWLYphw4btMQD16tUr6uvrWzTe8uXL44ILLoipU6dGRMSWLVvi1VdfbdJn3rx58ctf/jKeeuqpOOigg9pUPwDFyeQaAHQrl156abz11lvxxS9+MZ555pn44x//GA8//HB85StfaQxbw4YNi6effjpeffXV2LRpUzQ0NOxxvI9+9KNx9913x3PPPRfPP/98nHfeeU36P/LII3HNNdfETTfdFAceeGBUV1dHdXV11NTUJH+tAHQeghcA3cqQIUPiiSeeiPr6+pg4cWKMHDkyrrzyyigvL48ePfJ/Fq+++uooKSmJj3/843HIIYfsdr3WB914441x0EEHxSmnnBKTJ0+OiRMnxoknntj4+IoVK6K+vj4uvPDCqKysbFyuvPLK5K8VgM7DrIYAAACJOeIFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQmOAFAACQ2P8HlbeU4i39Cl0AAAAASUVORK5CYII=\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.9.13"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
"autoclose": false,
"autocomplete": true,
"bibliofile": "biblio.bib",
"cite_by": "apalike",
"current_citInitial": 1,
"eqLabelWithNumbers": true,
"eqNumInitial": 1,
"hotkeys": {
"equation": "Ctrl-E",
"itemize": "Ctrl-I"
},
"labels_anchors": false,
"latex_user_defs": false,
"report_style_numbering": false,
"user_envs_cfg": false
},
"livereveal": {
"start_slideshow_at": "selected",
"theme": "white"
}
},
"nbformat": 4,
"nbformat_minor": 4
}