{
"cells": [
{
"cell_type": "markdown",
"id": "2f8e19e4",
"metadata": {},
"source": [
"# Lineare Regression mit mehreren Features ($d>1$)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "643861b2",
"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 tqdm.notebook import tqdm"
]
},
{
"cell_type": "markdown",
"id": "315bd31f",
"metadata": {},
"source": [
"Wir verwenden hier beispielhaft den Datensatz [Melbourne Housing Snapshot](https://www.kaggle.com/datasets/dansbecker/melbourne-housing-snapshot). Diesen finden Sie auch im Moodle unter `data/kaggle/melb_data.csv`."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "e3381ac0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG',\n",
" 'Date', 'Distance', 'Postcode', 'Bedroom2', 'Bathroom', 'Car',\n",
" 'Landsize', 'BuildingArea', 'YearBuilt', 'CouncilArea', 'Lattitude',\n",
" 'Longtitude', 'Regionname', 'Propertycount'],\n",
" dtype='object')"
]
},
"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",
"melbourne_data.columns # Spaltennamen der Tabelle (potentielle Features)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "0f80237c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Suburb | \n",
" Address | \n",
" Rooms | \n",
" Type | \n",
" Price | \n",
" Method | \n",
" SellerG | \n",
" Date | \n",
" Distance | \n",
" Postcode | \n",
" ... | \n",
" Bathroom | \n",
" Car | \n",
" Landsize | \n",
" BuildingArea | \n",
" YearBuilt | \n",
" CouncilArea | \n",
" Lattitude | \n",
" Longtitude | \n",
" Regionname | \n",
" Propertycount | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" Abbotsford | \n",
" 25 Bloomburg St | \n",
" 2 | \n",
" h | \n",
" 1035000.0 | \n",
" S | \n",
" Biggin | \n",
" 4/02/2016 | \n",
" 2.5 | \n",
" 3067.0 | \n",
" ... | \n",
" 1.0 | \n",
" 0.0 | \n",
" 156.0 | \n",
" 79.0 | \n",
" 1900.0 | \n",
" Yarra | \n",
" -37.8079 | \n",
" 144.9934 | \n",
" Northern Metropolitan | \n",
" 4019.0 | \n",
"
\n",
" \n",
" 2 | \n",
" Abbotsford | \n",
" 5 Charles St | \n",
" 3 | \n",
" h | \n",
" 1465000.0 | \n",
" SP | \n",
" Biggin | \n",
" 4/03/2017 | \n",
" 2.5 | \n",
" 3067.0 | \n",
" ... | \n",
" 2.0 | \n",
" 0.0 | \n",
" 134.0 | \n",
" 150.0 | \n",
" 1900.0 | \n",
" Yarra | \n",
" -37.8093 | \n",
" 144.9944 | \n",
" Northern Metropolitan | \n",
" 4019.0 | \n",
"
\n",
" \n",
" 4 | \n",
" Abbotsford | \n",
" 55a Park St | \n",
" 4 | \n",
" h | \n",
" 1600000.0 | \n",
" VB | \n",
" Nelson | \n",
" 4/06/2016 | \n",
" 2.5 | \n",
" 3067.0 | \n",
" ... | \n",
" 1.0 | \n",
" 2.0 | \n",
" 120.0 | \n",
" 142.0 | \n",
" 2014.0 | \n",
" Yarra | \n",
" -37.8072 | \n",
" 144.9941 | \n",
" Northern Metropolitan | \n",
" 4019.0 | \n",
"
\n",
" \n",
" 6 | \n",
" Abbotsford | \n",
" 124 Yarra St | \n",
" 3 | \n",
" h | \n",
" 1876000.0 | \n",
" S | \n",
" Nelson | \n",
" 7/05/2016 | \n",
" 2.5 | \n",
" 3067.0 | \n",
" ... | \n",
" 2.0 | \n",
" 0.0 | \n",
" 245.0 | \n",
" 210.0 | \n",
" 1910.0 | \n",
" Yarra | \n",
" -37.8024 | \n",
" 144.9993 | \n",
" Northern Metropolitan | \n",
" 4019.0 | \n",
"
\n",
" \n",
" 7 | \n",
" Abbotsford | \n",
" 98 Charles St | \n",
" 2 | \n",
" h | \n",
" 1636000.0 | \n",
" S | \n",
" Nelson | \n",
" 8/10/2016 | \n",
" 2.5 | \n",
" 3067.0 | \n",
" ... | \n",
" 1.0 | \n",
" 2.0 | \n",
" 256.0 | \n",
" 107.0 | \n",
" 1890.0 | \n",
" Yarra | \n",
" -37.8060 | \n",
" 144.9954 | \n",
" Northern Metropolitan | \n",
" 4019.0 | \n",
"
\n",
" \n",
"
\n",
"
5 rows × 21 columns
\n",
"
"
],
"text/plain": [
" Suburb Address Rooms Type Price Method SellerG \\\n",
"1 Abbotsford 25 Bloomburg St 2 h 1035000.0 S Biggin \n",
"2 Abbotsford 5 Charles St 3 h 1465000.0 SP Biggin \n",
"4 Abbotsford 55a Park St 4 h 1600000.0 VB Nelson \n",
"6 Abbotsford 124 Yarra St 3 h 1876000.0 S Nelson \n",
"7 Abbotsford 98 Charles St 2 h 1636000.0 S Nelson \n",
"\n",
" Date Distance Postcode ... Bathroom Car Landsize BuildingArea \\\n",
"1 4/02/2016 2.5 3067.0 ... 1.0 0.0 156.0 79.0 \n",
"2 4/03/2017 2.5 3067.0 ... 2.0 0.0 134.0 150.0 \n",
"4 4/06/2016 2.5 3067.0 ... 1.0 2.0 120.0 142.0 \n",
"6 7/05/2016 2.5 3067.0 ... 2.0 0.0 245.0 210.0 \n",
"7 8/10/2016 2.5 3067.0 ... 1.0 2.0 256.0 107.0 \n",
"\n",
" YearBuilt CouncilArea Lattitude Longtitude Regionname \\\n",
"1 1900.0 Yarra -37.8079 144.9934 Northern Metropolitan \n",
"2 1900.0 Yarra -37.8093 144.9944 Northern Metropolitan \n",
"4 2014.0 Yarra -37.8072 144.9941 Northern Metropolitan \n",
"6 1910.0 Yarra -37.8024 144.9993 Northern Metropolitan \n",
"7 1890.0 Yarra -37.8060 144.9954 Northern Metropolitan \n",
"\n",
" Propertycount \n",
"1 4019.0 \n",
"2 4019.0 \n",
"4 4019.0 \n",
"6 4019.0 \n",
"7 4019.0 \n",
"\n",
"[5 rows x 21 columns]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"melbourne_data.head()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "b4939e52",
"metadata": {},
"outputs": [],
"source": [
"#features = ['BuildingArea', Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude', 'YearBuilt', 'Distance']\n",
"features = ['Rooms', 'BuildingArea']\n",
"data = melbourne_data[features + ['Price']]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "47f35849",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Rooms | \n",
" BuildingArea | \n",
" Price | \n",
"
\n",
" \n",
" \n",
" \n",
" count | \n",
" 6196.000000 | \n",
" 6196.000000 | \n",
" 6.196000e+03 | \n",
"
\n",
" \n",
" mean | \n",
" 2.931407 | \n",
" 141.568645 | \n",
" 1.068828e+06 | \n",
"
\n",
" \n",
" std | \n",
" 0.971079 | \n",
" 90.834824 | \n",
" 6.751564e+05 | \n",
"
\n",
" \n",
" min | \n",
" 1.000000 | \n",
" 0.000000 | \n",
" 1.310000e+05 | \n",
"
\n",
" \n",
" 25% | \n",
" 2.000000 | \n",
" 91.000000 | \n",
" 6.200000e+05 | \n",
"
\n",
" \n",
" 50% | \n",
" 3.000000 | \n",
" 124.000000 | \n",
" 8.800000e+05 | \n",
"
\n",
" \n",
" 75% | \n",
" 4.000000 | \n",
" 170.000000 | \n",
" 1.325000e+06 | \n",
"
\n",
" \n",
" max | \n",
" 8.000000 | \n",
" 3112.000000 | \n",
" 9.000000e+06 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Rooms BuildingArea Price\n",
"count 6196.000000 6196.000000 6.196000e+03\n",
"mean 2.931407 141.568645 1.068828e+06\n",
"std 0.971079 90.834824 6.751564e+05\n",
"min 1.000000 0.000000 1.310000e+05\n",
"25% 2.000000 91.000000 6.200000e+05\n",
"50% 3.000000 124.000000 8.800000e+05\n",
"75% 4.000000 170.000000 1.325000e+06\n",
"max 8.000000 3112.000000 9.000000e+06"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.describe()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "ed0fdea0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Rooms | \n",
" BuildingArea | \n",
" Price | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" 2 | \n",
" 79.0 | \n",
" 1035000.0 | \n",
"
\n",
" \n",
" 2 | \n",
" 3 | \n",
" 150.0 | \n",
" 1465000.0 | \n",
"
\n",
" \n",
" 4 | \n",
" 4 | \n",
" 142.0 | \n",
" 1600000.0 | \n",
"
\n",
" \n",
" 6 | \n",
" 3 | \n",
" 210.0 | \n",
" 1876000.0 | \n",
"
\n",
" \n",
" 7 | \n",
" 2 | \n",
" 107.0 | \n",
" 1636000.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Rooms BuildingArea Price\n",
"1 2 79.0 1035000.0\n",
"2 3 150.0 1465000.0\n",
"4 4 142.0 1600000.0\n",
"6 3 210.0 1876000.0\n",
"7 2 107.0 1636000.0"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.head()"
]
},