diff --git a/wyk/03_Regresja_liniowa_2.ipynb b/wyk/03_Regresja_liniowa_2.ipynb
index 605ad58..4d849ae 100644
--- a/wyk/03_Regresja_liniowa_2.ipynb
+++ b/wyk/03_Regresja_liniowa_2.ipynb
@@ -1496,7 +1496,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.10.4"
+ "version": "3.10.6"
},
"livereveal": {
"start_slideshow_at": "selected",
diff --git a/wyk/04_Regresja_logistyczna.ipynb b/wyk/04_Regresja_logistyczna.ipynb
index b61990d..ceeabc6 100644
--- a/wyk/04_Regresja_logistyczna.ipynb
+++ b/wyk/04_Regresja_logistyczna.ipynb
@@ -8,8 +8,8 @@
}
},
"source": [
- "### AITech — Uczenie maszynowe\n",
- "# 3. Regresja logistyczna"
+ "### Uczenie maszynowe\n",
+ "# 4. Regresja logistyczna"
]
},
{
@@ -86,7 +86,7 @@
}
},
"source": [
- "## 3.1. Dwuklasowa regresja logistyczna"
+ "## 4.1. Dwuklasowa regresja logistyczna"
]
},
{
@@ -115,7 +115,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 147,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -127,7 +127,7 @@
"\n",
"import numpy as np\n",
"import matplotlib\n",
- "import matplotlib.pyplot as pl\n",
+ "import matplotlib.pyplot as plt\n",
"import pandas\n",
"import ipywidgets as widgets\n",
"\n",
@@ -138,8 +138,8 @@
"\n",
"# Przydatne funkcje\n",
"\n",
- "# Wyświetlanie macierzy w LaTeX-u\n",
"def LatexMatrix(matrix):\n",
+ " \"\"\"Wyświetlanie macierzy w LaTeX-u\"\"\"\n",
" ltx = r'\\left[\\begin{array}'\n",
" m, n = matrix.shape\n",
" ltx += '{' + (\"r\" * n) + '}'\n",
@@ -148,13 +148,13 @@
" ltx += r'\\end{array}\\right]'\n",
" return ltx\n",
"\n",
- "# Hipoteza (wersja macierzowa)\n",
- "def hMx(theta, X):\n",
+ "def h(theta, X):\n",
+ " \"\"\"Hipoteza (wersja macierzowa)\"\"\"\n",
" return X * theta\n",
"\n",
- "# Wykres danych (wersja macierzowa)\n",
- "def regdotsMx(X, y, xlabel, ylabel): \n",
- " fig = pl.figure(figsize=(16*.6, 9*.6))\n",
+ "def regdots(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",
@@ -162,12 +162,12 @@
" ax.set_xlabel(xlabel)\n",
" ax.set_ylabel(ylabel)\n",
" ax.margins(.05, .05)\n",
- " pl.ylim(y.min() - 1, y.max() + 1)\n",
- " pl.xlim(np.min(X[:, 1]) - 1, np.max(X[:, 1]) + 1)\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",
- "# Wykres krzywej regresji (wersja macierzowa)\n",
- "def reglineMx(fig, fun, theta, X):\n",
+ "def regline(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",
@@ -179,8 +179,8 @@
" theta1=(float(theta[1][0]) if theta[1][0] >= 0 else float(-theta[1][0])),\n",
" op='+' if theta[1][0] >= 0 else '-')))\n",
"\n",
- "# Legenda wykresu\n",
"def legend(fig):\n",
+ " \"\"\"Legenda wykresu\"\"\"\n",
" ax = fig.axes[0]\n",
" handles, labels = ax.get_legend_handles_labels()\n",
" # try-except block is a fix for a bug in Poly3DCollection\n",
@@ -189,20 +189,19 @@
" except AttributeError:\n",
" pass\n",
"\n",
- "# Wersja macierzowa funkcji kosztu\n",
- "def JMx(theta,X,y):\n",
+ "def J(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",
- "# Wersja macierzowa gradientu funkcji kosztu\n",
- "def dJMx(theta,X,y):\n",
+ "def dJ(theta,X,y):\n",
+ " \"\"\"Wersja macierzowa gradientu funkcji kosztu\"\"\"\n",
" return 1.0 / len(y) * (X.T * (X * theta - y)) \n",
"\n",
- "# Implementacja algorytmu gradientu prostego za pomocą numpy i macierzy\n",
- "def GDMx(fJ, fdJ, theta, X, y, alpha=0.1, eps=10**-3):\n",
+ "def GD(fJ, fdJ, theta, X, y, alpha=0.1, eps=10**-3):\n",
+ " \"\"\"Implementacja algorytmu gradientu prostego za pomocą numpy i macierzy\"\"\"\n",
" current_cost = fJ(theta, X, y)\n",
- " logs = [[current_cost, theta]]\n",
" while True:\n",
" theta = theta - alpha * fdJ(theta, X, y) # implementacja wzoru\n",
" current_cost, prev_cost = fJ(theta, X, y), current_cost\n",
@@ -210,13 +209,12 @@
" break\n",
" if abs(prev_cost - current_cost) <= eps:\n",
" break\n",
- " logs.append([current_cost, theta]) \n",
- " return theta, logs\n",
+ " return theta\n",
"\n",
- "thetaStartMx = np.matrix([0, 0]).reshape(2, 1)\n",
+ "theta_start = np.matrix([0, 0]).reshape(2, 1)\n",
"\n",
- "# Funkcja, która rysuje próg\n",
"def threshold(fig, theta):\n",
+ " \"\"\"Funkcja, która rysuje próg\"\"\"\n",
" x_thr = (0.5 - theta.item(0)) / theta.item(1)\n",
" ax = fig.axes[0]\n",
" ax.plot([x_thr, x_thr], [-1, 2],\n",
@@ -226,7 +224,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 148,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -250,13 +248,13 @@
"source": [
"# Wczytanie pełnych (oryginalnych) danych\n",
"\n",
- "data_iris = pandas.read_csv('iris.csv')\n",
- "print(data_iris[:6])"
+ "data_iris = pandas.read_csv(\"iris.csv\")\n",
+ "print(data_iris[:6])\n"
]
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 149,
"metadata": {
"scrolled": true,
"slideshow": {
@@ -282,14 +280,16 @@
"# Ograniczenie danych do 2 klas i 1 cechy\n",
"\n",
"data_iris_setosa = pandas.DataFrame()\n",
- "data_iris_setosa['dł. płatka'] = data_iris['pl'] # \"pl\" oznacza \"petal length\"\n",
- "data_iris_setosa['Iris setosa?'] = data_iris['Gatunek'].apply(lambda x: 1 if x=='Iris-setosa' else 0)\n",
- "print(data_iris_setosa[:6])"
+ "data_iris_setosa[\"dł. płatka\"] = data_iris[\"pl\"] # \"pl\" oznacza \"petal length\"\n",
+ "data_iris_setosa[\"Iris setosa?\"] = data_iris[\"Gatunek\"].apply(\n",
+ " lambda x: 1 if x == \"Iris-setosa\" else 0\n",
+ ")\n",
+ "print(data_iris_setosa[:6])\n"
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 150,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -304,16 +304,16 @@
"n = n_plus_1 - 1\n",
"Xn = data_iris_setosa.values[:, 0:n].reshape(m, n)\n",
"\n",
- "XMx3 = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
- "yMx3 = np.matrix(data_iris_setosa.values[:, 1]).reshape(m, 1)\n",
+ "X = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
+ "y = np.matrix(data_iris_setosa.values[:, 1]).reshape(m, 1)\n",
"\n",
"# Regresja liniowa\n",
- "theta_e3, logs3 = GDMx(JMx, dJMx, thetaStartMx, XMx3, yMx3, alpha=0.03, eps=0.000001)"
+ "theta_lin = GD(J, dJ, theta_start, X, y, alpha=0.03, eps=0.000001)\n"
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 151,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -323,969 +323,997 @@
{
"data": {
"image/svg+xml": [
- "\r\n",
- "\r\n",
- "\r\n",
- "\r\n"
+ "\n",
+ "\n",
+ "\n"
],
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
"source": [
- "fig = regdotsMx(XMx3, yMx3, 'x', 'Iris setosa?')\n",
- "legend(fig)"
+ "fig = regdots(X, y, \"x\", \"Iris setosa?\")\n",
+ "legend(fig)\n"
]
},
{
@@ -1303,7 +1331,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 152,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -1313,1040 +1341,1072 @@
{
"data": {
"image/svg+xml": [
- "\r\n",
- "\r\n",
- "\r\n",
- "\r\n"
+ "\n",
+ "\n",
+ "\n"
],
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
"source": [
- "fig = regdotsMx(XMx3, yMx3, 'x', 'Iris setosa?')\n",
- "reglineMx(fig, hMx, theta_e3, XMx3)\n",
- "legend(fig)"
+ "fig = regdots(X, y, \"x\", \"Iris setosa?\")\n",
+ "regline(fig, h, theta_lin, X)\n",
+ "legend(fig)\n"
]
},
{
@@ -2362,7 +2422,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 153,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -2372,1168 +2432,1206 @@
{
"data": {
"image/svg+xml": [
- "\r\n",
- "\r\n",
- "\r\n",
- "\r\n"
+ "\n",
+ "\n",
+ "\n"
],
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
"source": [
- "fig = regdotsMx(XMx3, yMx3, 'x', 'Iris setosa?')\n",
- "theta_e3, logs3 = GDMx(JMx, dJMx, thetaStartMx, XMx3, yMx3, alpha=0.03, eps=0.000001)\n",
- "reglineMx(fig, hMx, theta_e3, XMx3)\n",
- "threshold(fig, theta_e3) # pomarańczowa linia oznacza granicę między klasą \"1\" a klasą \"0\" wyznaczoną przez próg \"h(x) = 0.5\"\n",
- "legend(fig)"
+ "fig = regdots(X, y, \"x\", \"Iris setosa?\")\n",
+ "theta_lin = GD(J, dJ, theta_start, X, y, alpha=0.03, eps=0.000001)\n",
+ "regline(fig, h, theta_lin, X)\n",
+ "threshold(\n",
+ " fig, theta_lin\n",
+ ") # pomarańczowa linia oznacza granicę między klasą \"1\" a klasą \"0\" wyznaczoną przez próg \"h(x) = 0.5\"\n",
+ "legend(fig)\n"
]
},
{
@@ -3588,7 +3686,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 154,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@@ -3596,15 +3694,14 @@
},
"outputs": [],
"source": [
- "# Funkjca logistycza\n",
- "\n",
"def logistic(x):\n",
- " return 1.0 / (1.0 + np.exp(-x))"
+ " \"\"\"Funkcja logistyczna\"\"\"\n",
+ " return 1.0 / (1.0 + np.exp(-x))\n"
]
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 155,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -3613,14 +3710,16 @@
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
- "def plot_logistic():\n",
- " x = np.linspace(-5,5,200)\n",
- " y = logistic(x)\n",
"\n",
- " fig = plt.figure(figsize=(7,5))\n",
+ "\n",
+ "def plot_logistic():\n",
+ " \"\"\"Wykres funkcji logistycznej\"\"\"\n",
+ " x = np.linspace(-5, 5, 200)\n",
+ " y = logistic(x)\n",
+ " fig = plt.figure(figsize=(7, 5))\n",
" ax = fig.add_subplot(111)\n",
- " plt.ylim(-.1,1.1)\n",
- " ax.plot(x, y, linewidth='2')"
+ " plt.ylim(-0.1, 1.1)\n",
+ " ax.plot(x, y, linewidth=\"2\")\n"
]
},
{
@@ -3636,7 +3735,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 156,
"metadata": {
"scrolled": true,
"slideshow": {
@@ -3647,481 +3746,495 @@
{
"data": {
"image/svg+xml": [
- "\r\n",
- "\r\n",
- "\r\n",
- "\r\n"
+ "\n",
+ "\n",
+ "\n"
],
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
"source": [
- "plot_logistic()"
+ "plot_logistic()\n"
]
},
{
@@ -4163,7 +4276,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 157,
"metadata": {
"slideshow": {
"slide_type": "skip"
@@ -4171,9 +4284,9 @@
},
"outputs": [],
"source": [
- "# Funkcja regresji logistcznej\n",
"def h(theta, X):\n",
- " return 1.0/(1.0 + np.exp(-X * theta))"
+ " \"\"\"Funkcja regresji logistcznej\"\"\"\n",
+ " return 1.0 / (1.0 + np.exp(-X * theta))\n"
]
},
{
@@ -4206,7 +4319,7 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 158,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -4214,18 +4327,18 @@
},
"outputs": [],
"source": [
- "# Funkcja kosztu dla regresji logistycznej\n",
"def J(h, theta, X, y):\n",
+ " \"\"\"Funkcja kosztu dla regresji logistycznej\"\"\"\n",
" m = len(y)\n",
" h_val = h(theta, X)\n",
" s1 = np.multiply(y, np.log(h_val))\n",
" s2 = np.multiply((1 - y), np.log(1 - h_val))\n",
- " return -np.sum(s1 + s2, axis=0) / m"
+ " return -np.sum(s1 + s2, axis=0) / m\n"
]
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 159,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@@ -4233,14 +4346,14 @@
},
"outputs": [],
"source": [
- "# Gradient dla regresji logistycznej\n",
"def dJ(h, theta, X, y):\n",
- " return 1.0 / len(y) * (X.T * (h(theta, X) - y))"
+ " \"\"\"Gradient dla regresji logistycznej\"\"\"\n",
+ " return 1.0 / len(y) * (X.T * (h(theta, X) - y))\n"
]
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 160,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -4248,27 +4361,28 @@
},
"outputs": [],
"source": [
- "# Metoda gradientu prostego dla regresji logistycznej\n",
- "def GD(h, fJ, fdJ, theta, X, y, alpha=0.01, eps=10**-3, maxSteps=10000):\n",
- " errorCurr = fJ(h, theta, X, y)\n",
- " errors = [[errorCurr, theta]]\n",
+ "def GD(h, fJ, fdJ, theta, X, y, alpha=0.01, eps=10**-3, max_steps=10000):\n",
+ " \"\"\"Metoda gradientu prostego dla regresji logistycznej\"\"\"\n",
+ " curr_cost = fJ(h, theta, X, y)\n",
+ " history = [[curr_cost, 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",
+ " prev_cost = curr_cost\n",
+ " curr_cost = fJ(h, theta, X, y)\n",
" # kryteria stopu\n",
- " if abs(errorPrev - errorCurr) <= eps:\n",
+ " if abs(prev_cost - curr_cost) <= eps:\n",
" break\n",
- " if len(errors) > maxSteps:\n",
+ " if len(history) > max_steps:\n",
" break\n",
- " errors.append([errorCurr, theta]) \n",
- " return theta, errors"
+ " history.append([curr_cost, theta])\n",
+ " return theta, history\n"
]
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 161,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -4279,7 +4393,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "error = [[0.05755617]]\n",
+ "Koszt: [[0.05755617]]\n",
"theta = [[ 5.02530461]\n",
" [-1.99174803]]\n"
]
@@ -4287,15 +4401,16 @@
],
"source": [
"# Uruchomienie metody gradientu prostego dla regresji logistycznej\n",
- "thetaBest, errors = GD(h, J, dJ, thetaStartMx, XMx3, yMx3, \n",
- " alpha=0.1, eps=10**-7, maxSteps=1000)\n",
- "print(\"error =\", errors[-1][0])\n",
- "print(\"theta =\", thetaBest)"
+ "theta_best, history = GD(\n",
+ " h, J, dJ, theta_start, X, y, alpha=0.1, eps=10**-7, max_steps=1000\n",
+ ")\n",
+ "print(f\"Koszt: {history[-1][0]}\")\n",
+ "print(f\"theta = {theta_best}\")\n"
]
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 162,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -4303,30 +4418,36 @@
},
"outputs": [],
"source": [
- "# Funkcja regresji logistycznej (wersja skalarna)\n",
"def scalar_logistic_regression_function(theta, x):\n",
- " return 1.0/(1.0 + np.exp(-(theta.item(0) + theta.item(1) * x)))\n",
+ " \"\"\"Funkcja regresji logistycznej (wersja skalarna)\"\"\"\n",
+ " return 1.0 / (1.0 + np.exp(-(theta.item(0) + theta.item(1) * x)))\n",
+ "\n",
"\n",
- "# Rysowanie progu\n",
"def threshold_val(fig, x_thr):\n",
+ " \"\"\"Rysowanie progu\"\"\"\n",
" ax = fig.axes[0]\n",
- " ax.plot([x_thr, x_thr], [-1, 2],\n",
- " color='orange', linestyle='dashed',\n",
- " label=u'próg: $x={:.2F}$'.format(x_thr))\n",
+ " ax.plot(\n",
+ " [x_thr, x_thr],\n",
+ " [-1, 2],\n",
+ " color=\"orange\",\n",
+ " linestyle=\"dashed\",\n",
+ " label=\"próg: $x={:.2F}$\".format(x_thr),\n",
+ " )\n",
+ "\n",
"\n",
- "# Wykres krzywej regresji logistycznej\n",
"def logistic_regline(fig, theta, X):\n",
+ " \"\"\"Wykres krzywej regresji logistycznej\"\"\"\n",
" ax = fig.axes[0]\n",
" x0 = np.min(X[:, 1]) - 1.0\n",
" x1 = np.max(X[:, 1]) + 1.0\n",
" Arg = np.arange(x0, x1, 0.1)\n",
" Val = scalar_logistic_regression_function(theta, Arg)\n",
- " ax.plot(Arg, Val, linewidth='2')"
+ " ax.plot(Arg, Val, linewidth=\"2\")\n"
]
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 163,
"metadata": {
"scrolled": true,
"slideshow": {
@@ -4337,990 +4458,1016 @@
{
"data": {
"image/svg+xml": [
- "\r\n",
- "\r\n",
- "\r\n",
- "\r\n"
+ "\n",
+ "\n",
+ "\n"
],
"text/plain": [
- ""
+ ""
]
},
- "metadata": {
- "needs_background": "light"
- },
+ "metadata": {},
"output_type": "display_data"
}
],
"source": [
- "fig = regdotsMx(XMx3, yMx3, xlabel='x', ylabel='Iris setosa?')\n",
- "logistic_regline(fig, thetaBest, XMx3)\n",
- "threshold_val(fig, 2.5)"
+ "fig = regdots(X, y, xlabel=\"x\", ylabel=\"Iris setosa?\")\n",
+ "logistic_regline(fig, theta_best, X)\n",
+ "threshold_val(fig, 2.5)\n"
]
},
{
@@ -5382,12 +5529,16 @@
"source": [
"Jak postąpić, jeżeli będziemy mieli więcej niż jedną cechę $x$?\n",
"\n",
- "Weźmy teraz wszystkie cechy występujące w zbiorze *Iris*."
+ "Weźmy teraz wszystkie cechy występujące w zbiorze *Iris*:\n",
+ "* długość płatków (`pl`, *petal length*)\n",
+ "* szerokość płatków (`pw`, *petal width*)\n",
+ "* długość działek kielicha (`sl`, *sepal length*)\n",
+ "* szerokość działek kielicha (`sw`, *sepal width*)"
]
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": 164,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5398,45 +5549,29 @@
"name": "stdout",
"output_type": "stream",
"text": [
- " dł. płatków szer. płatków dł. dz. k. szer. dz. k. Iris setosa?\n",
- "0 1.4 0.2 5.2 3.4 1\n",
- "1 1.5 0.4 5.1 3.7 1\n",
- "2 5.6 2.4 6.7 3.1 0\n",
- "3 5.1 2.0 6.5 3.2 0\n",
- "4 4.5 1.7 4.9 2.5 0\n",
- "5 5.1 1.6 6.0 2.7 0\n"
+ " pl pw sl sw Iris setosa?\n",
+ "0 1.4 0.2 5.2 3.4 1\n",
+ "1 1.5 0.4 5.1 3.7 1\n",
+ "2 5.6 2.4 6.7 3.1 0\n",
+ "3 5.1 2.0 6.5 3.2 0\n",
+ "4 4.5 1.7 4.9 2.5 0\n",
+ "5 5.1 1.6 6.0 2.7 0\n"
]
}
],
"source": [
"data_iris_setosa_multi = pandas.DataFrame()\n",
- "data_iris_setosa_multi['dł. płatków'] = data_iris['pl'] # \"pl\" oznacza \"petal length\" (długość płatków)\n",
- "data_iris_setosa_multi['szer. płatków'] = data_iris['pw'] # \"pw\" oznacza \"petal width\" (szerokość płatków)\n",
- "data_iris_setosa_multi['dł. dz. k.'] = data_iris['sl'] # \"sl\" oznacza \"sepal length\" (długość działek kielicha)\n",
- "data_iris_setosa_multi['szer. dz. k.'] = data_iris['sw'] # \"sw\" oznacza \"sepal width\" (szerokość działek kielicha)\n",
- "data_iris_setosa_multi['Iris setosa?'] = data_iris['Gatunek'].apply(lambda x: 1 if x=='Iris-setosa' else 0)\n",
- "print(data_iris_setosa_multi[:6])"
+ "for feature in [\"pl\", \"pw\", \"sl\", \"sw\"]:\n",
+ " data_iris_setosa_multi[feature] = data_iris[feature]\n",
+ "data_iris_setosa_multi[\"Iris setosa?\"] = data_iris[\"Gatunek\"].apply(\n",
+ " lambda x: 1 if x == \"Iris-setosa\" else 0\n",
+ ")\n",
+ "print(data_iris_setosa_multi[:6])\n"
]
},
{
"cell_type": "code",
- "execution_count": 19,
- "metadata": {
- "slideshow": {
- "slide_type": "notes"
- }
- },
- "outputs": [],
- "source": [
- "%matplotlib inline\n",
- "\n",
- "import matplotlib.pyplot as plt\n",
- "import seaborn"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
+ "execution_count": 165,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5468,16 +5603,16 @@
"n = n_plus_1 - 1\n",
"Xn = data_iris_setosa_multi.values[:, 0:n].reshape(m, n)\n",
"\n",
- "XMx4 = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
- "yMx4 = np.matrix(data_iris_setosa_multi.values[:, n]).reshape(m, 1)\n",
+ "X = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
+ "y = np.matrix(data_iris_setosa_multi.values[:, n]).reshape(m, 1)\n",
"\n",
- "print(XMx4[:6])\n",
- "print(yMx4[:6])"
+ "print(X[:6])\n",
+ "print(y[:6])\n"
]
},
{
"cell_type": "code",
- "execution_count": 21,
+ "execution_count": 166,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5486,16 +5621,16 @@
"outputs": [],
"source": [
"# Podział danych na zbiór trenujący i testowy\n",
- "XTrain, XTest = XMx4[:100], XMx4[100:]\n",
- "yTrain, yTest = yMx4[:100], yMx4[100:]\n",
+ "XTrain, XTest = X[:100], X[100:]\n",
+ "yTrain, yTest = y[:100], y[100:]\n",
"\n",
"# Macierz parametrów początkowych\n",
- "thetaTemp = np.ones(5).reshape(5,1)"
+ "theta_start = np.ones(5).reshape(5, 1)\n"
]
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": 167,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5506,7 +5641,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "error = [[0.006797]]\n",
+ "Koszt: [[0.006797]]\n",
"theta = [[ 1.11414027]\n",
" [-2.89324615]\n",
" [-0.66543637]\n",
@@ -5516,10 +5651,11 @@
}
],
"source": [
- "thetaBest, errors = GD(h, J, dJ, thetaTemp, XTrain, yTrain, \n",
- " alpha=0.1, eps=10**-7, maxSteps=1000)\n",
- "print(\"error =\", errors[-1][0])\n",
- "print(\"theta =\", thetaBest)"
+ "theta_best, history = GD(\n",
+ " h, J, dJ, theta_start, XTrain, yTrain, alpha=0.1, eps=10**-7, max_steps=1000\n",
+ ")\n",
+ "print(f\"Koszt: {history[-1][0]}\")\n",
+ "print(f\"theta = {theta_best}\")\n"
]
},
{
@@ -5546,7 +5682,7 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 168,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5563,21 +5699,22 @@
" [ 0.14887292]\n",
" [ 2.13284493]]\n",
"x0 = [[1. 6.3 1.8 7.3 2.9]]\n",
- "h(x0) = 1.6061436959824898e-05\n",
- "c(x0) = (0, 1.6061436959824898e-05) \n",
- "\n"
+ "h(x0) = 1.606143695982487e-05\n",
+ "c(x0) = (0, 1.606143695982487e-05)\n"
]
}
],
"source": [
"def classifyBi(theta, X):\n",
+ " \"\"\"Funkcja decyzyjna regresji logistycznej\"\"\"\n",
" prob = h(theta, X).item()\n",
" return (1, prob) if prob > 0.5 else (0, prob)\n",
"\n",
- "print(\"theta =\", thetaBest)\n",
- "print(\"x0 =\", XTest[0])\n",
- "print(\"h(x0) =\", h(thetaBest, XTest[0]).item())\n",
- "print(\"c(x0) =\", classifyBi(thetaBest, XTest[0]), \"\\n\")"
+ "\n",
+ "print(f\"theta = {theta_best}\")\n",
+ "print(f\"x0 = {XTest[0]}\")\n",
+ "print(f\"h(x0) = {h(theta_best, XTest[0]).item()}\")\n",
+ "print(f\"c(x0) = {classifyBi(theta_best, XTest[0])}\")\n"
]
},
{
@@ -5593,7 +5730,7 @@
},
{
"cell_type": "code",
- "execution_count": 24,
+ "execution_count": 169,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -5604,7 +5741,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "0 <=> 0 -- prob: 0.0\n",
+ "0 <=> 0 -- prob: 0.0000\n",
"1 <=> 1 -- prob: 0.9816\n",
"0 <=> 0 -- prob: 0.0001\n",
"0 <=> 0 -- prob: 0.0005\n",
@@ -5620,14 +5757,15 @@
}
],
"source": [
- "acc = 0.0\n",
+ "correct = 0\n",
"for i, rest in enumerate(yTest):\n",
- " cls, prob = classifyBi(thetaBest, XTest[i])\n",
+ " cls, prob = classifyBi(theta_best, XTest[i])\n",
" if i < 10:\n",
- " print(int(yTest[i].item()), \"<=>\", cls, \"-- prob:\", round(prob, 4))\n",
- " acc += cls == yTest[i].item()\n",
+ " print(f\"{yTest[i].item():1.0f} <=> {cls} -- prob: {prob:6.4f}\")\n",
+ " correct += cls == yTest[i].item()\n",
+ "accuracy = correct / len(XTest)\n",
"\n",
- "print(\"\\nAccuracy:\", acc / len(XTest))"
+ "print(f\"\\nAccuracy: {accuracy}\")\n"
]
},
{
@@ -5638,7 +5776,7 @@
}
},
"source": [
- "## 3.2. Wieloklasowa regresja logistyczna"
+ "## 4.2. Wieloklasowa regresja logistyczna"
]
},
{
@@ -5654,7 +5792,7 @@
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 170,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@@ -5752,20 +5890,21 @@
"5 6.0 2.7 5.1 1.6 Iris-versicolor"
]
},
- "execution_count": 25,
+ "execution_count": 170,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas\n",
- "data_iris = pandas.read_csv('iris.csv')\n",
- "data_iris[:6]"
+ "\n",
+ "data_iris = pandas.read_csv(\"iris.csv\")\n",
+ "data_iris[:6]\n"
]
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 171,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5792,7 +5931,7 @@
"\n",
"import numpy as np\n",
"\n",
- "features = ['sl', 'sw', 'pl', 'pw']\n",
+ "features = [\"sl\", \"sw\", \"pl\", \"pw\"]\n",
"m = len(data_iris)\n",
"X = np.matrix(data_iris[features])\n",
"X0 = np.ones(m).reshape(m, 1)\n",
@@ -5800,7 +5939,7 @@
"y = np.matrix(data_iris[[\"Gatunek\"]]).reshape(m, 1)\n",
"\n",
"print(\"X = \", X[:4])\n",
- "print(\"y = \", y[:4])"
+ "print(\"y = \", y[:4])\n"
]
},
{
@@ -5872,7 +6011,7 @@
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 172,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -5883,9 +6022,10 @@
"def mapY(y, cls):\n",
" m = len(y)\n",
" yBi = np.matrix(np.zeros(m)).reshape(m, 1)\n",
- " yBi[y == cls] = 1.\n",
+ " yBi[y == cls] = 1.0\n",
" return yBi\n",
"\n",
+ "\n",
"def indicatorMatrix(y):\n",
" classes = np.unique(y.tolist())\n",
" m = len(y)\n",
@@ -5895,13 +6035,14 @@
" Y[:, i] = mapY(y, cls)\n",
" return Y\n",
"\n",
- "# one-hot matrix\n",
- "Y = indicatorMatrix(y)"
+ "\n",
+ "# Macierz jednostkowa\n",
+ "Y = indicatorMatrix(y)\n"
]
},
{
"cell_type": "code",
- "execution_count": 28,
+ "execution_count": 173,
"metadata": {
"slideshow": {
"slide_type": "notes"
@@ -5914,7 +6055,7 @@
"YTrain, YTest = Y[:100], Y[100:]\n",
"\n",
"# Macierz parametrów początkowych - niech skłąda się z samych jedynek\n",
- "thetaTemp = np.ones(5).reshape(5,1)"
+ "theta_start = np.ones(5).reshape(5, 1)\n"
]
},
{
@@ -5973,7 +6114,7 @@
},
{
"cell_type": "code",
- "execution_count": 29,
+ "execution_count": 174,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -5981,9 +6122,9 @@
},
"outputs": [],
"source": [
- "# Zapis macierzowy funkcji softmax\n",
"def softmax(X):\n",
- " return np.exp(X) / np.sum(np.exp(X))"
+ " \"\"\"Funkcja softmax (wersja macierzowa)\"\"\"\n",
+ " return np.exp(X) / np.sum(np.exp(X))\n"
]
},
{
@@ -5999,7 +6140,7 @@
},
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": 175,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@@ -6017,12 +6158,35 @@
"source": [
"Z = np.matrix([[2.1, 0.5, 0.8, 0.9, 3.2]])\n",
"P = softmax(Z)\n",
- "print(np.sum(P)) "
+ "print(np.sum(P))\n"
]
},
{
"cell_type": "code",
- "execution_count": 31,
+ "execution_count": 176,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def multiple_binary_classifiers(X, Y):\n",
+ " n = X.shape[1]\n",
+ " thetas = []\n",
+ " # Dla każdej klasy wytrenujmy osobny klasyfikator dwuklasowy.\n",
+ " for c in range(Y.shape[1]):\n",
+ " YBi = Y[:, c]\n",
+ " theta = np.matrix(np.random.random(n)).reshape(n, 1)\n",
+ " # Macierz parametrów theta obliczona dla każdej klasy osobno.\n",
+ " theta_best, history = GD(h, J, dJ, theta, X, YBi, alpha=0.1, eps=10**-4)\n",
+ " thetas.append(theta_best)\n",
+ " return thetas\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 177,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -6034,48 +6198,34 @@
"output_type": "stream",
"text": [
"Otrzymana macierz parametrów theta dla klasy 0:\n",
- " [[ 0.68590262]\n",
- " [ 0.39948964]\n",
- " [ 1.13312933]\n",
- " [-2.17550597]\n",
- " [-0.53088875]] \n",
+ " [[ 0.30877778]\n",
+ " [-0.16504776]\n",
+ " [ 1.92701194]\n",
+ " [-1.83418434]\n",
+ " [-0.50458444]] \n",
"\n",
"Otrzymana macierz parametrów theta dla klasy 1:\n",
- " [[ 0.95431453]\n",
- " [ 0.07249434]\n",
- " [-1.07233395]\n",
- " [ 0.53801787]\n",
- " [-0.65001214]] \n",
+ " [[ 0.93723385]\n",
+ " [-0.13501701]\n",
+ " [-0.8448612 ]\n",
+ " [ 0.77823106]\n",
+ " [-0.95577092]] \n",
"\n",
"Otrzymana macierz parametrów theta dla klasy 2:\n",
- " [[-0.66101185]\n",
- " [-1.40133883]\n",
- " [-2.01776182]\n",
- " [ 2.18505283]\n",
- " [ 2.74690482]] \n",
+ " [[-0.72237014]\n",
+ " [-1.56606505]\n",
+ " [-1.71063165]\n",
+ " [ 2.21207268]\n",
+ " [ 2.78489436]] \n",
"\n"
]
}
],
"source": [
- "# Dla każdej klasy wytrenujmy osobny klasyfikator dwuklasowy.\n",
- "\n",
- "def trainMaxEnt(X, Y):\n",
- " n = X.shape[1]\n",
- " thetas = []\n",
- " for c in range(Y.shape[1]):\n",
- " YBi = Y[:,c]\n",
- " theta = np.matrix(np.random.random(n)).reshape(n,1)\n",
- " # Macierz parametrów theta obliczona dla każdej klasy osobno.\n",
- " thetaBest, errors = GD(h, J, dJ, theta, \n",
- " X, YBi, alpha=0.1, eps=10**-4)\n",
- " thetas.append(thetaBest)\n",
- " return thetas\n",
- "\n",
"# Macierze theta dla każdej klasy\n",
- "thetas = trainMaxEnt(XTrain, YTrain);\n",
+ "thetas = multiple_binary_classifiers(XTrain, YTrain)\n",
"for c, theta in enumerate(thetas):\n",
- " print(f\"Otrzymana macierz parametrów theta dla klasy {c}:\\n\", theta, \"\\n\")"
+ " print(f\"Otrzymana macierz parametrów theta dla klasy {c}:\\n\", theta, \"\\n\")\n"
]
},
{
@@ -6093,7 +6243,30 @@
},
{
"cell_type": "code",
- "execution_count": 32,
+ "execution_count": 178,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def classify(thetas, X, debug=False):\n",
+ " regs = np.array([(X * theta).item() for theta in thetas])\n",
+ " if debug:\n",
+ " print(\"Po zastosowaniu regresji: \", regs)\n",
+ " probs = softmax(regs)\n",
+ " if debug:\n",
+ " print(\"Otrzymane prawdopodobieństwa: \", np.around(probs, decimals=3))\n",
+ " result = np.argmax(probs)\n",
+ " if debug:\n",
+ " print(\"Wybrana klasa: \", result)\n",
+ " return result\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 179,
"metadata": {
"slideshow": {
"slide_type": "subslide"
@@ -6105,36 +6278,29 @@
"output_type": "stream",
"text": [
"Dla x = [[1. 7.3 2.9 6.3 1.8]]:\n",
- "Po zastosowaniu regresji: [-7.77303536 0.59324542 1.96796697]\n",
- "Otrzymane prawdopodobieństwa: [0. 0.202 0.798]\n",
+ "Po zastosowaniu regresji: [-7.77134959 0.68398021 1.83339097]\n",
+ "Otrzymane prawdopodobieństwa: [0. 0.241 0.759]\n",
"Wybrana klasa: 2\n",
"Obliczone y = 2\n",
"Oczekiwane y = 2\n",
"\n",
"Dla x = [[1. 4.8 3. 1.4 0.3]]:\n",
- "Po zastosowaniu regresji: [ 2.79786587 -1.35649314 -9.55757825]\n",
- "Otrzymane prawdopodobieństwa: [0.985 0.015 0. ]\n",
+ "Po zastosowaniu regresji: [ 2.57835094 -1.4426392 -9.43900726]\n",
+ "Otrzymane prawdopodobieństwa: [0.982 0.018 0. ]\n",
"Wybrana klasa: 0\n",
"Obliczone y = 0\n",
"Oczekiwane y = 0\n",
"\n",
"Dla x = [[1. 7.1 3. 5.9 2.1]]:\n",
- "Po zastosowaniu regresji: [-7.02868459 0.06130237 1.99650886]\n",
- "Otrzymane prawdopodobieństwa: [0. 0.126 0.874]\n",
+ "Po zastosowaniu regresji: [-6.96334044 0.0284738 1.92618005]\n",
+ "Otrzymane prawdopodobieństwa: [0. 0.13 0.87]\n",
"Wybrana klasa: 2\n",
"Obliczone y = 2\n",
"Oczekiwane y = 2\n",
"\n",
"Dla x = [[1. 5.9 3. 5.1 1.8]]:\n",
- "Po zastosowaniu regresji: [-5.60840075 -0.26110148 1.10600174]\n",
- "Otrzymane prawdopodobieństwa: [0.001 0.203 0.796]\n",
- "Wybrana klasa: 2\n",
- "Obliczone y = 2\n",
- "Oczekiwane y = 2\n",
- "\n",
- "Dla x = [[1. 6.1 2.6 5.6 1.4]]:\n",
- "Po zastosowaniu regresji: [-6.85715204 0.71134476 1.62660319]\n",
- "Otrzymane prawdopodobieństwa: [0. 0.286 0.714]\n",
+ "Po zastosowaniu regresji: [-5.14656032 -0.14535936 1.20033165]\n",
+ "Otrzymane prawdopodobieństwa: [0.001 0.206 0.792]\n",
"Wybrana klasa: 2\n",
"Obliczone y = 2\n",
"Oczekiwane y = 2\n",
@@ -6143,31 +6309,19 @@
}
],
"source": [
- "def classify(thetas, X, debug=False):\n",
- " regs = np.array([(X*theta).item() for theta in thetas])\n",
- " if debug:\n",
- " print(\"Po zastosowaniu regresji: \", regs)\n",
- " probs = softmax(regs)\n",
- " if debug:\n",
- " print(\"Otrzymane prawdopodobieństwa: \", np.around(probs,decimals=3))\n",
- " result = np.argmax(probs)\n",
- " if debug:\n",
- " print(\"Wybrana klasa: \", result)\n",
- " return result\n",
- "\n",
- "for i in range(5):\n",
+ "for i in range(4):\n",
" print(f\"Dla x = {XTest[i]}:\")\n",
" YPredicted = classify(thetas, XTest[i], debug=True)\n",
" print(f\"Obliczone y = {YPredicted}\")\n",
" print(f\"Oczekiwane y = {np.argmax(YTest[i])}\")\n",
- " print()"
+ " print()\n"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@@ -6181,11 +6335,16 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.3"
+ "version": "3.10.6"
},
"livereveal": {
"start_slideshow_at": "selected",
"theme": "white"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
+ }
}
},
"nbformat": 4,