105 lines
4.4 KiB
Python
105 lines
4.4 KiB
Python
#!/usr/bin/env python
|
|
# %% Imports
|
|
from telnetlib import BM
|
|
# imports überall im Code möglich, aber die Konvention ist alle benötigten import statements
|
|
# gleich zu Beginn einer Datei zu machen
|
|
# numpy ist ein Python-Modul für Numerik, das sowohl Funktionalität als auch Effizienz bietet
|
|
import numpy as np
|
|
# pandas ist sehr gut zum Arbeiten mit tabellarischen Daten, egal ob csv, xls oder xlsx
|
|
from numpy.typing import NDArray as array
|
|
from numpy import float64 as float
|
|
import pandas as pd
|
|
from pandas.core.dtypes.dtypes import time
|
|
# plotting settings
|
|
pd.plotting.register_matplotlib_converters()
|
|
# matplotlib ist ein sehr umfangreiches Modul zum Erstellen von Visualisierungen/Plots
|
|
import matplotlib.pyplot as plt
|
|
%matplotlib inline
|
|
# seaborn erleichtert das Erstellen von oft verwendeten Plot-Typen;
|
|
# es basiert selbst auf matplotlib und man kann beides kombinieren
|
|
# eine schöne Einführung in Seaborn: https://www.kaggle.com/learn/data-visualization
|
|
import seaborn as sns
|
|
|
|
# %% load data
|
|
data = pd.read_csv("../data/melb_data.csv").dropna()
|
|
# filter data: Less than 400 area, and max 100 data points
|
|
data = data[(data["BuildingArea"] < 400) ][:100][["BuildingArea", "Price"]]
|
|
ax = sns.scatterplot(x=data['BuildingArea'], y=data['Price'])
|
|
data.head()
|
|
|
|
# %% prepare data with useless math extra values because we need to add one as a factor to all of these
|
|
X = []
|
|
Y = []
|
|
# aufbereitung, x braucht noch den konstanten eins faktor
|
|
for _, row in data.iterrows():
|
|
X.append([1]+ [row['BuildingArea']])
|
|
Y.append(row['Price'])
|
|
X = np.array(X)
|
|
Y = np.array(Y)
|
|
|
|
# %% solve the linear thing
|
|
w_ana = np.linalg.solve(X.T @ X , X.T @ Y)
|
|
print(f"w_ana: {w_ana}")
|
|
|
|
# %% define that h function, this is just f(x) = mx + b
|
|
|
|
def h(weights: array[float], x):
|
|
"""
|
|
x can be a float or an array because numpy does it all the same
|
|
the return type depends on the type of x
|
|
"""
|
|
return weights[0] + weights[1] * x
|
|
|
|
# %% plot the h function combined with the calculated wieghts
|
|
|
|
|
|
ax = sns.scatterplot(x=data['BuildingArea'], y=data['Price'])
|
|
|
|
xplot = [min(data['BuildingArea']), max(data['BuildingArea'])]
|
|
yplot = [h(w_ana, x) for x in xplot]
|
|
sns.lineplot(x=xplot, y=yplot, ax=ax)
|
|
# %% Bewertungsfunktion
|
|
def j(weights: array[float], x: array[float] ,y: array[float]) -> float:
|
|
# angeblich sollen x,y UNBEDINGT numpy arrays sein, idk warum, sehen für mich aus wie floats, nicht wie arrays
|
|
errw = y- h(weights, x=y) # pyright hat eigentlich recht, aber irgendwie kann ich doch nen array reinschmeißen auch wenns nen float frisst
|
|
return 1.0/(2.0 * len(errw) * (errw @ errw))
|
|
# example usage
|
|
j(w_ana, np.array([1.1,1.3]), np.array([2.4,2.6]))
|
|
# %% calculate score of analytic approach
|
|
# pyright sagt to_numpy ist unknown, ist es aber aus irgendeinem grund nicht, python doof
|
|
x = data['BuildingArea'].to_numpy(copy=True)
|
|
y = data['Price'].to_numpy(copy=True)
|
|
j_ana = j(w_ana, x=x, y=y)
|
|
print('Kosten der analytischen Lösung: {}'.format(j_ana))
|
|
# %% define grad_dsc functions
|
|
# Gradient Descent
|
|
# Let's be honest, no idea what I'm really doing here...
|
|
def __gradsc_iter(weights: array[float], alpha: float, x: array[float], y: array[float]) -> array[float]:
|
|
errw: array[float] = y - h(x=x, weights=weights) # weis nicht warum aber das geht doch datentypen mäßig
|
|
return np.array([
|
|
weights[0] + alpha / len(x) * sum(errw),
|
|
weights[1] + alpha / len(x) * errw @ x
|
|
])
|
|
|
|
def grad_dsc(weights: array[float], alpha: float, x, y, n: int) -> tuple[array[float], array[float]]:
|
|
j_all = [j(weights,x,y)]
|
|
for i in range(n):
|
|
w = __gradsc_iter(weights, alpha, x, y)
|
|
j_all.append(j(weights,x,y))
|
|
return weights, np.array(j_all)
|
|
# %% no idea what this is
|
|
w_tmp, j_tmp = grad_dsc(np.array([1e5,1000.0]),alpha=1e-9, x=data["BuildingArea"].to_numpy(), y=data["Price"].to_numpy(), n=1)
|
|
j_tmp[1] / j_tmp[0]
|
|
# %% do the actual gradient descent
|
|
w_init = np.array([1e6, 1000.])
|
|
x = np.array(data['BuildingArea'])
|
|
y = np.array(data['Price'])
|
|
w_gd_1e4, J_all_1e4 = grad_dsc(weights=w_init, alpha=np.float64(0.0001), x=x, y=y, n=100000)
|
|
|
|
print('w_gd_1e4: {}'.format(w_gd_1e4))
|
|
print('Vergleich zu Startkosten: {}'.format(J_all_1e4[-1]/J_all_1e4[0]))
|
|
print('Vergleich zu analytischer Lösung: {}'.format(J_all_1e4[-1]/j_ana))
|
|
print('(w0_gd - w0_ana)/w0_ana: {}'.format((w_gd_1e4[0]-w_ana[0])/w_ana[0]))
|
|
print('(w1_gd - w1_ana)/w1_ana: {}'.format((w_gd_1e4[1]-w_ana[1])/w_ana[1]))
|
|
# again, no idea what these values mean?
|