From b343b993959f419ddb434c6c514bbd0ffa3fb549 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Thu, 30 Jan 2025 10:07:11 +0100 Subject: [PATCH] some kind of pipeline with sklearn? --- .../01 - linear regression - 1 feature.ipynb | 2 +- .../05 - lineare regression - sklearn.ipynb | 381 ++++++ requirements.txt | 4 + tasks/03skykit-regularisierung.ipynb | 1079 +++++++++++++++++ tasks/Untitled.ipynb | 128 +- 5 files changed, 1570 insertions(+), 24 deletions(-) create mode 100644 Aufgaben/05 - lineare regression - sklearn.ipynb create mode 100644 tasks/03skykit-regularisierung.ipynb diff --git a/Aufgaben/01 - linear regression - 1 feature.ipynb b/Aufgaben/01 - linear regression - 1 feature.ipynb index 937e5f7..b555913 100644 --- a/Aufgaben/01 - linear regression - 1 feature.ipynb +++ b/Aufgaben/01 - linear regression - 1 feature.ipynb @@ -1066,7 +1066,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.8" }, "varInspector": { "cols": { diff --git a/Aufgaben/05 - lineare regression - sklearn.ipynb b/Aufgaben/05 - lineare regression - sklearn.ipynb new file mode 100644 index 0000000..81a6be4 --- /dev/null +++ b/Aufgaben/05 - lineare regression - sklearn.ipynb @@ -0,0 +1,381 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f19ad4d1", + "metadata": {}, + "source": [ + "# Lineare Regression mit scikit-learn" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "fca110ae", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "# plotting settings\n", + "pd.plotting.register_matplotlib_converters()\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "import seaborn as sns\n", + "from sklearn.linear_model import LinearRegression" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "6edf6b65", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BuildingAreaRoomsPrice
179.021035000.0
2150.031465000.0
4142.041600000.0
6210.031876000.0
7107.021636000.0
\n", + "
" + ], + "text/plain": [ + " BuildingArea Rooms Price\n", + "1 79.0 2 1035000.0\n", + "2 150.0 3 1465000.0\n", + "4 142.0 4 1600000.0\n", + "6 210.0 3 1876000.0\n", + "7 107.0 2 1636000.0" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "melbourne_file_path = 'data/melb_data.csv'\n", + "melbourne_data = pd.read_csv(melbourne_file_path)\n", + "melbourne_data = melbourne_data.dropna(axis=0) # entfernen von Daten mit fehlenden Werten\n", + "# wählen für unser Beispiel einen kleinen Ausschnitt aus den Daten (denselben, wie im ersten Beispiel)\n", + "max_area = 400\n", + "max_datapoints = 100\n", + "data = melbourne_data[melbourne_data['BuildingArea'] < max_area][:max_datapoints][['BuildingArea', 'Rooms', 'Price']]\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "7b226e29", + "metadata": {}, + "source": [ + "Die scikit-learn API erwartet die Trainingsdaten (Inputs, Features) ähnlich zu unserer Feature-Matrix als 2D-Array, allerdings ohne der '1'." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9e851d19", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 2, 3])" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r = np.array([1,2,3])\n", + "r" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a2903e63", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[1],\n", + " [2],\n", + " [3]])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ändern eines Vektors der Länge n in eine Matrix der Dimension n x 1:\n", + "r.reshape((-1,1))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "89d8210c", + "metadata": {}, + "outputs": [], + "source": [ + "x = data[['BuildingArea'] ].to_numpy(copy=True).reshape((-1, 1))\n", + "y = data['Price'].to_numpy(copy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b0d5c350", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(100, 1)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "bd1d76e9", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "w0: 441524.4208318128\n", + "w1: [6024.22929588]\n" + ] + } + ], + "source": [ + "model = LinearRegression().fit(x, y)\n", + "# print model parameters\n", + "print('w0: {}'.format(model.intercept_))\n", + "print('w1: {}'.format(model.coef_))" + ] + }, + { + "cell_type": "markdown", + "id": "12eacd13", + "metadata": {}, + "source": [ + "Vergleichen Sie die Werte mit der selbstprogrammierten Lösung!" + ] + }, + { + "cell_type": "markdown", + "id": "c5f6e509", + "metadata": {}, + "source": [ + "**Achtung:** Alle scikit-learn Modelle haben Parameter, die das Verhalten beeinflussen. Mehr in der scikit-learn Dokumentation, z.B. hier für LinearRegression: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "055183fa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "erklärte Varianz (R^2): 0.22971025499088593\n" + ] + } + ], + "source": [ + "r_sq = model.score(x, y)\n", + "print('erklärte Varianz (R^2): {}'.format(r_sq))" + ] + }, + { + "cell_type": "markdown", + "id": "5a66667c", + "metadata": {}, + "source": [ + "Vorhersage mit trainiertem scikit-learn Modell" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "b81f3f03", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Preis-Vorhersage für ein neues Haus mit Wohnfläche 287: [2170478.22874863]\n" + ] + } + ], + "source": [ + "building_area_new_house = [[287]]\n", + "y_pred = model.predict(building_area_new_house)\n", + "print('Preis-Vorhersage für ein neues Haus mit Wohnfläche {}: {}'.format(building_area_new_house[0][0], y_pred))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0d1da016", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Preis-Vorhersagen für Objekte mit den Wohnflächen [[287], [80], [110]]: [2170478.22874863 923462.76450201 1104189.64337833]\n" + ] + } + ], + "source": [ + "# Vorhersage für mehrere Objekte auf einmal\n", + "building_area_new_houses = [[287], [80], [110]]\n", + "y_preds = model.predict(building_area_new_houses)\n", + "print('Preis-Vorhersagen für Objekte mit den Wohnflächen {}: {}'.format(building_area_new_houses, y_preds))" + ] + }, + { + "cell_type": "markdown", + "id": "5aac9e7a", + "metadata": {}, + "source": [ + "Alle scikit-learm Modelle haben bestimmte Funktionen, insbesondere `model.fit()` und `model.predict()`, sodass es sehr einfach ist, verschiedene ML-Modelle auszuprobieren." + ] + }, + { + "cell_type": "markdown", + "id": "f39ef84b", + "metadata": {}, + "source": [ + "**Aufgabe: Mehrere Input-Features ausprobieren!**" + ] + } + ], + "metadata": { + "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.13.1" + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/requirements.txt b/requirements.txt index cdc4384..b4696d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,6 +31,7 @@ ipywidgets==8.1.5 isoduration==20.11.0 jedi==0.19.2 Jinja2==3.1.5 +joblib==1.4.2 json5==0.10.0 jsonpointer==3.0.0 jsonschema==4.23.0 @@ -86,6 +87,8 @@ requests==2.32.3 rfc3339-validator==0.1.4 rfc3986-validator==0.1.1 rpds-py==0.22.3 +scikit-learn==1.6.1 +scipy==1.15.1 seaborn==0.13.2 Send2Trash==1.8.3 setuptools==75.8.0 @@ -94,6 +97,7 @@ sniffio==1.3.1 soupsieve==2.6 stack-data==0.6.3 terminado==0.18.1 +threadpoolctl==3.5.0 tinycss2==1.4.0 tornado==6.4.2 tqdm==4.67.1 diff --git a/tasks/03skykit-regularisierung.ipynb b/tasks/03skykit-regularisierung.ipynb new file mode 100644 index 0000000..9dc473c --- /dev/null +++ b/tasks/03skykit-regularisierung.ipynb @@ -0,0 +1,1079 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 23, + "id": "0c067959-88f2-4579-ba5f-b4fe8a3b81fe", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "# plotting settings\n", + "pd.plotting.register_matplotlib_converters()\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "import seaborn as sns\n", + "import sklearn\n", + "from sklearn.linear_model import LinearRegression,Ridge\n", + "from sklearn.pipeline import make_pipeline\n", + "from sklearn.preprocessing import StandardScaler, PolynomialFeatures" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f068fcd9-6023-4f40-87fe-3323ef241ab1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BuildingAreaRoomsPrice
179.021035000.0
2150.031465000.0
4142.041600000.0
6210.031876000.0
7107.021636000.0
\n", + "
" + ], + "text/plain": [ + " BuildingArea Rooms Price\n", + "1 79.0 2 1035000.0\n", + "2 150.0 3 1465000.0\n", + "4 142.0 4 1600000.0\n", + "6 210.0 3 1876000.0\n", + "7 107.0 2 1636000.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "melbourne_file_path = 'data/melb_data.csv'\n", + "melbourne_data = pd.read_csv(melbourne_file_path)\n", + "melbourne_data = melbourne_data.dropna(axis=0) # entfernen von Daten mit fehlenden Werten\n", + "# wählen für unser Beispiel einen kleinen Ausschnitt aus den Daten (denselben, wie im ersten Beispiel)\n", + "max_area = 400\n", + "max_datapoints = 10\n", + "data = melbourne_data[melbourne_data['BuildingArea'] < max_area][:max_datapoints][['BuildingArea', 'Rooms', 'Price']]\n", + "data.head()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d09ea079-2ec7-4e6c-ba46-497874008564", + "metadata": {}, + "outputs": [], + "source": [ + "x = data[['BuildingArea'] ].to_numpy(copy=True).reshape((-1, 1))\n", + "y = data['Price'].to_numpy(copy=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "41a5faf5-33a0-4b71-bb3c-7255d09602a4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
PolynomialFeatures(degree=4)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "PolynomialFeatures(degree=4)" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pfeats = PolynomialFeatures(4)\n", + "pfeats" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "fbb2ddae-a717-41be-8eb5-c777f60344c9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Pipeline(steps=[('polynomialfeatures',\n",
+       "                 PolynomialFeatures(degree=4, include_bias=False)),\n",
+       "                ('standardscaler', StandardScaler()),\n",
+       "                ('linearregression', LinearRegression())])
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "Pipeline(steps=[('polynomialfeatures',\n", + " PolynomialFeatures(degree=4, include_bias=False)),\n", + " ('standardscaler', StandardScaler()),\n", + " ('linearregression', LinearRegression())])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pipeline = make_pipeline(PolynomialFeatures(4,include_bias=False), StandardScaler(), LinearRegression())\n", + "pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "3daa0a07-5e9f-49b8-a3b2-ca33ae47bd79", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "w0: 708105.2074469186\n", + "w1: [4974.440132]\n" + ] + } + ], + "source": [ + "pipeline.fit(x,y)\n", + "# print model parameters\n", + "print('w0: {}'.format(model.intercept_))\n", + "print('w1: {}'.format(model.coef_))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "ce945e46-d16a-47dd-ba9c-6bf3920cf8c5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "erklärte Varianz (R^2): 0.4874972676252126\n" + ] + } + ], + "source": [ + "r_sq = model.score(x, y)\n", + "print('erklärte Varianz (R^2): {}'.format(r_sq))\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (ki)", + "language": "python", + "name": "myenv" + }, + "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.13.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tasks/Untitled.ipynb b/tasks/Untitled.ipynb index c749d4c..cd097e5 100644 --- a/tasks/Untitled.ipynb +++ b/tasks/Untitled.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 74, "id": "8b1ff6ff-f80e-4cc3-b266-0ad417911d1d", "metadata": {}, "outputs": [], @@ -27,7 +27,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 75, "id": "f698283d-7346-4618-9b87-60a3de061a98", "metadata": {}, "outputs": [ @@ -41,7 +41,7 @@ " dtype='object')" ] }, - "execution_count": 52, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -55,10 +55,18 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 83, "id": "dac65c52-f2ce-47b6-ba65-3c6bd915dfe8", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/plex/.pyenv/versions/ki/lib/python3.12/site-packages/pandas/core/nanops.py:1016: RuntimeWarning: invalid value encountered in subtract\n", + " sqr = _ensure_numeric((avg - values) ** 2)\n" + ] + }, { "data": { "text/html": [ @@ -94,7 +102,7 @@ " 79.0\n", " -37.8079\n", " 1035000.0\n", - " 161460000.0\n", + " 6634.615385\n", " \n", " \n", " 2\n", @@ -102,7 +110,7 @@ " 150.0\n", " -37.8093\n", " 1465000.0\n", - " 196310000.0\n", + " 10932.835821\n", " \n", " \n", " 4\n", @@ -110,7 +118,7 @@ " 142.0\n", " -37.8072\n", " 1600000.0\n", - " 192000000.0\n", + " 13333.333333\n", " \n", " \n", " 6\n", @@ -118,7 +126,7 @@ " 210.0\n", " -37.8024\n", " 1876000.0\n", - " 459620000.0\n", + " 7657.142857\n", " \n", " \n", " 7\n", @@ -126,7 +134,7 @@ " 107.0\n", " -37.8060\n", " 1636000.0\n", - " 418816000.0\n", + " 6390.625000\n", " \n", " \n", "\n", @@ -134,14 +142,14 @@ ], "text/plain": [ " Rooms BuildingArea Lattitude Price price_per_area\n", - "1 2 79.0 -37.8079 1035000.0 161460000.0\n", - "2 3 150.0 -37.8093 1465000.0 196310000.0\n", - "4 4 142.0 -37.8072 1600000.0 192000000.0\n", - "6 3 210.0 -37.8024 1876000.0 459620000.0\n", - "7 2 107.0 -37.8060 1636000.0 418816000.0" + "1 2 79.0 -37.8079 1035000.0 6634.615385\n", + "2 3 150.0 -37.8093 1465000.0 10932.835821\n", + "4 4 142.0 -37.8072 1600000.0 13333.333333\n", + "6 3 210.0 -37.8024 1876000.0 7657.142857\n", + "7 2 107.0 -37.8060 1636000.0 6390.625000" ] }, - "execution_count": 53, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -150,14 +158,14 @@ "#features = ['BuildingArea', Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude', 'YearBuilt', 'Distance']\n", "features = ['Rooms', 'BuildingArea', 'Lattitude']\n", "data = melbourne_data[features + ['Price']]\n", - "data = data.assign(price_per_area = melbourne_data['Price'] * melbourne_data[\"Landsize\"])\n", + "data = data.assign(price_per_area = melbourne_data['Price'] / melbourne_data[\"Landsize\"])\n", "data.describe()\n", "data.head()" ] }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 77, "id": "afe5a08a-abec-4164-85c4-1d3ac8398a62", "metadata": {}, "outputs": [], @@ -173,7 +181,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 78, "id": "c2e256a3-3575-45c4-a99c-d41c3c56e1c3", "metadata": {}, "outputs": [], @@ -192,7 +200,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 79, "id": "b41b9c03-0c1d-4a6b-80e8-d7e8775b69c0", "metadata": {}, "outputs": [], @@ -204,7 +212,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 80, "id": "2c631e17-eb36-43d0-97b1-59add1c93dd9", "metadata": {}, "outputs": [], @@ -218,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 81, "id": "8301eb74-9aae-446c-ad46-924811b99777", "metadata": {}, "outputs": [ @@ -229,8 +237,8 @@ "Die 4 Parameter der linearen Regression:\n", "[-6.97461781e+07 2.41559504e+05 2.31456611e+03 -1.84562537e+06]\n", "Kostenfunktion J(w_ana): 137899453867.5851\n", - "CPU times: user 475 μs, sys: 38 μs, total: 513 μs\n", - "Wall time: 500 μs\n" + "CPU times: user 495 μs, sys: 39 μs, total: 534 μs\n", + "Wall time: 553 μs\n" ] } ], @@ -241,6 +249,80 @@ "J_ana = J(w=w_ana, X=X, y=y)\n", "print('Kostenfunktion J(w_ana): {}'.format(J_ana))\n" ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "a89c591c-4ebd-4a3d-958b-915738d7361a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 6634.615385\n", + "2 10932.835821\n", + "4 13333.333333\n", + "6 7657.142857\n", + "7 6390.625000\n", + "Name: price_per_area, dtype: float64\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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wAMPaMyYMY2eP336dN17773HrZ5AbV2T7RXNtAMAgJZlaY/K3//+d7388st65ZVXtGLFCr344ot65JFH9OKLLzZ6/tSpU1VeXh772r59e4vW4/elNdme3Uw7AABoWZb2qPzmN7/RlClT9J//+Z+SpJ49e2rr1q2aPn26xo4dm3C+1+uV1+s9bvXkZ3k0uEu+FjUy/DO4S77yszzH7bkBAEAiS3tUqqur5XTGl+ByuRSNRi2pJyfDoxmjemlwl/y444O75GvmqF7KySCoAACQTJb2qIwcOVIPPPCAOnXqpO7du2vlypX6wx/+oPHjx1tWU8fcdD0xuo9KK0OqqK1Tti9N+VkeQgoAABZwGBburlZRUaG7775bc+fO1Z49e9SxY0eNHj1a06ZNk8fTfDAIBALKyclReXm5/H5/EioGAADH6kg+vy0NKseKoAIAwInnSD6/udcPAACwLYIKAACwLUsn09pVeXVIpZUhBWrr5E9PU34mk2kBALACQaUBbkoIAIB9MPRjwk0JAQCwF4KKCTclBADAXggqJtyUEAAAeyGomHBTQgAA7IWgYlJ/U8LGcFNCAACSj6Biwk0JAQCwF5YnN8BNCQEAsA+CSiNyMggmAADYAUM/AADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAttxWF2BH5dUhlVaGFKitkz89TfmZHuVkeKwuCwCAlENQaWBHWY0mv75GizeXxo4N7pKvGaN6qWNuuoWVAQCQehj6MSmvDiWEFElatLlUU15fo/LqkEWVAQCQmggqJqWVoYSQUm/R5lKVVhJUAABIJoKKSaC2rsn2imbaAQBAyyKomPh9aU22ZzfTDgAAWhZBxSQ/y6PBXfIbbRvcJV/5Waz8AQAgmQgqJjkZHs0Y1SshrAzukq+Zo3qxRBkAgCRjeXIDHXPT9cToPiqtDKmitk7ZvjTlZ7GPCgAAViCoNCIng2ACAIAdEFQa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hikQCOirr76KndPU6344f2OHU0trFYlENGfOHFVVVWnAgAG8LzYwYcIEjRgxIuH1471JnhP6Xj8trbS0VJFIJO4flSS1a9dOX3/9tUVVtR67du2SpEZf3/q2Xbt2qW3btnHtbrdbJ510Utw5hYWFCdeob2vTpo127drV7PM0V0trFY1GNWnSJBUXF6tHjx6SDr4eHo9Hubm5cec2fM0ae73q25o6JxAIqKamRgcOHGj2b+xwamlt1q5dqwEDBqi2tlZZWVmaO3euunXrplWrVvG+WGjOnDlasWKFli1bltDG30zyEFSAFDNhwgStW7dOS5YssboUfO+ss87SqlWrVF5ern/84x8aO3asPv74Y6vLSmnbt2/Xbbfdpg8++EA+n8/qclIaQz8m+fn5crlcCTOld+/erfbt21tUVetR/xo29fq2b99ee/bsiWsPh8Pav39/3DmNXcP8HIc6x9zeXC2t0cSJEzV//nx9+OGHcXceb9++vUKhkMrKyuLOb/iaHe3r7vf7lZ6eflh/Y4dTS2vj8XhUVFSkvn37avr06TrnnHP0xz/+kffFQsuXL9eePXt07rnnyu12y+126+OPP9bjjz8ut9utdu3a8d4kCUHFxOPxqG/fvlqwYEHsWDQa1YIFCzRgwAALK2sdCgsL1b59+7jXNxAI6PPPP4+9vgMGDFBZWZmWL18eO2fhwoWKRqPq379/7JxFixaprq4uds4HH3ygs846S23atImdY36e+nPqn+dwamlNDMPQxIkTNXfuXC1cuDBh6Kxv375KS0uLez02btyobdu2xb03a9eujQuSH3zwgfx+v7p16xY7p6nX/XD+xg6nltYuGo0qGAzyvljooosu0tq1a7Vq1arYV79+/TRmzJjY97w3SWL1bF67mTNnjuH1eo0XXnjBWL9+vXHDDTcYubm5cbO2cWgVFRXGypUrjZUrVxqSjD/84Q/GypUrja1btxqGcXBJcG5urvHPf/7TWLNmjXH55Zc3ujy5T58+xueff24sWbLE6NKlS9zy5LKyMqNdu3bGtddea6xbt86YM2eOkZGRkbA82e12G4888oixYcMG43e/+12jy5Obq6W1uOmmm4ycnBzjo48+Mnbu3Bn7qq6ujp1z4403Gp06dTIWLlxofPnll8aAAQOMAQMGxNrrl1oOHTrUWLVqlfHuu+8aJ598cqNLLX/zm98YGzZsMJ566qlGl1o29zfWXC2tyZQpU4yPP/7Y2LJli7FmzRpjypQphsPhMN5//33DMHhf7MS86scweG+ShaDSiCeeeMLo1KmT4fF4jPPPP9/47LPPrC7phPHhhx8akhK+xo4daxjGwWXBd999t9GuXTvD6/UaF110kbFx48a4a+zbt88YPXq0kZWVZfj9fmPcuHFGRUVF3DmrV682Bg4caHi9XuOUU04xZsyYkVDL3//+d+PMM880PB6P0b17d+Ott96Kaz+cWlqLxt4TScbs2bNj59TU1Bg333yz0aZNGyMjI8O48sorjZ07d8Zd59///rcxfPhwIz093cjPzzd+/etfG3V1dXHnfPjhh0bv3r0Nj8djnH766XHPUa+5v7HDqaW1GD9+vHHaaacZHo/HOPnkk42LLrooFlIMg/fFThoGFd6b5ODuyQAAwLaYowIAAGyLoAIAAGyLoAIAAGyLoAIAAGyLoAIAAGyLoAIAAGyLoAIAAGyLoAIAAGyLoALgiL3wwgtxt5S/55571Lt37yZ/5rrrrtMVV1wRe/yTn/xEkyZNOi71AWg9CCpAirnuuuvkcDhiX3l5ebr44ou1Zs2aw77G1VdfrU2bNh1THW+88Ybuu+++Y7pGU4YNGyaXy6Vly5Ydt+cAcPwRVIAUdPHFF2vnzp3auXOnFixYILfbrUsvvfSwfz49PV1t27Y9phpOOukkZWdnH9M1DmXbtm365JNPNHHiRM2aNavZ80Oh0HGpA8CxI6gAKcjr9ap9+/Zq3769evfurSlTpmj79u3au3evPvroIzkcDpWVlcXOX7VqlRwOh/79739LShz6aSgSiej2229Xbm6u8vLy9Nvf/lYNbyvWcOinc+fOevDBBzV+/HhlZ2erU6dOeuaZZ+J+5pNPPlHv3r3l8/nUr18/zZs3Tw6HQ6tWrYo7b/bs2br00kt100036dVXX1VNTU3Cc0+cOFGTJk1Sfn6+hg0bJklat26dhg8frqysLLVr107XXnutSktLYz/37rvvauDAgbHf69JLL9U333zTzKsN4FgQVIAUV1lZqb/+9a8qKipSXl5ei1zz0Ucf1QsvvKBZs2ZpyZIl2r9/v+bOnXtYP9evXz+tXLlSN998s2666SZt3LhRkhQIBDRy5Ej17NlTK1as0H333afJkycnXMMwDM2ePVvXXHONunbtqqKiIv3jH/9IOO/FF1+Ux+PR0qVL9ec//1llZWW68MIL1adPH3355Zd69913tXv3bl111VWxn6mqqtLtt9+uL7/8UgsWLJDT6dSVV16paDR6DK8WgKa4rS4AQPLNnz9fWVlZkg5++Hbo0EHz58+X09ky/3d57LHHNHXqVP30pz+VJP35z3/We++91+zPXXLJJbr55pslSZMnT9b//u//6sMPP9RZZ52lV155RQ6HQ88++6x8Pp+6deum7777Tr/85S/jrvF///d/qq6ujvWSXHPNNXr++ed17bXXxp3XpUsXPfTQQ7HH999/v/r06aMHH3wwdmzWrFkqKCjQpk2bdOaZZ2rUqFFx15g1a5ZOPvlkrV+/Xj169DiCVwjA4aJHBUhBF1xwgVatWqVVq1bpiy++0LBhwzR8+HBt3br1mK9dXl6unTt3qn///rFjbrdb/fr1a/Zne/XqFfve4XCoffv22rNnjyRp48aN6tWrl3w+X+yc888/P+Eas2bN0tVXXy23++D/w0aPHq2lS5cmDNH07ds37vHq1av14YcfKisrK/bVtWtXSYr97ObNmzV69Gidfvrp8vv96ty5s6SDc2IAHB/0qAApKDMzU0VFRbHHzz33nHJycvTss89q6NChkhQ3p6Suri4pdaWlpcU9djgcRzSsUj/EVFdXp6effjp2PBKJaNasWXrggQdixzIzM+N+trKyUiNHjtTMmTMTrtuhQwdJ0siRI3Xaaafp2WefVceOHRWNRtWjRw8m4wLHET0qAORwOOR0OlVTU6OTTz5ZkrRz585Ye8PJqk3JyclRhw4d9Pnnn8eOhcNhLV++/JhqPOuss7R27VoFg8HYsYZLj19++WWdeuqpWr16dazHaNWqVbE5M5FI5JDXP/fcc/XVV1+pc+fOKioqivvKzMzUvn37tHHjRt1111266KKLdPbZZ+vAgQPH9DsBaB5BBUhBwWBQu3bt0q5du7RhwwbdcsstsR6FoqIiFRQU6J577tHmzZv11ltv6dFHHz2i6992222aMWOG5s2bp6+//lo333xz3Cqio/GLX/xC0WhUN9xwgzZs2KD33ntPjzzyiKSDQUuSnn/+ef3sZz9Tjx494r6uv/56lZaW6t133z3k9SdMmKD9+/dr9OjRWrZsmb755hu99957GjdunCKRiNq0aaO8vDw988wzKikp0cKFC3X77bcf0+8EoHkEFSAFvfvuu+rQoYM6dOig/v37a9myZXrttdf0k5/8RGlpaXr11Vf19ddfq1evXpo5c6buv//+I7r+r3/9a1177bUaO3asBgwYoOzsbF155ZXHVLPf79ebb76pVatWqXfv3rrzzjs1bdo0SZLP59Py5cu1evXqhAmv0sFenosuukjPP//8Ia/fsWNHLV26VJFIREOHDlXPnj01adIk5ebmyul0yul0as6cOVq+fLl69OihX/3qV3r44YeP6XcC0DyH0XBzAwA4Qbz88ssaN26cysvLlZ6ebnU5AI4DJtMCOGG89NJLOv3003XKKado9erVmjx5sq666ipCCtCKEVQAnDB27dqladOmadeuXerQoYN+/vOfx63kAdD6MPQDAABsi8m0AADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtv5/GeBqqUxKouEAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ax = sns.scatterplot(x=data['BuildingArea'], y=data['Price'])\n", + "\n", + "xplot = data['price_per_area']\n", + "yplot = data['price_per_area'][0:len(xplot)]\n", + "print(yplot.head())\n", + "sns.lineplot(x=xplot, y=yplot, ax=ax)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "e4fc1d51-3435-415d-875f-db85dfda39e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1 6634.615385\n", + "2 10932.835821\n", + "4 13333.333333\n", + "6 7657.142857\n", + "7 6390.625000\n", + "Name: price_per_area, dtype: float64" + ] + }, + "execution_count": 85, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data['price_per_area'].head()" + ] } ], "metadata": {