{
"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 (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": [
"\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": "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 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": [
"## 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": "slide"
}
},
"source": [
"### Metryki dla zadań regresji\n",
"\n",
"Dla zadań regresji możemy zastosować np.:\n",
" * błąd średniokwadratowy (*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": 34,
"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": 35,
"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": 36,
"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": 37,
"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": 38,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
"