===== Technische Details ===== Genauere Erklärung einiger Funktionen ==== Aus Quantilen eine Verteilung bestimmten ==== **Problem:** Für eine gewisse Anzahl an Agenten relative Werte festlegen, wobei vorher definierte Quantiele mit relativen nicht-kumulierten Werten erfüllt sein müssen. Dafür gibt es mehrere Lösungen. Wir haben uns entschieden wie bei linearer Regression vorzugehen, nur mit dem Ziel, das die Integrale im Bereich der Quantile $Q$ gleich dem Wert der Quantile sind und nicht möglichst viele Punkte getroffen werden sollen. Als Ergebnis erhält man eine Dichtefunktion, die angibt, wie viele Einkommen an eine Stelle liegt. Die Dichtefunktion $f$ ist dann wie folgt definiert: $$f(x) = \beta_1 \cdot x^g + \beta_0 $$ und hat folgende Parameter $\beta_1$ und $\beta_0$, die Verändert werden können. Der Grad der Funktion $g$ muss vorher gegeben sein. Für diese Parameter soll nun ein Wert gefunden werden, der ermöglicht, das die Integralle im Bereich der Quantile $Q$ der Funktion $d$ dem Wert der Quantile entspricht. Also das: $$ Quantilwert \approx \int_{x_{von}}^{x_{bis}} f(x) \, dx $$ Dazu muss eine Loss-Funktion definiert werden, die für jede Eingabe an Parametern ausgibt, wie Groß der Abstand zwischen dem Wert des Integrals und dem gewühntschtem Wert im Qunatil $Q$ ist. Die Lossfunktion $l$ lässt sich definieren als: $$ l(\beta_0, \beta_1) = \sum_{i=1}^{n} \left( d[i] - \int_{\frac{i-1}{n}}^{\frac{i}{n}} \beta_0 + \beta_1 \cdot x^g \,dx \right)^2$$ wobei: * $beta_0$: Y-Achsenabschnitt * $beta_1$: Regressionskoeffizienz / Steigung der Parabell * $d$: Liste mit allen Quartielwerten * $n$: Anzahl an Quartilen $|d|$ * $g$: Grad der Zielfunktion Alle Parameter, bis auf $\beta_0$ und $\beta_1$, müssen vorher gegeben sein! Da es sich um eine Polynomenfunktion handelt, kann das Integral symbolisch gelöst weren (Quelle ChatGPT). Dadurch gilt folgendes: \begin{align*} \int_{a}^{b} \beta_1 \cdot x^g + \beta_0 \, dx &= \beta^1 \cdot \int_{a}^{b} x^g \, dx \cdot \int_{a}^{b} 1 \, dx = \beta_1 \cdot \left[ \frac{x^{g+1}}{g+1} \right]^b_a + \beta_0 \cdot (b-a) \\ &= \beta_1 \cdot \left( \frac{b^{g+1} - a^{g+1}}{g+1} \right) + \beta_0 \cdot (b-a) \end{align*} Dadurch kann die Loss-Funktion wie folgt geschrieben werden: $$ l(\beta_0, \beta_1) = \sum_{i=1}^{n} \left(d[i] - \left[ \beta_1 \cdot \left( \frac{ \left(\frac{i}{n}\right)^{g+1} - \left(\frac{i-1}{n}\right)^{g+1}}{g+1} \right) + \beta_0 \cdot \frac{1}{n} \right] \right)^2 $$ Nun kann mit der Funktion ''minimize'' aus ''scipy.optimize'' das Problem, die besten Werte für $\beta_0$ und $\beta_1$ zu finden, gelöst werden. Wie genau die Lösungsalgorithmen funktionieren weiß ich auch nicht. import matplotlib.pyplot as plt import numpy as np from scipy.optimize import minimize # Quantile - Hier Dezile als Beispiel quantile = np.array([3,5,6,7,8,9,10,12,15,25])/100 # Grad der Funktion g = 2 # Weitere Variablen, die berechnet werden n = len(quantile) b_0 = 0 b_1 = 0 def l(xy): b_0, b_1 = xy error = 0 for i, element in enumerate(quantile): integral = (b_1 * (((((i+1) / n)**(g+1)) - (((i)/n)**(g+1)))/(g+1)) + b_0 * (1/n)) error += (element - integral)**2 return error def f(x): return b_1 * (x**g) + b_0 res = minimize(l, (1,1), method='L-BFGS-B') # (1,1) ist der Startwert b_0, b_1 = res.x print(f'Die Funktion lautet: f(x) = {b_1} * x^{g} + {b_0}') print(f'Der Fehlerwert ist : {l(res.x)}') # Darstellung der Werte x = np.linspace(0, 1, 10) x_quantile = np.linspace(0.05, 0.95, len(quantile)) plt.figure() plt.bar(x_quantile, quantile, width=0.1, alpha=0.6, label='Dezile', color='orange', edgecolor='black') plt.plot(x, f(x), label='f(x)') plt.title(rf"$f(x) = {b_1}\, \cdot x^{g} + {b_0}$") plt.legend() plt.show() Aus der Dichtefunktion lassen sich aber noch keine relativen Werte für die Agenten berechnen. Erstmal kann mit der Dichtefunktion $f$ nur ein absoluter Wert für jeden Agenten berechnet werden. Dazu braucht man einen konstanten Wert, der mit dem Funktoinswert von $f$ multipliziert wird. Also für das absolute Einkommen des Agenten ergibt sich: $$ Einkommen = f(x) + C $$ Dabei ist $x$ die realtive Position des Agenten. Wenn der Agent die Position $i$ hat ist $x = \frac{i}{n}$, wobei $n$ die Anzahl von Agenten ist. $C$ ist eine Konstante, die z.B. das durchschnittliche Einkommen pro Person sein könnte. Um nun das relative Einkommen zu erhalten, muss nur das absolute Einkommen durch das Gesamteinkommen gerechnet werden. Dadruch ergibt sich das Einkommen der Agenten aus: $$ Einkommen_i = \frac{Absolutes Einkommen}{Gesamteinkommen} = \frac{f(x_i) + C}{\sum_{i=0}^{n} f(x_j) +C } = \frac{f(x_i)}{\sum_{i=0}^{n} f(x_j)} $$ Das lässt sich sehr einfach mit ''numpy.arrays'' umsetzen. Die gesamte Funktion sieht nun so aus def g(n, Q) -> np.ndarray: """Die Funktion berechnet für eine Anzalh an Agenten n und Quantilen Q die passende Verteilung und gibt als Rückgabewert einen Array mit den relativen Werten für jeden Agenten :param n: Anzahl an Agenten bzw. Werten, die Zurückgegeben werden sollen :type n: int :param Q: Liste mit realtiven nicht-kumulierten Quantilwerten :type Q: list :return: Liste mit relativen Werten für jeden Agenten bzw. mit Länge n :rtype: array """ array = np.linspace(0.5/n, 1 - 0.5/n, n) # relative Positionen von jedem Agenten # Variablen zuschreiben g = 2 quantile = np.array(Q)/100 n = len(quantile) b_0 = 0 b_1 = 0 # ALTER CODE - VON OBEN KOPIERT def l(xy): b_0, b_1 = xy error = 0 for i, element in enumerate(quantile): integral = (b_1 * (((((i+1) / n)**(g+1)) - (((i)/n)**(g+1)))/(g+1)) + b_0 * (1/n)) error += (element - integral)**2 return error def f(x): return b_1 * (x**g) + b_0 # Dichtefunktion f erstellen res = minimize(l, (1,1), method='L-BFGS-B') # (1,1) ist der Startwert b_0, b_1 = res.x print(f'Die Funktion lautet: f(x) = {b_1} * x^{g} + {b_0}') print(f'Der Fehlerwert ist : {l(res.x)}') # NEUER CODE # relative Werte für jeden Agenten Ermitteln array = f(array) # Für jedes ELement im Array wird die Funktion angewendet array = array/np.sum(array) # relative Werte erghalten return array