
{
"cell_type": "markdown",
"id": "b5126919",
"metadata": {},
"source": [
"## Definition der Funktionen für die Lineare Regression"
]
},
{
"cell_type": "markdown",
"id": "dacabf66",
"metadata": {},
"source": [
"Aus der Vorlesung:\n",
"\n",
"$$ h(x, w) = w^T x . $$\n",
"\n",
"In der Vorlesung haben wir $\\theta$ statt $w$ verwendet.\n",
"\n",
"**Wichtig:** Diese Definition von $h$ nimmt an, dass die erste Komponente von $x$, also in Python code `x[0]`, immer 1 ist.\n",
"\n",
"Wir können auch eine vektorisierte Form von $h(x, w)$ definieren, bei der der Input $X$ mehrere (oder alle) Trainingsbeispiele umfasst und der Output ein Vektor aus den zugehörigen Werten von h zu jedem der Trainingsbeispiele ist. In Matrixschreibweise:\n",
"\n",
"$$ h(X, w) = X w , $$\n",
"\n",
"wobei die Zeilen von $X$ aus je einem Trainingsbeispiel (inkl. der \"1\" in der ersten Komponente) bestehen.\n",
"\n",
"Aufgrund der Art wie `numpy` den Spezialfall der Multiplikation zweier Vektoren handhabt können wir den Code für beide oben erwähnten Varianten von $h$ vereinheitlichen und eine Funktion $h(x, w)$ definieren, die sowohl mit einer Inputzeile als auch mit mehreren Inputzeilen umgehen kann.\n",
"\n",
"Bei der Multiplikation zweier numpy arrays (also zweier Vektoren) mittels `@`-Operator bildet numpy stets das Skalarprodukt der Vektoren, ohne dass man einen der Vektoren transponieren müsste. D.h., wenn wir zwei Spaltenvektoren $w, x$ haben, lautet die korrekte Schreibweise eigentlich:\n",
"$$w^T x$$\n",
"numpy erlaubt es uns aber einfach `w @ x` oder auch `x @ w` zu schreiben anstelle (des ebenfalls möglichen) `w.T @ x`.\n",
"\n",
"Dies ermöglicht es uns eine vektorisierte Form von $h(x, w)$ leicht aufzuschreiben, die sowohl mit einem Parameter `x` bestehend aus einer Zeile an Inputdaten (also z.B. einem einzelnen Trainingsbeispiel) funktioniert als auch mit der gesamten Feature-Matrix `X`, bestehend aus allen (oder mehreren) Trainingsdaten auf einmal."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "14116a52",
"metadata": {},
"outputs": [],
"source": [
"def h(x, w):\n",
" \"\"\"x und w sind numpy arrays; x kann auch die komplette Feature-Matrix sein\"\"\"\n",
" # Diese Form erlaubt es für x eine ganze (Feature-)Matrix zu übergeben. Die Matrix enthält\n",
" # zeilenweise je einen Datenpunkt, für den h berechnet werden soll.\n",
" # w @ x.T ist dann ein Vektor mit je einem Ergebnis in den Komponenten des Vektors pro Zeile\n",
" # der übergebenen (Feature-)Matrix.\n",
" return x @ w"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "82129a25",
"metadata": {},
"outputs": [],
"source": [
"# Definition der Kostenfunktion\n",
"def J(w, X, y):\n",
" \"\"\"\n",
" w, X, y müssen numpy arrays sein\n",
" X: Feature-Matrix aller Trainingsdaten inkl. Spalte mit 1; Dimension: n x (d+1)\n",
" y: Vektor aller Targets zu X\n",
" \"\"\"\n",
" errors = y - h(x=X, w=w)\n",
" mse = 1.0/(2.0*len(y)) * ( errors @ errors )\n",
" return mse"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "4209dc9c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(6196, 3)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data.shape"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "8b34a5c7",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1.],\n",
" [1.],\n",
" [1.],\n",
" ...,\n",
" [1.],\n",
" [1.],\n",
" [1.]])"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.ones((len(data),1))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "6632cabe",
"metadata": {},
"outputs": [],
"source": [
"def feature_matrix_from_data(data):\n",
" # hier erzeugen wir die Matrix mit unseren Input-Daten (Features) inklusive der Spalte mit \"1\"\n",
" return np.hstack((np.ones((len(data),1)), data.to_numpy(copy=True)))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "74556a69",
"metadata": {},
"outputs": [],
"source": [
"# hier erzeugen wir die Matrix mit unseren Input-Daten (Features) inklusive der Spalte mit \"1\"\n",
"#X = np.hstack((np.ones((len(data),1)), data[features].to_numpy(copy=True)))\n",
"X = feature_matrix_from_data(data[features])\n",
"# und ausserdem den Vektor der Targets\n",
"y = data.Price.to_numpy(copy=True)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "79f5e3e0",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(6196, 3)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X.shape"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "8f9724c3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 1. , 2. , 79. ],\n",
" [ 1. , 3. , 150. ],\n",
" [ 1. , 4. , 142. ],\n",
" ...,\n",
" [ 1. , 1. , 35.64],\n",
" [ 1. , 2. , 61.6 ],\n",
" [ 1. , 6. , 388.5 ]])"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"X"
]
},