809 lines
136 KiB
Plaintext
809 lines
136 KiB
Plaintext
|
{
|
|||
|
"cells": [
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "slide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"## Uczenie maszynowe UMZ 2019/2020\n",
|
|||
|
"### 5 maja 2020\n",
|
|||
|
"# 8. Uczenie nienadzorowane"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Wyobraźmy sobie, że mamy następujący problem:\n",
|
|||
|
"\n",
|
|||
|
"Mamy zbiór okazów roślin i dysponujemy pewnymi danymi na ich temat (długość płatków kwiatów, ich szerokość itp.), ale zupełnie **nie wiemy**, do jakich gatunków one należą (nie wiemy nawet, ile jest tych gatunków).\n",
|
|||
|
"\n",
|
|||
|
"Chcemy automatycznie podzielić zbiór posiadanych okazów na nie więcej niż $k$ grup (klastrów) ($k$ ustalamy z góry), czyli dokonać **grupowania (klastrowania)** zbioru przykładów.\n",
|
|||
|
"\n",
|
|||
|
"Jest to zagadnienie z kategorii uczenia nienadzorowanego.\n",
|
|||
|
"\n",
|
|||
|
"W celu jego rozwiązania użyjemy algorytmu $k$ średnich."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "slide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"## 8.1. Algorytm $k$ średnich"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"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": [
|
|||
|
"# Wczytanie danych (gatunki kosaćców)\n",
|
|||
|
"\n",
|
|||
|
"data_iris_raw = pandas.read_csv('iris.csv')\n",
|
|||
|
"data_iris = pandas.DataFrame()\n",
|
|||
|
"data_iris['x1'] = data_iris_raw['sl']\n",
|
|||
|
"data_iris['x2'] = data_iris_raw['sw']\n",
|
|||
|
"data_iris['x3'] = data_iris_raw['pl']\n",
|
|||
|
"data_iris['x4'] = data_iris_raw['sw']\n",
|
|||
|
"\n",
|
|||
|
"# Nie używamy w ogóle kolumny ostatniej kolumny (\"Gatunek\"), \n",
|
|||
|
"# ponieważ chcemy dokonać uczenia nienadzorowanego.\n",
|
|||
|
"# Przyjmujemy, że w ogóle nie dysponujemy danymi na temat gatunku,\n",
|
|||
|
"# mamy tylko 150 nieznanych roślin.\n",
|
|||
|
"\n",
|
|||
|
"X = data_iris.values\n",
|
|||
|
"Xs = data_iris.values[:, 2:4]"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 3,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Wykres danych\n",
|
|||
|
"def plot_unlabeled_data(X, col1=0, col2=1, x1label=r'$x_1$', x2label=r'$x_2$'): \n",
|
|||
|
" fig = plt.figure(figsize=(16*.7, 9*.7))\n",
|
|||
|
" ax = fig.add_subplot(111)\n",
|
|||
|
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
|
|||
|
" X1 = X[:, col1].tolist()\n",
|
|||
|
" X2 = X[:, col2].tolist()\n",
|
|||
|
" ax.scatter(X1, X2, c='k', marker='o', s=50, label='Dane')\n",
|
|||
|
" ax.set_xlabel(x1label)\n",
|
|||
|
" ax.set_ylabel(x2label)\n",
|
|||
|
" ax.margins(.05, .05)\n",
|
|||
|
" return fig"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 4,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Przygotowanie interaktywnego wykresu\n",
|
|||
|
"\n",
|
|||
|
"dropdown_arg1 = widgets.Dropdown(options=[0, 1, 2, 3], value=2, description='arg1')\n",
|
|||
|
"dropdown_arg2 = widgets.Dropdown(options=[0, 1, 2, 3], value=3, description='arg2')\n",
|
|||
|
"\n",
|
|||
|
"def interactive_unlabeled_data(arg1, arg2):\n",
|
|||
|
" fig = plot_unlabeled_data(\n",
|
|||
|
" X, col1=arg1, col2=arg2, x1label='$x_{}$'.format(arg1), x2label='$x_{}$'.format(arg2))"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 5,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"image/png": "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
|
|||
|
"text/plain": [
|
|||
|
"<Figure size 806.4x453.6 with 1 Axes>"
|
|||
|
]
|
|||
|
},
|
|||
|
"metadata": {
|
|||
|
"needs_background": "light"
|
|||
|
},
|
|||
|
"output_type": "display_data"
|
|||
|
},
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"text/plain": [
|
|||
|
"<function __main__.interactive_unlabeled_data(arg1, arg2)>"
|
|||
|
]
|
|||
|
},
|
|||
|
"execution_count": 5,
|
|||
|
"metadata": {},
|
|||
|
"output_type": "execute_result"
|
|||
|
}
|
|||
|
],
|
|||
|
"source": [
|
|||
|
"widgets.interact(interactive_unlabeled_data, arg1=dropdown_arg1, arg2=dropdown_arg2)"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Powyższy wykres przedstawia surowe dane.\n",
|
|||
|
"Ponieważ nasze obserwacje mają 4 współrzędne, na płaskim wykresie możemy przedstawić tylko dwie z nich.\n",
|
|||
|
"\n",
|
|||
|
"Dlatego powyższy wykres umożliwia wybór dwóch współrzędnych, na które chcemy rzutować.\n",
|
|||
|
"\n",
|
|||
|
"Wszystkie takie „rzuty” przedstawia również wykres poniżej."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 6,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [
|
|||
|
{
|
|||
|
"name": "stderr",
|
|||
|
"output_type": "stream",
|
|||
|
"text": [
|
|||
|
"/home/pawel/anaconda3/lib/python3.7/site-packages/seaborn/axisgrid.py:2065: UserWarning: The `size` parameter has been renamed to `height`; pleaes update your code.\n",
|
|||
|
" warnings.warn(msg, UserWarning)\n"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"text/plain": [
|
|||
|
"<seaborn.axisgrid.PairGrid at 0x7fba0d6cc310>"
|
|||
|
]
|
|||
|
},
|
|||
|
"execution_count": 6,
|
|||
|
"metadata": {},
|
|||
|
"output_type": "execute_result"
|
|||
|
},
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"image/png": "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
|
|||
|
"text/plain": [
|
|||
|
"<Figure size 756x432 with 20 Axes>"
|
|||
|
]
|
|||
|
},
|
|||
|
"metadata": {
|
|||
|
"needs_background": "light"
|
|||
|
},
|
|||
|
"output_type": "display_data"
|
|||
|
}
|
|||
|
],
|
|||
|
"source": [
|
|||
|
"seaborn.pairplot(data_iris, vars=data_iris.columns, size=1.5, aspect=1.75)"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 7,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Odległość euklidesowa\n",
|
|||
|
"def euclidean_distance(x1, x2):\n",
|
|||
|
" return np.linalg.norm(x1 - x2)"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 8,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Algorytm k średnich\n",
|
|||
|
"def k_means(X, k, distance=euclidean_distance):\n",
|
|||
|
" history = []\n",
|
|||
|
" Y = []\n",
|
|||
|
" \n",
|
|||
|
" # Wylosuj centroid dla każdej klasy\n",
|
|||
|
" centroids = [[random.uniform(X.min(axis=0)[f], X.max(axis=0)[f])\n",
|
|||
|
" for f in range(X.shape[1])]\n",
|
|||
|
" for c in range(k)]\n",
|
|||
|
"\n",
|
|||
|
" # Powtarzaj, dopóki klasy się zmieniają\n",
|
|||
|
" while True:\n",
|
|||
|
" distances = [[distance(centroids[c], x) for c in range(k)] for x in X]\n",
|
|||
|
" Y_new = [d.index(min(d)) for d in distances]\n",
|
|||
|
" if Y_new == Y:\n",
|
|||
|
" break\n",
|
|||
|
" Y = Y_new\n",
|
|||
|
" XY = np.asarray(np.concatenate((X, np.matrix(Y).T), axis=1))\n",
|
|||
|
" Xc = [XY[XY[:, 2] == c][:, :-1] for c in range(k)]\n",
|
|||
|
" centroids = [[Xc[c].mean(axis=0)[f] for f in range(X.shape[1])]\n",
|
|||
|
" for c in range(k)]\n",
|
|||
|
" history.append((centroids, Y))\n",
|
|||
|
"\n",
|
|||
|
" result = history[-1][1]\n",
|
|||
|
" return result, history"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 9,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Wykres danych - klastrowanie\n",
|
|||
|
"def plot_clusters(X, Y, k, centroids=None):\n",
|
|||
|
" color = ['r', 'g', 'b', 'c', 'm', 'y', 'k']\n",
|
|||
|
" fig = plt.figure(figsize=(16*.7, 9*.7))\n",
|
|||
|
" ax = fig.add_subplot(111)\n",
|
|||
|
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
|
|||
|
"\n",
|
|||
|
" X1 = X[:, 0].tolist()\n",
|
|||
|
" X2 = X[:, 1].tolist()\n",
|
|||
|
" X1 = [[x for x, y in zip(X1, Y) if y == c] for c in range(k)]\n",
|
|||
|
" X2 = [[x for x, y in zip(X2, Y) if y == c] for c in range(k)]\n",
|
|||
|
"\n",
|
|||
|
" for c in range(k):\n",
|
|||
|
" ax.scatter(X1[c], X2[c], c=color[c], marker='o', s=25, label='Dane')\n",
|
|||
|
" if centroids:\n",
|
|||
|
" ax.scatter([centroids[c][0]], [centroids[c][1]], c=color[c], marker='+', s=500, label='Centroid')\n",
|
|||
|
"\n",
|
|||
|
" ax.set_xlabel(r'$x_1$')\n",
|
|||
|
" ax.set_ylabel(r'$x_2$')\n",
|
|||
|
" ax.margins(.05, .05)\n",
|
|||
|
" return fig"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 10,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"image/png": "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
|
|||
|
"text/plain": [
|
|||
|
"<Figure size 806.4x453.6 with 1 Axes>"
|
|||
|
]
|
|||
|
},
|
|||
|
"metadata": {
|
|||
|
"needs_background": "light"
|
|||
|
},
|
|||
|
"output_type": "display_data"
|
|||
|
}
|
|||
|
],
|
|||
|
"source": [
|
|||
|
"Ys, history = k_means(Xs, 2)\n",
|
|||
|
"fig = plot_clusters(Xs, Ys, 2, centroids=history[-1][0]),"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 11,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Przygotowanie interaktywnego wykresu\n",
|
|||
|
"\n",
|
|||
|
"slider_k = widgets.IntSlider(min=1, max=7, step=1, value=2, description=r'$k$', width=300)\n",
|
|||
|
"\n",
|
|||
|
"def interactive_kmeans_k(steps, history, k):\n",
|
|||
|
" if steps >= len(history) or steps == 10:\n",
|
|||
|
" steps = len(history) - 1\n",
|
|||
|
" fig = plot_clusters(Xs, history[steps][1], k, centroids=history[steps][0])\n",
|
|||
|
" \n",
|
|||
|
"def interactive_kmeans(k):\n",
|
|||
|
" slider_steps = widgets.IntSlider(min=1, max=10, step=1, value=1, description=r'steps', width=300)\n",
|
|||
|
" _, history = k_means(Xs, k)\n",
|
|||
|
" widgets.interact(interactive_kmeans_k, steps=slider_steps,\n",
|
|||
|
" history=widgets.fixed(history), k=widgets.fixed(k))"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 12,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"application/vnd.jupyter.widget-view+json": {
|
|||
|
"model_id": "d848eb486dd04d669b73755d43a99fb1",
|
|||
|
"version_major": 2,
|
|||
|
"version_minor": 0
|
|||
|
},
|
|||
|
"text/plain": [
|
|||
|
"interactive(children=(IntSlider(value=2, description='$k$', max=7, min=1), Button(description='Run Interact', …"
|
|||
|
]
|
|||
|
},
|
|||
|
"metadata": {},
|
|||
|
"output_type": "display_data"
|
|||
|
},
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"text/plain": [
|
|||
|
"<function __main__.interactive_kmeans(k)>"
|
|||
|
]
|
|||
|
},
|
|||
|
"execution_count": 12,
|
|||
|
"metadata": {},
|
|||
|
"output_type": "execute_result"
|
|||
|
}
|
|||
|
],
|
|||
|
"source": [
|
|||
|
"widgets.interact_manual(interactive_kmeans, k=slider_k) "
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Algorytm $k$ średnich – dane wejściowe\n",
|
|||
|
"\n",
|
|||
|
"* $k$ – liczba klastrów\n",
|
|||
|
"* zbiór uczący $X = \\{ x^{(1)}, x^{(2)}, \\ldots, x^{(m)} \\}$, $x^{(i)} \\in \\mathbb{R}^n$"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Na wejściu nie ma zbioru $Y$, ponieważ jest to uczenie nienadzorowane!"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Algorytm $k$ średnich – pseudokod\n",
|
|||
|
"\n",
|
|||
|
"1. Zainicjalizuj losowo $k$ centroidów (środków ciężkości klastrów): $\\mu_1, \\ldots, \\mu_k$.\n",
|
|||
|
"1. Powtarzaj dopóki przyporządkowania klastrów się zmieniają:\n",
|
|||
|
" 1. Dla $i = 1$ do $m$:\n",
|
|||
|
" za $y^{(i)}$ przyjmij klasę najbliższego centroidu.\n",
|
|||
|
" 1. Dla $c = 1$ do $k$:\n",
|
|||
|
" za $\\mu_c$ przyjmij średnią wszystkich punktów $x^{(i)}$ takich, że $y^{(i)} = c$."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 13,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"# Algorytm k średnich\n",
|
|||
|
"def k_means(X, k, distance=euclidean_distance):\n",
|
|||
|
" Y = []\n",
|
|||
|
" centroids = [[random.uniform(X.min(axis=0)[f],X.max(axis=0)[f])\n",
|
|||
|
" for f in range(X.shape[1])]\n",
|
|||
|
" for c in range(k)] # Wylosuj centroidy\n",
|
|||
|
" while True:\n",
|
|||
|
" distances = [[distance(centroids[c], x) for c in range(k)]\n",
|
|||
|
" for x in X] # Oblicz odległości\n",
|
|||
|
" Y_new = [d.index(min(d)) for d in distances]\n",
|
|||
|
" if Y_new == Y:\n",
|
|||
|
" break # Jeśli nic się nie zmienia, przerwij\n",
|
|||
|
" Y = Y_new\n",
|
|||
|
" XY = np.asarray(np.concatenate((X,np.matrix(Y).T),axis=1))\n",
|
|||
|
" Xc = [XY[XY[:, 2] == c][:, :-1] for c in range(k)]\n",
|
|||
|
" centroids = [[Xc[c].mean(axis=0)[f]\n",
|
|||
|
" for f in range(X.shape[1])]\n",
|
|||
|
" for c in range(k)] # Przesuń centroidy\n",
|
|||
|
" return Y"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Liczba klastrów jest określona z góry i wynosi $k$."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Jeżeli w którymś kroku algorytmu jedna z klas nie zostanie przyporządkowana żadnemu z przykładów, pomija się ją – w ten sposób wynikiem działania algorytmu może być mniej niż $k$ klastrów."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Funkcja kosztu dla problemu klastrowania\n",
|
|||
|
"\n",
|
|||
|
"$$ J \\left( y^{(i)}, \\ldots, y^{(m)}, \\mu_{1}, \\ldots, \\mu_{k} \\right) = \\frac{1}{m} \\sum_{i=1}^{m} || x^{(i)} - \\mu_{y^{(i)}} || ^2 $$"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Zauważmy, że z każdym krokiem algorytmu $k$ średnich koszt się zmniejsza (lub ewentualnie pozostaje taki sam)."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Wielokrotna inicjalizacja\n",
|
|||
|
"\n",
|
|||
|
"* Algorytm $k$ średnich zawsze znajdzie lokalne minimum funkcji kosztu $J$, ale nie zawsze będzie to globalne minimum."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Aby temu zaradzić, można uruchomić algorytm $k$ średnich wiele razy, za każdym razem z innym losowym położeniem centroidów (tzw. **wielokrotna losowa inicjalizacja** – _multiple random initialization_).\n",
|
|||
|
"* Za każdym razem obliczamy koszt $J$. Wybieramy ten wynik, który ma najniższy koszt."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Wybór liczby klastrów $k$\n",
|
|||
|
"\n",
|
|||
|
"Ile powinna wynosić liczba grup $k$?\n",
|
|||
|
"* Najlepiej wybrać $k$ ręcznie w zależności od kształtu danych i celu, który chcemy osiągnąć."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "slide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"## 8.2. Analiza głównych składowych"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Analiza głównych składowych to inny przykład zagadnienia z dziedziny uczenia nienadzorowanego.\n",
|
|||
|
"\n",
|
|||
|
"Polega na próbie zredukowania liczby wymiarów dla danych wielowymiarowych, czyli zmniejszenia liczby cech, gdy rozpatrujemy przykłady o dużej liczbie cech."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Redukcja liczby wymiarów\n",
|
|||
|
"\n",
|
|||
|
"Z jakich powodów chcemy redukować liczbę wymiarów?"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Chcemy pozbyć się nadmiarowych cech, np. „długość w cm” / „długość w calach”, „długość” i „szerokość” / „powierzchnia”."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Chcemy znaleźć bardziej optymalną kombinację cech."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Chcemy przyspieszyć działanie algorytmów."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "fragment"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* Chcemy zwizualizować dane."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Błąd rzutowania\n",
|
|||
|
"\n",
|
|||
|
"**Błąd rzutowania** – błąd średniokwadratowy pomiędzy danymi oryginalnymi a danymi zrzutowanymi."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Sformułowanie problemu\n",
|
|||
|
"\n",
|
|||
|
"**Analiza głównych składowych** (_Principal Component Analysis_, PCA):\n",
|
|||
|
"\n",
|
|||
|
"Zredukować liczbę wymiarów z $n$ do $k$, czyli znaleźć $k$ wektorów $u^{(1)}, u^{(2)}, \\ldots, u^{(k)}$ takich, że rzutowanie danych na podprzeztrzeń rozpiętą na tych wektorach minimalizuje błąd rzutowania."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"* **Uwaga:** analiza głównych składowych to (mimo pozornych podobieństw) zupełnie inne zagadnienie niż regresja liniowa!"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"### Algorytm PCA\n",
|
|||
|
"\n",
|
|||
|
"1. Dany jest zbiór składający się z $x^{(1)}, x^{(2)}, \\ldots, x^{(m)} \\in \\mathbb{R}^n$.\n",
|
|||
|
"1. Chcemy zredukować liczbę wymiarów z $n$ do $k$ ($k < n$).\n",
|
|||
|
"1. W ramach wstępnego przetwarzania dokonujemy skalowania i normalizacji średniej.\n",
|
|||
|
"1. Znajdujemy macierz kowariancji:\n",
|
|||
|
" $$ \\Sigma = \\frac{1}{m} \\sum_{i=1}^{n} \\left( x^{(i)} \\right) \\left( x^{(i)} \\right)^T $$\n",
|
|||
|
"1. Znajdujemy wektory własne macierzy $\\Sigma$ (rozkład SVD):\n",
|
|||
|
" $$ (U, S, V) := \\mathop{\\rm SVD}(\\Sigma) $$\n",
|
|||
|
"1. Pierwszych $k$ kolumn macierzy $U$ to szukane wektory."
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 14,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [],
|
|||
|
"source": [
|
|||
|
"from sklearn.preprocessing import StandardScaler\n",
|
|||
|
"\n",
|
|||
|
"# Algorytm PCA - implementacja\n",
|
|||
|
"def pca(X, k):\n",
|
|||
|
" X_std = StandardScaler().fit_transform(X) # normalizacja\n",
|
|||
|
" mean_vec = np.mean(X_std, axis=0)\n",
|
|||
|
" cov_mat = np.cov(X_std.T) # macierz kowariancji\n",
|
|||
|
" n = cov_mat.shape[0]\n",
|
|||
|
" eig_vals, eig_vecs = np.linalg.eig(cov_mat) # wektory własne\n",
|
|||
|
" eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:, i])\n",
|
|||
|
" for i in range(len(eig_vals))]\n",
|
|||
|
" eig_pairs.sort()\n",
|
|||
|
" eig_pairs.reverse()\n",
|
|||
|
" matrix_w = np.hstack([eig_pairs[i][1].reshape(n, 1)\n",
|
|||
|
" for i in range(k)]) # wybór\n",
|
|||
|
" return X_std.dot(matrix_w) # transformacja"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "code",
|
|||
|
"execution_count": 15,
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "subslide"
|
|||
|
}
|
|||
|
},
|
|||
|
"outputs": [
|
|||
|
{
|
|||
|
"data": {
|
|||
|
"image/png": "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
|
|||
|
"text/plain": [
|
|||
|
"<Figure size 806.4x453.6 with 1 Axes>"
|
|||
|
]
|
|||
|
},
|
|||
|
"metadata": {
|
|||
|
"needs_background": "light"
|
|||
|
},
|
|||
|
"output_type": "display_data"
|
|||
|
}
|
|||
|
],
|
|||
|
"source": [
|
|||
|
"# X - dane ze zbioru \"iris\" z poprzedniego przykładu\n",
|
|||
|
"\n",
|
|||
|
"X_pca = pca(X, 2)\n",
|
|||
|
"fig = plot_unlabeled_data(X_pca)"
|
|||
|
]
|
|||
|
},
|
|||
|
{
|
|||
|
"cell_type": "markdown",
|
|||
|
"metadata": {
|
|||
|
"slideshow": {
|
|||
|
"slide_type": "notes"
|
|||
|
}
|
|||
|
},
|
|||
|
"source": [
|
|||
|
"Analiza głównych składowych umożliwiła stowrzenie powyższego wykresu, który wizualizuje 4-wymiarowe dane ze zbioru *iris* na 2-wymiarowej płaszczyźnie.\n",
|
|||
|
"\n",
|
|||
|
"Współrzędne $x_1$ i $x_2$, stanowiące osi wykresu, zostały uzyskane w wyniku działania algorytmu PCA (nie są to żadne z oryginalnych cech ze zbioru *iris* – długość płatka, szerokość płatka itp.)."
|
|||
|
]
|
|||
|
}
|
|||
|
],
|
|||
|
"metadata": {
|
|||
|
"celltoolbar": "Slideshow",
|
|||
|
"kernelspec": {
|
|||
|
"display_name": "Python 3",
|
|||
|
"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.8.3"
|
|||
|
},
|
|||
|
"livereveal": {
|
|||
|
"start_slideshow_at": "selected",
|
|||
|
"theme": "amu"
|
|||
|
}
|
|||
|
},
|
|||
|
"nbformat": 4,
|
|||
|
"nbformat_minor": 4
|
|||
|
}
|