Maschinelles Lernen für Wirtschaft und Finanzen
Universität Hamburg
+Universität Hamburg
Aufgabenserie 1
+Vorab ¶
-
+
- Ziel dieses Tutorials ist es, einige der wichtigsten Konzepte zu üben, die in den ersten Wochen des ML Kurses behandelt werden. +
Aufbau ¶
Die Hauptaufgabe dieses Problemsets besteht darin, die Rendite des US-Aktienmarktes vorherzusagen. Dazu verwenden wir den Datensatz stockmarketdata.RDS von Welch und Goyal (2007), der auf OpenOlat verfügbar ist. Der Datensatz enthält vierteljährliche Renditen des US-Aktienmarktes ($ret$) sowie mehrere andere Variablen, die von Finanzforschern vorgeschlagen wurden, um Aktienrenditen vorherzusagen. Eine Liste aller Variablen zusammen mit einer Beschreibung finden Sie im Anhang. Für das erste Quartal 1999 (date = 19991) enthält er beispielsweise Variablen wie die Rendite des Aktienmarktes ($ret_{t}$), das Dividenden-zu-Preis-Verhältnis ($DP_{t}$), den Kreditspread ($CS_{t}$) und so weiter. Da das Ziel darin besteht, Renditen im folgenden Quartal vorherzusagen, interessieren uns Modelle der Form
$ret_{t+1} = f (DP_{t}, CS_{t}, ...) + ϵ_{t+1}$
+Angenommen, Sie sind ein Vermögensverwalter und es ist Ende 1994, dh Sie haben alle Daten vor 1995 zur Verfügung, um Ihr Modell zu trainieren und zu validieren. Ihr Ziel ist es, ein Modell zu entwickeln, das nicht nur in der Stichprobe funktioniert, sondern auch zukünftige Renditen vorhersagen kann (nach 1995).
+Aufgabe 1: Vorbereitung und Analyse der Daten ¶
-
+
Zuerst müssen wir die Daten so ausrichten, dass eine Zeile, die die Merkmale für das Datum t enthält, die Rendite für das Datum $t + 1$ enthält (anstelle der Rendite für das Datum t, wie es derzeit der Fall ist). Dadurch wird sichergestellt, dass wir tatsächlich die Renditen für das nächste Quartal vorhersagen. Hierfür müssen wir die Zeitreihe der Rendite um einen Zeitraum nach vorne verschieben. (Hinweis: Verwenden Sie die Funktion
+shift(), um eine neue Variable zum Dataframe hinzuzufügen, die die Rendite um einen Zeitraum verschiebt. Entfernen Sie anschließend die alte Zeitreihe der Rendite aus dem Dataframe.)
+Entfernen Sie alle Zeilen, die fehlende Werte im Datensatz enthalten. Google bietet viele verschiedene Möglichkeiten, wie Sie dies tun können. Wenn Sie Schwierigkeiten mit dieser Übung haben, tun Sie Folgendes: Verwenden Sie die kombination der Funktionen
+.isna().sum()auf das DataFrame, um die Summe aller Zeilen zu bestimmen, die fehlende Werte enthalten. Finden Sie die fehlenden Werte für diese Variablen durch Augeninspektion. Beginnen und beenden Sie die Stichprobe so, dass diese Zeilen mit fehlenden Werten nicht enthalten sind. Verwenden Sie anschließend erneut die Funktion.isna().sum(), um sicherzustellen, dass Sie alle fehlenden Werte entfernt haben.
+Teilen Sie die Stichprobe in zwei Teile auf. Daten vor 1995 für das Training und die Validierung und Daten nach und einschließlich 1995 für das Out-of-Sample-Testen.
+
+Berechnen Sie die durchschnittliche vierteljährliche Rendite und ihre Standardabweichung in den Trainings- und Testdaten. Gibt es etwas, das erwähnenswert ist?
+
+Berechnen Sie die Korrelationsmatrix für die Trainingsdaten (einschließlich sowohl der Ergebnisse als auch der Merkmale). Gibt es etwas, das erwähnenswert ist?
+
+
Vorbereitung:¶
-
+
- Einlesen und Grundanpassungen der
stockmarketdata.rdsDaten
+
import warnings # Paket zum Unterdrücken von "warnings"
+import pyreadr # Paket zum einlesen von RDS Datein - https://github.com/ofajardo/pyreadr
+
+df = pyreadr.read_r('stockmarketdata.rds')
+df = df[None] # Extrahieren des verfügbaren Pandas-DataFrame Objekts.
+
+df.head() # Zeige die ersten 5 Zeilen des DataFrames an.
+| + | date | +ret | +DP | +CS | +ntis | +cay | +TS | +svar | +
|---|---|---|---|---|---|---|---|---|
| 0 | +19291.0 | +0.050490 | +-3.367688 | +0.010357 | +0.079805 | +NaN | +-0.0083 | +0.007982 | +
| 1 | +19292.0 | +0.087235 | +-3.412851 | +0.011105 | +0.116197 | +NaN | +-0.0113 | +0.008405 | +
| 2 | +19293.0 | +0.091067 | +-3.468392 | +0.012517 | +0.121390 | +NaN | +-0.0083 | +0.008056 | +
| 3 | +19294.0 | +-0.268418 | +-3.096184 | +0.012155 | +0.163522 | +NaN | +0.0037 | +0.100171 | +
| 4 | +19301.0 | +0.165884 | +-3.252345 | +0.010554 | +0.145496 | +NaN | +0.0040 | +0.004662 | +
import pandas as pd
+
+# Definierung einer Funktion, um die numerische Darstellung in das Format 'JJJJ-QX' zu erreichen.
+def convert_to_quarterly_date(numeric_date):
+ year = int(numeric_date) // 10 # Ziehen der Information des Jahres
+ quarter = int(numeric_date) % 10 # Ziehen der Information des Quartals
+ quarter_str = f'Q{quarter}' # Umwandling der "float" Quartal Daten zu "string" Format
+ return f'{year}-Q{quarter}' # Rückgabe der überschriebenen Schreibweise
+
+# Anwendung der Fuktion auf die Variable "date".
+df['date'] = df['date'].apply(convert_to_quarterly_date)
+
+df.tail()
+| + | date | +ret | +DP | +CS | +ntis | +cay | +TS | +svar | +
|---|---|---|---|---|---|---|---|---|
| 360 | +2019-Q1 | +0.137489 | +-3.943400 | +0.010258 | +-0.023230 | +-0.039336 | +0.0017 | +0.004651 | +
| 361 | +2019-Q2 | +0.042688 | +-3.960033 | +0.010006 | +-0.012562 | +-0.033844 | +-0.0010 | +0.003271 | +
| 362 | +2019-Q3 | +0.017042 | +-3.951689 | +0.008505 | +-0.010862 | +-0.029529 | +-0.0019 | +0.005517 | +
| 363 | +2019-Q4 | +0.090143 | +-4.015896 | +0.008410 | +-0.007222 | +-0.033609 | +0.0032 | +0.002319 | +
| 364 | +2020-Q1 | +-0.193794 | +-3.769992 | +0.012252 | +-0.007731 | +-0.050141 | +0.0058 | +0.079049 | +
Aufgabe 1.1:¶
-
+
- Anpassung der Rendite Zeitdaten +
# Verschiebung der Spalte Rendite um einen Zeitraum t+1.
+df['ret_next'] = df['ret'].shift(-1)
+
+# Entfernen der Spalte "ret" aus dem DataFrame.
+df.drop('ret', axis=1, inplace=True)
+
+df.tail()
+| + | date | +DP | +CS | +ntis | +cay | +TS | +svar | +ret_next | +
|---|---|---|---|---|---|---|---|---|
| 360 | +2019-Q1 | +-3.943400 | +0.010258 | +-0.023230 | +-0.039336 | +0.0017 | +0.004651 | +0.042688 | +
| 361 | +2019-Q2 | +-3.960033 | +0.010006 | +-0.012562 | +-0.033844 | +-0.0010 | +0.003271 | +0.017042 | +
| 362 | +2019-Q3 | +-3.951689 | +0.008505 | +-0.010862 | +-0.029529 | +-0.0019 | +0.005517 | +0.090143 | +
| 363 | +2019-Q4 | +-4.015896 | +0.008410 | +-0.007222 | +-0.033609 | +0.0032 | +0.002319 | +-0.193794 | +
| 364 | +2020-Q1 | +-3.769992 | +0.012252 | +-0.007731 | +-0.050141 | +0.0058 | +0.079049 | +NaN | +
Aufgabe 1.2:¶
-
+
- Anpassung fehlender Datenwerte im DataFrame +
# Aufzählung aller NaN's (je Variable) des DataFrame.
+df.isna().sum()
+date 0 +DP 0 +CS 0 +ntis 0 +cay 92 +TS 0 +svar 0 +ret_next 1 +dtype: int64+
import numpy as np
+
+# Verwerfen aller Zeilen, bei denen Variablen eine NaN Zelle besitzen.
+df = df.dropna()
+df.isna().sum()
+date 0 +DP 0 +CS 0 +ntis 0 +cay 0 +TS 0 +svar 0 +ret_next 0 +dtype: int64+
Aufgabe 1.3:¶
-
+
- Aufteilung des Datensatzes in zwei Teile. Training Datensatz mit Daten vor 1995 und Validierung Datensatz mit den Daten nach 1995 als Out-of-Sample Datensatz. +
# Erstellen von Variablen mit der Information "1994-Q4" und der Position, welche als Schnittpunkt dienen.
+split_date = '1994-Q4'
+split_ind = df.index[df['date'] == split_date][0]
+
+# Aufteilung der Daten zu "train_data" und "test_data".
+train_data = df.loc[:split_ind] # für in-sample tests
+test_data = df.loc[split_ind + 1:] # für out-of-sample tests
+
+print(f"train_data besitzt {len(train_data)} Beobachtung.")
+print(f"test_data besitzt {len(test_data)} Beobachtung.")
+train_data besitzt 172 Beobachtung. +test_data besitzt 100 Beobachtung. ++
Aufgabe 1.4:¶
-
+
- Berechnung der durchschnittlichen vierteljährlichen Rendite und ihre Standardabweichung in den Trainings- und Testdaten. +
train_mean_ret = train_data['ret_next'].mean() # durchschnittliche vierteljährlichen Rendite (train_data)
+train_std_ret = train_data['ret_next'].std() # Standardabweichung der vierteljährlichen Rendite (train_data)
+
+test_mean_ret = test_data['ret_next'].mean() # durchschnittliche vierteljährlichen Rendite (test_data)
+test_std_ret = test_data['ret_next'].std() # Standardabweichung der vierteljährlichen Rendite (test_data)
+
+# Ausgabe der Ergebnisse
+print("Trainingsdaten:")
+print(f"Durchschnittliche Rendite: {train_mean_ret:.4f}")
+print(f"Standardabweichung der Rendite: {train_std_ret:.4f}")
+print("\nTestdaten:")
+print(f"Durchschnittliche Rendite: {test_mean_ret:.4f}")
+print(f"Standardabweichung der Rendite: {test_std_ret:.4f}")
+Trainingsdaten: +Durchschnittliche Rendite: 0.0306 +Standardabweichung der Rendite: 0.0763 + +Testdaten: +Durchschnittliche Rendite: 0.0252 +Standardabweichung der Rendite: 0.0823 ++
Aufgabe 1.5:¶
-
+
- Berechnung der Korrelationsmatrix für die Trainingsdaten (einschließlich sowohl der Ergebnisse als auch der Merkmale). +
# Berechnung der Korrelationsmatrix für die Trainingsdaten
+train_cor_matrix = train_data.loc[:, train_data.columns != 'date'].corr(method='pearson') # "date" Spalte ausgelassen (Nur numerische Spalten)
+
+# Ausgabe der Korrelationsmatrix. Werte auf zwei Nachkommastellen aufgerundet.
+print("Korrelationsmatrix für Trainingsdaten:")
+print(round(train_cor_matrix,2))
+Korrelationsmatrix für Trainingsdaten: + DP CS ntis cay TS svar ret_next +DP 1.00 0.38 -0.12 -0.21 -0.14 0.11 0.23 +CS 0.38 1.00 -0.31 -0.02 0.21 0.22 0.18 +ntis -0.12 -0.31 1.00 -0.40 -0.07 -0.12 -0.19 +cay -0.21 -0.02 -0.40 1.00 0.46 0.04 0.17 +TS -0.14 0.21 -0.07 0.46 1.00 0.08 0.16 +svar 0.11 0.22 -0.12 0.04 0.08 1.00 0.13 +ret_next 0.23 0.18 -0.19 0.17 0.16 0.13 1.00 ++
-
+
- Zusatz: Grafische Abbildung der Korrelationsmatrix +
import seaborn as sns
+import matplotlib.pyplot as plt
+
+fig, ax = plt.subplots(figsize=(10,8))
+s = sns.heatmap(train_data.loc[:, train_data.columns != 'date'].corr(),
+ annot=True,
+ center=0,
+ linewidths=.5,
+ square=True,
+ vmin=-1,
+ vmax=1,
+ xticklabels='auto',
+ yticklabels='auto',
+ fmt='0.2f',
+ cmap="coolwarm")
+s.set_title('Korrelationsmatrix der trainingsdaten Variablen')
+s.set(xlabel='Variablen', ylabel='Variablen')
+plt.show()
+Aufgabe 2: Vorhersage von Renditen ¶
Nachdem die Daten bereinigt wurden, sind Sie bereit, das erste Modell zur Vorhersage von Renditen zu erstellen.
+-
+
Verwenden Sie die Trainingsdaten, um ein lineares Modell unter Verwendung aller Variablen (stellen Sie sicher, dass Sie die Datumsvariable ausschließen) anzupassen. Welche Merkmale sind nützlich für die Vorhersage von Renditen?
+
+Berechnen Sie das R² in der Stichprobe sowie den mittleren quadratischen Fehler. Glauben Sie, dass vierteljährliche Renditen leicht vorhergesagt werden können?
+
+Verwenden Sie eine 5-fache Kreuzvalidierung, um eine Schätzung für den mittleren quadratischen Fehler außerhalb der Stichprobe zu erhalten. Vergleichen Sie diese Schätzung mit dem mittleren quadratischen Fehler in der Stichprobe aus "Aufgabe 2.2".
+
+Basierend auf Ihren Ergebnissen aus "Aufgabe 2.1" wählen Sie nur eine Teilmenge der Merkmale aus, um Ihr Modell zu verbessern. Welche Merkmale wählen Sie aus und warum? Berechnen Sie das R² in der Stichprobe sowie den mittleren quadratischen Fehler für dieses Modell und verwenden Sie eine 5-fache Kreuzvalidierung, um eine Schätzung für den mittleren quadratischen Fehler außerhalb der Stichprobe zu erhalten. Vergleichen Sie Ihre Ergebnisse mit dem Modell unter Verwendung aller Merkmale.
+
+Angenommen, Sie verwenden die beiden Modelle, die Sie erstellt haben, um vierteljährliche Renditen in den nächsten 25 Jahren vorherzusagen. Berechnen Sie die mittleren quadratischen Fehler außerhalb der Stichprobe für die Testdaten. Vergleichen Sie diese Fehler mit den Schätzungen für die außerhalb der Stichprobe erhaltenen Fehler aus der k-fachen Kreuzvalidierung. Interpretieren Sie.
+
+
Aufgabe 2.1:¶
-
+
- MLR unter Verwendung aller Variablen des Trainingdatensatzes +
import statsmodels.api as sm
+# Alle nutzen außer - entfernen der "Unabhängige Variablen" und der "qualitativen variablen /bzw. level Variablen" - hier aber die "date" Variable!
+
+# Möglichkeit 1 - doch ohne weitere Anpassung problematisch:
+#X = train_data.drop(columns=['date','ret_next'])
+# DOCH dann fehlt aber der Intercept in der summary !!
+
+# Möglichkeit 2:
+#X = pd.DataFrame({'intercept': np.ones(train_data.shape[0]),
+# 'DP': train_data['DP'],
+# 'CS': train_data['CS'],
+# 'ntis': train_data['ntis'],
+# 'cay': train_data['cay'],
+# 'TS': train_data['TS'],
+# 'svar': train_data['svar']
+# })
+
+# Möglichkeit 3: finale Lösung - Füllung der Exogenen Variable
+# Erstellen der Modell-Matrix:
+X = train_data.drop(columns=['date','ret_next']) # Entfernen der endogenen und qualitativen Variablen
+X.insert(0, 'intercept', np.ones(train_data.shape[0]))
+
+y = train_data['ret_next'] # Setzen der Endogene Variable
+model = sm.OLS(y, X) # OLS Modell füllen.
+fit_lm = model.fit() # Fit des univariaten linearen Regressionsmodells.
+fit_lm.summary() # Ausgabe der Modellstatistik
+| Dep. Variable: | ret_next | R-squared: | 0.129 | +
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.097 | +
| Method: | Least Squares | F-statistic: | 4.063 | +
| Date: | Sun, 14 Apr 2024 | Prob (F-statistic): | 0.000793 | +
| Time: | 20:47:06 | Log-Likelihood: | 210.80 | +
| No. Observations: | 172 | AIC: | -407.6 | +
| Df Residuals: | 165 | BIC: | -385.6 | +
| Df Model: | 6 | + | |
| Covariance Type: | nonrobust | + |
| coef | std err | t | P>|t| | [0.025 | 0.975] | +|
|---|---|---|---|---|---|---|
| intercept | 0.2968 | 0.097 | 3.063 | 0.003 | 0.106 | 0.488 | +
| DP | 0.0839 | 0.028 | 3.031 | 0.003 | 0.029 | 0.139 | +
| CS | 0.4750 | 1.739 | 0.273 | 0.785 | -2.958 | 3.908 | +
| ntis | -0.3945 | 0.410 | -0.961 | 0.338 | -1.205 | 0.416 | +
| cay | 0.4215 | 0.306 | 1.379 | 0.170 | -0.182 | 1.025 | +
| TS | 0.6310 | 0.482 | 1.309 | 0.192 | -0.320 | 1.583 | +
| svar | 0.8027 | 0.828 | 0.969 | 0.334 | -0.832 | 2.438 | +
| Omnibus: | 26.211 | Durbin-Watson: | 1.810 | +
|---|---|---|---|
| Prob(Omnibus): | 0.000 | Jarque-Bera (JB): | 40.178 | +
| Skew: | -0.823 | Prob(JB): | 1.89e-09 | +
| Kurtosis: | 4.701 | Cond. No. | 1.10e+03 | +
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.1e+03. This might indicate that there are
strong multicollinearity or other numerical problems. +
Aufgabe 2.2:¶
-
+
- $R^{2}$-Wert des Trainingdatatensatzes. +
print(f"Das train_data R^2 beträgt: {fit_lm.rsquared:.4f}")
+Das train_data R^2 beträgt: 0.1287 ++
-
+
- Bestimmung des in-sample MSE Wertes. +
#from sklearn.metrics import mean_squared_error # kann benutzt werden
+#Oder wie hier, selbst definiert werden:
+
+##### Computing the MSE for the Auto Data: #####
+# Compute predicted values y_head for training data
+y_head = fit_lm.predict(X)
+
+# Function to compute the mean squared error (MSE)
+def MSE(y, y_head):
+ return np.mean((y - y_head)**2)
+
+# Compute the mean squared error in the training data
+MSE_train_data = MSE(train_data['ret_next'], y_head)
+print(f"in-sample (MSE): {MSE_train_data:.4f}")
+in-sample (MSE): 0.0050 ++
Aufgabe 2.3:¶
-
+
- Vergleich des out-of-sample MSE's mit dem 5-fach Kreuzvalidierung MSE's: +
from sklearn.linear_model import LinearRegression
+from sklearn.model_selection import cross_val_score
+from sklearn.metrics import mean_squared_error
+import numpy as np
+
+# Separate features and target variables
+X_train = train_data.drop(columns=['ret_next','date'])
+y_train = train_data['ret_next']
+X_test = test_data.drop(columns=['ret_next','date'])
+y_test = test_data['ret_next']
+
+# Train the model on the training data
+model = LinearRegression()
+model.fit(X_train, y_train)
+
+# Predict on the test data
+y_pred_test = model.predict(X_test)
+
+# Calculate the mean squared error (MSE) on the test data
+mse_test = mean_squared_error(y_test, y_pred_test)
+print(f"Out-of-sample MSE: {mse_test:.4f}")
+
+# Perform 5-fold cross-validation and calculate the mean of MSEs
+mse_cv = -cross_val_score(model, X_train, y_train, scoring='neg_mean_squared_error', cv=5).mean()
+print(f"Cross-validated MSE: {mse_cv:.4f}")
+Out-of-sample MSE: 0.0086 +Cross-validated MSE: 0.0081 ++
Aufgabe 2.4:¶
-
+
- Bestimmung des out-of-sample MSE's und mittel 5-fache Kreuzvalidierung den Cross-validation MSE
-
+
- Auswertung der Modellgüte mittels verschiedener variablen Kombinationen. +
+
import pandas as pd
+from sklearn.linear_model import LinearRegression
+from sklearn.model_selection import cross_val_score
+from sklearn.metrics import mean_squared_error, r2_score
+
+# Select subset of features
+selected_features = ['DP']
+
+# Separate features and target variables for selected features
+X_train_selected = train_data[selected_features]
+X_test_selected = test_data[selected_features]
+y_train = train_data['ret_next']
+y_test = test_data['ret_next']
+
+# Train the model on the training data using selected features
+model_selected = LinearRegression()
+model_selected.fit(X_train_selected, y_train)
+
+# Predict on the training data
+y_pred_train_selected = model_selected.predict(X_train_selected)
+
+# Compute in-sample R^2
+r2_in_sample_selected = r2_score(y_train, y_pred_train_selected)
+print(f"In-sample R^2 mit der Variable (DP): {r2_in_sample_selected:.4f}")
+
+# Compute mean squared error (MSE) for the training data
+mse_train_selected = mean_squared_error(y_train, y_pred_train_selected)
+print(f"In-sample MSE mit der Variable (DP): {mse_train_selected:.4f}")
+
+# Perform 5-fold cross-validation and compute out-of-sample MSE for the selected features
+mse_cv_selected = -cross_val_score(model_selected, X_train_selected, y_train, scoring='neg_mean_squared_error', cv=5).mean()
+print(f"Out-of-sample MSE bei 5-fold cross-validation mit der Variable (DP): {mse_cv_selected:.4f}")
+In-sample R^2 mit der Variable (DP): 0.0541 +In-sample MSE mit der Variable (DP): 0.0055 +Out-of-sample MSE bei 5-fold cross-validation mit der Variable (DP): 0.0056 ++
import pandas as pd
+from sklearn.linear_model import LinearRegression
+from sklearn.model_selection import cross_val_score
+from sklearn.metrics import mean_squared_error, r2_score
+
+# Select subset of features
+selected_features = ['DP', 'cay']
+
+# Separate features and target variables for selected features
+X_train_selected = train_data[selected_features]
+X_test_selected = test_data[selected_features]
+y_train = train_data['ret_next']
+y_test = test_data['ret_next']
+
+# Train the model on the training data using selected features
+model_selected = LinearRegression()
+model_selected.fit(X_train_selected, y_train)
+
+# Predict on the training data
+y_pred_train_selected = model_selected.predict(X_train_selected)
+
+# Compute in-sample R^2
+r2_in_sample_selected = r2_score(y_train, y_pred_train_selected)
+print(f"In-sample R^2 mit den Variablen (DP+cay): {r2_in_sample_selected:.4f}")
+
+# Compute mean squared error (MSE) for the training data
+mse_train_selected = mean_squared_error(y_train, y_pred_train_selected)
+print(f"In-sample MSE mit den Variablen (DP+cay): {mse_train_selected:.4f}")
+
+# Perform 5-fold cross-validation and compute out-of-sample MSE for the selected features
+mse_cv_selected = -cross_val_score(model_selected, X_train_selected, y_train, scoring='neg_mean_squared_error', cv=5).mean()
+print(f"Out-of-sample MSE bei 5-fold cross-validation mit den Variablen (DP+cay): {mse_cv_selected:.4f}")
+In-sample R^2 mit den Variablen (DP+cay): 0.1040 +In-sample MSE mit den Variablen (DP+cay): 0.0052 +Out-of-sample MSE bei 5-fold cross-validation mit den Variablen (DP+cay): 0.0053 ++
Aufgabe 3: Vorhersage der Richtung des Aktienmarktes ¶
Statt Renditen quantitativ vorherzusagen, nehmen Sie nun an, dass Sie die Richtung des Aktienmarktes vorhersagen möchten, d. h. ob die Aktien steigen oder fallen. Basierend auf diesen Vorhersagen möchten Sie entweder in Aktien investieren oder nicht.
+-
+
Erstellen Sie eine neue Variable sowohl in den Trainings- als auch in den Testdaten, die 1 ist, wenn die Rendite größer als Null ist, und 0 sonst.
+
+Berechnen Sie den Anteil positiver Aktienrenditen sowohl in den Trainings- als auch in den Testdaten.
+
+Passen Sie eine logistische Regression an die Trainingsdaten an, um die Richtung des Aktienmarktes vorherzusagen (stellen Sie sicher, dass Sie die Datumsvariable und die alte quantitative Renditevariable ausschließen). Welche Merkmale sind nützliche Prädiktoren? Berechnen Sie die In-Sample-Genauigkeit und die Fehlerquote. Glauben Sie, dass Sie ein gutes Modell zur Vorhersage der Richtung des Aktienmarktes erstellt haben?
+
+Angenommen, Sie verwenden das von Ihnen erstellte Modell, um die Richtung des Aktienmarktes in den nächsten 25 Jahren vorherzusagen. Berechnen Sie die außerhalb der Stichprobe liegende Genauigkeit und Fehlerquote für die Testdaten. Vergleichen Sie diese Ergebnisse mit den In-Sample-Statistiken. Glauben Sie, dass Ihr Modell gut außerhalb der Stichprobe funktioniert? Interpretieren Sie die Ergebnisse.
+
+
Aufgabe 3.1:¶
-
+
- Erstelle eine neue Variable, die 1 ist, wenn die Rendite größer als Null ist, und 0 sonst. +
warnings.filterwarnings('ignore') # to hide the warning message - it's fixed here.
+# Erstelle eine neue Variable, die 1 ist, wenn die Rendite größer als Null ist, und 0 sonst
+
+# raises a Warning message: A value is trying to be set on a copy of a slice from a DataFrame.
+#train_data['return_positive'] = train_data['ret_next'].apply(lambda x: 1 if x > 0 else 0)
+#test_data['return_positive'] = test_data['ret_next'].apply(lambda x: 1 if x > 0 else 0)
+
+# .iloc solution to fix the warning:
+train_data.loc[:, 'return_positive'] = train_data['ret_next'].apply(lambda x: 1 if x > 0 else 0)
+test_data.loc[:, 'return_positive'] = test_data['ret_next'].apply(lambda x: 1 if x > 0 else 0)
+
+train_data.head()
+| + | date | +DP | +CS | +ntis | +cay | +TS | +svar | +ret_next | +return_positive | +
|---|---|---|---|---|---|---|---|---|---|
| 92 | +1952-Q1 | +-2.842696 | +0.005328 | +0.032094 | +-0.010595 | +0.0104 | +0.002102 | +0.038275 | +1 | +
| 93 | +1952-Q2 | +-2.845711 | +0.005425 | +0.027731 | +0.000055 | +0.0089 | +0.001660 | +-0.004980 | +0 | +
| 94 | +1952-Q3 | +-2.828741 | +0.005521 | +0.031038 | +-0.000695 | +0.0106 | +0.001076 | +0.102295 | +1 | +
| 95 | +1952-Q4 | +-2.936193 | +0.005231 | +0.026535 | +-0.015950 | +0.0070 | +0.001753 | +-0.035683 | +0 | +
| 96 | +1953-Q1 | +-2.886819 | +0.004354 | +0.024013 | +-0.019021 | +0.0093 | +0.001574 | +-0.032102 | +0 | +
Aufgabe 3.2:¶
-
+
- Anteil der positiven Aktienrenditen in den Trainingsdaten & Testdaten +
# Berechne den Anteil der positiven Aktienrenditen in den Trainingsdaten
+positive_proportion_train = train_data['return_positive'].mean()
+print(f"Anteil der positiven Aktienrenditen in den Trainingsdaten: {positive_proportion_train:.2f}")
+
+# Berechne den Anteil der positiven Aktienrenditen in den Testdaten
+positive_proportion_test = test_data['return_positive'].mean()
+print(f"Anteil der positiven Aktienrenditen in den Testdaten: {positive_proportion_test:.2f}")
+Anteil der positiven Aktienrenditen in den Trainingsdaten: 0.69 +Anteil der positiven Aktienrenditen in den Testdaten: 0.73 ++
Aufgabe 3.3:¶
-
+
- Logistische Regression über die Trainingsdaten, um die Richtung des Aktienmarktes vorherzusagen. +
from sklearn.linear_model import LogisticRegression
+from sklearn.metrics import accuracy_score, confusion_matrix
+
+# Separate features and target variables
+X_train = train_data.drop(columns=['return_positive', 'date', 'ret_next'])
+y_train = train_data['return_positive']
+
+# Train the logistic regression model
+model = LogisticRegression()
+model.fit(X_train, y_train)
+
+# Predict on the training data
+y_pred_train = model.predict(X_train)
+
+# Compute in-sample accuracy and error rate
+accuracy = accuracy_score(y_train, y_pred_train)
+error_rate = 1 - accuracy
+
+print(f"In-sample accuracy: {accuracy:.2f}")
+print(f"In-sample error rate: {error_rate:.2f}")
+
+# Compute useful predictors
+coefficients = model.coef_[0]
+useful_predictors = X_train.columns[coefficients != 0]
+print("Useful predictors:", useful_predictors) # Variablen die nicht-null Koeffizienten sind, sind nützlich.
+In-sample accuracy: 0.69 +In-sample error rate: 0.31 +Useful predictors: Index(['DP', 'CS', 'ntis', 'cay', 'TS', 'svar'], dtype='object') ++
Aufgabe 3.4:¶
-
+
- Äquivalent hierzu werden nun die Testdaten genutzt um Out-of-sample accuracy und error rate zu bestimmen und anschließend zu vergleichen mit den Ergebnissen aus Aufgabe 3.3. +
# Separate features and target variables for test data
+X_test = test_data.drop(columns=['return_positive', 'date', 'ret_next'])
+y_test = test_data['return_positive']
+
+# Predict on the test data
+y_pred_test = model.predict(X_test)
+
+# Compute out-of-sample accuracy and error rate
+accuracy_test = accuracy_score(y_test, y_pred_test)
+error_rate_test = 1 - accuracy_test
+
+print(f"Out-of-sample accuracy: {accuracy_test:.2f}")
+print(f"Out-of-sample error rate: {error_rate_test:.2f}")
+
+# Compare with in-sample statistics
+print("\nComparison with in-sample statistics:")
+print(f"In-sample accuracy: {accuracy:.2f}")
+print(f"In-sample error rate: {error_rate:.2f}")
+Out-of-sample accuracy: 0.73 +Out-of-sample error rate: 0.27 + +Comparison with in-sample statistics: +In-sample accuracy: 0.69 +In-sample error rate: 0.31 ++
Anhang ¶
Der Datensatz enthält die folgenden Variablen:
+-
+
- ret: Die vierteljährliche Rendite des US-Aktienmarktes (eine Zahl von 0,01 entspricht einer Rendite von 1% pro Quartal) +date: Das Datum im Format JJJJQ (19941 bedeutet das erste Quartal 1994) +
- DP: Das Dividenden-zu-Preis-Verhältnis des Aktienmarktes (eine Bewertungsmessung, ob die Preise im Verhältnis zu den gezahlten Dividenden hoch oder niedrig sind) +
- CS: Der Kreditspread definiert als die Differenz der Renditen zwischen hoch bewerteten Unternehmensanleihen (sichere Anlagen) und niedrig bewerteten Unternehmensanleihen (Unternehmen, die möglicherweise bankrott gehen). CS misst die zusätzliche Rendite, die Investoren für Investitionen in riskante Unternehmen im Vergleich zu etablierten Unternehmen mit geringeren Risiken verlangen. +
- ntis: Ein Maß für die Aktivität bei der Ausgabe von Unternehmensanleihen (IPOs, Rückkäufe von Aktien,...) +
- cay: Ein Maß für das Verhältnis von Vermögen zu Verbrauch (wie viel wird im Verhältnis zum Gesamtvermögen verbraucht) +
- TS: Der Term Spread ist die Differenz zwischen der langfristigen Rendite von Staatsanleihen und kurzfristigen Renditen. +
- svar: Ein Maß für die Varianz des Aktienmarktes +Für eine vollständige Beschreibung der Daten siehe Welch und Goyal (2007). Google ist auch sehr hilfreich, wenn Sie mehr über die Variablen erfahren möchten. +
Literatur ¶
Welch, I. and A. Goyal (2007, 03). A Comprehensive Look at The Empirical Performance of Equity +Premium Prediction. The Review of Financial Studies 21 (4), 1455–1508.
+