diff --git a/wyk/02_Regresja_liniowa.ipynb b/wyk/02_Regresja_liniowa.ipynb
new file mode 100644
index 0000000..c627d51
--- /dev/null
+++ b/wyk/02_Regresja_liniowa.ipynb
@@ -0,0 +1,39155 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Uczenie maszynowe\n",
+ "# 2. Regresja liniowa – część 1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 2.1. Funkcja kosztu"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Zadanie\n",
+ "Znając $x$ – ludność miasta, należy przewidzieć $y$ – dochód firmy transportowej.\n",
+ "\n",
+ "(Dane pochodzą z kursu „Machine Learning”, Andrew Ng, Coursera)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "**Uwaga**: Ponieważ ten przykład ma być tak prosty, jak to tylko możliwe, ludność miasta podana jest w dziesiątkach tysięcy mieszkańców, a dochód firmy w dziesiątkach tysięcy dolarów. Dzięki temu funkcja kosztu obliczona w dalszej części wykładu będzie osiągać wartości, które łatwo przedstawić na wykresie."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "import ipywidgets as widgets\n",
+ "\n",
+ "%matplotlib inline\n",
+ "%config InlineBackend.figure_format = \"svg\"\n",
+ "\n",
+ "from IPython.display import display, Math, Latex"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Dane"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " x y\n",
+ "0 6.1101 17.59200\n",
+ "1 5.5277 9.13020\n",
+ "2 8.5186 13.66200\n",
+ "3 7.0032 11.85400\n",
+ "4 5.8598 6.82330\n",
+ ".. ... ...\n",
+ "75 6.5479 0.29678\n",
+ "76 7.5386 3.88450\n",
+ "77 5.0365 5.70140\n",
+ "78 10.2740 6.75260\n",
+ "79 5.1077 2.05760\n",
+ "\n",
+ "[80 rows x 2 columns]\n"
+ ]
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "data = pd.read_csv(\"data01_train.csv\", names=[\"x\", \"y\"])\n",
+ "print(data)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "x = data[\"x\"].to_numpy()\n",
+ "y = data[\"y\"].to_numpy()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Hipoteza i parametry modelu"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Jak przewidzieć $y$ na podstawie danego $x$? W celu odpowiedzi na to pytanie będziemy starać się znaleźć taką funkcję $h(x)$, która będzie najlepiej obrazować zależność między $x$ a $y$, tj. $y \\sim h(x)$.\n",
+ "\n",
+ "Zacznijmy od najprostszego przypadku, kiedy $h(x)$ jest po prostu funkcją liniową. Ogólny wzór funkcji liniowej to"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ h(x) = a \\, x + b $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Pamiętajmy jednak, że współczynniki $a$ i $b$ nie są w tej chwili dane z góry – naszym zadaniem właśnie będzie znalezienie takich ich wartości, żeby $h(x)$ było „możliwie jak najbliżej” $y$ (co właściwie oznacza to sformułowanie, wyjaśnię potem)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "Poszukiwaną funkcję $h$ będziemy nazywać **funkcją hipotezy**, a jej współczynniki – **parametrami modelu**."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "W teorii uczenia maszynowego parametry modelu oznacza się na ogół grecką literą $\\theta$ z odpowiednimi indeksami, dlatego powyższy wzór opisujący liniową funkcję hipotezy zapiszemy jako\n",
+ "$$ h(x) = \\theta_0 + \\theta_1 x $$\n",
+ "\n",
+ "**Parametry modelu** tworzą wektor, który oznaczymy po prostu przez $\\theta$:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "$$ \\theta = \\left[\\begin{array}{c}\\theta_0\\\\ \\theta_1\\end{array}\\right] $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Żeby podkreślić fakt, że funkcja hipotezy zależy od parametrów modelu, będziemy pisać $h_\\theta$ zamiast $h$:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ h_{\\theta}(x) = \\theta_0 + \\theta_1 x $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Przyjrzyjmy się teraz, jak wyglądają dane, które mamy modelować:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Na poniższym wykresie możesz spróbować ręcznie dopasować parametry modelu $\\theta_0$ i $\\theta_1$ tak, aby jak najlepiej modelowały zależność między $x$ a $y$:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Funkcje rysujące wykres kropkowy oraz prostą regresyjną\n",
+ "\n",
+ "\n",
+ "def regdots(x, y):\n",
+ " fig = plt.figure(figsize=(16 * 0.6, 9 * 0.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, y, c=\"r\", label=\"Dane\")\n",
+ "\n",
+ " ax.set_xlabel(\"Wielkość miejscowości\")\n",
+ " ax.set_ylabel(\"Dochód firmy\")\n",
+ " ax.margins(0.05, 0.05)\n",
+ " plt.ylim(min(y) - 1, max(y) + 1)\n",
+ " plt.xlim(min(x) - 1, max(x) + 1)\n",
+ " return fig\n",
+ "\n",
+ "\n",
+ "def regline(fig, fun, theta, x):\n",
+ " ax = fig.axes[0]\n",
+ " x0, x1 = min(x), max(x)\n",
+ " X = [x0, x1]\n",
+ " Y = [fun(theta, x) for x in X]\n",
+ " ax.plot(\n",
+ " X,\n",
+ " Y,\n",
+ " linewidth=\"2\",\n",
+ " label=(\n",
+ " r\"$y={theta0}{op}{theta1}x$\".format(\n",
+ " theta0=theta[0],\n",
+ " theta1=(theta[1] if theta[1] >= 0 else -theta[1]),\n",
+ " op=\"+\" if theta[1] >= 0 else \"-\",\n",
+ " )\n",
+ " ),\n",
+ " )\n",
+ "\n",
+ "\n",
+ "def legend(fig):\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",
+ " try:\n",
+ " fig.legend(handles, labels, fontsize=\"15\", loc=\"lower right\")\n",
+ " except AttributeError:\n",
+ " pass\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig = regdots(x, y)\n",
+ "legend(fig)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Hipoteza: funkcja liniowa jednej zmiennej\n",
+ "\n",
+ "\n",
+ "def h(theta, x):\n",
+ " return theta[0] + theta[1] * x\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Przygotowanie interaktywnego wykresu\n",
+ "\n",
+ "sliderTheta01 = widgets.FloatSlider(\n",
+ " min=-10, max=10, step=0.1, value=0, description=r\"$\\theta_0$\", width=300\n",
+ ")\n",
+ "sliderTheta11 = widgets.FloatSlider(\n",
+ " min=-5, max=5, step=0.1, value=0, description=r\"$\\theta_1$\", width=300\n",
+ ")\n",
+ "\n",
+ "\n",
+ "def slide1(theta0, theta1):\n",
+ " fig = regdots(x, y)\n",
+ " regline(fig, h, [theta0, theta1], x)\n",
+ " legend(fig)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "4880be41c52643798571f509b333a025",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "interactive(children=(FloatSlider(value=0.0, description='$\\\\theta_0$', max=10.0, min=-10.0), FloatSlider(valu…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "widgets.interact_manual(slide1, theta0=sliderTheta01, theta1=sliderTheta11)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Skąd wiadomo, że przewidywania modelu (wartości funkcji $h(x)$) zgadzaja się z obserwacjami (wartości $y$)?\n",
+ "\n",
+ "Aby to zmierzyć wprowadzimy pojęcie funkcji kosztu."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Funkcja kosztu"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Funkcję kosztu zdefiniujemy w taki sposób, żeby odzwierciedlała ona różnicę między przewidywaniami modelu a obserwacjami.\n",
+ "\n",
+ "Jedną z możliwosci jest zdefiniowanie funkcji kosztu jako wartość **błędu średniokwadratowego** (metoda najmniejszych kwadratów, *mean-square error, MSE*).\n",
+ "\n",
+ "My zdefiniujemy funkcję kosztu jako *połowę* błędu średniokwadratowego w celu ułatwienia późniejszych obliczeń (obliczenie pochodnej funkcji kosztu w dalszej części wykładu). Możemy tak zrobić, ponieważ $\\frac{1}{2}$ jest stałą, a pomnożenie przez stałą nie wpływa na przebieg zmienności funkcji."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ J(\\theta) \\, = \\, \\frac{1}{2m} \\sum_{i = 1}^{m} \\left( h_{\\theta} \\left( x^{(i)} \\right) - y^{(i)} \\right) ^2 $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "gdzie $m$ jest liczbą wszystkich przykładów (obserwacji), czyli wielkością zbioru danych uczących.\n",
+ "\n",
+ "W powyższym wzorze sumujemy kwadraty różnic między przewidywaniami modelu ($h_\\theta \\left( x^{(i)} \\right)$) a obserwacjami ($y^{(i)}$) po wszystkich przykładach $i$."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Teraz nasze zadanie sprowadza się do tego, że będziemy szukać takich parametrów $\\theta = \\left[\\begin{array}{c}\\theta_0\\\\ \\theta_1\\end{array}\\right]$, które minimalizują fukcję kosztu $J(\\theta)$:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ \\hat\\theta = \\mathop{\\arg\\min}_{\\theta} J(\\theta) $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ \\theta \\in \\mathbb{R}^2, \\quad J \\colon \\mathbb{R}^2 \\to \\mathbb{R} $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Proszę zwrócić uwagę, że dziedziną funkcji kosztu jest zbiór wszystkich możliwych wartości parametrów $\\theta$."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "$$ J(\\theta_0, \\theta_1) \\, = \\, \\frac{1}{2m} \\sum_{i = 1}^{m} \\left( \\theta_0 + \\theta_1 x^{(i)} - y^{(i)} \\right) ^2 $$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def J(h, theta, x, y):\n",
+ " \"\"\"Funkcja kosztu\"\"\"\n",
+ " m = len(y)\n",
+ " return 1.0 / (2 * m) * sum((h(theta, x[i]) - y[i]) ** 2 for i in range(m))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Oblicz wartość funkcji kosztu i pokaż na wykresie\n",
+ "\n",
+ "\n",
+ "def regline2(fig, fun, theta, xx, yy):\n",
+ " \"\"\"Rysuj regresję liniową\"\"\"\n",
+ " ax = fig.axes[0]\n",
+ " x0, x1 = min(xx), max(xx)\n",
+ " X = [x0, x1]\n",
+ " Y = [fun(theta, x) for x in X]\n",
+ " cost = J(fun, theta, xx, yy)\n",
+ " ax.plot(\n",
+ " X,\n",
+ " Y,\n",
+ " linewidth=\"2\",\n",
+ " label=(\n",
+ " r\"$y={theta0}{op}{theta1}x, \\; J(\\theta)={cost:.3}$\".format(\n",
+ " theta0=theta[0],\n",
+ " theta1=(theta[1] if theta[1] >= 0 else -theta[1]),\n",
+ " op=\"+\" if theta[1] >= 0 else \"-\",\n",
+ " cost=cost,\n",
+ " )\n",
+ " ),\n",
+ " )\n",
+ "\n",
+ "\n",
+ "sliderTheta02 = widgets.FloatSlider(\n",
+ " min=-10, max=10, step=0.1, value=0, description=r\"$\\theta_0$\", width=300\n",
+ ")\n",
+ "sliderTheta12 = widgets.FloatSlider(\n",
+ " min=-5, max=5, step=0.1, value=0, description=r\"$\\theta_1$\", width=300\n",
+ ")\n",
+ "\n",
+ "\n",
+ "def slide2(theta0, theta1):\n",
+ " fig = regdots(x, y)\n",
+ " regline2(fig, h, [theta0, theta1], x, y)\n",
+ " legend(fig)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Poniższy interaktywny wykres pokazuje wartość funkcji kosztu $J(\\theta)$. Czy teraz łatwiej jest dobrać parametry modelu?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "c67ea652bba946cf83a86485848bb0b0",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "interactive(children=(FloatSlider(value=0.0, description='$\\\\theta_0$', max=10.0, min=-10.0), FloatSlider(valu…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "widgets.interact_manual(slide2, theta0=sliderTheta02, theta1=sliderTheta12)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Funkcja kosztu jako funkcja zmiennej $\\theta$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Funkcja kosztu zdefiniowana jako MSE jest funkcją zmiennej wektorowej $\\theta$, czyli funkcją dwóch zmiennych rzeczywistych: $\\theta_0$ i $\\theta_1$.\n",
+ " \n",
+ "Zobaczmy, jak wygląda jej wykres."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Wykres funkcji kosztu dla ustalonego theta_1=1.0\n",
+ "\n",
+ "\n",
+ "def costfun(fun, x, y):\n",
+ " return lambda theta: J(fun, theta, x, y)\n",
+ "\n",
+ "\n",
+ "def costplot(hypothesis, x, y, theta1=1.0):\n",
+ " fig = plt.figure(figsize=(16 * 0.6, 9 * 0.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.set_xlabel(r\"$\\theta_0$\")\n",
+ " ax.set_ylabel(r\"$J(\\theta)$\")\n",
+ " j = costfun(hypothesis, x, y)\n",
+ " fun = lambda theta0: j([theta0, theta1])\n",
+ " X = np.arange(-10, 10, 0.1)\n",
+ " Y = [fun(x) for x in X]\n",
+ " ax.plot(\n",
+ " X, Y, linewidth=\"2\", label=(r\"$J(\\theta_0, {theta1})$\".format(theta1=theta1))\n",
+ " )\n",
+ " return fig\n",
+ "\n",
+ "\n",
+ "def slide3(theta1):\n",
+ " fig = costplot(h, x, y, theta1)\n",
+ " legend(fig)\n",
+ "\n",
+ "\n",
+ "sliderTheta13 = widgets.FloatSlider(\n",
+ " min=-5, max=5, step=0.1, value=1.0, description=r\"$\\theta_1$\", width=300\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "f5ea28655cad4743b9e58a3ecd0b1fc3",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "interactive(children=(FloatSlider(value=1.0, description='$\\\\theta_1$', max=5.0, min=-5.0), Button(description…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 52,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "widgets.interact_manual(slide3, theta1=sliderTheta13)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Wykres funkcji kosztu względem theta_0 i theta_1\n",
+ "\n",
+ "from mpl_toolkits.mplot3d import Axes3D\n",
+ "import pylab\n",
+ "\n",
+ "%matplotlib inline\n",
+ "\n",
+ "def costplot3d(hypothesis, x, y, show_gradient=False):\n",
+ " fig = plt.figure(figsize=(16*.6, 9*.6))\n",
+ " ax = fig.add_subplot(111, projection='3d')\n",
+ " fig.subplots_adjust(left=0.0, right=1.0, bottom=0.0, top=1.0)\n",
+ " ax.set_xlabel(r'$\\theta_0$')\n",
+ " ax.set_ylabel(r'$\\theta_1$')\n",
+ " ax.set_zlabel(r'$J(\\theta)$')\n",
+ " \n",
+ " j = lambda theta0, theta1: costfun(hypothesis, x, y)([theta0, theta1])\n",
+ " X = np.arange(-10, 10.1, 0.1)\n",
+ " Y = np.arange(-1, 4.1, 0.1)\n",
+ " X, Y = np.meshgrid(X, Y)\n",
+ " Z = np.array([[J(hypothesis, [theta0, theta1], x, y) \n",
+ " for theta0, theta1 in zip(xRow, yRow)] \n",
+ " for xRow, yRow in zip(X, Y)])\n",
+ " \n",
+ " ax.plot_surface(X, Y, Z, rstride=2, cstride=8, linewidth=0.5,\n",
+ " alpha=0.5, cmap='jet', zorder=0,\n",
+ " label=r\"$J(\\theta)$\")\n",
+ " ax.view_init(elev=20., azim=-150)\n",
+ "\n",
+ " ax.set_xlim3d(-10, 10);\n",
+ " ax.set_ylim3d(-1, 4);\n",
+ " ax.set_zlim3d(-100, 800);\n",
+ "\n",
+ " N = range(0, 800, 20)\n",
+ " plt.contour(X, Y, Z, N, zdir='z', offset=-100, cmap='coolwarm', alpha=1)\n",
+ " \n",
+ " ax.plot([-3.89578088] * 2,\n",
+ " [ 1.19303364] * 2,\n",
+ " [-100, 4.47697137598], \n",
+ " color='red', alpha=1, linewidth=1.3, zorder=100, linestyle='dashed',\n",
+ " label=r'minimum: $J(-3.90, 1.19) = 4.48$')\n",
+ " ax.scatter([-3.89578088] * 2,\n",
+ " [ 1.19303364] * 2,\n",
+ " [-100, 4.47697137598], \n",
+ " c='r', s=80, marker='x', alpha=1, linewidth=1.3, zorder=100, \n",
+ " label=r'minimum: $J(-3.90, 1.19) = 4.48$')\n",
+ " \n",
+ " if show_gradient:\n",
+ " ax.plot([3.0, 1.1],\n",
+ " [3.0, 2.4],\n",
+ " [263.0, 125.0], \n",
+ " color='green', alpha=1, linewidth=1.3, zorder=100)\n",
+ " ax.scatter([3.0],\n",
+ " [3.0],\n",
+ " [263.0], \n",
+ " c='g', s=30, marker='D', alpha=1, linewidth=1.3, zorder=100)\n",
+ "\n",
+ " ax.margins(0,0,0)\n",
+ " fig.tight_layout()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "costplot3d(h, x, y)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Na powyższym wykresie poszukiwane minimum funkcji kosztu oznaczone jest czerwonym krzyżykiem.\n",
+ "\n",
+ "Możemy też zobaczyć rzut powyższego trójwymiarowego wykresu na płaszczyznę $(\\theta_0, \\theta_1)$ poniżej:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def costplot2d(hypothesis, x, y, gradient_values=[], nohead=False):\n",
+ " fig = plt.figure(figsize=(16 * 0.6, 9 * 0.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.set_xlabel(r\"$\\theta_0$\")\n",
+ " ax.set_ylabel(r\"$\\theta_1$\")\n",
+ "\n",
+ " j = lambda theta0, theta1: costfun(hypothesis, x, y)([theta0, theta1])\n",
+ " X = np.arange(-10, 10.1, 0.1)\n",
+ " Y = np.arange(-1, 4.1, 0.1)\n",
+ " X, Y = np.meshgrid(X, Y)\n",
+ " Z = np.array(\n",
+ " [\n",
+ " [\n",
+ " J(hypothesis, [theta0, theta1], x, y)\n",
+ " for theta0, theta1 in zip(xRow, yRow)\n",
+ " ]\n",
+ " for xRow, yRow in zip(X, Y)\n",
+ " ]\n",
+ " )\n",
+ "\n",
+ " N = range(0, 800, 20)\n",
+ " plt.contour(X, Y, Z, N, cmap=\"coolwarm\", alpha=1)\n",
+ "\n",
+ " ax.scatter(\n",
+ " [-3.89578088],\n",
+ " [1.19303364],\n",
+ " c=\"r\",\n",
+ " s=80,\n",
+ " marker=\"x\",\n",
+ " label=r\"minimum: $J(-3.90, 1.19) = 4.48$\",\n",
+ " )\n",
+ "\n",
+ " if len(gradient_values) > 0:\n",
+ " prev_theta = gradient_values[0][1]\n",
+ " ax.scatter(\n",
+ " [prev_theta[0]], [prev_theta[1]], c=\"g\", s=30, marker=\"D\", zorder=100\n",
+ " )\n",
+ " for cost, theta in gradient_values[1:]:\n",
+ " dtheta = [theta[0] - prev_theta[0], theta[1] - prev_theta[1]]\n",
+ " ax.arrow(\n",
+ " prev_theta[0],\n",
+ " prev_theta[1],\n",
+ " dtheta[0],\n",
+ " dtheta[1],\n",
+ " color=\"green\",\n",
+ " head_width=(0.0 if nohead else 0.1),\n",
+ " head_length=(0.0 if nohead else 0.2),\n",
+ " zorder=100,\n",
+ " )\n",
+ " prev_theta = theta\n",
+ "\n",
+ " return fig\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig = costplot2d(h, x, y)\n",
+ "legend(fig)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Cechy funkcji kosztu\n",
+ "Funkcja kosztu $J(\\theta)$ zdefiniowana powyżej jest funkcją wypukłą, dlatego posiada tylko jedno minimum lokalne."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 2.2. Metoda gradientu prostego"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Metoda gradientu prostego\n",
+ "Metoda znajdowania minimów lokalnych."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "Idea:\n",
+ " * Zacznijmy od dowolnego $\\theta$.\n",
+ " * Zmieniajmy powoli $\\theta$ tak, aby zmniejszać $J(\\theta)$, aż w końcu znajdziemy minimum."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "costplot3d(h, x, y, show_gradient=True)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Przykładowe wartości kolejnych przybliżeń (sztuczne)\n",
+ "\n",
+ "gv = [\n",
+ " [_, [3.0, 3.0]],\n",
+ " [_, [2.6, 2.4]],\n",
+ " [_, [2.2, 2.0]],\n",
+ " [_, [1.6, 1.6]],\n",
+ " [_, [0.4, 1.2]],\n",
+ "]\n",
+ "\n",
+ "# Przygotowanie interaktywnego wykresu\n",
+ "\n",
+ "sliderSteps1 = widgets.IntSlider(\n",
+ " min=0, max=3, step=1, value=0, description=\"kroki\", width=300\n",
+ ")\n",
+ "\n",
+ "\n",
+ "def slide4(steps):\n",
+ " costplot2d(h, x, y, gradient_values=gv[: steps + 1])\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "ba49ab01f3694550a13b124b599f9d17",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "interactive(children=(IntSlider(value=0, description='kroki', max=3), Output()), _dom_classes=('widget-interac…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 59,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "widgets.interact(slide4, steps=sliderSteps1)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Metoda gradientu prostego\n",
+ "W każdym kroku będziemy aktualizować parametry $\\theta_j$:\n",
+ "\n",
+ "$$ \\theta_j := \\theta_j - \\alpha \\frac{\\partial}{\\partial \\theta_j} J(\\theta) $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "Współczynnik $\\alpha$ nazywamy **długością kroku** lub **współczynnikiem szybkości uczenia** (*learning rate*)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "$$ \\begin{array}{rcl}\n",
+ "\\dfrac{\\partial}{\\partial \\theta_j} J(\\theta)\n",
+ " & = & \\dfrac{\\partial}{\\partial \\theta_j} \\dfrac{1}{2m} \\displaystyle\\sum_{i = 1}^{m} \\left( h_{\\theta} \\left( x^{(i)} \\right) - y^{(i)} \\right) ^2 \\\\\n",
+ " & = & 2 \\cdot \\dfrac{1}{2m} \\displaystyle\\sum_{i=1}^m \\left( h_\\theta \\left( x^{(i)} \\right) - y^{(i)} \\right) \\cdot \\dfrac{\\partial}{\\partial\\theta_j} \\left( h_\\theta \\left( x^{(i)} \\right) - y^{(i)} \\right) \\\\\n",
+ " & = & \\dfrac{1}{m}\\displaystyle\\sum_{i=1}^m \\left( h_\\theta \\left( x^{(i)} \\right) - y^{(i)} \\right) \\cdot \\dfrac{\\partial}{\\partial\\theta_j} \\left( \\displaystyle\\sum_{i=0}^n \\theta_i x_i^{(i)} - y^{(i)} \\right)\\\\\n",
+ " & = & \\dfrac{1}{m}\\displaystyle\\sum_{i=1}^m \\left( h_\\theta \\left( x^{(i)} \\right) -y^{(i)} \\right) x_j^{(i)} \\\\\n",
+ "\\end{array} $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Czyli dla regresji liniowej jednej zmiennej:\n",
+ "\n",
+ "$$ h_\\theta(x) = \\theta_0 + \\theta_1x $$\n",
+ "\n",
+ "w każdym kroku będziemy aktualizować:\n",
+ "\n",
+ "$$\n",
+ "\\begin{array}{rcl}\n",
+ "\\theta_0 & := & \\theta_0 - \\alpha \\, \\dfrac{1}{m}\\displaystyle\\sum_{i=1}^m \\left( h_\\theta(x^{(i)})-y^{(i)} \\right) \\\\ \n",
+ "\\theta_1 & := & \\theta_1 - \\alpha \\, \\dfrac{1}{m}\\displaystyle\\sum_{i=1}^m \\left( h_\\theta(x^{(i)})-y^{(i)} \\right) x^{(i)}\\\\ \n",
+ "\\end{array}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "###### Uwaga!\n",
+ " * W każdym kroku aktualizujemy *jednocześnie* $\\theta_0$ i $\\theta_1$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ " * Kolejne kroki wykonujemy aż uzyskamy zbieżność"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Metoda gradientu prostego – implementacja"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Wyświetlanie macierzy w LaTeX-u\n",
+ "\n",
+ "\n",
+ "def LatexMatrix(matrix):\n",
+ " ltx = r\"\\left[\\begin{array}\"\n",
+ " m, n = matrix.shape\n",
+ " ltx += \"{\" + (\"r\" * n) + \"}\"\n",
+ " for i in range(m):\n",
+ " ltx += r\" & \".join([(\"%.4f\" % j.item()) for j in matrix[i]]) + r\" \\\\ \"\n",
+ " ltx += r\"\\end{array}\\right]\"\n",
+ " return ltx\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def gradient_descent(h, cost_fun, theta, x, y, alpha, eps):\n",
+ " current_cost = cost_fun(h, theta, x, y)\n",
+ " history = [\n",
+ " [current_cost, theta]\n",
+ " ] # zapiszmy wartości kosztu i parametrów, by potem zrobić wykres\n",
+ " m = len(y)\n",
+ " while True:\n",
+ " new_theta = [\n",
+ " theta[0] - alpha / float(m) * sum(h(theta, x[i]) - y[i] for i in range(m)),\n",
+ " theta[1]\n",
+ " - alpha / float(m) * sum((h(theta, x[i]) - y[i]) * x[i] for i in range(m)),\n",
+ " ]\n",
+ " theta = new_theta # jednoczesna aktualizacja - używamy zmiennej tymczasowej\n",
+ " try:\n",
+ " prev_cost = current_cost\n",
+ " current_cost = cost_fun(h, theta, x, y)\n",
+ " except OverflowError:\n",
+ " break\n",
+ " if abs(prev_cost - current_cost) <= eps:\n",
+ " break\n",
+ " history.append([current_cost, theta])\n",
+ " return theta, history\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\large\\textrm{Wynik:}\\quad \\theta = \\left[\\begin{array}{r}-1.8792 \\\\ 1.0231 \\\\ \\end{array}\\right] \\quad J(\\theta) = 5.0010 \\quad \\textrm{po 4114 iteracjach}$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "best_theta, history = gradient_descent(h, J, [0.0, 0.0], x, y, alpha=0.001, eps=0.0001)\n",
+ "\n",
+ "display(\n",
+ " Math(\n",
+ " r\"\\large\\textrm{Wynik:}\\quad \\theta = \"\n",
+ " + LatexMatrix(np.matrix(best_theta).reshape(2, 1))\n",
+ " + (r\" \\quad J(\\theta) = %.4f\" % history[-1][0])\n",
+ " + r\" \\quad \\textrm{po %d iteracjach}\" % len(history)\n",
+ " )\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Przygotowanie interaktywnego wykresu\n",
+ "\n",
+ "sliderSteps2 = widgets.IntSlider(\n",
+ " min=0, max=500, step=1, value=1, description=\"kroki\", width=300\n",
+ ")\n",
+ "\n",
+ "\n",
+ "def slide5(steps):\n",
+ " costplot2d(h, x, y, gradient_values=history[: steps + 1], nohead=True)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "metadata": {
+ "scrolled": true,
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "59091adc5a5f4d20bf2ad5e92c17b234",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "interactive(children=(IntSlider(value=1, description='kroki', max=500), Button(description='Run Interact', sty…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 64,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "widgets.interact_manual(slide5, steps=sliderSteps2)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Współczynnik szybkości uczenia $\\alpha$ (długość kroku)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Tempo zbieżności metody gradientu prostego możemy regulować za pomocą parametru $\\alpha$, pamiętając, że:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ " * Jeżeli długość kroku jest zbyt mała, algorytm może działać zbyt wolno."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ " * Jeżeli długość kroku jest zbyt duża, algorytm może nie być zbieżny."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 2.3. Predykcja wyników"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Zbudowaliśmy model, dzięki któremu wiemy, jaka jest zależność między dochodem firmy transportowej ($y$) a ludnością miasta ($x$).\n",
+ "\n",
+ "Wróćmy teraz do postawionego na początku wykładu pytania: jak przewidzieć dochód firmy transportowej w mieście o danej wielkości?\n",
+ "\n",
+ "Odpowiedź polega po prostu na zastosowaniu funkcji $h$ z wyznaczonymi w poprzednim kroku parametrami $\\theta$.\n",
+ "\n",
+ "Na przykład, jeżeli miasto ma $536\\,000$ ludności, to $x = 53.6$ (bo dane trenujące były wyrażone w dziesiątkach tysięcy mieszkańców, a $536\\,000 = 53.6 \\cdot 10\\,000$) i możemy użyć znalezionych parametrów $\\theta$, by wykonać następujące obliczenia:\n",
+ "$$ \\hat{y} \\, = \\, h_\\theta(x) \\, = \\, \\theta_0 + \\theta_1 \\, x \\, = \\, 0.0494 + 0.7591 \\cdot 53.6 \\, = \\, 40.7359 $$\n",
+ "\n",
+ "Czyli używając zdefiniowanych wcześniej funkcji:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "52.96131370254696\n"
+ ]
+ }
+ ],
+ "source": [
+ "example_x = 53.6\n",
+ "predicted_y = h(best_theta, example_x)\n",
+ "print(\n",
+ " predicted_y\n",
+ ") ## taki jest przewidywany dochód tej firmy transportowej w 536-tysięcznym mieście\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 2.4. Ewaluacja modelu"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Jak ocenić jakość stworzonego przez nas modelu?\n",
+ "\n",
+ " * Trzeba sprawdzić, jak przewidywania modelu zgadzają się z oczekiwaniami!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Czy możemy w tym celu użyć danych, których użyliśmy do wytrenowania modelu?\n",
+ "**NIE!**\n",
+ "\n",
+ " * Istotą uczenia maszynowego jest budowanie modeli/algorytmów, które dają dobre przewidywania dla **nieznanych** danych – takich, z którymi algorytm nie miał jeszcze styczności! Nie sztuką jest przewidywać rzeczy, które już sie zna.\n",
+ " * Dlatego testowanie/ewaluowanie modelu na zbiorze uczącym mija się z celem i jest nieprzydatne.\n",
+ " * Do ewaluacji modelu należy użyć oddzielnego zbioru danych.\n",
+ " * **Dane uczące i dane testowe zawsze powinny stanowić oddzielne zbiory!**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Na wykładzie *5. Dobre praktyki w uczeniu maszynowym* dowiesz się, jak podzielić posiadane dane na zbiór uczący i zbiór testowy.\n",
+ "\n",
+ "Tutaj, na razie, do ewaluacji użyjemy specjalnie przygotowanego zbioru testowego."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Jako metrykę ewaluacji wykorzystamy znany nam już błąd średniokwadratowy (MSE):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def mse(expected, predicted):\n",
+ " \"\"\"Błąd średniokwadratowy\"\"\"\n",
+ " m = len(expected)\n",
+ " if len(predicted) != m:\n",
+ " raise Exception(\"Wektory mają różne długości!\")\n",
+ " return 1.0 / (2 * m) * sum((expected[i] - predicted[i]) ** 2 for i in range(m))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "4.36540743711836\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Wczytwanie danych testowych z pliku za pomocą numpy\n",
+ "\n",
+ "test_data = np.loadtxt(\"data01_test.csv\", delimiter=\",\")\n",
+ "x_test = test_data[:, 0]\n",
+ "y_test = test_data[:, 1]\n",
+ "\n",
+ "# Obliczenie przewidywań modelu\n",
+ "y_pred = h(best_theta, x_test)\n",
+ "\n",
+ "# Obliczenie MSE na zbiorze testowym (im mniejszy MSE, tym lepiej!)\n",
+ "evaluation_result = mse(y_test, y_pred)\n",
+ "\n",
+ "print(evaluation_result)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Otrzymana wartość mówi nam o tym, jak dobry jest stworzony przez nas model.\n",
+ "\n",
+ "W przypadku metryki MSE im mniejsza wartość, tym lepiej.\n",
+ "\n",
+ "W ten sposób możemy np. porównywać różne modele."
+ ]
+ }
+ ],
+ "metadata": {
+ "celltoolbar": "Slideshow",
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.4"
+ },
+ "livereveal": {
+ "start_slideshow_at": "selected",
+ "theme": "white"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/wyk/03_Regresja_liniowa_2.ipynb b/wyk/03_Regresja_liniowa_2.ipynb
new file mode 100644
index 0000000..3e786c8
--- /dev/null
+++ b/wyk/03_Regresja_liniowa_2.ipynb
@@ -0,0 +1,9657 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Uczenie maszynowe\n",
+ "# 3. Regresja liniowa – część 2"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 3.1. Regresja liniowa wielu zmiennych"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Do przewidywania wartości $y$ możemy użyć więcej niż jednej cechy $x$:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Przykład – ceny mieszkań"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 70,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "y : price x1: isNew x2: rooms x3: floor x4: location x5: sqrMetres\n",
+ "476118.0 False 3 1 Centrum 78 \n",
+ "459531.0 False 3 2 Sołacz 62 \n",
+ "411557.0 False 3 0 Sołacz 15 \n",
+ "496416.0 False 4 0 Sołacz 14 \n",
+ "406032.0 False 3 0 Sołacz 15 \n",
+ "450026.0 False 3 1 Naramowice 80 \n",
+ "571229.15 False 2 4 Wilda 39 \n",
+ "325000.0 False 3 1 Grunwald 54 \n",
+ "268229.0 False 2 1 Grunwald 90 \n"
+ ]
+ }
+ ],
+ "source": [
+ "import csv\n",
+ "\n",
+ "reader = csv.reader(open(\"data02_train.tsv\", encoding=\"utf-8\"), delimiter=\"\\t\")\n",
+ "for i, row in enumerate(list(reader)[:10]):\n",
+ " if i == 0:\n",
+ " print(\n",
+ " \" \".join(\n",
+ " [\n",
+ " \"{}: {:8}\".format(\"x\" + str(j) if j > 0 else \"y \", entry)\n",
+ " for j, entry in enumerate(row)\n",
+ " ]\n",
+ " )\n",
+ " )\n",
+ " else:\n",
+ " print(\" \".join([\"{:12}\".format(entry) for entry in row]))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ x^{(2)} = ({\\rm \"False\"}, 3, 2, {\\rm \"Sołacz\"}, 62), \\quad x_3^{(2)} = 2 $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Hipoteza"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "W naszym przypadku (wybraliśmy 5 cech):\n",
+ "\n",
+ "$$ h_\\theta(x) = \\theta_0 + \\theta_1 x_1 + \\theta_2 x_2 + \\theta_3 x_3 + \\theta_4 x_4 + \\theta_5 x_5 $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "W ogólności ($n$ cech):\n",
+ "\n",
+ "$$ h_\\theta(x) = \\theta_0 + \\theta_1 x_1 + \\theta_2 x_2 + \\ldots + \\theta_n x_n $$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Jeżeli zdefiniujemy $x_0 = 1$, będziemy mogli powyższy wzór zapisać w bardziej kompaktowy sposób:\n",
+ "\n",
+ "$$\n",
+ "\\begin{array}{rcl}\n",
+ "h_\\theta(x)\n",
+ " & = & \\theta_0 x_0 + \\theta_1 x_1 + \\theta_2 x_2 + \\ldots + \\theta_n x_n \\\\\n",
+ " & = & \\displaystyle\\sum_{i=0}^{n} \\theta_i x_i \\\\\n",
+ " & = & \\theta^T \\, x \\\\\n",
+ " & = & x^T \\, \\theta \\\\\n",
+ "\\end{array}\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Metoda gradientu prostego – notacja macierzowa"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Metoda gradientu prostego przyjmie bardzo elegancką formę, jeżeli do jej zapisu użyjemy wektorów i macierzy."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$\n",
+ "X=\\left[\\begin{array}{cc}\n",
+ "1 & \\left( \\vec x^{(1)} \\right)^T \\\\\n",
+ "1 & \\left( \\vec x^{(2)} \\right)^T \\\\\n",
+ "\\vdots & \\vdots\\\\\n",
+ "1 & \\left( \\vec x^{(m)} \\right)^T \\\\\n",
+ "\\end{array}\\right] \n",
+ "= \\left[\\begin{array}{cccc}\n",
+ "1 & x_1^{(1)} & \\cdots & x_n^{(1)} \\\\\n",
+ "1 & x_1^{(2)} & \\cdots & x_n^{(2)} \\\\\n",
+ "\\vdots & \\vdots & \\ddots & \\vdots\\\\\n",
+ "1 & x_1^{(m)} & \\cdots & x_n^{(m)} \\\\\n",
+ "\\end{array}\\right]\n",
+ "\\quad\n",
+ "\\vec{y} = \n",
+ "\\left[\\begin{array}{c}\n",
+ "y^{(1)}\\\\\n",
+ "y^{(2)}\\\\\n",
+ "\\vdots\\\\\n",
+ "y^{(m)}\\\\\n",
+ "\\end{array}\\right]\n",
+ "\\quad\n",
+ "\\theta = \\left[\\begin{array}{c}\n",
+ "\\theta_0\\\\\n",
+ "\\theta_1\\\\\n",
+ "\\vdots\\\\\n",
+ "\\theta_n\\\\\n",
+ "\\end{array}\\right]\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Wersje macierzowe funkcji rysowania wykresów punktowych oraz krzywej regresyjnej\n",
+ "\n",
+ "\n",
+ "def hMx(theta, X):\n",
+ " return X * theta\n",
+ "\n",
+ "\n",
+ "def regdotsMx(X, y):\n",
+ " fig = plt.figure(figsize=(16 * 0.6, 9 * 0.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(\"Populacja\")\n",
+ " ax.set_ylabel(\"Zysk\")\n",
+ " ax.margins(0.05, 0.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",
+ "\n",
+ "def reglineMx(fig, fun, theta, X):\n",
+ " ax = fig.axes[0]\n",
+ " x0, x1 = np.min(X[:, 1]), np.max(X[:, 1])\n",
+ " L = [x0, x1]\n",
+ " LX = np.matrix([1, x0, 1, x1]).reshape(2, 2)\n",
+ " ax.plot(\n",
+ " L,\n",
+ " fun(theta, LX),\n",
+ " linewidth=\"2\",\n",
+ " label=(\n",
+ " r\"$y={theta0:.2}{op}{theta1:.2}x$\".format(\n",
+ " theta0=float(theta[0][0]),\n",
+ " theta1=(\n",
+ " float(theta[1][0]) if theta[1][0] >= 0 else float(-theta[1][0])\n",
+ " ),\n",
+ " op=\"+\" if theta[1][0] >= 0 else \"-\",\n",
+ " )\n",
+ " ),\n",
+ " )\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[[ 1. 3. 1. 78.]\n",
+ " [ 1. 3. 2. 62.]\n",
+ " [ 1. 3. 0. 15.]\n",
+ " [ 1. 4. 0. 14.]\n",
+ " [ 1. 3. 0. 15.]]\n",
+ "(1339, 4)\n",
+ "\n",
+ "[[476118.]\n",
+ " [459531.]\n",
+ " [411557.]\n",
+ " [496416.]\n",
+ " [406032.]]\n",
+ "(1339, 1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Wczytwanie danych z pliku za pomocą numpy – regresja liniowa wielu zmiennych – notacja macierzowa\n",
+ "\n",
+ "import pandas\n",
+ "\n",
+ "data = pandas.read_csv(\n",
+ " \"data02_train.tsv\", delimiter=\"\\t\", usecols=[\"price\", \"rooms\", \"floor\", \"sqrMetres\"]\n",
+ ")\n",
+ "m, n_plus_1 = data.values.shape\n",
+ "n = n_plus_1 - 1\n",
+ "Xn = data.values[:, 1:].reshape(m, n)\n",
+ "\n",
+ "# Dodaj kolumnę jedynek do macierzy\n",
+ "XMx = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
+ "yMx = np.matrix(data.values[:, 0]).reshape(m, 1)\n",
+ "\n",
+ "print(XMx[:5])\n",
+ "print(XMx.shape)\n",
+ "\n",
+ "print()\n",
+ "\n",
+ "print(yMx[:5])\n",
+ "print(yMx.shape)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Funkcja kosztu – notacja macierzowa"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$J(\\theta)=\\dfrac{1}{2|\\vec y|}\\left(X\\theta-\\vec{y}\\right)^T\\left(X\\theta-\\vec{y}\\right)$$ \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\Large J(\\theta) = 85104141370.9717$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from IPython.display import display, Math, Latex\n",
+ "\n",
+ "\n",
+ "def JMx(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",
+ "\n",
+ "thetaMx = np.matrix([10, 90, -1, 2.5]).reshape(4, 1)\n",
+ "\n",
+ "cost = JMx(thetaMx, XMx, yMx)\n",
+ "display(Math(r\"\\Large J(\\theta) = %.4f\" % cost))\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Gradient – notacja macierzowa"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$\\nabla J(\\theta) = \\frac{1}{|\\vec y|} X^T\\left(X\\theta-\\vec y\\right)$$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\large \\theta = \\left[\\begin{array}{r}10.0000 \\\\ 90.0000 \\\\ -1.0000 \\\\ 2.5000 \\\\ \\end{array}\\right]\\quad\\large \\nabla J(\\theta) = \\left[\\begin{array}{r}-373492.7442 \\\\ -1075656.5086 \\\\ -989554.4921 \\\\ -23806475.6561 \\\\ \\end{array}\\right]$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from IPython.display import display, Math, Latex\n",
+ "\n",
+ "\n",
+ "def dJMx(theta, X, y):\n",
+ " \"\"\"Wersja macierzowa gradientu funckji kosztu\"\"\"\n",
+ " return 1.0 / len(y) * (X.T * (X * theta - y))\n",
+ "\n",
+ "\n",
+ "thetaMx = np.matrix([10, 90, -1, 2.5]).reshape(4, 1)\n",
+ "\n",
+ "display(\n",
+ " Math(\n",
+ " r\"\\large \\theta = \"\n",
+ " + LatexMatrix(thetaMx)\n",
+ " + r\"\\quad\"\n",
+ " + r\"\\large \\nabla J(\\theta) = \"\n",
+ " + LatexMatrix(dJMx(thetaMx, XMx, yMx))\n",
+ " )\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Algorytm gradientu prostego – notacja macierzowa"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "$$ \\theta := \\theta - \\alpha \\, \\nabla J(\\theta) $$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\large\\textrm{Wynik:}\\quad \\theta = \\left[\\begin{array}{r}17446.2135 \\\\ 86476.7960 \\\\ -1374.8950 \\\\ 2165.0689 \\\\ \\end{array}\\right] \\quad J(\\theta) = 10324864803.1591 \\quad \\textrm{po 374575 iteracjach}$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Implementacja algorytmu gradientu prostego za pomocą numpy i macierzy\n",
+ "\n",
+ "\n",
+ "def GDMx(fJ, fdJ, theta, X, y, alpha, eps):\n",
+ " current_cost = fJ(theta, X, y)\n",
+ " history = [[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",
+ " if abs(prev_cost - current_cost) <= eps:\n",
+ " break\n",
+ " if current_cost > prev_cost:\n",
+ " print(\"Długość kroku (alpha) jest zbyt duża!\")\n",
+ " break\n",
+ " history.append([current_cost, theta])\n",
+ " return theta, history\n",
+ "\n",
+ "\n",
+ "thetaStartMx = np.zeros((n + 1, 1))\n",
+ "\n",
+ "# Zmieniamy wartości alpha (rozmiar kroku) oraz eps (kryterium stopu)\n",
+ "thetaBestMx, history = GDMx(JMx, dJMx, thetaStartMx, XMx, yMx, alpha=0.0001, eps=0.1)\n",
+ "\n",
+ "######################################################################\n",
+ "display(\n",
+ " Math(\n",
+ " r\"\\large\\textrm{Wynik:}\\quad \\theta = \"\n",
+ " + LatexMatrix(thetaBestMx)\n",
+ " + (r\" \\quad J(\\theta) = %.4f\" % history[-1][0])\n",
+ " + r\" \\quad \\textrm{po %d iteracjach}\" % len(history)\n",
+ " )\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 3.2. Metoda gradientu prostego w praktyce"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "### Kryterium stopu"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Algorytm gradientu prostego polega na wykonywaniu określonych kroków w pętli. Pytanie brzmi: kiedy należy zatrzymać wykonywanie tej pętli?\n",
+ "\n",
+ "W każdej kolejnej iteracji wartość funkcji kosztu maleje o coraz mniejszą wartość.\n",
+ "Parametr `eps` określa, jaka wartość graniczna tej różnicy jest dla nas wystarczająca:\n",
+ "\n",
+ " * Im mniejsza wartość `eps`, tym dokładniejszy wynik, ale dłuższy czas działania algorytmu.\n",
+ " * Im większa wartość `eps`, tym krótszy czas działania algorytmu, ale mniej dokładny wynik."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "Na wykresie zobaczymy porównanie regresji dla różnych wartości `eps`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Wczytwanie danych z pliku za pomocą numpy – wersja macierzowa\n",
+ "data = np.loadtxt(\"data01_train.csv\", delimiter=\",\")\n",
+ "m, n_plus_1 = data.shape\n",
+ "n = n_plus_1 - 1\n",
+ "Xn = data[:, 0:n].reshape(m, n)\n",
+ "\n",
+ "# Dodaj kolumnę jedynek do macierzy\n",
+ "XMx = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
+ "yMx = np.matrix(data[:, 1]).reshape(m, 1)\n",
+ "\n",
+ "thetaStartMx = np.zeros((2, 1))\n",
+ "\n",
+ "fig = regdotsMx(XMx, yMx)\n",
+ "theta_e1, history1 = GDMx(\n",
+ " JMx, dJMx, thetaStartMx, XMx, yMx, alpha=0.01, eps=0.01\n",
+ ") # niebieska linia\n",
+ "reglineMx(fig, hMx, theta_e1, XMx)\n",
+ "theta_e2, history2 = GDMx(\n",
+ " JMx, dJMx, thetaStartMx, XMx, yMx, alpha=0.01, eps=0.000001\n",
+ ") # pomarańczowa linia\n",
+ "reglineMx(fig, hMx, theta_e2, XMx)\n",
+ "legend(fig)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\theta_{10^{-2}} = \\left[\\begin{array}{r}0.0531 \\\\ 0.8365 \\\\ \\end{array}\\right]\\quad\\theta_{10^{-6}} = \\left[\\begin{array}{r}-3.4895 \\\\ 1.1786 \\\\ \\end{array}\\right]$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(\n",
+ " Math(\n",
+ " r\"\\theta_{10^{-2}} = \"\n",
+ " + LatexMatrix(theta_e1)\n",
+ " + r\"\\quad\\theta_{10^{-6}} = \"\n",
+ " + LatexMatrix(theta_e2)\n",
+ " )\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Długość kroku ($\\alpha$)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Jak zmienia się koszt w kolejnych krokach w zależności od alfa\n",
+ "\n",
+ "\n",
+ "def costchangeplot(history):\n",
+ " fig = plt.figure(figsize=(16 * 0.6, 9 * 0.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.set_xlabel(\"krok\")\n",
+ " ax.set_ylabel(r\"$J(\\theta)$\")\n",
+ "\n",
+ " X = np.arange(0, 500, 1)\n",
+ " Y = [history[step][0] for step in X]\n",
+ " ax.plot(X, Y, linewidth=\"2\", label=(r\"$J(\\theta)$\"))\n",
+ " return fig\n",
+ "\n",
+ "\n",
+ "def slide7(alpha):\n",
+ " best_theta, history = gradient_descent(\n",
+ " h, J, [0.0, 0.0], x, y, alpha=alpha, eps=0.0001\n",
+ " )\n",
+ " fig = costchangeplot(history)\n",
+ " legend(fig)\n",
+ "\n",
+ "\n",
+ "sliderAlpha1 = widgets.FloatSlider(\n",
+ " min=0.01, max=0.03, step=0.001, value=0.02, description=r\"$\\alpha$\", width=300\n",
+ ")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "52b0d91e39104f4facbb7f57819aae0c",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "interactive(children=(FloatSlider(value=0.02, description='$\\\\alpha$', max=0.03, min=0.01, step=0.001), Button…"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 79,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "widgets.interact_manual(slide7, alpha=sliderAlpha1)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## 3.3. Normalizacja danych"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Normalizacja danych to proces, który polega na dostosowaniu danych wejściowych w taki sposób, żeby ułatwić działanie algorytmowi gradientu prostego.\n",
+ "\n",
+ "Wyjaśnię to na przykladzie."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "Użyjemy danych z „Gratka flats challenge 2017”.\n",
+ "\n",
+ "Rozważmy model $h(x) = \\theta_0 + \\theta_1 x_1 + \\theta_2 x_2$, w którym cena mieszkania prognozowana jest na podstawie liczby pokoi $x_1$ i metrażu $x_2$:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 81,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " price | \n",
+ " rooms | \n",
+ " sqrMetres | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 476118.00 | \n",
+ " 3 | \n",
+ " 78 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 459531.00 | \n",
+ " 3 | \n",
+ " 62 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 411557.00 | \n",
+ " 3 | \n",
+ " 15 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 496416.00 | \n",
+ " 4 | \n",
+ " 14 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 406032.00 | \n",
+ " 3 | \n",
+ " 15 | \n",
+ "
\n",
+ " \n",
+ " 5 | \n",
+ " 450026.00 | \n",
+ " 3 | \n",
+ " 80 | \n",
+ "
\n",
+ " \n",
+ " 6 | \n",
+ " 571229.15 | \n",
+ " 2 | \n",
+ " 39 | \n",
+ "
\n",
+ " \n",
+ " 7 | \n",
+ " 325000.00 | \n",
+ " 3 | \n",
+ " 54 | \n",
+ "
\n",
+ " \n",
+ " 8 | \n",
+ " 268229.00 | \n",
+ " 2 | \n",
+ " 90 | \n",
+ "
\n",
+ " \n",
+ " 9 | \n",
+ " 604836.00 | \n",
+ " 4 | \n",
+ " 40 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " price rooms sqrMetres\n",
+ "0 476118.00 3 78\n",
+ "1 459531.00 3 62\n",
+ "2 411557.00 3 15\n",
+ "3 496416.00 4 14\n",
+ "4 406032.00 3 15\n",
+ "5 450026.00 3 80\n",
+ "6 571229.15 2 39\n",
+ "7 325000.00 3 54\n",
+ "8 268229.00 2 90\n",
+ "9 604836.00 4 40"
+ ]
+ },
+ "execution_count": 81,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Wczytanie danych przy pomocy biblioteki pandas\n",
+ "import pandas\n",
+ "\n",
+ "alldata = pandas.read_csv(\n",
+ " \"data_flats.tsv\", header=0, sep=\"\\t\", usecols=[\"price\", \"rooms\", \"sqrMetres\"]\n",
+ ")\n",
+ "alldata[:10]\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Funkcja, która pokazuje wartości minimalne i maksymalne w macierzy X\n",
+ "\n",
+ "\n",
+ "def show_mins_and_maxs(XMx):\n",
+ " mins = np.amin(XMx, axis=0).tolist()[0] # wartości minimalne\n",
+ " maxs = np.amax(XMx, axis=0).tolist()[0] # wartości maksymalne\n",
+ " for i, (xmin, xmax) in enumerate(zip(mins, maxs)):\n",
+ " display(Math(r\"${:.2F} \\leq x_{} \\leq {:.2F}$\".format(xmin, i, xmax)))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 83,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Przygotowanie danych\n",
+ "\n",
+ "import numpy as np\n",
+ "\n",
+ "%matplotlib inline\n",
+ "\n",
+ "data2 = np.matrix(alldata[['rooms', 'sqrMetres', 'price']])\n",
+ "\n",
+ "m, n_plus_1 = data2.shape\n",
+ "n = n_plus_1 - 1\n",
+ "Xn = data2[:, 0:n]\n",
+ "\n",
+ "XMx2 = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n_plus_1)\n",
+ "yMx2 = np.matrix(data2[:, -1]).reshape(m, 1) / 1000.0"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Cechy w danych treningowych przyjmują wartości z zakresu:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 84,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 1.00 \\leq x_0 \\leq 1.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 2.00 \\leq x_1 \\leq 7.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 12.00 \\leq x_2 \\leq 196.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "show_mins_and_maxs(XMx2)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "Jak widzimy, $x_2$ przyjmuje wartości dużo większe niż $x_1$.\n",
+ "Powoduje to, że wykres funkcji kosztu jest bardzo „spłaszczony” wzdłuż jednej z osi:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 85,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def contour_plot(X, y, rescale=10**8):\n",
+ " theta0_vals = np.linspace(-100000, 100000, 100)\n",
+ " theta1_vals = np.linspace(-100000, 100000, 100)\n",
+ "\n",
+ " J_vals = np.zeros(shape=(theta0_vals.size, theta1_vals.size))\n",
+ " for t1, element in enumerate(theta0_vals):\n",
+ " for t2, element2 in enumerate(theta1_vals):\n",
+ " thetaT = np.matrix([1.0, element, element2]).reshape(3, 1)\n",
+ " J_vals[t1, t2] = JMx(thetaT, X, y) / rescale\n",
+ "\n",
+ " plt.figure()\n",
+ " plt.contour(theta0_vals, theta1_vals, J_vals.T, np.logspace(-2, 3, 20))\n",
+ " plt.xlabel(r\"$\\theta_1$\")\n",
+ " plt.ylabel(r\"$\\theta_2$\")\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 86,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "contour_plot(XMx2, yMx2, rescale=10**10)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Jeżeli funkcja kosztu ma kształt taki, jak na powyższym wykresie, to łatwo sobie wyobrazić, że znalezienie minimum lokalnego przy użyciu metody gradientu prostego musi stanowć nie lada wyzwanie: algorytm szybko znajdzie „rynnę”, ale „zjazd” wzdłuż „rynny” w poszukiwaniu minimum będzie odbywał się bardzo powoli.\n",
+ "\n",
+ "Jak temu zaradzić?\n",
+ "\n",
+ "Spróbujemy przekształcić dane tak, żeby funkcja kosztu miała „ładny”, regularny kształt."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Skalowanie"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "Będziemy dążyć do tego, żeby każda z cech przyjmowała wartości w podobnym zakresie.\n",
+ "\n",
+ "W tym celu przeskalujemy wartości każdej z cech, dzieląc je przez wartość maksymalną:\n",
+ "\n",
+ "$$ \\hat{x_i}^{(j)} := \\frac{x_i^{(j)}}{\\max_j x_i^{(j)}} $$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 87,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 1.00 \\leq x_0 \\leq 1.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 0.29 \\leq x_1 \\leq 1.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 0.06 \\leq x_2 \\leq 1.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "XMx2_scaled = XMx2 / np.amax(XMx2, axis=0)\n",
+ "\n",
+ "show_mins_and_maxs(XMx2_scaled)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 88,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "contour_plot(XMx2_scaled, yMx2)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Normalizacja średniej"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "Będziemy dążyć do tego, żeby dodatkowo średnia wartość każdej z cech była w okolicach $0$.\n",
+ "\n",
+ "W tym celu oprócz przeskalowania odejmiemy wartość średniej od wartości każdej z cech:\n",
+ "\n",
+ "$$ \\hat{x_i}^{(j)} := \\frac{x_i^{(j)} - \\mu_i}{\\max_j x_i^{(j)}} $$"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle 0.00 \\leq x_0 \\leq 0.00$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle -0.10 \\leq x_1 \\leq 0.62$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle -0.23 \\leq x_2 \\leq 0.70$"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "XMx2_norm = (XMx2 - np.mean(XMx2, axis=0)) / np.amax(XMx2, axis=0)\n",
+ "\n",
+ "show_mins_and_maxs(XMx2_norm)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "contour_plot(XMx2_norm, yMx2)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "notes"
+ }
+ },
+ "source": [
+ "Teraz funkcja kosztu ma wykres o bardzo regularnym kształcie – algorytm gradientu prostego zastosowany w takim przypadku bardzo szybko znajdzie minimum funkcji kosztu."
+ ]
+ }
+ ],
+ "metadata": {
+ "celltoolbar": "Slideshow",
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.4"
+ },
+ "livereveal": {
+ "start_slideshow_at": "selected",
+ "theme": "white"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/wyk/data01_test.csv b/wyk/data01_test.csv
new file mode 100644
index 0000000..72c4017
--- /dev/null
+++ b/wyk/data01_test.csv
@@ -0,0 +1,17 @@
+5.7292,0.47953
+5.1884,0.20421
+6.3557,0.67861
+9.7687,7.5435
+6.5159,5.3436
+8.5172,4.2415
+9.1802,6.7981
+6.002,0.92695
+5.5204,0.152
+5.0594,2.8214
+5.7077,1.8451
+7.6366,4.2959
+5.8707,7.2029
+5.3054,1.9869
+8.2934,0.14454
+13.394,9.0551
+5.4369,0.61705
diff --git a/wyk/data01_train.csv b/wyk/data01_train.csv
new file mode 100644
index 0000000..ab04fdf
--- /dev/null
+++ b/wyk/data01_train.csv
@@ -0,0 +1,80 @@
+6.1101,17.592
+5.5277,9.1302
+8.5186,13.662
+7.0032,11.854
+5.8598,6.8233
+8.3829,11.886
+7.4764,4.3483
+8.5781,12
+6.4862,6.5987
+5.0546,3.8166
+5.7107,3.2522
+14.164,15.505
+5.734,3.1551
+8.4084,7.2258
+5.6407,0.71618
+5.3794,3.5129
+6.3654,5.3048
+5.1301,0.56077
+6.4296,3.6518
+7.0708,5.3893
+6.1891,3.1386
+20.27,21.767
+5.4901,4.263
+6.3261,5.1875
+5.5649,3.0825
+18.945,22.638
+12.828,13.501
+10.957,7.0467
+13.176,14.692
+22.203,24.147
+5.2524,-1.22
+6.5894,5.9966
+9.2482,12.134
+5.8918,1.8495
+8.2111,6.5426
+7.9334,4.5623
+8.0959,4.1164
+5.6063,3.3928
+12.836,10.117
+6.3534,5.4974
+5.4069,0.55657
+6.8825,3.9115
+11.708,5.3854
+5.7737,2.4406
+7.8247,6.7318
+7.0931,1.0463
+5.0702,5.1337
+5.8014,1.844
+11.7,8.0043
+5.5416,1.0179
+7.5402,6.7504
+5.3077,1.8396
+7.4239,4.2885
+7.6031,4.9981
+6.3328,1.4233
+6.3589,-1.4211
+6.2742,2.4756
+5.6397,4.6042
+9.3102,3.9624
+9.4536,5.4141
+8.8254,5.1694
+5.1793,-0.74279
+21.279,17.929
+14.908,12.054
+18.959,17.054
+7.2182,4.8852
+8.2951,5.7442
+10.236,7.7754
+5.4994,1.0173
+20.341,20.992
+10.136,6.6799
+7.3345,4.0259
+6.0062,1.2784
+7.2259,3.3411
+5.0269,-2.6807
+6.5479,0.29678
+7.5386,3.8845
+5.0365,5.7014
+10.274,6.7526
+5.1077,2.0576
diff --git a/wyk/data02_train.tsv b/wyk/data02_train.tsv
new file mode 100644
index 0000000..0819da9
--- /dev/null
+++ b/wyk/data02_train.tsv
@@ -0,0 +1,1340 @@
+price isNew rooms floor location sqrMetres
+476118.0 False 3 1 Centrum 78
+459531.0 False 3 2 Sołacz 62
+411557.0 False 3 0 Sołacz 15
+496416.0 False 4 0 Sołacz 14
+406032.0 False 3 0 Sołacz 15
+450026.0 False 3 1 Naramowice 80
+571229.15 False 2 4 Wilda 39
+325000.0 False 3 1 Grunwald 54
+268229.0 False 2 1 Grunwald 90
+604836.0 False 4 5 Grunwald 40
+232050.0 False 3 0 Nowe 41
+399406.0 False 3 2 Wilda 89
+305739.0 False 2 2 Grunwald 53
+531976.68 False 4 1 Wilda 38
+288465.0 True 2 1 Starołęka 77
+305000.0 True 3 3 Winogrady 47
+410000.0 True 2 5 Rataje 30
+305000.0 True 3 3 Winogrady 48
+289000.0 True 2 2 Zawady 48
+419000.0 True 2 0 Rataje 56
+193000.0 True 2 5 Malta 37
+270000.0 True 3 4 Rataje 48
+360000.0 True 3 2 Rataje 20
+240000.0 True 2 10 Rataje 36
+299000.0 True 2 4 Nowe 47
+298000.0 True 2 4 Wilda 45
+289000.0 True 2 2 Komandoria 48
+300000.0 True 2 1 Podolany 45
+177000.0 True 2 2 Dębiec 25
+404000.0 True 3 2 Rataje 70
+335000.0 True 3 7 Rataje 63
+305000.0 True 3 3 Winogrady 60
+254900.0 True 2 14 Winogrady 80
+348000.0 True 3 9 Rataje 65
+320000.0 True 3 4 Winogrady 50
+284000.0 True 3 4 Rataje 48
+188000.0 True 2 2 Dębiec 61
+477000.0 True 4 3 Piątkowo 70
+390000.0 True 3 2 Podolany 68
+439000.0 True 3 3 Piątkowo 70
+263000.0 True 2 1 Rataje 44
+435000.0 True 2 0 Świerczewo 60
+610000.0 True 3 6 Centrum 77
+714000.0 True 3 2 Malta 84
+295000.0 True 2 2 Naramowice 58
+270000.0 True 3 10 Nowe 48
+259000.0 True 2 0 Rataje 38
+350000.0 True 3 0 Jeżyce 90
+295000.0 True 2 2 Grunwald 60
+338000.0 True 3 1 Jeżyce 37
+420000.0 True 4 3 Jeżyce 78
+565000.0 True 4 0 Sołacz 90
+355000.0 True 2 3 Nowe 90
+330000.0 True 2 4 Chwaliszewo 56
+299000.0 True 2 16 Rataje 49
+270000.0 True 2 2 Sołacz 49
+329000.0 True 3 3 Jeżyce 45
+405000.0 True 3 2 Rataje 70
+270000.0 True 2 2 Winogrady 49
+235000.0 True 2 6 Winogrady 38
+270000.0 True 2 2 Sołacz 49
+365000.0 True 3 2 Jeżyce 50
+325000.0 True 3 1 Nowe 90
+340000.0 True 3 16 Rataje 80
+329000.0 True 3 2 Rataje 59
+429000.0 True 3 4 Dębiec 60
+349000.0 True 3 3 Rataje 63
+329000.0 True 4 4 Nowe 20
+249000.0 True 2 2 Grunwald 46
+260000.0 True 2 0 Rataje 40
+275000.0 True 2 9 Rataje 38
+263000.0 True 2 1 Rataje 44
+269000.0 True 2 9 Rataje 49
+450000.0 True 3 11 Jeżyce 50
+299000.0 True 3 2 Łazarz 80
+330000.0 True 4 2 Rataje 62
+289000.0 True 3 3 Rataje 48
+750000.0 True 4 0 Naramowice 133
+635000.0 True 4 3 Grunwald 70
+279000.0 True 2 1 Naramowice 60
+399900.0 False 3 1 Grunwald 34
+255000.0 True 2 1 Winogrady 38
+239000.0 True 2 1 Grunwald 36
+229000.0 True 2 2 Wilda 50
+348000.0 True 3 9 Rataje 65
+384000.0 True 4 0 Grunwald 60
+232034.0 True 2 1 Starołęka 86
+270000.0 True 3 4 Rataje 48
+350000.0 False 5 1 Komorniki 97
+240000.0 True 2 16 Rataje 36
+619000.0 True 4 0 Jeżyce 99
+295000.0 True 3 4 Grunwald 45
+349000.0 True 3 1 Grunwald 57
+279000.0 True 3 0 Winogrady 48
+269000.0 True 3 3 Winogrady 48
+250000.0 True 2 6 Winogrady 42
+270000.0 True 2 4 Jeżyce 43
+285383.0 False 5 4 Winogrady 37
+348750.0 False 2 3 Stare 47
+240157.0 False 2 0 Winogrady 37
+285678.0 False 2 2 Winogrady 42
+272800.0 False 2 5 Winogrady 44
+267702.0 False 2 2 Grunwald 45
+327584.0 False 3 3 Grunwald 21
+235000.0 False 2 3 Winogrady 38
+286445.0 False 2 2 Winogrady 49
+156085.0 False 2 2 Starołęka 30
+282000.0 False 3 3 Winogrady 57
+365000.0 True 4 4 Grunwald 64
+519000.0 True 3 1 Rataje 50
+779000.0 True 3 2 Stare 113
+499000.0 True 4 2 Wilda 120
+255000.0 True 3 0 Grunwald 53
+270000.0 True 3 4 Rataje 48
+257000.0 True 2 5 Rataje 49
+499000.0 True 2 2 Stare 43
+399000.0 True 3 1 Nowe 62
+149000.0 True 3 5 Nowe 56
+435000.0 True 3 5 Wilda 70
+400000.0 False 4 0 Grunwald 81
+389000.0 True 3 3 Stare 49
+299000.0 True 3 6 Jeżyce 70
+325000.0 True 3 3 Łazarz 62
+399000.0 True 3 1 Grunwald 65
+279000.0 True 2 1 Naramowice 60
+334117.0 False 3 2 Grunwald 63
+364620.0 False 3 2 Grunwald 80
+529900.0 True 4 1 Podolany 103
+369000.0 True 4 3 Grunwald 74
+329000.0 True 2 2 Jeżyce 45
+320000.0 True 3 4 Winogrady 54
+275000.0 True 2 13 Rataje 80
+295120.0 False 2 1 Winogrady 60
+374000.0 True 3 4 Wilczak 30
+288000.0 True 3 4 Winogrady 30
+340000.0 True 3 1 Grunwald 70
+329000.0 True 3 3 Piątkowo 60
+290000.0 True 2 6 Sołacz 49
+229000.0 True 4 3 Wilda 54
+339000.0 True 3 1 Grunwald 65
+288000.0 True 3 4 Winogrady 30
+280000.0 True 3 1 Jeżyce 58
+295000.0 True 2 2 Naramowice 50
+264250.0 False 2 2 Jeżyce 29
+308039.0 False 2 0 Winogrady 21
+285200.0 False 2 1 Winogrady 46
+346624.0 False 3 1 Ogrody 54
+313566.0 False 3 1 Jeżyce 51
+290970.0 False 2 0 Winogrady 60
+304000.0 False 3 5 Winogrady 29
+225316.0 False 2 0 Starołęka 33
+186600.0 False 2 2 Starołęka 62
+336474.0 False 3 4 Winogrady 27
+299513.0 False 2 1 Starołęka 85
+257000.0 False 3 1 Winogrady 76
+244071.0 False 2 2 Starołęka 52
+291838.0 False 2 0 Starołęka 55
+322276.0 False 2 3 Winogrady 98
+280860.0 False 2 1 Winogrady 30
+297600.0 False 2 3 Winogrady 50
+349668.0 False 2 1 Garbary 44
+321656.0 False 2 1 Winogrady 88
+302176.0 False 2 2 Malta 45
+199000.0 True 2 1 Grunwald 33
+363000.0 True 3 2 Grunwald 77
+375000.0 True 3 4 Winogrady 65
+287000.0 True 2 10 Winogrady 47
+230000.0 True 2 1 Dębiec 37
+365000.0 True 3 2 Rataje 65
+389000.0 True 3 1 Naramowice 20
+325000.0 True 2 2 Grunwald 35
+391729.0 False 3 2 Winogrady 21
+479000.0 True 3 3 Grunwald 23
+249000.0 True 2 10 Grunwald 42
+286000.0 True 2 5 Centrum 49
+313000.0 True 2 4 Piątkowo 49
+409000.0 True 3 1 Rataje 62
+255000.0 True 2 1 Nowe 49
+270000.0 True 3 4 Jeżyce 50
+699000.0 True 2 1 Grunwald 68
+330000.0 True 2 3 Wilda 53
+335000.0 True 3 16 Rataje 80
+488000.0 True 3 3 Grunwald 70
+339000.0 True 3 1 Jeżyce 65
+410000.0 True 3 5 Grunwald 81
+269000.0 True 2 4 Naramowice 43
+710000.0 True 5 7 Grunwald 91
+359600.0 False 3 5 Grunwald 58
+249441.0 False 2 2 Jeżyce 50
+440000.0 True 4 1 Grunwald 95
+389000.0 True 3 2 Jeżyce 50
+590000.0 True 4 3 Rataje 90
+706655.0 False 3 2 Nowe 45
+269000.0 True 2 6 Rataje 70
+240000.0 True 2 16 Rataje 36
+310000.0 True 2 2 Centrum 53
+240000.0 False 3 0 Nowe 64
+230000.0 True 2 0 Grunwald 52
+770000.0 True 4 1 Centrum 142
+249000.0 True 2 4 Rataje 44
+350000.0 True 2 1 Rataje 54
+313000.0 True 2 4 Piątkowo 49
+310000.0 True 2 2 Śródka 72
+569000.0 True 4 0 Wilda 50
+460000.0 True 4 2 Bonin 87
+485000.0 True 2 2 Centrum 55
+286000.0 True 2 5 Centrum 80
+364000.0 True 3 1 Grunwald 62
+299000.0 True 3 3 Wilda 66
+365000.0 True 2 5 Wilda 30
+237000.0 True 2 10 Grunwald 38
+425000.0 True 4 6 Rataje 85
+332160.0 True 2 1 Grunwald 60
+230000.0 True 2 1 Dębiec 37
+249000.0 True 2 10 Grunwald 42
+270000.0 True 3 4 Rataje 48
+350000.0 True 2 4 Jeżyce 56
+309000.0 True 2 3 Grunwald 56
+283500.0 True 2 0 Stare 50
+177595.0 False 2 0 Nowe 29
+339000.0 True 2 2 Centrum 53
+399000.0 True 3 1 Grunwald 65
+329000.0 True 3 3 Piątkowo 60
+706655.0 False 3 2 Nowe 45
+289000.0 True 2 2 Jeżyce 42
+389000.0 True 3 0 Wilda 67
+375000.0 True 3 4 Wilda 40
+319000.0 True 3 2 Wilda 66
+310000.0 True 3 0 Grunwald 60
+252000.0 True 2 12 Winogrady 47
+249147.0 False 2 4 Zawady 71
+649000.0 True 4 0 Winogrady 80
+204000.0 True 2 0 Grunwald 37
+389000.0 True 3 4 Rataje 84
+369000.0 True 3 0 Grunwald 87
+300000.0 True 2 1 Naramowice 52
+470000.0 True 4 2 Sołacz 87
+326000.0 True 2 1 Winogrady 39
+655000.0 True 3 4 Stare 60
+348000.0 True 3 9 Rataje 65
+399000.0 True 3 1 Bonin 68
+390000.0 True 3 2 Podolany 68
+265000.0 True 2 0 Centrum 40
+279999.0 True 3 4 Winogrady 54
+280000.0 True 3 9 Jeżyce 49
+419000.0 True 2 0 Malta 56
+249000.0 True 2 4 Grunwald 38
+259000.0 True 2 3 Żegrze 49
+270000.0 True 2 0 Jeżyce 20
+349000.0 True 3 2 Grunwald 39
+349000.0 True 2 3 Piątkowo 60
+548000.0 True 3 1 Grunwald 84
+249000.0 True 2 10 Grunwald 43
+549000.0 True 3 2 Dąbrowskiego 106
+290000.0 True 2 6 Piątkowo 49
+442827.0 False 4 2 Starołęka 14
+530000.0 True 3 0 Grunwald 63
+279000.0 True 3 1 Plewiska 50
+410000.0 True 2 5 Rataje 50
+396000.0 True 3 1 Wilda 50
+279000.0 True 2 1 Stare 60
+399000.0 True 3 4 Piątkowo 16
+329000.0 True 2 2 Jeżyce 45
+270000.0 True 3 10 Grunwald 52
+360000.0 True 2 0 Centrum 57
+255000.0 True 3 2 Grunwald 20
+395000.0 True 3 1 Grunwald 100
+139000.0 True 2 0 Grunwald 49
+320000.0 True 3 4 Winogrady 50
+899000.0 True 4 0 Stare 100
+237000.0 True 2 2 Dębiec 44
+425000.0 True 3 1 Rataje 70
+315000.0 True 2 0 Winogrady 53
+485000.0 True 2 2 Centrum 55
+365000.0 True 3 1 Żegrze 88
+345000.0 True 3 1 Winogrady 17
+319000.0 True 3 3 Rataje 50
+265000.0 True 2 0 Dębiec 50
+978000.0 True 4 5 Centrum 106
+489000.0 True 2 5 Centrum 53
+382280.0 True 3 3 Centrum 80
+267900.0 True 2 6 Winogrady 30
+259000.0 True 2 3 Łazarz 47
+280000.0 True 2 4 Rataje 63
+250000.0 True 4 1 Wilda 31
+340000.0 True 2 2 Naramowice 16
+160000.0 True 2 0 Podolany 27
+390000.0 True 2 0 Centrum 60
+469000.0 True 2 1 Winogrady 30
+429000.0 True 3 4 Dębiec 50
+270000.0 True 2 2 Naramowice 52
+330000.0 True 3 0 Jeżyce 78
+279000.0 True 2 1 Stare 60
+289000.0 True 2 6 Jeżyce 49
+449000.0 True 4 1 Górczyn 90
+499000.0 True 4 4 Stare 85
+270000.0 True 2 16 Rataje 49
+295000.0 True 2 0 Stare 44
+210000.0 True 2 2 Dębiec 40
+519000.0 True 3 1 Rataje 50
+490000.0 True 4 0 Naramowice 40
+300000.0 True 2 1 Stare 23
+325000.0 True 3 4 Jeżyce 30
+238000.0 True 2 13 Rataje 49
+329000.0 True 3 1 Piątkowo 63
+270000.0 True 2 0 Piątkowo 43
+395000.0 True 3 0 Grunwald 70
+330000.0 True 2 1 Jeżyce 50
+439000.0 True 4 2 Grunwald 89
+259500.0 True 2 0 Grunwald 55
+355000.0 True 2 4 Jeżyce 56
+282000.0 True 2 1 Jeżyce 38
+335000.0 True 2 2 Górczyn 52
+375000.0 True 2 1 Grunwald 51
+399000.0 True 3 4 Stare 70
+474000.0 False 4 0 Plewiska 30
+309000.0 True 2 0 Grunwald 55
+379000.0 True 3 0 Rataje 57
+399000.0 True 3 1 Nowe 62
+570000.0 True 3 5 Grunwald 60
+105000.0 True 2 3 Nowe 50
+296000.0 True 3 6 Dębiec 63
+326000.0 True 2 1 Winiary 39
+1725000.0 True 3 0 Stare 136
+350550.0 True 3 4 Stare 50
+252000.0 True 2 12 Winogrady 47
+368000.0 True 2 2 Wilda 67
+549000.0 True 3 3 Grunwald 60
+409000.0 True 3 1 Rataje 90
+362000.0 True 2 1 Centrum 50
+250000.0 True 3 2 Nowe 80
+399900.0 True 4 2 Nowe 66
+429000.0 True 3 4 Wilda 60
+370000.0 True 2 0 Górczyn 65
+274000.0 True 2 1 Górczyn 13
+239000.0 True 2 3 Piątkowo 59
+259000.0 True 2 2 Rataje 90
+246330.0 True 2 0 Wilda 55
+289000.0 True 3 4 Winogrady 48
+100000.0 True 3 4 Stare 70
+270000.0 True 2 2 Sołacz 60
+430000.0 True 2 3 Grunwald 70
+355000.0 True 2 0 Podolany 93
+287000.0 True 2 11 Winogrady 47
+1200000.0 False 5 0 Starołęka 193
+305000.0 True 3 3 Winogrady 48
+329000.0 True 3 3 Piątkowo 60
+315000.0 True 3 0 Piątkowo 63
+267705.0 True 2 2 Grunwald 45
+247707.0 True 2 1 Jeżyce 50
+388750.0 True 4 5 Winogrady 65
+371931.0 True 4 4 Jeżyce 57
+232408.0 True 2 0 Stare 38
+247708.0 True 2 1 Jeżyce 50
+242731.0 True 2 0 Jeżyce 50
+247710.0 True 2 1 Jeżyce 50
+339200.0 True 3 1 Jeżyce 53
+349100.0 True 4 0 Rataje 85
+296277.0 True 3 1 Stare 49
+333694.0 True 3 1 Jeżyce 68
+250000.0 True 2 0 Naramowice 40
+200000.0 True 2 0 Rataje 30
+470000.0 True 4 2 Sołacz 87
+370000.0 True 4 4 Piątkowo 76
+315000.0 True 3 0 Piątkowo 60
+287000.0 True 2 10 Winogrady 80
+230000.0 True 2 3 Nowe 47
+900000.0 True 3 3 Centrum 120
+399000.0 True 3 4 Piątkowo 16
+250000.0 True 2 6 Sołacz 71
+318000.0 True 2 4 Piątkowo 20
+269000.0 True 2 9 Rataje 49
+239592.0 True 2 5 Grunwald 59
+307881.0 True 3 0 Grunwald 16
+319055.0 True 3 3 Grunwald 21
+267702.0 True 2 2 Grunwald 22
+299000.0 True 3 2 Dębiec 70
+435000.0 True 3 0 Stare 25
+690000.0 True 2 0 Grunwald 60
+204450.0 True 2 1 Nowe 33
+228144.0 True 3 2 Nowe 56
+285383.0 True 2 1 Winogrady 37
+391729.0 True 3 2 Winogrady 21
+330000.0 True 3 0 Jeżyce 78
+269984.0 True 3 4 Winogrady 76
+344141.0 True 2 8 Winogrady 47
+318384.0 True 3 6 Jeżyce 24
+249641.0 True 2 0 Jeżyce 54
+177000.0 True 2 2 Dębiec 33
+325000.0 True 2 2 Jeżyce 56
+429000.0 True 3 4 Rataje 70
+380000.0 True 3 3 Dolna 67
+448995.0 True 2 3 Jeżyce 66
+350000.0 True 2 3 Jeżyce 70
+269000.0 True 2 2 Dolna 38
+620000.0 True 3 1 Grunwald 96
+275000.0 True 2 0 Łazarz 52
+440000.0 True 2 0 Centrum 40
+505877.0 False 2 5 Centrum 22
+886860.0 False 3 5 Centrum 80
+502136.0 False 2 5 Centrum 77
+798966.0 False 2 5 Centrum 33
+561663.0 False 3 4 Centrum 69
+396248.0 False 2 4 Centrum 77
+368019.0 False 2 4 Centrum 18
+542141.0 False 3 4 Centrum 53
+698508.0 False 4 4 Centrum 59
+394787.0 False 2 4 Centrum 71
+597184.0 False 3 4 Centrum 61
+354177.0 False 2 3 Centrum 25
+353537.0 False 2 3 Centrum 17
+509468.0 False 3 3 Centrum 53
+652026.0 False 4 3 Centrum 89
+353457.0 False 2 3 Centrum 16
+356818.0 False 2 3 Centrum 58
+496573.0 False 3 2 Centrum 78
+349668.0 False 2 2 Centrum 15
+481903.0 False 3 2 Centrum 53
+309978.0 False 2 2 Centrum 16
+389528.0 False 2 2 Centrum 87
+341776.0 False 2 2 Centrum 14
+374216.0 False 2 2 Centrum 71
+534523.0 False 3 2 Centrum 62
+377418.0 False 2 1 Centrum 87
+330255.0 False 2 1 Centrum 14
+505032.0 False 3 1 Centrum 62
+375000.0 True 4 0 Grunwald 67
+375000.0 True 5 0 Grunwald 67
+363000.0 True 3 2 Grunwald 73
+495000.0 True 3 1 Grunwald 40
+270000.0 True 3 1 Starołęka 30
+365000.0 True 2 2 Grunwald 51
+450000.0 True 4 1 Grunwald 113
+190520.0 True 2 3 Nowe 30
+228492.0 True 2 1 Nowe 93
+169620.0 True 2 1 Nowe 55
+145000.0 True 2 1 Nowe 54
+270000.0 True 3 4 Rataje 48
+370000.0 True 4 4 Piątkowo 76
+289000.0 True 3 3 Grunwald 52
+585000.0 True 3 4 Jeżyce 59
+335000.0 True 3 7 Rataje 63
+329000.0 True 3 3 Piątkowo 60
+269000.0 True 2 0 Grunwald 46
+298000.0 True 2 4 Wilda 45
+398000.0 True 3 1 Grunwald 70
+395000.0 True 4 0 Grunwald 60
+389000.0 True 3 0 Wilda 96
+429000.0 True 3 4 Wilda 47
+715000.0 True 3 1 Wilda 95
+460000.0 True 2 2 Centrum 56
+555000.0 True 4 0 Stare 20
+655000.0 True 3 4 Stare 60
+188000.0 True 2 3 Stare 70
+390000.0 True 2 0 Nowe 61
+425000.0 True 2 9 Nowe 50
+359400.0 True 3 1 Stare 72
+497400.0 True 3 0 Wilda 48
+604395.0 True 5 1 Wilda 31
+330615.0 True 2 2 Stare 79
+290970.0 True 2 0 Stare 60
+283340.0 True 2 0 Stare 70
+282880.0 True 2 3 Stare 20
+339500.0 True 3 7 Nowe 80
+850000.0 True 2 7 Stare 69
+380000.0 True 4 6 Stare 90
+800000.0 True 4 3 Stare 103
+514000.0 True 4 1 Jeżyce 120
+290000.0 True 2 1 Stare 42
+640000.0 True 3 2 Stare 47
+1140000.0 True 6 0 Stare 40
+561000.0 True 2 4 Stare 50
+400000.0 True 2 1 Świerczewo 60
+220000.0 True 2 4 Grunwald 43
+490000.0 True 3 1 Jeżyce 115
+298000.0 True 2 4 Wilda 45
+449000.0 True 2 3 Jeżyce 60
+237000.0 True 2 2 Dębiec 44
+480000.0 True 2 2 Garbary 56
+298000.0 True 2 4 Wilda 37
+255000.0 True 2 3 Wilda 52
+480000.0 True 3 0 Stare 30
+451000.0 True 3 2 Wilda 30
+370000.0 True 3 4 Stare 84
+529000.0 True 3 3 Centrum 108
+360000.0 True 4 0 Grunwald 66
+419000.0 True 4 0 Kopernika 60
+350000.0 True 2 0 Stare 50
+348000.0 True 3 9 Rataje 65
+525000.0 True 4 3 Nowe 88
+450000.0 True 6 4 Wilda 90
+449000.0 True 4 2 Grunwald 90
+420000.0 True 3 0 Winogrady 58
+360000.0 True 3 3 Stare 63
+1000000.0 True 4 1 Centrum 103
+649400.0 False 3 4 Rataje 50
+311570.0 False 2 4 Rataje 51
+383928.0 False 3 3 Rataje 46
+309741.0 False 2 3 Rataje 89
+359000.0 True 2 0 Grunwald 46
+295734.0 False 2 3 Rataje 86
+384540.0 False 3 3 Rataje 55
+480000.0 True 3 1 Grunwald 40
+380091.0 False 3 2 Rataje 73
+293352.0 False 2 1 Rataje 14
+307156.0 False 2 1 Rataje 17
+293352.0 False 2 1 Rataje 14
+535000.0 True 2 3 Łazarz 59
+375606.0 False 3 1 Rataje 91
+293488.0 False 3 0 Rataje 94
+307428.0 False 2 0 Rataje 21
+293488.0 False 2 0 Rataje 16
+375408.0 False 3 0 Rataje 88
+299000.0 True 2 0 Piątkowo 47
+243828.0 False 2 4 Podolany 68
+348835.0 False 3 3 Podolany 63
+256171.0 False 2 3 Podolany 79
+298116.0 False 2 3 Podolany 96
+306247.0 False 2 3 Podolany 35
+337602.0 False 3 3 Podolany 71
+244647.0 False 2 3 Podolany 82
+641000.0 True 3 3 Łazarz 75
+277000.0 True 2 10 Nowe 80
+549000.0 True 4 0 Piątkowo 115
+499000.0 True 3 1 Suchy 95
+539000.0 True 4 2 Jeżyce 110
+450000.0 True 2 2 Grunwald 70
+242000.0 True 2 1 Grunwald 52
+310000.0 True 3 4 Jeżyce 50
+259000.0 True 2 3 Winogrady 40
+475000.0 True 3 4 Wilda 66
+120000.0 True 3 3 Grunwald 35
+270000.0 True 3 4 Rataje 48
+1850000.0 True 5 1 Grunwald 196
+350000.0 True 4 4 Grunwald 50
+280000.0 True 4 4 Grunwald 40
+490000.0 True 4 4 Grunwald 70
+495000.0 True 3 1 Naramowice 70
+545000.0 True 3 0 Rataje 71
+310000.0 True 3 10 Rataje 80
+215000.0 True 2 0 Wilda 36
+295000.0 True 2 4 Garbary 33
+200000.0 True 2 8 Dębiec 50
+359900.0 True 4 4 Rataje 74
+320000.0 True 3 3 Jeżyce 70
+300000.0 True 2 1 Naramowice 23
+535000.0 True 4 2 Wilda 120
+620000.0 True 3 2 Naramowice 60
+597000.0 True 3 0 Naramowice 60
+399000.0 True 3 0 Winogrady 62
+390000.0 True 3 0 Grunwald 75
+310000.0 True 2 1 Rataje 30
+365000.0 True 3 1 Rataje 88
+382000.0 True 3 3 Centrum 30
+299000.0 True 2 2 Sołacz 58
+299000.0 True 2 2 Sołacz 58
+499000.0 True 3 1 Grunwald 64
+549000.0 True 3 2 Jeżyce 106
+549000.0 True 3 2 Jeżyce 106
+413000.0 True 3 3 Łazarz 46
+259000.0 True 2 1 Jeżyce 47
+949000.0 True 3 4 Śródka 98
+949000.0 True 3 4 Śródka 98
+270000.0 True 3 4 Rataje 48
+348000.0 True 3 9 Nowe 65
+260000.0 True 2 0 Ławica 60
+370000.0 True 4 4 Stare 60
+399000.0 True 3 4 Stare 16
+369000.0 True 4 3 Grunwald 74
+224000.0 True 2 0 Łazarz 50
+260000.0 True 3 4 Grunwald 49
+315000.0 True 3 0 Piątkowo 60
+379999.0 True 3 3 Wilda 67
+350000.0 True 2 1 Rataje 63
+270000.0 True 2 4 Grunwald 38
+439000.0 True 4 2 Łazarz 92
+519000.0 True 3 1 Rataje 50
+290000.0 True 2 2 Dębiec 66
+326000.0 True 2 4 Łazarz 80
+240000.0 True 2 3 Grunwald 42
+389000.0 True 3 0 Wilda 67
+420000.0 True 3 2 Dębiec 91
+279000.0 True 2 1 Naramowice 51
+220000.0 True 2 4 Grunwald 43
+465360.0 True 2 2 Grunwald 17
+777280.0 True 3 3 Grunwald 16
+1000000.0 True 4 1 Stare 146
+350000.0 True 2 3 Rataje 50
+469000.0 True 4 2 Jeżyce 87
+253498.0 True 2 5 Jeżyce 38
+334752.0 True 3 3 Jeżyce 51
+374792.0 True 4 5 Jeżyce 57
+329000.0 True 3 4 Rataje 63
+349668.0 False 2 2 Stare 15
+297420.0 False 2 3 Grunwald 24
+297420.0 False 2 3 Grunwald 24
+220000.0 True 2 1 Jeżyce 60
+399000.0 True 3 1 Sołacz 66
+488000.0 True 3 3 Grunwald 70
+220000.0 True 2 4 Grunwald 43
+390000.0 True 3 2 Podolany 68
+299000.0 True 2 0 Wilda 52
+234000.0 True 2 0 Wilda 37
+375000.0 True 3 2 Wilda 90
+820000.0 True 4 0 Centrum 163
+320000.0 True 3 4 Winogrady 50
+420000.0 False 4 0 Grunwald 82
+495000.0 True 4 1 Stare 98
+279000.0 True 2 1 Stare 52
+620000.0 True 3 1 Stare 99
+329000.0 True 2 1 Stare 54
+699000.0 True 3 2 Stare 92
+487000.0 True 3 0 Stare 73
+375000.0 True 3 0 Naramowice 69
+269000.0 True 2 9 Rataje 49
+220000.0 True 2 4 Grunwald 43
+230000.0 True 2 1 Dębiec 38
+435000.0 True 2 0 Górczyn 60
+390000.0 True 3 2 Podolany 68
+446240.0 True 2 1 Grunwald 78
+390000.0 True 3 2 Podolany 68
+619000.0 True 3 2 Winogrady 100
+240000.0 True 2 3 Dębiec 50
+270000.0 True 3 4 Rataje 48
+244968.0 True 2 0 Stare 42
+285679.0 True 2 4 Winogrady 48
+260000.0 True 2 6 Winiary 70
+585000.0 True 4 1 Piątkowo 100
+329000.0 True 3 1 Piątkowo 63
+269000.0 True 2 0 Naramowice 46
+348000.0 True 3 9 Rataje 65
+270000.0 True 3 4 Rataje 48
+359605.0 True 3 5 Grunwald 58
+375529.0 False 2 3 Stare 71
+247705.0 False 2 1 Podolany 74
+247705.0 False 2 1 Piątkowo 74
+156085.0 False 2 4 Głuszyna 45
+411684.0 False 3 3 Winogrady 17
+349000.0 False 4 0 Szczepankowo 29
+277823.0 False 2 2 Podolany 70
+249733.0 False 2 0 Ogrody 54
+424377.0 False 4 2 Starołęka 14
+282944.0 False 2 0 Starołęka 59
+460499.0 False 3 1 Stare 51
+270000.0 True 3 0 Grunwald 48
+350000.0 True 4 1 Wilda 80
+350000.0 True 4 4 Winogrady 90
+323000.0 True 4 0 Winogrady 56
+649000.0 True 4 4 Centrum 109
+341704.0 True 3 8 Grunwald 56
+297421.0 True 2 3 Grunwald 50
+245832.0 True 2 2 Grunwald 40
+285384.0 True 2 4 Winogrady 48
+240000.0 True 2 1 Wilda 40
+345865.0 True 3 2 Jeżyce 21
+261000.0 True 2 2 Jeżyce 57
+400000.0 True 3 2 Jeżyce 74
+400000.0 True 2 2 Jeżyce 74
+348000.0 True 3 9 Rataje 65
+369000.0 True 2 2 Grunwald 51
+339000.0 True 3 0 Rataje 63
+250000.0 True 2 4 Rataje 23
+245000.0 True 2 4 Rataje 44
+240000.0 True 2 2 Dębiec 48
+262000.0 True 2 4 Grunwald 60
+395000.0 True 4 1 Smochowice 69
+313000.0 True 2 4 Piątkowo 50
+409000.0 True 3 1 Malta 90
+599000.0 True 3 3 Grunwald 83
+289000.0 True 2 2 Jeżyce 42
+390000.0 True 3 3 Naramowice 48
+313000.0 True 2 4 Piątkowo 49
+375000.0 True 4 2 Centrum 72
+350000.0 True 3 1 Naramowice 51
+304140.0 False 3 5 Winogrady 18
+353275.0 False 2 14 Grunwald 74
+244071.0 False 2 1 Nowe 93
+348000.0 True 3 9 Rataje 65
+320000.0 True 3 4 Winogrady 53
+348000.0 True 3 9 Rataje 65
+348000.0 True 3 9 Rataje 65
+230000.0 True 2 1 Dębiec 37
+238000.0 True 2 2 Grunwald 37
+392000.0 True 4 0 Piątkowo 74
+380000.0 True 4 2 Piątkowo 74
+329000.0 True 2 4 Górczyn 20
+347000.0 True 3 1 Naramowice 47
+259900.0 True 2 6 Winogrady 38
+590000.0 True 5 3 Piątkowo 125
+320000.0 True 2 1 Naramowice 53
+432000.0 True 2 5 Centrum 40
+435000.0 True 3 1 Piątkowo 84
+389000.0 True 2 1 Podolany 46
+799999.0 True 3 1 Sołacz 90
+310000.0 True 3 3 Piątkowo 60
+260000.0 True 3 0 Jeżyce 74
+266000.0 True 2 2 Piątkowo 49
+316498.0 True 2 2 Stare 77
+519000.0 True 3 1 Rataje 50
+442150.0 True 2 2 Stare 75
+395000.0 True 3 2 Centrum 74
+599000.0 True 2 1 Centrum 70
+459000.0 True 2 1 Centrum 48
+339000.0 True 3 1 Winogrady 51
+375000.0 True 3 2 Jeżyce 50
+289000.0 True 2 4 Ogrody 41
+230000.0 True 2 5 Winogrady 60
+440000.0 True 2 4 Centrum 55
+599000.0 True 3 2 Centrum 80
+343200.0 True 3 4 Winogrady 52
+385000.0 True 2 1 Centrum 60
+300000.0 True 3 3 Centrum 88
+529000.0 True 4 4 Centrum 85
+349000.0 True 3 3 Wilda 82
+405000.0 True 4 2 Nowe 71
+355000.0 True 2 4 Jeżyce 89
+235000.0 True 2 0 Górczyn 50
+495000.0 True 4 1 Grunwald 64
+285000.0 True 2 3 Wilda 60
+385000.0 True 3 4 Łazarz 82
+379999.0 True 3 3 Wilda 67
+370000.0 True 2 13 Rataje 67
+450000.0 True 3 0 Naramowice 71
+479000.0 True 3 3 Górczyn 70
+439000.0 True 4 2 Łazarz 40
+385000.0 True 3 0 Łazarz 80
+550000.0 True 4 1 Łazarz 50
+260000.0 True 3 4 Grunwald 47
+755000.0 True 4 2 Łazarz 90
+319000.0 True 2 0 Górczyn 54
+380000.0 True 3 1 Łazarz 30
+530000.0 True 3 1 Piątkowo 76
+900000.0 True 3 2 Grunwald 112
+375000.0 True 3 8 Piątkowo 75
+576500.0 True 2 5 Centrum 50
+576500.0 True 2 5 Chwaliszewo 50
+438503.0 True 3 2 Centrum 57
+354454.0 False 2 3 Grunwald 17
+489780.0 False 4 2 Górczyn 63
+491520.0 False 4 1 Górczyn 92
+273875.5 False 2 1 Grunwald 13
+267000.0 True 2 2 Dębiec 35
+260000.0 True 2 2 Piątkowo 90
+587000.0 True 4 3 Łazarz 38
+460000.0 True 3 1 Naramowice 110
+695000.0 True 4 1 Rataje 70
+506657.0 True 4 11 Grunwald 73
+298250.0 True 2 5 Grunwald 38
+297421.0 True 2 2 Grunwald 24
+275000.0 True 2 9 Nowe 38
+267000.0 True 2 4 Nowe 70
+447000.0 True 3 4 Grunwald 20
+349900.0 True 3 4 Wilda 42
+360000.0 True 4 0 Centrum 66
+525000.0 True 4 3 Jeżyce 70
+450000.0 True 3 2 Strzeszyn 70
+690000.0 True 4 5 Górczyn 25
+334000.0 True 2 4 Sołacz 50
+240000.0 True 2 3 Jeżyce 43
+307000.0 True 3 2 Rataje 48
+307000.0 True 2 2 Rataje 48
+345000.0 True 3 8 Nowe 63
+333694.0 False 3 1 Podolany 32
+333694.0 False 3 1 Piątkowo 38
+299000.0 True 3 0 Grunwald 53
+389000.0 True 3 3 Stare 49
+310000.0 True 2 2 Centrum 74
+220000.0 True 2 0 Grunwald 50
+332800.0 True 2 1 Grunwald 52
+240000.0 True 2 2 Stare 38
+323206.0 False 2 2 Naramowice 50
+558745.0 False 3 3 Stare 62
+290000.0 True 2 6 Jeżyce 49
+285000.0 True 2 3 Piątkowo 49
+365000.0 True 3 1 Rataje 67
+263000.0 True 2 1 Rataje 47
+289000.0 True 2 2 Jeżyce 42
+265000.0 True 3 4 Grunwald 48
+310000.0 True 2 1 Nowe 40
+300000.0 True 3 2 Winogrady 48
+565964.0 True 2 5 Centrum 49
+747000.0 True 3 7 Rataje 84
+275000.0 True 2 0 Naramowice 50
+405000.0 True 4 2 Rataje 71
+491520.0 True 4 1 Górczyn 92
+363258.0 True 2 1 Górczyn 59
+305739.0 True 2 2 Górczyn 53
+399000.0 True 3 4 Piątkowo 69
+280000.0 True 2 1 Sołacz 38
+299900.0 True 2 0 Dębiec 48
+420000.0 True 2 3 Naramowice 59
+650000.0 True 4 8 Rataje 100
+329000.0 True 3 3 Wilda 82
+355000.0 True 3 2 Piątkowo 66
+375000.0 True 3 2 Rataje 79
+200000.0 True 3 4 Nowe 44
+315000.0 True 2 2 Zawady 52
+259000.0 True 2 3 Rataje 49
+379000.0 True 3 2 Podolany 56
+354454.0 True 2 3 Górczyn 17
+237000.0 True 2 10 Górczyn 38
+315000.0 True 2 2 Zawady 52
+379999.0 True 3 2 Wilda 67
+279000.0 True 2 1 Naramowice 52
+250000.0 True 2 4 Rataje 44
+620000.0 True 3 2 Naramowice 98
+450000.0 True 3 5 Grunwald 60
+290000.0 True 2 2 Dębiec 40
+393599.0 True 2 6 Winogrady 49
+289000.0 True 2 2 Nowe 48
+240000.0 True 2 8 Dębiec 37
+420000.0 True 2 5 Rataje 63
+800000.0 True 3 3 Chwaliszewo 70
+285000.0 True 2 2 Łazarz 52
+495000.0 True 3 0 Centrum 63
+289575.0 True 2 0 Jeżyce 43
+259000.0 True 2 5 Grunwald 46
+265000.0 True 2 4 Grunwald 43
+495000.0 True 5 1 Naramowice 98
+275000.0 True 2 0 Naramowice 50
+320000.0 True 2 3 Chwaliszewo 56
+360000.0 True 2 5 Grunwald 41
+360000.0 True 2 0 Winogrady 48
+750000.0 True 4 0 Kobylepole 105
+260000.0 True 2 0 Rataje 46
+260000.0 True 3 4 Centrum 44
+1050000.0 True 5 2 Centrum 161
+379000.0 True 2 0 Nowe 56
+560000.0 True 2 8 Grunwald 55
+335400.0 True 2 1 Łazarz 51
+290000.0 True 2 5 Winogrady 42
+235000.0 True 2 3 Winogrady 38
+300000.0 True 2 4 Winogrady 53
+399000.0 True 3 1 Winiary 66
+830000.0 True 3 1 Grunwald 91
+385500.0 True 2 6 Dębiec 38
+199000.0 True 5 0 Sołacz 129
+295000.0 True 2 4 Stare 33
+370000.0 True 4 11 Rataje 74
+335000.0 True 3 1 Piątkowo 63
+350000.0 True 3 7 Piątkowo 63
+380000.0 True 3 1 Łazarz 98
+184000.0 True 2 0 Grunwald 34
+855000.0 True 4 5 Jeżyce 96
+215000.0 True 2 0 Wilda 36
+495000.0 True 4 1 Naramowice 98
+250000.0 True 2 5 Nowe 50
+275000.0 True 3 7 Wilda 53
+409000.0 True 3 1 Malta 61
+200000.0 True 2 0 Głuszyna 52
+299000.0 True 3 3 Wilda 66
+490000.0 True 4 3 Sołacz 83
+245000.0 True 2 0 Stare 44
+950000.0 True 3 4 Nowe 99
+355000.0 True 2 3 Nowe 50
+380000.0 True 3 3 Łazarz 95
+525000.0 True 4 3 Jeżyce 104
+400000.0 True 2 3 Naramowice 50
+248000.0 True 2 10 Grunwald 42
+380000.0 True 3 0 Centrum 55
+453600.0 True 2 3 Naramowice 56
+290000.0 True 2 3 Winogrady 37
+690000.0 True 4 5 Grunwald 107
+350000.0 True 3 6 Jeżyce 64
+340000.0 True 4 3 Winogrady 65
+345000.0 True 3 1 Rataje 78
+395000.0 True 3 10 Piątkowo 67
+495000.0 True 5 1 Naramowice 98
+269000.0 True 2 3 Grunwald 47
+257000.0 True 2 12 Winogrady 46
+516000.0 True 3 3 Naramowice 75
+285000.0 True 2 4 Naramowice 42
+354000.0 True 3 1 Naramowice 60
+345000.0 True 2 0 Centrum 42
+550000.0 True 2 1 Naramowice 57
+670000.0 True 4 3 Grunwald 81
+659000.0 True 5 0 Podolany 135
+925000.0 True 5 1 Stare 105
+510000.0 True 5 1 Naramowice 98
+350000.0 True 3 3 Jeżyce 70
+345000.0 True 3 1 Winogrady 50
+279000.0 True 2 0 Piątkowo 48
+535000.0 True 2 2 Stare 55
+350000.0 True 2 1 Rataje 54
+349000.0 True 3 3 Rataje 63
+250000.0 True 2 3 Wilda 39
+270000.0 True 2 10 Nowe 48
+285000.0 True 2 0 Łazarz 49
+999000.0 True 3 4 Nowe 99
+425000.0 True 3 1 Piątkowo 74
+479000.0 True 3 1 Naramowice 66
+360000.0 True 3 0 Wilda 112
+495000.0 True 3 1 Łazarz 64
+599000.0 True 3 3 Grunwald 60
+390000.0 True 3 2 Podolany 68
+450000.0 True 4 1 Grunwald 101
+313000.0 True 2 4 Piątkowo 49
+338000.0 True 3 3 Wilda 63
+285000.0 True 2 11 Winogrady 47
+270000.0 True 2 0 Grunwald 42
+360000.0 True 4 4 Jeżyce 60
+399000.0 True 2 3 Centrum 60
+619000.0 True 3 5 Jeżyce 69
+330000.0 True 2 1 Jeżyce 53
+1612000.0 True 7 5 Jeżyce 166
+399000.0 True 3 3 Centrum 50
+365000.0 True 2 1 Stare 50
+450000.0 True 3 0 Grunwald 75
+288000.0 True 3 4 Winogrady 47
+240000.0 True 2 16 Rataje 36
+326000.0 True 2 0 Jeżyce 55
+250000.0 True 2 4 Zawady 66
+288000.0 True 2 4 Naramowice 44
+289000.0 True 2 7 Winiary 49
+515000.0 True 3 0 Rataje 69
+428000.0 True 3 3 Centrum 43
+510000.0 True 5 1 Naramowice 98
+320000.0 True 2 2 Piątkowo 48
+659200.0 True 4 3 Łazarz 103
+499000.0 True 5 0 Grunwald 130
+240000.0 True 2 2 Dębiec 48
+495000.0 True 4 1 Naramowice 98
+320000.0 True 3 0 Rataje 56
+430000.0 True 3 2 Rataje 64
+409000.0 True 5 4 Winogrady 64
+415000.0 True 3 4 Łazarz 53
+359000.0 True 3 2 Rataje 65
+410000.0 True 2 5 Rataje 53
+479000.0 True 3 3 Nowe 83
+365000.0 True 4 3 Grunwald 68
+369000.0 True 2 3 Grunwald 64
+259000.0 True 2 2 Nowe 42
+250000.0 True 3 4 Dębiec 45
+299000.0 True 2 4 Nowe 47
+430000.0 True 2 1 Centrum 72
+275000.0 True 2 0 Dębiec 50
+950000.0 True 3 4 Nowe 99
+329000.0 True 3 7 Rataje 78
+380000.0 True 4 6 Piątkowo 73
+299000.0 True 2 5 Centrum 49
+265000.0 True 2 1 Wilda 44
+370000.0 True 2 13 Rataje 48
+370000.0 True 4 4 Piątkowo 76
+379000.0 True 3 1 Piątkowo 78
+299000.0 True 2 3 Grunwald 44
+379999.0 True 2 5 Jeżyce 61
+1000000.0 True 5 1 Jeżyce 128
+549000.0 True 3 2 Jeżyce 106
+335000.0 True 3 9 Nowe 65
+489000.0 True 3 0 Jeżyce 65
+379000.0 True 3 4 Rataje 63
+245000.0 True 3 0 Grunwald 45
+235000.0 True 2 0 Łazarz 52
+295555.0 True 2 1 Jeżyce 45
+224000.0 True 2 0 Górczyn 38
+315000.0 True 2 2 Winogrady 38
+429000.0 True 3 4 Nowe 79
+595000.0 True 3 0 Naramowice 94
+330000.0 True 3 0 Bonin 56
+275000.0 True 2 13 Rataje 49
+499000.0 True 4 2 Wilda 120
+287000.0 True 2 10 Winogrady 46
+280000.0 True 2 10 Piątkowo 46
+273875.0 True 2 1 Górczyn 13
+450000.0 True 3 0 Winogrady 70
+325000.0 True 3 4 Jeżyce 64
+299817.0 True 2 3 Górczyn 59
+295000.0 True 2 2 Naramowice 58
+380000.0 True 4 6 Piątkowo 73
+399000.0 True 3 4 Winogrady 65
+305000.0 True 3 3 Winogrady 48
+220000.0 True 2 3 Jeżyce 37
+285000.0 True 3 2 Antoninek 61
+238000.0 True 2 2 Grunwald 37
+200000.0 True 2 0 Rataje 30
+298000.0 True 2 5 Centrum 50
+391729.0 False 3 2 Winogrady 42
+347090.0 False 3 2 Winogrady 41
+285678.0 False 2 1 Winogrady 82
+321656.0 False 2 4 Winogrady 38
+312259.0 False 2 6 Winogrady 60
+347090.0 False 3 1 Winogrady 90
+355042.0 False 3 6 Jeżyce 96
+496573.0 False 3 2 Stare 78
+300680.0 False 2 2 Starołęka 54
+395000.0 True 4 4 Piątkowo 90
+771672.0 False 4 4 Górczyn 66
+399000.0 True 4 1 Szczepankowo 60
+340100.0 True 3 0 Szczepankowo 45
+225228.0 False 2 5 Rataje 91
+324387.0 False 2 9 Grunwald 49
+362459.0 False 3 0 Starołęka 80
+247705.0 False 2 1 Podolany 74
+339000.0 True 3 8 Nowe 78
+207000.0 True 2 2 Wilda 33
+295000.0 True 2 4 Grunwald 50
+324500.0 True 2 5 Wilda 65
+429000.0 True 3 4 Wilda 47
+399000.0 True 4 0 Szczepankowo 71
+411804.0 True 3 1 Winogrady 42
+282613.0 True 2 3 Winogrady 33
+235399.0 True 2 1 Winogrady 59
+265741.0 True 2 7 Winogrady 21
+323340.0 True 3 3 Winogrady 89
+293848.0 True 3 7 Winogrady 57
+337303.0 True 4 2 Winogrady 17
+470092.0 True 2 3 Centrum 21
+310000.0 True 2 0 Wilda 53
+365000.0 True 4 1 Nowe 54
+259000.0 True 2 6 Winogrady 38
+414225.0 True 3 3 Centrum 23
+489000.0 True 3 3 Grunwald 104
+350000.0 True 4 3 Grunwald 30
+325000.0 True 2 3 Rataje 20
+321845.0 False 3 1 Grunwald 55
+248000.0 True 2 14 Rataje 49
+286000.0 True 2 5 Centrum 64
+399000.0 True 3 4 Piątkowo 16
+289000.0 True 2 7 Winiary 80
+329000.0 True 3 11 Winogrady 50
+252723.0 False 2 1 Winogrady 43
+300680.0 False 2 2 Starołęka 54
+496573.0 False 3 2 Stare 78
+392181.0 False 3 4 Winogrady 42
+496573.0 False 3 2 Stare 78
+412438.0 False 3 2 Naramowice 17
+286000.0 True 2 5 Centrum 49
+269000.0 True 2 9 Rataje 49
+315000.0 True 2 1 Grunwald 61
+318390.0 True 3 3 Jeżyce 48
+242406.0 True 2 0 Jeżyce 36
+296278.0 True 3 2 Stare 49
+223747.0 True 2 0 Stare 37
+388755.0 True 4 5 Winogrady 65
+347095.0 True 3 1 Winogrady 57
+269000.0 True 2 1 Ogrody 50
+285000.0 True 2 9 Grunwald 50
+114642.0 True 2 0 Łazarz 46
+286000.0 True 2 5 Stare 64
+333693.0 True 3 1 Jeżyce 68
+435000.0 True 2 0 Świerczewo 60
+320000.0 True 4 1 Jeżyce 40
+395000.0 True 4 0 Grunwald 60
+353457.0 True 2 3 Stare 44
+267704.0 True 2 3 Grunwald 45
+245831.0 True 2 2 Grunwald 40
+391729.0 True 3 2 Winogrady 69
+240875.0 True 2 7 Stare 39
+424380.0 True 4 2 Nowe 74
+282996.0 True 2 0 Nowe 55
+285000.0 True 3 1 Rataje 48
+284618.0 False 2 3 Nowe 55
+512034.0 False 4 2 Winogrady 94
+284618.0 False 2 3 Nowe 55
+255404.0 False 2 6 Jeżyce 12
+315810.0 False 3 8 Winogrady 20
+282994.0 False 2 0 Starołęka 59
+637135.0 False 3 7 Grunwald 65
+754000.0 False 5 0 Morasko 42
+336000.0 True 3 0 Szczepankowo 85
+355000.0 True 2 3 Nowe 90
+475000.0 True 3 0 Rataje 73
+275000.0 True 3 4 Winogrady 60
+275000.0 True 3 4 Winogrady 70
+289000.0 True 2 7 Winogrady 80
+315000.0 True 3 0 Rataje 63
+260000.0 True 2 1 Łazarz 54
+370000.0 True 4 4 Piątkowo 76
+319990.0 True 2 3 Jeżyce 70
+156085.0 False 2 3 Głuszyna 45
+225228.0 False 2 5 Rataje 91
+308237.0 False 2 1 Nowe 85
+353275.0 False 2 14 Grunwald 74
+228144.0 False 3 2 Głuszyna 56
+156085.0 False 2 2 Głuszyna 45
+353275.0 False 2 14 Grunwald 74
+353275.0 False 2 14 Grunwald 74
+156085.0 False 2 3 Głuszyna 45
+156085.0 False 2 4 Nowe 54
+267702.0 False 2 3 Grunwald 22
+353275.0 False 2 14 Grunwald 74
+247705.0 False 2 1 Podolany 74
+315810.0 False 3 8 Winogrady 20
+370000.0 True 4 4 Stare 60
+265000.0 True 2 2 Stare 70
+304140.0 False 3 3 Winogrady 27
+394000.0 False 4 0 Szczepankowo 77
+287882.0 False 2 1 Starołęka 85
+729000.0 True 3 0 Rataje 20
+445000.0 True 4 3 Piątkowo 65
+339000.0 True 3 1 Wilda 90
+382000.0 True 4 0 Piątkowo 74
+335000.0 True 2 4 Jeżyce 35
+258000.0 True 2 0 Plewiska 40
+195000.0 True 2 1 Grunwald 31
+229000.0 True 2 1 Grunwald 16
+327000.0 True 3 1 Piątkowo 40
+279000.0 True 3 1 Nowe 54
+329000.0 True 3 1 Piątkowo 63
+220000.0 True 2 3 Jeżyce 37
+285000.0 True 3 2 Antoninek 61
+286000.0 True 2 5 Stare 49
+550000.0 True 3 1 Jeżyce 73
+366770.0 True 3 1 Stare 58
+392000.0 True 4 0 Piątkowo 74
+504326.0 True 4 4 Stare 26
+232408.0 True 2 1 Winogrady 37
+247000.0 True 2 2 Jeżyce 38
+318384.0 True 3 2 Jeżyce 48
+371930.0 True 4 2 Jeżyce 57
+347092.0 True 3 1 Winogrady 57
+286445.0 True 2 2 Winogrady 49
+254309.0 True 2 2 Stare 42
+238950.0 True 2 4 Stare 39
+442080.0 True 3 1 Nowe 68
+319998.0 True 3 1 Nowe 14
+404965.0 True 3 2 Nowe 63
+336840.0 True 3 3 Nowe 14
+380931.0 True 3 3 Nowe 83
+341311.0 True 3 8 Grunwald 53
+325000.0 True 2 0 Nowe 80
+388000.0 True 2 1 Grunwald 33
+219000.0 True 2 1 Grunwald 35
+1007500.0 False 4 1 Starołęka 94
+1203616.0 False 5 0 Starołęka 71
+298980.0 False 2 5 Winogrady 30
+281988.0 False 2 7 Naramowice 76
+300680.0 False 2 2 Starołęka 54
+288405.0 False 2 1 Górczyn 37
+392861.0 False 3 2 Winogrady 42
+298250.0 False 2 6 Grunwald 38
+411684.0 False 3 3 Winogrady 17
+349000.0 False 4 0 Szczepankowo 29
+277823.0 False 2 2 Podolany 70
+310020.0 False 3 4 Winogrady 67
+424377.0 False 4 2 Starołęka 14
+282944.0 False 2 0 Starołęka 59
+392861.0 False 3 3 Naramowice 42
+249733.0 False 2 0 Ogrody 54
+282944.0 False 2 0 Starołęka 59
+349668.0 False 2 2 Stare 15
+294840.0 False 2 4 Winogrady 50
+252723.0 False 2 1 Winogrady 43
+399000.0 False 3 2 Winogrady 98
+359600.0 False 3 5 Grunwald 58
+245876.0 True 2 1 Jeżyce 38
+329538.0 True 3 1 Jeżyce 50
+286268.0 True 2 5 Winogrady 49
+367000.0 True 3 1 Centrum 30
+350000.0 True 3 1 Nowe 63
+350000.0 True 2 1 Rataje 63
+399000.0 True 3 5 Grunwald 98
+429000.0 True 3 3 Centrum 102
+267703.0 True 2 3 Grunwald 45
+356251.0 True 3 14 Grunwald 57
+225290.0 True 2 7 Rataje 39
+333701.0 True 3 1 Jeżyce 68
+368568.0 True 3 4 Jeżyce 68
+285000.0 True 3 2 Antoninek 61
+300000.0 True 2 9 Strzeszyn 45
+299000.0 True 2 5 Centrum 50
+249000.0 True 2 2 Grunwald 46
+599000.0 True 4 5 Malta 84
+250000.0 True 2 4 Wilda 54
+341776.0 True 2 2 Stare 44
+238000.0 True 2 13 Rataje 49
+279000.0 True 3 1 Wilda 68
+430000.0 True 2 3 Jeżyce 58
+255000.0 True 2 1 Winogrady 38
+360000.0 True 3 1 Grunwald 49
+339000.0 True 2 1 Górczyn 45
+855000.0 True 3 3 Centrum 90
+1179000.0 True 3 2 Centrum 40
+2700000.0 True 3 2 Centrum 90
+1170000.0 True 3 3 Centrum 90
+368712.0 True 2 2 Centrum 90
+991380.0 True 4 1 Nowe 20
+250000.0 True 2 3 Dębiec 53
+249000.0 True 3 4 Rataje 53
+350000.0 True 2 4 Jeżyce 56
+285000.0 True 2 2 Centrum 52
+285000.0 True 2 2 Łazarz 52
+490000.0 True 4 2 Jeżyce 87
+429000.0 True 4 2 Grunwald 92
+211190.0 False 2 0 Podolany 78
+375529.0 False 2 3 Centrum 71
+225228.0 False 2 0 Rataje 71
+991380.0 False 5 1 Starołęka 94
+1156054.0 False 4 0 Stare 52
+288000.0 True 2 4 Naramowice 44
+820000.0 True 4 1 Grunwald 133
+370000.0 True 4 4 Piątkowo 76
+156085.0 False 2 0 Głuszyna 54
+156085.0 False 2 0 Głuszyna 54
+200460.0 False 2 0 Głuszyna 55
+200460.0 False 2 0 Głuszyna 55
+156085.0 False 2 0 Głuszyna 54
+156085.0 False 2 0 Głuszyna 54
+308237.0 False 2 1 Nowe 85
+225288.0 False 2 9 Rataje 91
+267702.0 False 2 3 Grunwald 22
+364000.0 True 3 4 Nowe 90
+280000.0 True 2 4 Winogrady 30
+349000.0 True 4 0 Rataje 84
+412000.0 True 4 0 Nowe 88
+490000.0 True 3 4 Piątkowo 82
+359602.0 True 3 5 Grunwald 58
+333025.0 True 2 1 Stare 45
+450000.0 True 2 3 Stare 62
+248000.0 True 2 2 Winogrady 80
+270000.0 True 3 10 Śródka 48
+239000.0 True 2 11 Stare 38
+225292.0 True 2 1 Rataje 39
+290970.0 True 2 4 Górczyn 70
+194500.0 True 2 3 Nowe 90
+712980.0 True 4 3 Centrum 102
+712980.0 True 5 2 Centrum 102
+855000.0 True 3 2 Centrum 72
+279000.0 True 2 6 Stare 49
+313830.0 True 2 4 Jeżyce 55
+325050.0 True 2 4 Jeżyce 25
+240158.0 True 2 0 Stare 39
+211190.0 True 2 0 Jeżyce 38
+333690.0 True 3 2 Jeżyce 68
+388751.0 True 4 5 Winogrady 65
+347091.0 True 3 1 Winogrady 57
+362450.0 True 3 1 Górczyn 90
+225288.91 True 2 6 Rataje 91
+225288.91 True 2 5 Rataje 91
+225288.91 True 2 1 Rataje 91
+392860.63 True 4 3 Winogrady 41
+364762.0 True 4 4 Winogrady 89
+316498.0 True 2 2 Centrum 77
+442002.0 True 2 3 Centrum 73
+276610.0 True 2 4 Centrum 80
+316355.0 True 2 4 Centrum 67
+280250.0 True 2 0 Górczyn 50
+327127.5 True 2 0 Centrum 50
+449000.0 False 5 0 Szczepankowo 68
+225288.0 False 2 1 Rataje 91
+286327.0 False 2 3 Naramowice 82
+365690.0 False 4 2 Naramowice 50
+389528.0 False 2 2 Stare 87
+481903.0 False 3 2 Stare 53
+349000.0 False 4 0 Szczepankowo 29
+347090.0 False 3 2 Naramowice 41
+534523.0 False 3 2 Stare 62
+412670.0 False 3 1 Naramowice 17
+285678.0 False 2 2 Naramowice 82
+263000.0 True 2 0 Wilda 75
+245000.0 True 2 2 Winogrady 20
+232410.0 True 2 0 Stare 38
+245488.0 True 2 0 Jeżyce 37
+225288.0 True 2 7 Rataje 39
+180000.0 True 3 2 Wilda 35
+189000.0 True 2 4 Wilda 35
+460499.0 True 3 1 Centrum 51
+903965.44 True 4 0 Centrum 80
+1366410.0 True 4 0 Centrum 71
+285383.0 True 2 4 Winogrady 37
+286091.0 True 2 3 Winogrady 49
+347090.0 True 3 1 Winogrady 90
+225288.91 True 2 7 Rataje 91
+442150.0 True 2 2 Centrum 75
+318000.0 True 4 8 Nowe 82
+278047.0 False 2 3 Podolany 74
+278047.0 False 2 4 Podolany 74
+278047.0 False 2 4 Podolany 74
+650958.0 False 4 5 Winogrady 51
+290360.0 False 2 4 Górczyn 60
+278047.0 False 2 4 Podolany 74
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+442080.0 False 3 1 Starołęka 65
+460499.0 False 3 1 Stare 51
+412670.0 False 3 1 Winogrady 17
+357692.0 False 3 2 Starołęka 31
+282994.0 False 2 0 Starołęka 59
+211190.0 False 2 0 Piątkowo 78
+252723.0 False 2 1 Winogrady 43
+232408.0 False 2 0 Winogrady 79
+349000.0 False 4 0 Szczepankowo 29
+277823.0 False 2 2 Podolany 70
+310020.0 False 3 4 Winogrady 67
+249733.0 False 2 0 Ogrody 54
+424377.0 False 4 2 Starołęka 14
+282944.0 False 2 0 Starołęka 59
+282944.0 False 2 0 Starołęka 59
+347633.0 True 3 10 Grunwald 57
+293436.0 True 2 1 Grunwald 50
+247705.0 True 2 1 Jeżyce 50
+398000.0 True 3 1 Jeżyce 72
+570000.0 True 4 0 Jeżyce 90
+285200.0 True 2 1 Stare 46
+347100.0 True 3 1 Winogrady 57
+223749.0 True 2 0 Stare 37
+245880.0 True 2 1 Jeżyce 38
+460050.0 True 3 5 Grunwald 74
+329000.0 True 3 2 Piątkowo 40
+279000.0 True 2 1 Stare 60
+720000.0 True 4 7 Jeżyce 90
+225290.0 True 2 5 Rataje 39
+355000.0 False 3 0 Stare 61
+355000.0 False 3 0 Podolany 61
+430000.0 False 4 0 Podolany 75
+270000.0 True 3 3 Stare 47
+475000.0 False 4 0 Stare 72
+475000.0 False 4 0 Podolany 72
+325000.0 True 2 2 Centrum 51
+455000.0 False 4 0 Stare 72
+455000.0 False 4 0 Podolany 72
+372000.0 False 4 1 Grunwald 87
+270000.0 True 2 10 Śródka 48
+207845.0 True 2 0 Nowe 79
+285000.0 True 2 2 Grunwald 52
+262500.0 True 4 0 Wilda 75
+350000.0 True 2 1 Rataje 80
+200000.0 True 2 0 Rataje 30
+210000.0 True 2 3 Grunwald 35
+368712.0 True 2 0 Centrum 90
+360288.0 True 2 1 Centrum 60
+390312.0 True 2 3 Centrum 60
+481103.0 True 3 1 Centrum 51
+455348.0 True 3 0 Centrum 61
+417231.0 True 2 2 Centrum 50
+411684.0 False 3 3 Winogrady 17
+481903.0 False 3 2 Centrum 53
+746787.0 False 3 7 Górczyn 53
+319998.0 False 3 1 Starołęka 95
+460040.0 False 3 5 Grunwald 20
+349000.0 False 4 0 Szczepankowo 29
+399000.0 False 5 0 Szczepankowo 68
+234000.0 True 2 7 Wilda 50
+210000.0 True 2 1 Wilda 65
+279000.0 True 2 2 Łazarz 36
diff --git a/wyk/data_flats.tsv b/wyk/data_flats.tsv
new file mode 100644
index 0000000..151a3c8
--- /dev/null
+++ b/wyk/data_flats.tsv
@@ -0,0 +1,1675 @@
+price isNew rooms floor location sqrMetres
+476118.0 False 3 1 Centrum 78
+459531.0 False 3 2 Sołacz 62
+411557.0 False 3 0 Sołacz 15
+496416.0 False 4 0 Sołacz 14
+406032.0 False 3 0 Sołacz 15
+450026.0 False 3 1 Naramowice 80
+571229.15 False 2 4 Wilda 39
+325000.0 False 3 1 Grunwald 54
+268229.0 False 2 1 Grunwald 90
+604836.0 False 4 5 Grunwald 40
+232050.0 False 3 0 Nowe 41
+399406.0 False 3 2 Wilda 89
+305739.0 False 2 2 Grunwald 53
+531976.68 False 4 1 Wilda 38
+288465.0 True 2 1 Starołęka 77
+305000.0 True 3 3 Winogrady 47
+410000.0 True 2 5 Rataje 30
+305000.0 True 3 3 Winogrady 48
+289000.0 True 2 2 Zawady 48
+419000.0 True 2 0 Rataje 56
+193000.0 True 2 5 Malta 37
+270000.0 True 3 4 Rataje 48
+360000.0 True 3 2 Rataje 20
+240000.0 True 2 10 Rataje 36
+299000.0 True 2 4 Nowe 47
+298000.0 True 2 4 Wilda 45
+289000.0 True 2 2 Komandoria 48
+300000.0 True 2 1 Podolany 45
+177000.0 True 2 2 Dębiec 25
+404000.0 True 3 2 Rataje 70
+335000.0 True 3 7 Rataje 63
+305000.0 True 3 3 Winogrady 60
+254900.0 True 2 14 Winogrady 80
+348000.0 True 3 9 Rataje 65
+320000.0 True 3 4 Winogrady 50
+284000.0 True 3 4 Rataje 48
+188000.0 True 2 2 Dębiec 61
+477000.0 True 4 3 Piątkowo 70
+390000.0 True 3 2 Podolany 68
+439000.0 True 3 3 Piątkowo 70
+263000.0 True 2 1 Rataje 44
+435000.0 True 2 0 Świerczewo 60
+610000.0 True 3 6 Centrum 77
+714000.0 True 3 2 Malta 84
+295000.0 True 2 2 Naramowice 58
+270000.0 True 3 10 Nowe 48
+259000.0 True 2 0 Rataje 38
+350000.0 True 3 0 Jeżyce 90
+295000.0 True 2 2 Grunwald 60
+338000.0 True 3 1 Jeżyce 37
+420000.0 True 4 3 Jeżyce 78
+565000.0 True 4 0 Sołacz 90
+355000.0 True 2 3 Nowe 90
+330000.0 True 2 4 Chwaliszewo 56
+299000.0 True 2 16 Rataje 49
+270000.0 True 2 2 Sołacz 49
+329000.0 True 3 3 Jeżyce 45
+405000.0 True 3 2 Rataje 70
+270000.0 True 2 2 Winogrady 49
+235000.0 True 2 6 Winogrady 38
+270000.0 True 2 2 Sołacz 49
+365000.0 True 3 2 Jeżyce 50
+325000.0 True 3 1 Nowe 90
+340000.0 True 3 16 Rataje 80
+329000.0 True 3 2 Rataje 59
+429000.0 True 3 4 Dębiec 60
+349000.0 True 3 3 Rataje 63
+329000.0 True 4 4 Nowe 20
+249000.0 True 2 2 Grunwald 46
+260000.0 True 2 0 Rataje 40
+275000.0 True 2 9 Rataje 38
+263000.0 True 2 1 Rataje 44
+269000.0 True 2 9 Rataje 49
+450000.0 True 3 11 Jeżyce 50
+299000.0 True 3 2 Łazarz 80
+330000.0 True 4 2 Rataje 62
+289000.0 True 3 3 Rataje 48
+750000.0 True 4 0 Naramowice 133
+635000.0 True 4 3 Grunwald 70
+279000.0 True 2 1 Naramowice 60
+399900.0 False 3 1 Grunwald 34
+255000.0 True 2 1 Winogrady 38
+239000.0 True 2 1 Grunwald 36
+229000.0 True 2 2 Wilda 50
+348000.0 True 3 9 Rataje 65
+384000.0 True 4 0 Grunwald 60
+232034.0 True 2 1 Starołęka 86
+270000.0 True 3 4 Rataje 48
+350000.0 False 5 1 Komorniki 97
+240000.0 True 2 16 Rataje 36
+619000.0 True 4 0 Jeżyce 99
+295000.0 True 3 4 Grunwald 45
+349000.0 True 3 1 Grunwald 57
+279000.0 True 3 0 Winogrady 48
+269000.0 True 3 3 Winogrady 48
+250000.0 True 2 6 Winogrady 42
+270000.0 True 2 4 Jeżyce 43
+285383.0 False 5 4 Winogrady 37
+348750.0 False 2 3 Stare 47
+240157.0 False 2 0 Winogrady 37
+285678.0 False 2 2 Winogrady 42
+272800.0 False 2 5 Winogrady 44
+267702.0 False 2 2 Grunwald 45
+327584.0 False 3 3 Grunwald 21
+235000.0 False 2 3 Winogrady 38
+286445.0 False 2 2 Winogrady 49
+156085.0 False 2 2 Starołęka 30
+282000.0 False 3 3 Winogrady 57
+365000.0 True 4 4 Grunwald 64
+519000.0 True 3 1 Rataje 50
+779000.0 True 3 2 Stare 113
+499000.0 True 4 2 Wilda 120
+255000.0 True 3 0 Grunwald 53
+270000.0 True 3 4 Rataje 48
+257000.0 True 2 5 Rataje 49
+499000.0 True 2 2 Stare 43
+399000.0 True 3 1 Nowe 62
+149000.0 True 3 5 Nowe 56
+435000.0 True 3 5 Wilda 70
+400000.0 False 4 0 Grunwald 81
+389000.0 True 3 3 Stare 49
+299000.0 True 3 6 Jeżyce 70
+325000.0 True 3 3 Łazarz 62
+399000.0 True 3 1 Grunwald 65
+279000.0 True 2 1 Naramowice 60
+334117.0 False 3 2 Grunwald 63
+364620.0 False 3 2 Grunwald 80
+529900.0 True 4 1 Podolany 103
+369000.0 True 4 3 Grunwald 74
+329000.0 True 2 2 Jeżyce 45
+320000.0 True 3 4 Winogrady 54
+275000.0 True 2 13 Rataje 80
+295120.0 False 2 1 Winogrady 60
+374000.0 True 3 4 Wilczak 30
+288000.0 True 3 4 Winogrady 30
+340000.0 True 3 1 Grunwald 70
+329000.0 True 3 3 Piątkowo 60
+290000.0 True 2 6 Sołacz 49
+229000.0 True 4 3 Wilda 54
+339000.0 True 3 1 Grunwald 65
+288000.0 True 3 4 Winogrady 30
+280000.0 True 3 1 Jeżyce 58
+295000.0 True 2 2 Naramowice 50
+264250.0 False 2 2 Jeżyce 29
+308039.0 False 2 0 Winogrady 21
+285200.0 False 2 1 Winogrady 46
+346624.0 False 3 1 Ogrody 54
+313566.0 False 3 1 Jeżyce 51
+290970.0 False 2 0 Winogrady 60
+304000.0 False 3 5 Winogrady 29
+225316.0 False 2 0 Starołęka 33
+186600.0 False 2 2 Starołęka 62
+336474.0 False 3 4 Winogrady 27
+299513.0 False 2 1 Starołęka 85
+257000.0 False 3 1 Winogrady 76
+244071.0 False 2 2 Starołęka 52
+291838.0 False 2 0 Starołęka 55
+322276.0 False 2 3 Winogrady 98
+280860.0 False 2 1 Winogrady 30
+297600.0 False 2 3 Winogrady 50
+349668.0 False 2 1 Garbary 44
+321656.0 False 2 1 Winogrady 88
+302176.0 False 2 2 Malta 45
+199000.0 True 2 1 Grunwald 33
+363000.0 True 3 2 Grunwald 77
+375000.0 True 3 4 Winogrady 65
+287000.0 True 2 10 Winogrady 47
+230000.0 True 2 1 Dębiec 37
+365000.0 True 3 2 Rataje 65
+389000.0 True 3 1 Naramowice 20
+325000.0 True 2 2 Grunwald 35
+391729.0 False 3 2 Winogrady 21
+479000.0 True 3 3 Grunwald 23
+249000.0 True 2 10 Grunwald 42
+286000.0 True 2 5 Centrum 49
+313000.0 True 2 4 Piątkowo 49
+409000.0 True 3 1 Rataje 62
+255000.0 True 2 1 Nowe 49
+270000.0 True 3 4 Jeżyce 50
+699000.0 True 2 1 Grunwald 68
+330000.0 True 2 3 Wilda 53
+335000.0 True 3 16 Rataje 80
+488000.0 True 3 3 Grunwald 70
+339000.0 True 3 1 Jeżyce 65
+410000.0 True 3 5 Grunwald 81
+269000.0 True 2 4 Naramowice 43
+710000.0 True 5 7 Grunwald 91
+359600.0 False 3 5 Grunwald 58
+249441.0 False 2 2 Jeżyce 50
+440000.0 True 4 1 Grunwald 95
+389000.0 True 3 2 Jeżyce 50
+590000.0 True 4 3 Rataje 90
+706655.0 False 3 2 Nowe 45
+269000.0 True 2 6 Rataje 70
+240000.0 True 2 16 Rataje 36
+310000.0 True 2 2 Centrum 53
+240000.0 False 3 0 Nowe 64
+230000.0 True 2 0 Grunwald 52
+770000.0 True 4 1 Centrum 142
+249000.0 True 2 4 Rataje 44
+350000.0 True 2 1 Rataje 54
+313000.0 True 2 4 Piątkowo 49
+310000.0 True 2 2 Śródka 72
+569000.0 True 4 0 Wilda 50
+460000.0 True 4 2 Bonin 87
+485000.0 True 2 2 Centrum 55
+286000.0 True 2 5 Centrum 80
+364000.0 True 3 1 Grunwald 62
+299000.0 True 3 3 Wilda 66
+365000.0 True 2 5 Wilda 30
+237000.0 True 2 10 Grunwald 38
+425000.0 True 4 6 Rataje 85
+332160.0 True 2 1 Grunwald 60
+230000.0 True 2 1 Dębiec 37
+249000.0 True 2 10 Grunwald 42
+270000.0 True 3 4 Rataje 48
+350000.0 True 2 4 Jeżyce 56
+309000.0 True 2 3 Grunwald 56
+283500.0 True 2 0 Stare 50
+177595.0 False 2 0 Nowe 29
+339000.0 True 2 2 Centrum 53
+399000.0 True 3 1 Grunwald 65
+329000.0 True 3 3 Piątkowo 60
+706655.0 False 3 2 Nowe 45
+289000.0 True 2 2 Jeżyce 42
+389000.0 True 3 0 Wilda 67
+375000.0 True 3 4 Wilda 40
+319000.0 True 3 2 Wilda 66
+310000.0 True 3 0 Grunwald 60
+252000.0 True 2 12 Winogrady 47
+249147.0 False 2 4 Zawady 71
+649000.0 True 4 0 Winogrady 80
+204000.0 True 2 0 Grunwald 37
+389000.0 True 3 4 Rataje 84
+369000.0 True 3 0 Grunwald 87
+300000.0 True 2 1 Naramowice 52
+470000.0 True 4 2 Sołacz 87
+326000.0 True 2 1 Winogrady 39
+655000.0 True 3 4 Stare 60
+348000.0 True 3 9 Rataje 65
+399000.0 True 3 1 Bonin 68
+390000.0 True 3 2 Podolany 68
+265000.0 True 2 0 Centrum 40
+279999.0 True 3 4 Winogrady 54
+280000.0 True 3 9 Jeżyce 49
+419000.0 True 2 0 Malta 56
+249000.0 True 2 4 Grunwald 38
+259000.0 True 2 3 Żegrze 49
+270000.0 True 2 0 Jeżyce 20
+349000.0 True 3 2 Grunwald 39
+349000.0 True 2 3 Piątkowo 60
+548000.0 True 3 1 Grunwald 84
+249000.0 True 2 10 Grunwald 43
+549000.0 True 3 2 Dąbrowskiego 106
+290000.0 True 2 6 Piątkowo 49
+442827.0 False 4 2 Starołęka 14
+530000.0 True 3 0 Grunwald 63
+279000.0 True 3 1 Plewiska 50
+410000.0 True 2 5 Rataje 50
+396000.0 True 3 1 Wilda 50
+279000.0 True 2 1 Stare 60
+399000.0 True 3 4 Piątkowo 16
+329000.0 True 2 2 Jeżyce 45
+270000.0 True 3 10 Grunwald 52
+360000.0 True 2 0 Centrum 57
+255000.0 True 3 2 Grunwald 20
+395000.0 True 3 1 Grunwald 100
+139000.0 True 2 0 Grunwald 49
+320000.0 True 3 4 Winogrady 50
+899000.0 True 4 0 Stare 100
+237000.0 True 2 2 Dębiec 44
+425000.0 True 3 1 Rataje 70
+315000.0 True 2 0 Winogrady 53
+485000.0 True 2 2 Centrum 55
+365000.0 True 3 1 Żegrze 88
+345000.0 True 3 1 Winogrady 17
+319000.0 True 3 3 Rataje 50
+265000.0 True 2 0 Dębiec 50
+978000.0 True 4 5 Centrum 106
+489000.0 True 2 5 Centrum 53
+382280.0 True 3 3 Centrum 80
+267900.0 True 2 6 Winogrady 30
+259000.0 True 2 3 Łazarz 47
+280000.0 True 2 4 Rataje 63
+250000.0 True 4 1 Wilda 31
+340000.0 True 2 2 Naramowice 16
+160000.0 True 2 0 Podolany 27
+390000.0 True 2 0 Centrum 60
+469000.0 True 2 1 Winogrady 30
+429000.0 True 3 4 Dębiec 50
+270000.0 True 2 2 Naramowice 52
+330000.0 True 3 0 Jeżyce 78
+279000.0 True 2 1 Stare 60
+289000.0 True 2 6 Jeżyce 49
+449000.0 True 4 1 Górczyn 90
+499000.0 True 4 4 Stare 85
+270000.0 True 2 16 Rataje 49
+295000.0 True 2 0 Stare 44
+210000.0 True 2 2 Dębiec 40
+519000.0 True 3 1 Rataje 50
+490000.0 True 4 0 Naramowice 40
+300000.0 True 2 1 Stare 23
+325000.0 True 3 4 Jeżyce 30
+238000.0 True 2 13 Rataje 49
+329000.0 True 3 1 Piątkowo 63
+270000.0 True 2 0 Piątkowo 43
+395000.0 True 3 0 Grunwald 70
+330000.0 True 2 1 Jeżyce 50
+439000.0 True 4 2 Grunwald 89
+259500.0 True 2 0 Grunwald 55
+355000.0 True 2 4 Jeżyce 56
+282000.0 True 2 1 Jeżyce 38
+335000.0 True 2 2 Górczyn 52
+375000.0 True 2 1 Grunwald 51
+399000.0 True 3 4 Stare 70
+474000.0 False 4 0 Plewiska 30
+309000.0 True 2 0 Grunwald 55
+379000.0 True 3 0 Rataje 57
+399000.0 True 3 1 Nowe 62
+570000.0 True 3 5 Grunwald 60
+105000.0 True 2 3 Nowe 50
+296000.0 True 3 6 Dębiec 63
+326000.0 True 2 1 Winiary 39
+1725000.0 True 3 0 Stare 136
+350550.0 True 3 4 Stare 50
+252000.0 True 2 12 Winogrady 47
+368000.0 True 2 2 Wilda 67
+549000.0 True 3 3 Grunwald 60
+409000.0 True 3 1 Rataje 90
+362000.0 True 2 1 Centrum 50
+250000.0 True 3 2 Nowe 80
+399900.0 True 4 2 Nowe 66
+429000.0 True 3 4 Wilda 60
+370000.0 True 2 0 Górczyn 65
+274000.0 True 2 1 Górczyn 13
+239000.0 True 2 3 Piątkowo 59
+259000.0 True 2 2 Rataje 90
+246330.0 True 2 0 Wilda 55
+289000.0 True 3 4 Winogrady 48
+100000.0 True 3 4 Stare 70
+270000.0 True 2 2 Sołacz 60
+430000.0 True 2 3 Grunwald 70
+355000.0 True 2 0 Podolany 93
+287000.0 True 2 11 Winogrady 47
+1200000.0 False 5 0 Starołęka 193
+305000.0 True 3 3 Winogrady 48
+329000.0 True 3 3 Piątkowo 60
+315000.0 True 3 0 Piątkowo 63
+267705.0 True 2 2 Grunwald 45
+247707.0 True 2 1 Jeżyce 50
+388750.0 True 4 5 Winogrady 65
+371931.0 True 4 4 Jeżyce 57
+232408.0 True 2 0 Stare 38
+247708.0 True 2 1 Jeżyce 50
+242731.0 True 2 0 Jeżyce 50
+247710.0 True 2 1 Jeżyce 50
+339200.0 True 3 1 Jeżyce 53
+349100.0 True 4 0 Rataje 85
+296277.0 True 3 1 Stare 49
+333694.0 True 3 1 Jeżyce 68
+250000.0 True 2 0 Naramowice 40
+200000.0 True 2 0 Rataje 30
+470000.0 True 4 2 Sołacz 87
+370000.0 True 4 4 Piątkowo 76
+315000.0 True 3 0 Piątkowo 60
+287000.0 True 2 10 Winogrady 80
+230000.0 True 2 3 Nowe 47
+900000.0 True 3 3 Centrum 120
+399000.0 True 3 4 Piątkowo 16
+250000.0 True 2 6 Sołacz 71
+318000.0 True 2 4 Piątkowo 20
+269000.0 True 2 9 Rataje 49
+239592.0 True 2 5 Grunwald 59
+307881.0 True 3 0 Grunwald 16
+319055.0 True 3 3 Grunwald 21
+267702.0 True 2 2 Grunwald 22
+299000.0 True 3 2 Dębiec 70
+435000.0 True 3 0 Stare 25
+690000.0 True 2 0 Grunwald 60
+204450.0 True 2 1 Nowe 33
+228144.0 True 3 2 Nowe 56
+285383.0 True 2 1 Winogrady 37
+391729.0 True 3 2 Winogrady 21
+330000.0 True 3 0 Jeżyce 78
+269984.0 True 3 4 Winogrady 76
+344141.0 True 2 8 Winogrady 47
+318384.0 True 3 6 Jeżyce 24
+249641.0 True 2 0 Jeżyce 54
+177000.0 True 2 2 Dębiec 33
+325000.0 True 2 2 Jeżyce 56
+429000.0 True 3 4 Rataje 70
+380000.0 True 3 3 Dolna 67
+448995.0 True 2 3 Jeżyce 66
+350000.0 True 2 3 Jeżyce 70
+269000.0 True 2 2 Dolna 38
+620000.0 True 3 1 Grunwald 96
+275000.0 True 2 0 Łazarz 52
+440000.0 True 2 0 Centrum 40
+505877.0 False 2 5 Centrum 22
+886860.0 False 3 5 Centrum 80
+502136.0 False 2 5 Centrum 77
+798966.0 False 2 5 Centrum 33
+561663.0 False 3 4 Centrum 69
+396248.0 False 2 4 Centrum 77
+368019.0 False 2 4 Centrum 18
+542141.0 False 3 4 Centrum 53
+698508.0 False 4 4 Centrum 59
+394787.0 False 2 4 Centrum 71
+597184.0 False 3 4 Centrum 61
+354177.0 False 2 3 Centrum 25
+353537.0 False 2 3 Centrum 17
+509468.0 False 3 3 Centrum 53
+652026.0 False 4 3 Centrum 89
+353457.0 False 2 3 Centrum 16
+356818.0 False 2 3 Centrum 58
+496573.0 False 3 2 Centrum 78
+349668.0 False 2 2 Centrum 15
+481903.0 False 3 2 Centrum 53
+309978.0 False 2 2 Centrum 16
+389528.0 False 2 2 Centrum 87
+341776.0 False 2 2 Centrum 14
+374216.0 False 2 2 Centrum 71
+534523.0 False 3 2 Centrum 62
+377418.0 False 2 1 Centrum 87
+330255.0 False 2 1 Centrum 14
+505032.0 False 3 1 Centrum 62
+375000.0 True 4 0 Grunwald 67
+375000.0 True 5 0 Grunwald 67
+363000.0 True 3 2 Grunwald 73
+495000.0 True 3 1 Grunwald 40
+270000.0 True 3 1 Starołęka 30
+365000.0 True 2 2 Grunwald 51
+450000.0 True 4 1 Grunwald 113
+190520.0 True 2 3 Nowe 30
+228492.0 True 2 1 Nowe 93
+169620.0 True 2 1 Nowe 55
+145000.0 True 2 1 Nowe 54
+270000.0 True 3 4 Rataje 48
+370000.0 True 4 4 Piątkowo 76
+289000.0 True 3 3 Grunwald 52
+585000.0 True 3 4 Jeżyce 59
+335000.0 True 3 7 Rataje 63
+329000.0 True 3 3 Piątkowo 60
+269000.0 True 2 0 Grunwald 46
+298000.0 True 2 4 Wilda 45
+398000.0 True 3 1 Grunwald 70
+395000.0 True 4 0 Grunwald 60
+389000.0 True 3 0 Wilda 96
+429000.0 True 3 4 Wilda 47
+715000.0 True 3 1 Wilda 95
+460000.0 True 2 2 Centrum 56
+555000.0 True 4 0 Stare 20
+655000.0 True 3 4 Stare 60
+188000.0 True 2 3 Stare 70
+390000.0 True 2 0 Nowe 61
+425000.0 True 2 9 Nowe 50
+359400.0 True 3 1 Stare 72
+497400.0 True 3 0 Wilda 48
+604395.0 True 5 1 Wilda 31
+330615.0 True 2 2 Stare 79
+290970.0 True 2 0 Stare 60
+283340.0 True 2 0 Stare 70
+282880.0 True 2 3 Stare 20
+339500.0 True 3 7 Nowe 80
+850000.0 True 2 7 Stare 69
+380000.0 True 4 6 Stare 90
+800000.0 True 4 3 Stare 103
+514000.0 True 4 1 Jeżyce 120
+290000.0 True 2 1 Stare 42
+640000.0 True 3 2 Stare 47
+1140000.0 True 6 0 Stare 40
+561000.0 True 2 4 Stare 50
+400000.0 True 2 1 Świerczewo 60
+220000.0 True 2 4 Grunwald 43
+490000.0 True 3 1 Jeżyce 115
+298000.0 True 2 4 Wilda 45
+449000.0 True 2 3 Jeżyce 60
+237000.0 True 2 2 Dębiec 44
+480000.0 True 2 2 Garbary 56
+298000.0 True 2 4 Wilda 37
+255000.0 True 2 3 Wilda 52
+480000.0 True 3 0 Stare 30
+451000.0 True 3 2 Wilda 30
+370000.0 True 3 4 Stare 84
+529000.0 True 3 3 Centrum 108
+360000.0 True 4 0 Grunwald 66
+419000.0 True 4 0 Kopernika 60
+350000.0 True 2 0 Stare 50
+348000.0 True 3 9 Rataje 65
+525000.0 True 4 3 Nowe 88
+450000.0 True 6 4 Wilda 90
+449000.0 True 4 2 Grunwald 90
+420000.0 True 3 0 Winogrady 58
+360000.0 True 3 3 Stare 63
+1000000.0 True 4 1 Centrum 103
+649400.0 False 3 4 Rataje 50
+311570.0 False 2 4 Rataje 51
+383928.0 False 3 3 Rataje 46
+309741.0 False 2 3 Rataje 89
+359000.0 True 2 0 Grunwald 46
+295734.0 False 2 3 Rataje 86
+384540.0 False 3 3 Rataje 55
+480000.0 True 3 1 Grunwald 40
+380091.0 False 3 2 Rataje 73
+293352.0 False 2 1 Rataje 14
+307156.0 False 2 1 Rataje 17
+293352.0 False 2 1 Rataje 14
+535000.0 True 2 3 Łazarz 59
+375606.0 False 3 1 Rataje 91
+293488.0 False 3 0 Rataje 94
+307428.0 False 2 0 Rataje 21
+293488.0 False 2 0 Rataje 16
+375408.0 False 3 0 Rataje 88
+299000.0 True 2 0 Piątkowo 47
+243828.0 False 2 4 Podolany 68
+348835.0 False 3 3 Podolany 63
+256171.0 False 2 3 Podolany 79
+298116.0 False 2 3 Podolany 96
+306247.0 False 2 3 Podolany 35
+337602.0 False 3 3 Podolany 71
+244647.0 False 2 3 Podolany 82
+641000.0 True 3 3 Łazarz 75
+277000.0 True 2 10 Nowe 80
+549000.0 True 4 0 Piątkowo 115
+499000.0 True 3 1 Suchy 95
+539000.0 True 4 2 Jeżyce 110
+450000.0 True 2 2 Grunwald 70
+242000.0 True 2 1 Grunwald 52
+310000.0 True 3 4 Jeżyce 50
+259000.0 True 2 3 Winogrady 40
+475000.0 True 3 4 Wilda 66
+120000.0 True 3 3 Grunwald 35
+270000.0 True 3 4 Rataje 48
+1850000.0 True 5 1 Grunwald 196
+350000.0 True 4 4 Grunwald 50
+280000.0 True 4 4 Grunwald 40
+490000.0 True 4 4 Grunwald 70
+495000.0 True 3 1 Naramowice 70
+545000.0 True 3 0 Rataje 71
+310000.0 True 3 10 Rataje 80
+215000.0 True 2 0 Wilda 36
+295000.0 True 2 4 Garbary 33
+200000.0 True 2 8 Dębiec 50
+359900.0 True 4 4 Rataje 74
+320000.0 True 3 3 Jeżyce 70
+300000.0 True 2 1 Naramowice 23
+535000.0 True 4 2 Wilda 120
+620000.0 True 3 2 Naramowice 60
+597000.0 True 3 0 Naramowice 60
+399000.0 True 3 0 Winogrady 62
+390000.0 True 3 0 Grunwald 75
+310000.0 True 2 1 Rataje 30
+365000.0 True 3 1 Rataje 88
+382000.0 True 3 3 Centrum 30
+299000.0 True 2 2 Sołacz 58
+299000.0 True 2 2 Sołacz 58
+499000.0 True 3 1 Grunwald 64
+549000.0 True 3 2 Jeżyce 106
+549000.0 True 3 2 Jeżyce 106
+413000.0 True 3 3 Łazarz 46
+259000.0 True 2 1 Jeżyce 47
+949000.0 True 3 4 Śródka 98
+949000.0 True 3 4 Śródka 98
+270000.0 True 3 4 Rataje 48
+348000.0 True 3 9 Nowe 65
+260000.0 True 2 0 Ławica 60
+370000.0 True 4 4 Stare 60
+399000.0 True 3 4 Stare 16
+369000.0 True 4 3 Grunwald 74
+224000.0 True 2 0 Łazarz 50
+260000.0 True 3 4 Grunwald 49
+315000.0 True 3 0 Piątkowo 60
+379999.0 True 3 3 Wilda 67
+350000.0 True 2 1 Rataje 63
+270000.0 True 2 4 Grunwald 38
+439000.0 True 4 2 Łazarz 92
+519000.0 True 3 1 Rataje 50
+290000.0 True 2 2 Dębiec 66
+326000.0 True 2 4 Łazarz 80
+240000.0 True 2 3 Grunwald 42
+389000.0 True 3 0 Wilda 67
+420000.0 True 3 2 Dębiec 91
+279000.0 True 2 1 Naramowice 51
+220000.0 True 2 4 Grunwald 43
+465360.0 True 2 2 Grunwald 17
+777280.0 True 3 3 Grunwald 16
+1000000.0 True 4 1 Stare 146
+350000.0 True 2 3 Rataje 50
+469000.0 True 4 2 Jeżyce 87
+253498.0 True 2 5 Jeżyce 38
+334752.0 True 3 3 Jeżyce 51
+374792.0 True 4 5 Jeżyce 57
+329000.0 True 3 4 Rataje 63
+349668.0 False 2 2 Stare 15
+297420.0 False 2 3 Grunwald 24
+297420.0 False 2 3 Grunwald 24
+220000.0 True 2 1 Jeżyce 60
+399000.0 True 3 1 Sołacz 66
+488000.0 True 3 3 Grunwald 70
+220000.0 True 2 4 Grunwald 43
+390000.0 True 3 2 Podolany 68
+299000.0 True 2 0 Wilda 52
+234000.0 True 2 0 Wilda 37
+375000.0 True 3 2 Wilda 90
+820000.0 True 4 0 Centrum 163
+320000.0 True 3 4 Winogrady 50
+420000.0 False 4 0 Grunwald 82
+495000.0 True 4 1 Stare 98
+279000.0 True 2 1 Stare 52
+620000.0 True 3 1 Stare 99
+329000.0 True 2 1 Stare 54
+699000.0 True 3 2 Stare 92
+487000.0 True 3 0 Stare 73
+375000.0 True 3 0 Naramowice 69
+269000.0 True 2 9 Rataje 49
+220000.0 True 2 4 Grunwald 43
+230000.0 True 2 1 Dębiec 38
+435000.0 True 2 0 Górczyn 60
+390000.0 True 3 2 Podolany 68
+446240.0 True 2 1 Grunwald 78
+390000.0 True 3 2 Podolany 68
+619000.0 True 3 2 Winogrady 100
+240000.0 True 2 3 Dębiec 50
+270000.0 True 3 4 Rataje 48
+244968.0 True 2 0 Stare 42
+285679.0 True 2 4 Winogrady 48
+260000.0 True 2 6 Winiary 70
+585000.0 True 4 1 Piątkowo 100
+329000.0 True 3 1 Piątkowo 63
+269000.0 True 2 0 Naramowice 46
+348000.0 True 3 9 Rataje 65
+270000.0 True 3 4 Rataje 48
+359605.0 True 3 5 Grunwald 58
+375529.0 False 2 3 Stare 71
+247705.0 False 2 1 Podolany 74
+247705.0 False 2 1 Piątkowo 74
+156085.0 False 2 4 Głuszyna 45
+411684.0 False 3 3 Winogrady 17
+349000.0 False 4 0 Szczepankowo 29
+277823.0 False 2 2 Podolany 70
+249733.0 False 2 0 Ogrody 54
+424377.0 False 4 2 Starołęka 14
+282944.0 False 2 0 Starołęka 59
+460499.0 False 3 1 Stare 51
+270000.0 True 3 0 Grunwald 48
+350000.0 True 4 1 Wilda 80
+350000.0 True 4 4 Winogrady 90
+323000.0 True 4 0 Winogrady 56
+649000.0 True 4 4 Centrum 109
+341704.0 True 3 8 Grunwald 56
+297421.0 True 2 3 Grunwald 50
+245832.0 True 2 2 Grunwald 40
+285384.0 True 2 4 Winogrady 48
+240000.0 True 2 1 Wilda 40
+345865.0 True 3 2 Jeżyce 21
+261000.0 True 2 2 Jeżyce 57
+400000.0 True 3 2 Jeżyce 74
+400000.0 True 2 2 Jeżyce 74
+348000.0 True 3 9 Rataje 65
+369000.0 True 2 2 Grunwald 51
+339000.0 True 3 0 Rataje 63
+250000.0 True 2 4 Rataje 23
+245000.0 True 2 4 Rataje 44
+240000.0 True 2 2 Dębiec 48
+262000.0 True 2 4 Grunwald 60
+395000.0 True 4 1 Smochowice 69
+313000.0 True 2 4 Piątkowo 50
+409000.0 True 3 1 Malta 90
+599000.0 True 3 3 Grunwald 83
+289000.0 True 2 2 Jeżyce 42
+390000.0 True 3 3 Naramowice 48
+313000.0 True 2 4 Piątkowo 49
+375000.0 True 4 2 Centrum 72
+350000.0 True 3 1 Naramowice 51
+304140.0 False 3 5 Winogrady 18
+353275.0 False 2 14 Grunwald 74
+244071.0 False 2 1 Nowe 93
+348000.0 True 3 9 Rataje 65
+320000.0 True 3 4 Winogrady 53
+348000.0 True 3 9 Rataje 65
+348000.0 True 3 9 Rataje 65
+230000.0 True 2 1 Dębiec 37
+238000.0 True 2 2 Grunwald 37
+392000.0 True 4 0 Piątkowo 74
+380000.0 True 4 2 Piątkowo 74
+329000.0 True 2 4 Górczyn 20
+347000.0 True 3 1 Naramowice 47
+259900.0 True 2 6 Winogrady 38
+590000.0 True 5 3 Piątkowo 125
+320000.0 True 2 1 Naramowice 53
+432000.0 True 2 5 Centrum 40
+435000.0 True 3 1 Piątkowo 84
+389000.0 True 2 1 Podolany 46
+799999.0 True 3 1 Sołacz 90
+310000.0 True 3 3 Piątkowo 60
+260000.0 True 3 0 Jeżyce 74
+266000.0 True 2 2 Piątkowo 49
+316498.0 True 2 2 Stare 77
+519000.0 True 3 1 Rataje 50
+442150.0 True 2 2 Stare 75
+395000.0 True 3 2 Centrum 74
+599000.0 True 2 1 Centrum 70
+459000.0 True 2 1 Centrum 48
+339000.0 True 3 1 Winogrady 51
+375000.0 True 3 2 Jeżyce 50
+289000.0 True 2 4 Ogrody 41
+230000.0 True 2 5 Winogrady 60
+440000.0 True 2 4 Centrum 55
+599000.0 True 3 2 Centrum 80
+343200.0 True 3 4 Winogrady 52
+385000.0 True 2 1 Centrum 60
+300000.0 True 3 3 Centrum 88
+529000.0 True 4 4 Centrum 85
+349000.0 True 3 3 Wilda 82
+405000.0 True 4 2 Nowe 71
+355000.0 True 2 4 Jeżyce 89
+235000.0 True 2 0 Górczyn 50
+495000.0 True 4 1 Grunwald 64
+285000.0 True 2 3 Wilda 60
+385000.0 True 3 4 Łazarz 82
+379999.0 True 3 3 Wilda 67
+370000.0 True 2 13 Rataje 67
+450000.0 True 3 0 Naramowice 71
+479000.0 True 3 3 Górczyn 70
+439000.0 True 4 2 Łazarz 40
+385000.0 True 3 0 Łazarz 80
+550000.0 True 4 1 Łazarz 50
+260000.0 True 3 4 Grunwald 47
+755000.0 True 4 2 Łazarz 90
+319000.0 True 2 0 Górczyn 54
+380000.0 True 3 1 Łazarz 30
+530000.0 True 3 1 Piątkowo 76
+900000.0 True 3 2 Grunwald 112
+375000.0 True 3 8 Piątkowo 75
+576500.0 True 2 5 Centrum 50
+576500.0 True 2 5 Chwaliszewo 50
+438503.0 True 3 2 Centrum 57
+354454.0 False 2 3 Grunwald 17
+489780.0 False 4 2 Górczyn 63
+491520.0 False 4 1 Górczyn 92
+273875.5 False 2 1 Grunwald 13
+267000.0 True 2 2 Dębiec 35
+260000.0 True 2 2 Piątkowo 90
+587000.0 True 4 3 Łazarz 38
+460000.0 True 3 1 Naramowice 110
+695000.0 True 4 1 Rataje 70
+506657.0 True 4 11 Grunwald 73
+298250.0 True 2 5 Grunwald 38
+297421.0 True 2 2 Grunwald 24
+275000.0 True 2 9 Nowe 38
+267000.0 True 2 4 Nowe 70
+447000.0 True 3 4 Grunwald 20
+349900.0 True 3 4 Wilda 42
+360000.0 True 4 0 Centrum 66
+525000.0 True 4 3 Jeżyce 70
+450000.0 True 3 2 Strzeszyn 70
+690000.0 True 4 5 Górczyn 25
+334000.0 True 2 4 Sołacz 50
+240000.0 True 2 3 Jeżyce 43
+307000.0 True 3 2 Rataje 48
+307000.0 True 2 2 Rataje 48
+345000.0 True 3 8 Nowe 63
+333694.0 False 3 1 Podolany 32
+333694.0 False 3 1 Piątkowo 38
+299000.0 True 3 0 Grunwald 53
+389000.0 True 3 3 Stare 49
+310000.0 True 2 2 Centrum 74
+220000.0 True 2 0 Grunwald 50
+332800.0 True 2 1 Grunwald 52
+240000.0 True 2 2 Stare 38
+323206.0 False 2 2 Naramowice 50
+558745.0 False 3 3 Stare 62
+290000.0 True 2 6 Jeżyce 49
+285000.0 True 2 3 Piątkowo 49
+365000.0 True 3 1 Rataje 67
+263000.0 True 2 1 Rataje 47
+289000.0 True 2 2 Jeżyce 42
+265000.0 True 3 4 Grunwald 48
+310000.0 True 2 1 Nowe 40
+300000.0 True 3 2 Winogrady 48
+565964.0 True 2 5 Centrum 49
+747000.0 True 3 7 Rataje 84
+275000.0 True 2 0 Naramowice 50
+405000.0 True 4 2 Rataje 71
+491520.0 True 4 1 Górczyn 92
+363258.0 True 2 1 Górczyn 59
+305739.0 True 2 2 Górczyn 53
+399000.0 True 3 4 Piątkowo 69
+280000.0 True 2 1 Sołacz 38
+299900.0 True 2 0 Dębiec 48
+420000.0 True 2 3 Naramowice 59
+650000.0 True 4 8 Rataje 100
+329000.0 True 3 3 Wilda 82
+355000.0 True 3 2 Piątkowo 66
+375000.0 True 3 2 Rataje 79
+200000.0 True 3 4 Nowe 44
+315000.0 True 2 2 Zawady 52
+259000.0 True 2 3 Rataje 49
+379000.0 True 3 2 Podolany 56
+354454.0 True 2 3 Górczyn 17
+237000.0 True 2 10 Górczyn 38
+315000.0 True 2 2 Zawady 52
+379999.0 True 3 2 Wilda 67
+279000.0 True 2 1 Naramowice 52
+250000.0 True 2 4 Rataje 44
+620000.0 True 3 2 Naramowice 98
+450000.0 True 3 5 Grunwald 60
+290000.0 True 2 2 Dębiec 40
+393599.0 True 2 6 Winogrady 49
+289000.0 True 2 2 Nowe 48
+240000.0 True 2 8 Dębiec 37
+420000.0 True 2 5 Rataje 63
+800000.0 True 3 3 Chwaliszewo 70
+285000.0 True 2 2 Łazarz 52
+495000.0 True 3 0 Centrum 63
+289575.0 True 2 0 Jeżyce 43
+259000.0 True 2 5 Grunwald 46
+265000.0 True 2 4 Grunwald 43
+495000.0 True 5 1 Naramowice 98
+275000.0 True 2 0 Naramowice 50
+320000.0 True 2 3 Chwaliszewo 56
+360000.0 True 2 5 Grunwald 41
+360000.0 True 2 0 Winogrady 48
+750000.0 True 4 0 Kobylepole 105
+260000.0 True 2 0 Rataje 46
+260000.0 True 3 4 Centrum 44
+1050000.0 True 5 2 Centrum 161
+379000.0 True 2 0 Nowe 56
+560000.0 True 2 8 Grunwald 55
+335400.0 True 2 1 Łazarz 51
+290000.0 True 2 5 Winogrady 42
+235000.0 True 2 3 Winogrady 38
+300000.0 True 2 4 Winogrady 53
+399000.0 True 3 1 Winiary 66
+830000.0 True 3 1 Grunwald 91
+385500.0 True 2 6 Dębiec 38
+199000.0 True 5 0 Sołacz 129
+295000.0 True 2 4 Stare 33
+370000.0 True 4 11 Rataje 74
+335000.0 True 3 1 Piątkowo 63
+350000.0 True 3 7 Piątkowo 63
+380000.0 True 3 1 Łazarz 98
+184000.0 True 2 0 Grunwald 34
+855000.0 True 4 5 Jeżyce 96
+215000.0 True 2 0 Wilda 36
+495000.0 True 4 1 Naramowice 98
+250000.0 True 2 5 Nowe 50
+275000.0 True 3 7 Wilda 53
+409000.0 True 3 1 Malta 61
+200000.0 True 2 0 Głuszyna 52
+299000.0 True 3 3 Wilda 66
+490000.0 True 4 3 Sołacz 83
+245000.0 True 2 0 Stare 44
+950000.0 True 3 4 Nowe 99
+355000.0 True 2 3 Nowe 50
+380000.0 True 3 3 Łazarz 95
+525000.0 True 4 3 Jeżyce 104
+400000.0 True 2 3 Naramowice 50
+248000.0 True 2 10 Grunwald 42
+380000.0 True 3 0 Centrum 55
+453600.0 True 2 3 Naramowice 56
+290000.0 True 2 3 Winogrady 37
+690000.0 True 4 5 Grunwald 107
+350000.0 True 3 6 Jeżyce 64
+340000.0 True 4 3 Winogrady 65
+345000.0 True 3 1 Rataje 78
+395000.0 True 3 10 Piątkowo 67
+495000.0 True 5 1 Naramowice 98
+269000.0 True 2 3 Grunwald 47
+257000.0 True 2 12 Winogrady 46
+516000.0 True 3 3 Naramowice 75
+285000.0 True 2 4 Naramowice 42
+354000.0 True 3 1 Naramowice 60
+345000.0 True 2 0 Centrum 42
+550000.0 True 2 1 Naramowice 57
+670000.0 True 4 3 Grunwald 81
+659000.0 True 5 0 Podolany 135
+925000.0 True 5 1 Stare 105
+510000.0 True 5 1 Naramowice 98
+350000.0 True 3 3 Jeżyce 70
+345000.0 True 3 1 Winogrady 50
+279000.0 True 2 0 Piątkowo 48
+535000.0 True 2 2 Stare 55
+350000.0 True 2 1 Rataje 54
+349000.0 True 3 3 Rataje 63
+250000.0 True 2 3 Wilda 39
+270000.0 True 2 10 Nowe 48
+285000.0 True 2 0 Łazarz 49
+999000.0 True 3 4 Nowe 99
+425000.0 True 3 1 Piątkowo 74
+479000.0 True 3 1 Naramowice 66
+360000.0 True 3 0 Wilda 112
+495000.0 True 3 1 Łazarz 64
+599000.0 True 3 3 Grunwald 60
+390000.0 True 3 2 Podolany 68
+450000.0 True 4 1 Grunwald 101
+313000.0 True 2 4 Piątkowo 49
+338000.0 True 3 3 Wilda 63
+285000.0 True 2 11 Winogrady 47
+270000.0 True 2 0 Grunwald 42
+360000.0 True 4 4 Jeżyce 60
+399000.0 True 2 3 Centrum 60
+619000.0 True 3 5 Jeżyce 69
+330000.0 True 2 1 Jeżyce 53
+1612000.0 True 7 5 Jeżyce 166
+399000.0 True 3 3 Centrum 50
+365000.0 True 2 1 Stare 50
+450000.0 True 3 0 Grunwald 75
+288000.0 True 3 4 Winogrady 47
+240000.0 True 2 16 Rataje 36
+326000.0 True 2 0 Jeżyce 55
+250000.0 True 2 4 Zawady 66
+288000.0 True 2 4 Naramowice 44
+289000.0 True 2 7 Winiary 49
+515000.0 True 3 0 Rataje 69
+428000.0 True 3 3 Centrum 43
+510000.0 True 5 1 Naramowice 98
+320000.0 True 2 2 Piątkowo 48
+659200.0 True 4 3 Łazarz 103
+499000.0 True 5 0 Grunwald 130
+240000.0 True 2 2 Dębiec 48
+495000.0 True 4 1 Naramowice 98
+320000.0 True 3 0 Rataje 56
+430000.0 True 3 2 Rataje 64
+409000.0 True 5 4 Winogrady 64
+415000.0 True 3 4 Łazarz 53
+359000.0 True 3 2 Rataje 65
+410000.0 True 2 5 Rataje 53
+479000.0 True 3 3 Nowe 83
+365000.0 True 4 3 Grunwald 68
+369000.0 True 2 3 Grunwald 64
+259000.0 True 2 2 Nowe 42
+250000.0 True 3 4 Dębiec 45
+299000.0 True 2 4 Nowe 47
+430000.0 True 2 1 Centrum 72
+275000.0 True 2 0 Dębiec 50
+950000.0 True 3 4 Nowe 99
+329000.0 True 3 7 Rataje 78
+380000.0 True 4 6 Piątkowo 73
+299000.0 True 2 5 Centrum 49
+265000.0 True 2 1 Wilda 44
+370000.0 True 2 13 Rataje 48
+370000.0 True 4 4 Piątkowo 76
+379000.0 True 3 1 Piątkowo 78
+299000.0 True 2 3 Grunwald 44
+379999.0 True 2 5 Jeżyce 61
+1000000.0 True 5 1 Jeżyce 128
+549000.0 True 3 2 Jeżyce 106
+335000.0 True 3 9 Nowe 65
+489000.0 True 3 0 Jeżyce 65
+379000.0 True 3 4 Rataje 63
+245000.0 True 3 0 Grunwald 45
+235000.0 True 2 0 Łazarz 52
+295555.0 True 2 1 Jeżyce 45
+224000.0 True 2 0 Górczyn 38
+315000.0 True 2 2 Winogrady 38
+429000.0 True 3 4 Nowe 79
+595000.0 True 3 0 Naramowice 94
+330000.0 True 3 0 Bonin 56
+275000.0 True 2 13 Rataje 49
+499000.0 True 4 2 Wilda 120
+287000.0 True 2 10 Winogrady 46
+280000.0 True 2 10 Piątkowo 46
+273875.0 True 2 1 Górczyn 13
+450000.0 True 3 0 Winogrady 70
+325000.0 True 3 4 Jeżyce 64
+299817.0 True 2 3 Górczyn 59
+295000.0 True 2 2 Naramowice 58
+380000.0 True 4 6 Piątkowo 73
+399000.0 True 3 4 Winogrady 65
+305000.0 True 3 3 Winogrady 48
+220000.0 True 2 3 Jeżyce 37
+285000.0 True 3 2 Antoninek 61
+238000.0 True 2 2 Grunwald 37
+200000.0 True 2 0 Rataje 30
+298000.0 True 2 5 Centrum 50
+391729.0 False 3 2 Winogrady 42
+347090.0 False 3 2 Winogrady 41
+285678.0 False 2 1 Winogrady 82
+321656.0 False 2 4 Winogrady 38
+312259.0 False 2 6 Winogrady 60
+347090.0 False 3 1 Winogrady 90
+355042.0 False 3 6 Jeżyce 96
+496573.0 False 3 2 Stare 78
+300680.0 False 2 2 Starołęka 54
+395000.0 True 4 4 Piątkowo 90
+771672.0 False 4 4 Górczyn 66
+399000.0 True 4 1 Szczepankowo 60
+340100.0 True 3 0 Szczepankowo 45
+225228.0 False 2 5 Rataje 91
+324387.0 False 2 9 Grunwald 49
+362459.0 False 3 0 Starołęka 80
+247705.0 False 2 1 Podolany 74
+339000.0 True 3 8 Nowe 78
+207000.0 True 2 2 Wilda 33
+295000.0 True 2 4 Grunwald 50
+324500.0 True 2 5 Wilda 65
+429000.0 True 3 4 Wilda 47
+399000.0 True 4 0 Szczepankowo 71
+411804.0 True 3 1 Winogrady 42
+282613.0 True 2 3 Winogrady 33
+235399.0 True 2 1 Winogrady 59
+265741.0 True 2 7 Winogrady 21
+323340.0 True 3 3 Winogrady 89
+293848.0 True 3 7 Winogrady 57
+337303.0 True 4 2 Winogrady 17
+470092.0 True 2 3 Centrum 21
+310000.0 True 2 0 Wilda 53
+365000.0 True 4 1 Nowe 54
+259000.0 True 2 6 Winogrady 38
+414225.0 True 3 3 Centrum 23
+489000.0 True 3 3 Grunwald 104
+350000.0 True 4 3 Grunwald 30
+325000.0 True 2 3 Rataje 20
+321845.0 False 3 1 Grunwald 55
+248000.0 True 2 14 Rataje 49
+286000.0 True 2 5 Centrum 64
+399000.0 True 3 4 Piątkowo 16
+289000.0 True 2 7 Winiary 80
+329000.0 True 3 11 Winogrady 50
+252723.0 False 2 1 Winogrady 43
+300680.0 False 2 2 Starołęka 54
+496573.0 False 3 2 Stare 78
+392181.0 False 3 4 Winogrady 42
+496573.0 False 3 2 Stare 78
+412438.0 False 3 2 Naramowice 17
+286000.0 True 2 5 Centrum 49
+269000.0 True 2 9 Rataje 49
+315000.0 True 2 1 Grunwald 61
+318390.0 True 3 3 Jeżyce 48
+242406.0 True 2 0 Jeżyce 36
+296278.0 True 3 2 Stare 49
+223747.0 True 2 0 Stare 37
+388755.0 True 4 5 Winogrady 65
+347095.0 True 3 1 Winogrady 57
+269000.0 True 2 1 Ogrody 50
+285000.0 True 2 9 Grunwald 50
+114642.0 True 2 0 Łazarz 46
+286000.0 True 2 5 Stare 64
+333693.0 True 3 1 Jeżyce 68
+435000.0 True 2 0 Świerczewo 60
+320000.0 True 4 1 Jeżyce 40
+395000.0 True 4 0 Grunwald 60
+353457.0 True 2 3 Stare 44
+267704.0 True 2 3 Grunwald 45
+245831.0 True 2 2 Grunwald 40
+391729.0 True 3 2 Winogrady 69
+240875.0 True 2 7 Stare 39
+424380.0 True 4 2 Nowe 74
+282996.0 True 2 0 Nowe 55
+285000.0 True 3 1 Rataje 48
+284618.0 False 2 3 Nowe 55
+512034.0 False 4 2 Winogrady 94
+284618.0 False 2 3 Nowe 55
+255404.0 False 2 6 Jeżyce 12
+315810.0 False 3 8 Winogrady 20
+282994.0 False 2 0 Starołęka 59
+637135.0 False 3 7 Grunwald 65
+754000.0 False 5 0 Morasko 42
+336000.0 True 3 0 Szczepankowo 85
+355000.0 True 2 3 Nowe 90
+475000.0 True 3 0 Rataje 73
+275000.0 True 3 4 Winogrady 60
+275000.0 True 3 4 Winogrady 70
+289000.0 True 2 7 Winogrady 80
+315000.0 True 3 0 Rataje 63
+260000.0 True 2 1 Łazarz 54
+370000.0 True 4 4 Piątkowo 76
+319990.0 True 2 3 Jeżyce 70
+156085.0 False 2 3 Głuszyna 45
+225228.0 False 2 5 Rataje 91
+308237.0 False 2 1 Nowe 85
+353275.0 False 2 14 Grunwald 74
+228144.0 False 3 2 Głuszyna 56
+156085.0 False 2 2 Głuszyna 45
+353275.0 False 2 14 Grunwald 74
+353275.0 False 2 14 Grunwald 74
+156085.0 False 2 3 Głuszyna 45
+156085.0 False 2 4 Nowe 54
+267702.0 False 2 3 Grunwald 22
+353275.0 False 2 14 Grunwald 74
+247705.0 False 2 1 Podolany 74
+315810.0 False 3 8 Winogrady 20
+370000.0 True 4 4 Stare 60
+265000.0 True 2 2 Stare 70
+304140.0 False 3 3 Winogrady 27
+394000.0 False 4 0 Szczepankowo 77
+287882.0 False 2 1 Starołęka 85
+729000.0 True 3 0 Rataje 20
+445000.0 True 4 3 Piątkowo 65
+339000.0 True 3 1 Wilda 90
+382000.0 True 4 0 Piątkowo 74
+335000.0 True 2 4 Jeżyce 35
+258000.0 True 2 0 Plewiska 40
+195000.0 True 2 1 Grunwald 31
+229000.0 True 2 1 Grunwald 16
+327000.0 True 3 1 Piątkowo 40
+279000.0 True 3 1 Nowe 54
+329000.0 True 3 1 Piątkowo 63
+220000.0 True 2 3 Jeżyce 37
+285000.0 True 3 2 Antoninek 61
+286000.0 True 2 5 Stare 49
+550000.0 True 3 1 Jeżyce 73
+366770.0 True 3 1 Stare 58
+392000.0 True 4 0 Piątkowo 74
+504326.0 True 4 4 Stare 26
+232408.0 True 2 1 Winogrady 37
+247000.0 True 2 2 Jeżyce 38
+318384.0 True 3 2 Jeżyce 48
+371930.0 True 4 2 Jeżyce 57
+347092.0 True 3 1 Winogrady 57
+286445.0 True 2 2 Winogrady 49
+254309.0 True 2 2 Stare 42
+238950.0 True 2 4 Stare 39
+442080.0 True 3 1 Nowe 68
+319998.0 True 3 1 Nowe 14
+404965.0 True 3 2 Nowe 63
+336840.0 True 3 3 Nowe 14
+380931.0 True 3 3 Nowe 83
+341311.0 True 3 8 Grunwald 53
+325000.0 True 2 0 Nowe 80
+388000.0 True 2 1 Grunwald 33
+219000.0 True 2 1 Grunwald 35
+1007500.0 False 4 1 Starołęka 94
+1203616.0 False 5 0 Starołęka 71
+298980.0 False 2 5 Winogrady 30
+281988.0 False 2 7 Naramowice 76
+300680.0 False 2 2 Starołęka 54
+288405.0 False 2 1 Górczyn 37
+392861.0 False 3 2 Winogrady 42
+298250.0 False 2 6 Grunwald 38
+411684.0 False 3 3 Winogrady 17
+349000.0 False 4 0 Szczepankowo 29
+277823.0 False 2 2 Podolany 70
+310020.0 False 3 4 Winogrady 67
+424377.0 False 4 2 Starołęka 14
+282944.0 False 2 0 Starołęka 59
+392861.0 False 3 3 Naramowice 42
+249733.0 False 2 0 Ogrody 54
+282944.0 False 2 0 Starołęka 59
+349668.0 False 2 2 Stare 15
+294840.0 False 2 4 Winogrady 50
+252723.0 False 2 1 Winogrady 43
+399000.0 False 3 2 Winogrady 98
+359600.0 False 3 5 Grunwald 58
+245876.0 True 2 1 Jeżyce 38
+329538.0 True 3 1 Jeżyce 50
+286268.0 True 2 5 Winogrady 49
+367000.0 True 3 1 Centrum 30
+350000.0 True 3 1 Nowe 63
+350000.0 True 2 1 Rataje 63
+399000.0 True 3 5 Grunwald 98
+429000.0 True 3 3 Centrum 102
+267703.0 True 2 3 Grunwald 45
+356251.0 True 3 14 Grunwald 57
+225290.0 True 2 7 Rataje 39
+333701.0 True 3 1 Jeżyce 68
+368568.0 True 3 4 Jeżyce 68
+285000.0 True 3 2 Antoninek 61
+300000.0 True 2 9 Strzeszyn 45
+299000.0 True 2 5 Centrum 50
+249000.0 True 2 2 Grunwald 46
+599000.0 True 4 5 Malta 84
+250000.0 True 2 4 Wilda 54
+341776.0 True 2 2 Stare 44
+238000.0 True 2 13 Rataje 49
+279000.0 True 3 1 Wilda 68
+430000.0 True 2 3 Jeżyce 58
+255000.0 True 2 1 Winogrady 38
+360000.0 True 3 1 Grunwald 49
+339000.0 True 2 1 Górczyn 45
+855000.0 True 3 3 Centrum 90
+1179000.0 True 3 2 Centrum 40
+2700000.0 True 3 2 Centrum 90
+1170000.0 True 3 3 Centrum 90
+368712.0 True 2 2 Centrum 90
+991380.0 True 4 1 Nowe 20
+250000.0 True 2 3 Dębiec 53
+249000.0 True 3 4 Rataje 53
+350000.0 True 2 4 Jeżyce 56
+285000.0 True 2 2 Centrum 52
+285000.0 True 2 2 Łazarz 52
+490000.0 True 4 2 Jeżyce 87
+429000.0 True 4 2 Grunwald 92
+211190.0 False 2 0 Podolany 78
+375529.0 False 2 3 Centrum 71
+225228.0 False 2 0 Rataje 71
+991380.0 False 5 1 Starołęka 94
+1156054.0 False 4 0 Stare 52
+288000.0 True 2 4 Naramowice 44
+820000.0 True 4 1 Grunwald 133
+370000.0 True 4 4 Piątkowo 76
+156085.0 False 2 0 Głuszyna 54
+156085.0 False 2 0 Głuszyna 54
+200460.0 False 2 0 Głuszyna 55
+200460.0 False 2 0 Głuszyna 55
+156085.0 False 2 0 Głuszyna 54
+156085.0 False 2 0 Głuszyna 54
+308237.0 False 2 1 Nowe 85
+225288.0 False 2 9 Rataje 91
+267702.0 False 2 3 Grunwald 22
+364000.0 True 3 4 Nowe 90
+280000.0 True 2 4 Winogrady 30
+349000.0 True 4 0 Rataje 84
+412000.0 True 4 0 Nowe 88
+490000.0 True 3 4 Piątkowo 82
+359602.0 True 3 5 Grunwald 58
+333025.0 True 2 1 Stare 45
+450000.0 True 2 3 Stare 62
+248000.0 True 2 2 Winogrady 80
+270000.0 True 3 10 Śródka 48
+239000.0 True 2 11 Stare 38
+225292.0 True 2 1 Rataje 39
+290970.0 True 2 4 Górczyn 70
+194500.0 True 2 3 Nowe 90
+712980.0 True 4 3 Centrum 102
+712980.0 True 5 2 Centrum 102
+855000.0 True 3 2 Centrum 72
+279000.0 True 2 6 Stare 49
+313830.0 True 2 4 Jeżyce 55
+325050.0 True 2 4 Jeżyce 25
+240158.0 True 2 0 Stare 39
+211190.0 True 2 0 Jeżyce 38
+333690.0 True 3 2 Jeżyce 68
+388751.0 True 4 5 Winogrady 65
+347091.0 True 3 1 Winogrady 57
+362450.0 True 3 1 Górczyn 90
+225288.91 True 2 6 Rataje 91
+225288.91 True 2 5 Rataje 91
+225288.91 True 2 1 Rataje 91
+392860.63 True 4 3 Winogrady 41
+364762.0 True 4 4 Winogrady 89
+316498.0 True 2 2 Centrum 77
+442002.0 True 2 3 Centrum 73
+276610.0 True 2 4 Centrum 80
+316355.0 True 2 4 Centrum 67
+280250.0 True 2 0 Górczyn 50
+327127.5 True 2 0 Centrum 50
+449000.0 False 5 0 Szczepankowo 68
+225288.0 False 2 1 Rataje 91
+286327.0 False 2 3 Naramowice 82
+365690.0 False 4 2 Naramowice 50
+389528.0 False 2 2 Stare 87
+481903.0 False 3 2 Stare 53
+349000.0 False 4 0 Szczepankowo 29
+347090.0 False 3 2 Naramowice 41
+534523.0 False 3 2 Stare 62
+412670.0 False 3 1 Naramowice 17
+285678.0 False 2 2 Naramowice 82
+263000.0 True 2 0 Wilda 75
+245000.0 True 2 2 Winogrady 20
+232410.0 True 2 0 Stare 38
+245488.0 True 2 0 Jeżyce 37
+225288.0 True 2 7 Rataje 39
+180000.0 True 3 2 Wilda 35
+189000.0 True 2 4 Wilda 35
+460499.0 True 3 1 Centrum 51
+903965.44 True 4 0 Centrum 80
+1366410.0 True 4 0 Centrum 71
+285383.0 True 2 4 Winogrady 37
+286091.0 True 2 3 Winogrady 49
+347090.0 True 3 1 Winogrady 90
+225288.91 True 2 7 Rataje 91
+442150.0 True 2 2 Centrum 75
+318000.0 True 4 8 Nowe 82
+278047.0 False 2 3 Podolany 74
+278047.0 False 2 4 Podolany 74
+278047.0 False 2 4 Podolany 74
+650958.0 False 4 5 Winogrady 51
+290360.0 False 2 4 Górczyn 60
+278047.0 False 2 4 Podolany 74
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+350875.0 False 3 1 Starołęka 97
+442080.0 False 3 1 Starołęka 65
+460499.0 False 3 1 Stare 51
+412670.0 False 3 1 Winogrady 17
+357692.0 False 3 2 Starołęka 31
+282994.0 False 2 0 Starołęka 59
+211190.0 False 2 0 Piątkowo 78
+252723.0 False 2 1 Winogrady 43
+232408.0 False 2 0 Winogrady 79
+349000.0 False 4 0 Szczepankowo 29
+277823.0 False 2 2 Podolany 70
+310020.0 False 3 4 Winogrady 67
+249733.0 False 2 0 Ogrody 54
+424377.0 False 4 2 Starołęka 14
+282944.0 False 2 0 Starołęka 59
+282944.0 False 2 0 Starołęka 59
+347633.0 True 3 10 Grunwald 57
+293436.0 True 2 1 Grunwald 50
+247705.0 True 2 1 Jeżyce 50
+398000.0 True 3 1 Jeżyce 72
+570000.0 True 4 0 Jeżyce 90
+285200.0 True 2 1 Stare 46
+347100.0 True 3 1 Winogrady 57
+223749.0 True 2 0 Stare 37
+245880.0 True 2 1 Jeżyce 38
+460050.0 True 3 5 Grunwald 74
+329000.0 True 3 2 Piątkowo 40
+279000.0 True 2 1 Stare 60
+720000.0 True 4 7 Jeżyce 90
+225290.0 True 2 5 Rataje 39
+355000.0 False 3 0 Stare 61
+355000.0 False 3 0 Podolany 61
+430000.0 False 4 0 Podolany 75
+270000.0 True 3 3 Stare 47
+475000.0 False 4 0 Stare 72
+475000.0 False 4 0 Podolany 72
+325000.0 True 2 2 Centrum 51
+455000.0 False 4 0 Stare 72
+455000.0 False 4 0 Podolany 72
+372000.0 False 4 1 Grunwald 87
+270000.0 True 2 10 Śródka 48
+207845.0 True 2 0 Nowe 79
+285000.0 True 2 2 Grunwald 52
+262500.0 True 4 0 Wilda 75
+350000.0 True 2 1 Rataje 80
+200000.0 True 2 0 Rataje 30
+210000.0 True 2 3 Grunwald 35
+368712.0 True 2 0 Centrum 90
+360288.0 True 2 1 Centrum 60
+390312.0 True 2 3 Centrum 60
+481103.0 True 3 1 Centrum 51
+455348.0 True 3 0 Centrum 61
+417231.0 True 2 2 Centrum 50
+411684.0 False 3 3 Winogrady 17
+481903.0 False 3 2 Centrum 53
+746787.0 False 3 7 Górczyn 53
+319998.0 False 3 1 Starołęka 95
+460040.0 False 3 5 Grunwald 20
+349000.0 False 4 0 Szczepankowo 29
+399000.0 False 5 0 Szczepankowo 68
+234000.0 True 2 7 Wilda 50
+210000.0 True 2 1 Wilda 65
+279000.0 True 2 2 Łazarz 36
+325000.0 True 2 0 Rataje 47
+285000.0 True 2 3 Grunwald 58
+360000.0 True 3 2 Rataje 69
+355000.0 True 2 2 Rataje 90
+362804.0 False 3 5 Jeżyce 39
+252723.0 False 2 1 Winogrady 43
+285200.0 False 2 1 Winogrady 46
+249641.0 False 2 0 Ogrody 54
+302887.0 False 2 4 Górczyn 25
+242731.0 False 2 0 Podolany 74
+991380.0 False 5 1 Starołęka 94
+265000.0 True 2 2 Piątkowo 70
+344000.0 True 2 0 Stare 49
+313000.0 True 2 4 Stare 49
+315000.0 True 3 0 Stare 60
+315000.0 True 3 0 Rataje 63
+690000.0 True 2 1 Stare 20
+465000.0 True 2 2 Wilda 49
+368110.0 True 3 2 Nowe 64
+282994.0 True 2 0 Nowe 55
+350000.0 True 2 3 Rataje 52
+780000.0 True 3 0 Grunwald 87
+263000.0 True 2 0 Rataje 38
+219000.0 True 2 7 Winogrady 38
+250000.0 True 3 3 Rataje 53
+394000.0 True 4 0 Nowe 88
+535000.0 True 2 2 Centrum 55
+329000.0 True 3 13 Rataje 65
+192750.0 True 2 2 Nowe 55
+375408.0 True 3 0 Nowe 88
+649400.0 True 3 4 Nowe 50
+294906.0 True 2 3 Nowe 74
+291720.0 True 2 5 Stare 20
+290646.0 True 2 2 Stare 80
+285678.0 False 2 1 Winogrady 42
+156085.0 False 2 4 Nowe 54
+496573.0 False 3 2 Stare 78
+1156054.0 False 4 0 Stare 52
+380931.0 False 3 3 Starołęka 82
+285200.0 True 2 0 Stare 46
+434201.0 True 4 1 Nowe 54
+269984.0 True 3 0 Stare 76
+333024.0 True 2 1 Stare 45
+637037.0 True 4 3 Stare 79
+319060.0 True 3 3 Grunwald 56
+267700.0 True 2 2 Grunwald 45
+365690.0 True 4 1 Winogrady 63
+285678.0 True 2 4 Winogrady 48
+295363.0 True 3 1 Stare 48
+223750.0 True 2 0 Stare 37
+277823.0 True 2 1 Jeżyce 50
+333695.0 True 3 2 Jeżyce 68
+288000.0 True 2 4 Naramowice 22
+518000.0 True 4 0 Wilda 41
+235000.0 True 2 4 Dębiec 44
+364762.0 True 4 1 Winogrady 62
+320000.0 True 4 3 Stare 40
+449000.0 True 5 3 Wilda 97
+249000.0 True 2 10 Grunwald 42
+279000.0 True 2 3 Piątkowo 30
+289000.0 True 3 4 Winogrady 48
+318645.0 True 2 2 Stare 30
+289000.0 True 2 7 Jeżyce 80
+285000.0 True 2 2 Łazarz 20
+399000.0 True 3 4 Piątkowo 69
+350000.0 True 3 1 Rataje 63
+240000.0 True 2 2 Dębiec 48
+356160.0 False 4 4 Winogrady 36
+290970.0 False 2 0 Winogrady 52
+289000.0 True 3 4 Stare 47
+399000.0 True 3 4 Piątkowo 69
+315000.0 True 3 0 Piatkowo 50
+329000.0 True 2 1 Grunwald 66
+253000.0 True 2 4 Grunwald 70
+179000.0 True 2 0 Grunwald 34
+250000.0 True 2 0 Naramowice 50
+410000.0 True 2 4 Jeżyce 43
+360000.0 True 3 3 Jeżyce 62
+590000.0 True 3 3 Jeżyce 80
+325000.0 True 3 2 Jeżyce 64
+247705.0 False 2 1 Podolany 74
+247705.0 False 2 1 Piątkowo 74
+392861.0 False 3 3 Winogrady 42
+156085.0 False 2 4 Głuszyna 45
+249441.0 False 2 5 Jeżyce 51
+398000.0 True 3 3 Łazarz 96
+255000.0 True 2 2 Wilda 72
+329000.0 True 2 1 Naramowice 40
+232409.0 True 2 0 Stare 38
+296300.0 True 3 2 Stare 49
+364762.0 True 4 4 Winogrady 63
+239592.0 True 2 5 Grunwald 36
+395000.0 True 3 0 Naramowice 73
+333694.0 False 3 1 Piątkowo 38
+344500.0 False 3 6 Jeżyce 53
+377652.0 False 4 6 Jeżyce 22
+332145.0 False 3 0 Winogrady 45
+328241.0 False 3 3 Winogrady 81
+328241.0 False 3 5 Winogrady 81
+355041.6 False 3 6 Jeżyce 96
+318384.0 False 3 6 Jeżyce 24
+328241.0 False 3 1 Winogrady 81
+323340.0 False 3 0 Winogrady 89
+332145.0 False 3 1 Winogrady 45
+392607.0 False 4 5 Jeżyce 94
+345180.0 False 3 1 Jeżyce 30
+315810.0 False 4 8 Winogrady 20
+263581.0 False 2 2 Winogrady 21
+323340.0 False 3 2 Winogrady 89
+263581.0 False 2 6 Winogrady 21
+238948.0 False 2 5 Winogrady 54
+240875.0 False 2 7 Winogrady 54
+246379.0 False 2 0 Winogrady 39
+345240.0 False 4 1 Winogrady 54
+345240.0 False 4 0 Winogrady 54
+332145.0 False 3 3 Winogrady 45
+348117.0 False 4 5 Winogrady 54
+348117.0 False 4 6 Winogrady 54
+339282.0 False 3 7 Winogrady 62
+317200.0 False 3 8 Winogrady 52
+329422.5 False 3 6 Winogrady 45
+265741.5 False 2 7 Winogrady 21
+238948.0 False 2 6 Winogrady 54
+348117.0 False 4 7 Winogrady 54
+339282.0 False 3 5 Winogrady 62
+263581.0 False 2 4 Winogrady 21
+348117.0 False 4 4 Winogrady 54
+296277.0 False 3 0 Winogrady 57
+304133.5 False 3 1 Winogrady 27
+296277.0 False 3 2 Winogrady 57
+263581.0 False 2 3 Winogrady 21
+345240.0 False 4 2 Winogrady 54
+263581.0 False 2 1 Winogrady 21
+345240.0 False 4 3 Winogrady 54
+339282.0 False 3 6 Winogrady 62
+323340.0 False 3 3 Winogrady 89
+310020.0 False 3 0 Winogrady 67
+252723.0 False 2 1 Winogrady 43
+366850.0 False 4 1 Winogrady 25
+319875.0 False 2 8 Grunwald 18
+249641.0 False 2 0 Jeżyce 54
+356160.0 False 4 4 Winogrady 36
+156085.0 False 2 4 Nowe 54
+319875.0 False 2 7 Grunwald 18
+329763.26 False 2 9 Grunwald 94
+324400.97 False 2 7 Grunwald 94
+388352.0 False 3 7 Grunwald 60
+347633.0 False 3 10 Grunwald 20
+409713.0 False 3 11 Grunwald 62
+330368.0 False 2 12 Grunwald 62
+356251.9 False 3 14 Grunwald 20
+347839.75 False 2 12 Grunwald 58
+350506.16 False 3 11 Grunwald 20
+342405.13 False 2 11 Grunwald 58
+429699.0 False 3 15 Grunwald 62
+319875.0 False 2 9 Grunwald 18
+341703.96 False 3 8 Grunwald 21
+336969.98 False 2 10 Grunwald 58
+413044.0 False 3 12 Grunwald 62
+405104.0 False 3 1 Grunwald 34
+341703.96 False 3 9 Grunwald 21
+424977.14 False 4 5 Grunwald 20
+327787.0 False 2 11 Grunwald 62
+353378.74 False 3 12 Grunwald 20
+332949.0 False 2 13 Grunwald 62
+383760.0 False 3 6 Grunwald 60
+335530.0 False 2 14 Grunwald 62
+387040.0 False 3 5 Grunwald 60
+302985.6 False 2 4 Grunwald 18
+410780.0 False 3 3 Grunwald 44
+417773.83 False 4 3 Grunwald 20
+303286.5 False 2 3 Grunwald 13
+364080.0 False 3 1 Grunwald 60
+319055.27 False 3 3 Grunwald 21
+292100.0 False 2 1 Grunwald 80
+245830.0 False 2 2 Grunwald 67
+352390.0 False 2 12 Grunwald 80
+377200.0 False 3 3 Grunwald 60
+313080.0 False 3 5 Winogrady 18
+314089.0 False 2 5 Grunwald 49
+308237.0 False 2 1 Nowe 85
+339072.0 False 2 9 Grunwald 98
+321812.5 False 2 8 Grunwald 49
+322643.5 False 2 10 Grunwald 81
+500203.02 False 4 10 Grunwald 73
+343978.41 False 3 9 Grunwald 14
+325184.0 False 2 11 Grunwald 81
+351130.0 False 3 10 Grunwald 85
+297420.8 False 2 3 Grunwald 24
+267702.4 False 2 2 Grunwald 22
+506566.5 False 4 11 Grunwald 73
+297420.8 False 2 2 Grunwald 24
+495722.51 False 4 9 Grunwald 99
+426416.8 False 4 6 Grunwald 20
+327081.85 False 2 8 Grunwald 94
+307080.0 False 2 5 Grunwald 18
+305793.0 False 2 4 Grunwald 13
+312198.0 False 2 6 Grunwald 18
+333231.99 False 3 7 Grunwald 21
+514939.5 False 4 13 Grunwald 73
+317880.0 False 2 2 Grunwald 98
+267702.4 False 2 3 Grunwald 22
+519126.0 False 4 14 Grunwald 73
+510753.0 False 4 12 Grunwald 73
+347010.0 False 2 10 Grunwald 80
+324387.0 False 2 9 Grunwald 49
+311514.5 False 2 4 Grunwald 49
+298249.6 False 2 6 Grunwald 38
+333774.0 False 2 6 Grunwald 98
+495722.51 False 4 8 Grunwald 99
+331125.0 False 2 5 Grunwald 98
+336423.0 False 2 8 Grunwald 98
+325312.98 False 3 3 Grunwald 14
+298249.6 False 2 5 Grunwald 38
+495782.26 False 4 7 Grunwald 99
+341311.84 False 3 8 Grunwald 14
+328476.0 False 2 4 Grunwald 98
+316848.0 False 2 6 Grunwald 52
+328241.0 False 3 2 Winogrady 81
+332145.0 False 3 2 Winogrady 45
+348750.0 True 2 4 Centrum 50
+297600.0 True 2 3 Winogrady 50
+300160.0 True 2 3 Winogrady 90
+293760.0 True 2 3 Winogrady 90
+315819.0 False 2 5 Grunwald 13
+435784.0 False 3 5 Grunwald 44
+407208.0 False 3 2 Grunwald 44
+370640.0 False 3 2 Grunwald 60
+329422.5 False 3 4 Winogrady 45
+329422.5 False 3 7 Winogrady 45
+328241.0 False 3 4 Winogrady 81
+323340.0 False 3 1 Winogrady 89
+329422.5 False 3 5 Winogrady 45
+335000.0 True 3 1 Piątkowo 63
+391728.59 True 3 2 Winogrady 21
+285678.0 True 2 2 Winogrady 42
+287566.0 True 2 1 Winogrady 74
+421049.88 True 4 1 Grunwald 42
+332388.13 True 2 4 Grunwald 96
+330359.78 True 2 14 Grunwald 56
+301206.53 True 2 7 Grunwald 81
+307490.0 True 2 14 Grunwald 94
+307880.88 True 3 3 Grunwald 16
+319047.97 True 3 3 Grunwald 21
+495782.25 True 4 7 Grunwald 99
+413044.03 True 3 12 Grunwald 62
+380480.0 True 3 4 Grunwald 60
+426416.78 True 4 6 Grunwald 20
+324387.0 True 2 9 Grunwald 49
+333212.88 True 2 7 Grunwald 21
+579000.0 True 4 3 Naramowice 97
+215000.0 True 2 2 Grunwald 44
+267702.41 True 2 3 Grunwald 22
+245830.0 True 2 2 Grunwald 67
+410000.0 True 2 5 Rataje 53
+365000.0 True 4 2 Łazarz 62
+257000.0 True 2 12 Winogrady 47
+240000.0 True 2 16 Rataje 36
+319055.0 True 3 3 Grunwald 56
+267702.0 True 2 2 Grunwald 45
+245830.0 True 2 2 Grunwald 40
+253193.0 True 2 6 Jeżyce 38
+318384.0 True 3 6 Jeżyce 48
+245875.0 True 2 1 Jeżyce 38
+347090.0 True 3 1 Winogrady 57
+238948.0 True 2 4 Stare 39
+355000.0 True 3 3 Łazarz 62
+330255.0 False 2 1 Stare 14
+442080.0 False 3 1 Starołęka 68
+277823.0 False 2 2 Podolany 70
+308039.0 False 2 0 Naramowice 71
+321656.0 False 2 1 Naramowice 50
+304140.0 False 3 5 Winogrady 18
+771672.0 False 4 4 Górczyn 66
+322497.0 False 2 6 Naramowice 60
+333024.0 False 2 1 Stare 51
+290000.0 True 3 14 Nowe 20
+515000.0 True 3 0 Rataje 71
+372000.0 True 4 1 Nadolnik 125
+410000.0 True 2 5 Rataje 53
+259000.0 True 2 0 Grunwald 52
+298950.0 True 2 0 Piątkowo 70
+495000.0 True 4 3 Naramowice 104
+245000.0 True 2 7 Jeżyce 53
+319000.0 True 2 1 Centrum 52
+420000.0 True 2 1 Naramowice 50
+420000.0 True 2 3 Naramowice 50
+300000.0 True 3 2 Grunwald 49
+300000.0 True 3 2 Winogrady 48
+339000.0 True 2 2 Stare 53
+298000.0 True 3 1 Nowe 30
+250000.0 True 3 0 Stare 45
+475000.0 True 4 4 Naramowice 50
+329000.0 True 3 1 Jeżyce 112
+299000.0 True 2 0 Piątkowo 20
+259000.0 True 3 1 Grunwald 48
+370000.0 True 4 4 Piątkowo 60
+249641.0 False 2 0 Ogrody 54
+375000.0 True 3 1 Nowe 63
+390000.0 True 4 4 Piątkowo 74
+288000.0 True 3 4 Stare 30
+468000.0 True 2 3 Grunwald 60
+279000.0 True 3 1 Wilda 68
+250000.0 True 2 6 Winogrady 42
+350000.0 True 2 2 Jeżyce 46
+310000.0 True 2 1 Nowe 40
+289000.0 True 3 4 Winogrady 47
+405900.0 True 3 2 Stare 82
+359000.0 True 3 1 Wilda 20
+326000.0 True 2 1 Sołacz 39
+350000.0 True 2 2 Jeżyce 47
+239000.0 True 2 4 Grunwald 50
+224343.0 False 2 4 Starołęka 35
+362220.0 False 3 3 Starołęka 60
+287394.0 False 2 2 Starołęka 50
+320739.0 False 3 1 Starołęka 56
+460499.0 False 3 1 Stare 51
+242731.0 False 2 0 Podolany 74
+156085.0 False 2 4 Nowe 54
+285200.0 False 2 1 Winogrady 46
+211190.0 False 2 0 Podolany 78
+309000.0 True 3 3 Wilda 80
+313000.0 True 2 1 Górczyn 48
+313000.0 True 2 1 Dębiec 48
+643720.0 True 4 0 Stare 60
+415000.0 True 2 5 Nowe 53
+325000.0 True 2 3 Stare 60
+599000.0 True 4 3 Stare 97
+319000.0 True 2 0 Grunwald 20
+299000.0 True 3 6 Stare 63
+299000.0 True 2 0 Grunwald 51
+339000.0 True 2 2 Centrum 53
+320000.0 True 3 4 Stare 65
+364000.0 True 3 1 Nowe 67
+209000.0 True 3 3 Grunwald 50