
{
"cell_type": "markdown",
"id": "85733d6b",
"metadata": {},
"source": [
"**Hinweis:** Die Matrix $X$ hat zwar die gleiche Dimension wie `data`, allerdings enthält data eine Spalte `Price`, die in $X$ nicht enthalten ist. Dafür hat $X$ als erste Spalte die \"1er\"."
]
},
{
"cell_type": "markdown",
"id": "1d8e64e6",
"metadata": {},
"source": [
"## Analytische Lösung der linearen Regression\n",
"\n",
"Die analytische Lösung verläuft identisch zum Fall mit nur einem Feature.\n",
"\n",
"`np.linalg.solve(A, b)` berechnet $w$ im linearen Gleichungssystem\n",
"\n",
"$ A w = b $\n",
"\n",
"$A$ - Matrix,\n",
"$w$ - Vektor (unsere unbekannten),\n",
"$b$ - Vektor.\n",
"\n",
"Wir suchen die Lösung $w$ im folgenden Gleichungssystem:\n",
"\n",
"$$ X^T X w = X^T Y $$\n",
"\n",
"Mit $A = X^TX$ und $b = X^T Y$ berechnet `np.linalg.solve(A, b)` unsere gesuchten Paramter für die lineare Regression."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "fc1d2c0a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Die 3 Parameter der linearen Regression:\n",
"[ 42769.88494072 232612.86504788 2431.15453776]\n",
"Kostenfunktion J(w_ana): 147658829426.14856\n",
"CPU times: user 11.3 ms, sys: 2.13 ms, total: 13.4 ms\n",
"Wall time: 1.7 ms\n"
]
}
],
"source": [
"%%time\n",
"w_ana = np.linalg.solve(X.T @ X, X.T @ y)\n",
"print('Die {} Parameter der linearen Regression:\\n{}'.format(len(w_ana), w_ana))\n",
"J_ana = J(w=w_ana, X=X, y=y)\n",
"print('Kostenfunktion J(w_ana): {}'.format(J_ana))"
]
},
{
"cell_type": "markdown",
"id": "daab4572",
"metadata": {},
"source": [
"## Numerische Lösung mit Gradient Descent"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "b314f36a",
"metadata": {},
"outputs": [],
"source": [
"## Numerische Lösung mit Gradient Descent\n",
"def grad_desc_upd(w, alpha, x, y):\n",
" \"\"\"y, x sind Vektoren (numpy-arrays)\"\"\"\n",
" errors = y - h(x=x, w=w)\n",
" w = w + alpha / len(y) * (x.T @ errors)\n",
" return w"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "3dc2775c",
"metadata": {},
"outputs": [],
"source": [
"def grad_desc(w, alpha, x, y, n_iterations):\n",
" J_all = [[0], [J(w=w, X=x, y=y)]]\n",
" for it in tqdm(range(n_iterations)):\n",
" w = grad_desc_upd(w=w, alpha=alpha, x=x, y=y)\n",
" if it % 100 == 0:\n",
" J_all[1].append(J(w=w, X=x, y=y))\n",
" J_all[0].append(it)\n",
" return w, J_all"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "a801cac3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 2.43686014, 5.00088371, 206.19316114])"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"grad_desc_upd(w=np.ones(X.shape[1]), alpha=1e-6, x=X[:7], y=y[:7])"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "dc6f778a",
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e9c9403f9b08472294edb52bb2c10c1d",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/10000 [00:00, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 1.94 s, sys: 1.87 s, total: 3.81 s\n",
"Wall time: 417 ms\n"
]
}
],
"source": [
"%%time\n",
"w_init = np.ones(X.shape[1])\n",
"alpha = 3.1e-10 # verschiedene alpha ausprobieren\n",
"n_iterations = 10000\n",
"_, J_tmp = grad_desc(w=w_init, alpha=alpha, x=X, y=y, n_iterations=n_iterations)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "c04ebb9f",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "57bac370a44f48e9951dc5dba56b29ef",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/100000 [00:00, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Die 3 Parameter der linearen Regression:\n",
"[ 10.49970832 31.89447067 1601.95876825]\n",
"Kostenfunktion J: 540959857400.77966\n",
"J relativ zu Startkosten: 0.6771395257663181\n",
"Vergleich Kostenfunktion zu analytischer Lösung: 3.66*J_ana\n",
"Relative Abweichung der Parameter zu analytischer Lösung: [2.45493022e-04 1.37113958e-04 6.58929222e-01]*w_ana\n",
"CPU times: user 21.5 s, sys: 11 s, total: 32.6 s\n",
"Wall time: 3.53 s\n"
]
}
],
"source": [
"%%time\n",
"w_init = np.ones(X.shape[1])\n",
"alpha = 1e-10 # verschiedene alpha ausprobieren\n",
"n_iterations = 100000\n",
"w_gd, J_all = grad_desc(w=w_init, alpha=alpha, x=X, y=y, n_iterations=n_iterations)\n",
"print('Die {} Parameter der linearen Regression:\\n{}'.format(len(w_gd), w_gd))\n",
"print('Kostenfunktion J: {}'.format(J_all[1][-1]))\n",
"print('J relativ zu Startkosten: {}'.format(J_all[1][-1]/J_all[1][0]))\n",
"print('Vergleich Kostenfunktion zu analytischer Lösung: {:.2f}*J_ana'.format(J_all[1][-1]/J_ana))\n",
"print('Relative Abweichung der Parameter zu analytischer Lösung: {}*w_ana'.format((w_gd)/w_ana))"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "8b4db3ee",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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",
"text/plain": [
"