- Data-Science-Anwendungsfall im Bankwesen: Betrug erkennen
- Datensatz vorbereiten
- Betrugsanteil im Datensatz berechnen
- SMOTE zur Daten-Balancierung einsetzen
- Logistische Regression anwenden
- Fazit
Das Bankwesen gehört zu den Glücksfällen, in denen historisch sehr viele strukturierte Daten erhoben wurden – und es zählt zu den ersten Branchen, die Data-Science-Technologien eingesetzt haben.
Wie wird Data Science im Bankwesen genutzt? Heute sind Daten der wertvollste Rohstoff dieser Branche. Data Science ist für Banken unverzichtbar, um mit der Konkurrenz Schritt zu halten, neue Kundinnen und Kunden zu gewinnen, die Loyalität bestehender Kundschaft zu steigern, effizientere datenbasierte Entscheidungen zu treffen, das Geschäft zu stärken, operative Effizienz zu erhöhen, bestehende Services/Produkte zu verbessern und neue einzuführen, die Sicherheit zu erhöhen und so am Ende mehr Umsatz zu erzielen. Es ist kein Wunder, dass ein Großteil der Nachfrage nach Data-Science-Jobs aus dem Bankwesen kommt.
Data Science ermöglicht der Bankenbranche unter anderem folgende Aufgaben:
- Analyse von Investitionsrisiken
- Vorhersage des Customer Lifetime Value
- Kundensegmentierung
- Prognose der Abwanderungsrate
- Personalisierte Ansprache
- Stimmungsanalyse von Kundinnen und Kunden
- Virtuelle Assistenten und Chatbots
Im Folgenden schauen wir uns einen der häufigsten Data-Science-Anwendungsfälle im Bankwesen genauer an.
Data-Science-Anwendungsfall im Bankwesen: Betrug erkennen
Betrügerische Aktivitäten sind nicht nur im Bankwesen eine große Herausforderung, sondern auch in vielen anderen Bereichen wie öffentliche Verwaltung, Versicherungen, öffentlicher Sektor, Vertrieb und Gesundheitswesen. Jedes Unternehmen mit vielen Online-Transaktionen trägt ein erhebliches Betrugsrisiko. Finanzdelikte nehmen viele Formen an: betrügerische Kreditkartentransaktionen, gefälschte Schecks, Steuerhinterziehung, Geldwäsche, Cyberangriffe, Kontodiebstahl, synthetische Identitäten, Fake-Anträge und Scams.
Betrugserkennung umfasst proaktive Maßnahmen, um betrügerische Aktivitäten und finanzielle Verluste zu identifizieren und zu verhindern. Die wichtigsten Analysetechniken lassen sich in zwei Gruppen einteilen:
- Statistisch: Berechnung statistischer Parameter, Regression, Wahrscheinlichkeitsverteilungen, Datenabgleich
- Künstliche Intelligenz (KI): Data Mining, Machine Learning, Deep Learning
Machine Learning ist eine tragende Säule der Betrugserkennung. Das Toolkit bietet zwei Ansätze:
- Überwachte Methoden: k-nächste Nachbarn, logistische Regression, Support Vector Machines, Entscheidungsbaum, Random Forest, Zeitreihenanalyse, neuronale Netze etc.
- Unüberwachte Methoden: Clusteranalyse, Linkanalyse, selbstorganisierende Karten, Hauptkomponentenanalyse, Anomalieerkennung etc.
Es gibt keinen universellen, zuverlässigen Machine-Learning-Algorithmus für die Betrugserkennung. In realen Projekten testet man mehrere Techniken oder Kombinationen daraus, berechnet die Vorhersagegenauigkeit und wählt dann den besten Ansatz aus.
Die größte Herausforderung für Systeme zur Betrugserkennung ist, sich schnell an ständig wechselnde Muster und Taktiken der Betrüger anzupassen und neue, immer ausgeklügeltere Schemata rasch aufzudecken. Betrugsfälle sind stets in der Minderheit und gut zwischen echten Transaktionen verborgen.
Datensatz vorbereiten
Wir schauen uns nun eine Machine-Learning-Implementierung zur Erkennung von Kreditkartenbetrug in der Programmiersprache Python an. Wir arbeiten mit dem Datensatz creditcard_data, einer modifizierten Stichprobe aus einem Kaggle-Datensatz zur Credit Card Fraud Detection. Die Originaldaten umfassen Transaktionen europäischer Kreditkarteninhaber innerhalb von zwei Tagen im September 2013.
Importieren wir die Daten und werfen einen kurzen Blick darauf:
import pandas as pd
creditcard_data = pd.read_csv('creditcard_data.csv', index_col=0)
print(creditcard_data.info())
print('\n')
pd.options.display.max_columns = len(creditcard_data)
print(creditcard_data.head(3))
<class 'pandas.core.frame.DataFrame'>
Int64Index: 5050 entries, 0 to 5049
Data columns (total 30 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 V1 5050 non-null float64
1 V2 5050 non-null float64
2 V3 5050 non-null float64
3 V4 5050 non-null float64
4 V5 5050 non-null float64
5 V6 5050 non-null float64
6 V7 5050 non-null float64
7 V8 5050 non-null float64
8 V9 5050 non-null float64
9 V10 5050 non-null float64
10 V11 5050 non-null float64
11 V12 5050 non-null float64
12 V13 5050 non-null float64
13 V14 5050 non-null float64
14 V15 5050 non-null float64
15 V16 5050 non-null float64
16 V17 5050 non-null float64
17 V18 5050 non-null float64
18 V19 5050 non-null float64
19 V20 5050 non-null float64
20 V21 5050 non-null float64
21 V22 5050 non-null float64
22 V23 5050 non-null float64
23 V24 5050 non-null float64
24 V25 5050 non-null float64
25 V26 5050 non-null float64
26 V27 5050 non-null float64
27 V28 5050 non-null float64
28 Amount 5050 non-null float64
29 Class 5050 non-null int64
dtypes: float64(29), int64(1)
memory usage: 1.2 MB
V1 V2 V3 V4 V5 V6 V7 \
0 1.725265 -1.337256 -1.012687 -0.361656 -1.431611 -1.098681 -0.842274
1 0.683254 -1.681875 0.533349 -0.326064 -1.455603 0.101832 -0.520590
2 1.067973 -0.656667 1.029738 0.253899 -1.172715 0.073232 -0.745771
V8 V9 V10 V11 V12 V13 V14 \
0 -0.026594 -0.032409 0.215113 1.618952 -0.654046 -1.442665 -1.546538
1 0.114036 -0.601760 0.444011 1.521570 0.499202 -0.127849 -0.237253
2 0.249803 1.383057 -0.483771 -0.782780 0.005242 -1.273288 -0.269260
V15 V16 V17 V18 V19 V20 V21 \
0 -0.230008 1.785539 1.419793 0.071666 0.233031 0.275911 0.414524
1 -0.752351 0.667190 0.724785 -1.736615 0.702088 0.638186 0.116898
2 0.091287 -0.347973 0.495328 -0.925949 0.099138 -0.083859 -0.189315
V22 V23 V24 V25 V26 V27 V28 \
0 0.793434 0.028887 0.419421 -0.367529 -0.155634 -0.015768 0.010790
1 -0.304605 -0.125547 0.244848 0.069163 -0.460712 -0.017068 0.063542
2 -0.426743 0.079539 0.129692 0.002778 0.970498 -0.035056 0.017313
Amount Class
0 189.00 0
1 315.17 0
2 59.98 0
Der Datensatz enthält folgende Variablen:
- Numerisch kodierte Variablen V1 bis V28, also die Hauptkomponenten aus einer PCA-Transformation. Aus Vertraulichkeitsgründen gibt es keine Hintergrundinfos zu den ursprünglichen Merkmalen.
- Die Variable Amount steht für den Transaktionsbetrag.
- Die Variable Class zeigt, ob die Transaktion betrügerisch war (1) oder nicht (0).
Zum Glück sind Betrugsfälle in jeder Transaktionsliste stark in der Minderheit. Machine-Learning-Algorithmen funktionieren jedoch meist am besten, wenn die Klassen im Datensatz in etwa gleich stark vertreten sind. Andernfalls gibt es zu wenig Lernsignale. Dieses Problem heißt Klassenungleichgewicht.
Betrugsanteil im Datensatz berechnen
Berechnen wir den prozentualen Anteil betrügerischer Transaktionen an allen Transaktionen in unserem Datensatz:
round(creditcard_data['Class'].value_counts()*100/len(creditcard_data)).convert_dtypes()
0 99
1 1
Name: Class, dtype: Int64
Und erstellen wir eine Grafik, um Betrugs- und Nicht-Betrugsfälle zu visualisieren:
import matplotlib.pyplot as plt
import numpy as np
def prep_data(df):
X = df.iloc[:, 1:28]
X = np.array(X).astype(float)
y = df.iloc[:, 29]
y = np.array(y).astype(float)
return X, y
def plot_data(X, y):
plt.scatter(X[y==0, 0], X[y==0, 1], label='Class #0', alpha=0.5, linewidth=0.15)
plt.scatter(X[y==1, 0], X[y==1, 1], label='Class #1', alpha=0.5, linewidth=0.15, c='r')
plt.legend()
return plt.show()
X, y = prep_data(creditcard_data)
plot_data(X, y)

SMOTE zur Daten-Balancierung einsetzen
Wir sehen, dass der Anteil betrügerischer Transaktionen sehr gering ist – ein klassischer Fall von Klassenungleichgewicht. Um das zu beheben, können wir die Daten mit der Synthetic Minority Oversampling Technique (SMOTE) ausbalancieren. Anders als beim zufälligen Oversampling erzeugt SMOTE nicht einfach exakte Kopien, sondern nutzt Eigenschaften der nächsten Nachbarn von Betrugsfällen, um neue, synthetische Stichproben zu generieren, die der Minderheitsklasse ähneln. Wenden wir SMOTE auf unsere Kreditkartendaten an:
from imblearn.over_sampling import SMOTE
method = SMOTE()
X_resampled, y_resampled = method.fit_resample(X, y)
plot_data(X_resampled, y_resampled)

Wie man sieht, liefert SMOTE deutlich mehr Beobachtungen der Minderheitsklasse. Um das noch klarer zu machen, vergleichen wir die Ergebnisse mit den Originaldaten:
def compare_plot(X, y, X_resampled, y_resampled, method):
f, (ax1, ax2) = plt.subplots(1, 2)
c0 = ax1.scatter(X[y==0, 0], X[y==0, 1], label='Class #0',alpha=0.5)
c1 = ax1.scatter(X[y==1, 0], X[y==1, 1], label='Class #1',alpha=0.5, c='r')
ax1.set_title('Original set')
ax2.scatter(X_resampled[y_resampled==0, 0], X_resampled[y_resampled==0, 1], label='Class #0', alpha=.5)
ax2.scatter(X_resampled[y_resampled==1, 0], X_resampled[y_resampled==1, 1], label='Class #1', alpha=.5,c='r')
ax2.set_title(method)
plt.figlegend((c0, c1), ('Class #0', 'Class #1'), loc='lower center', ncol=2, labelspacing=0.)
plt.tight_layout(pad=3)
return plt.show()
print(f'Original set:\n'
f'{pd.value_counts(pd.Series(y))}\n\n'
f'SMOTE:\n'
f'{pd.value_counts(pd.Series(y_resampled))}\n')
compare_plot(X, y, X_resampled, y_resampled, method='SMOTE')
Original set:
0.0 5000
1.0 50
dtype: int64
SMOTE:
0.0 5000
1.0 5000
dtype: int64

Die SMOTE-Methode hat unsere Daten also komplett ausbalanciert; die Minderheitsklasse ist nun genauso groß wie die Mehrheitsklasse.
Wir kehren gleich zur praktischen Anwendung von SMOTE zurück. Zunächst betrachten wir aber wieder die Originaldaten und versuchen, Betrugsfälle zu erkennen. Auf dem „Old-School“-Weg definieren wir Regeln, um Betrug zu fassen – etwa ungewöhnliche Ortsangaben oder verdächtig häufige Transaktionen. Die Idee: Schwellwerte auf Basis einfacher Statistiken (oft Mittelwerte) festlegen und diese auf unsere Features anwenden.
print(creditcard_data.groupby('Class').mean().round(3)[['V1', 'V3']])
V1 V3
Class
0 0.035 0.037
1 -4.985 -7.294
In unserem Fall setzen wir folgende Bedingungen: V1 < -3 und V3 < -5. Um die Leistung dieses Ansatzes zu bewerten, vergleichen wir die markierten Betrugsfälle mit den tatsächlichen:
creditcard_data['flag_as_fraud'] = np.where(np.logical_and(creditcard_data['V1']<-3, creditcard_data['V3']<-5), 1, 0)
print(pd.crosstab(creditcard_data['Class'], creditcard_data['flag_as_fraud'], rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud 0 1
Actual Fraud
0 4984 16
1 28 22
Logistische Regression anwenden
Wir haben 22 von 50 Betrugsfällen erkannt, 28 jedoch verpasst und 16 False Positives erzeugt. Schauen wir, ob Machine-Learning-Methoden diese Ergebnisse schlagen.
Wir implementieren nun eine einfache Klassifikation mit logistischer Regression auf unseren Kreditkartendaten, um Betrugsfälle zu identifizieren, und visualisieren die Ergebnisse in einer Confusion-Matrix:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
lr = LogisticRegression()
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
print(pd.crosstab(y_test, predictions, rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud 0.0 1.0
Actual Fraud
0.0 1504 1
1.0 1 9
Wichtig: In dieser Confusion-Matrix sehen wir weniger Beobachtungen, weil wir nur den Test-Teil des Datensatzes für die Modellbewertung verwenden, also rund 30% der Gesamtdaten.
Wir haben einen höheren Anteil an Betrugsfällen erkannt: 90% (9 von 10) gegenüber zuvor 44% (22 von 50). Zudem gibt es deutlich weniger False Positives – ein klarer Fortschritt.
Kehren wir nun zum Problem des Klassenungleichgewichts zurück und prüfen, ob sich die Vorhersage weiter verbessern lässt, wenn wir die logistische Regression mit SMOTE kombinieren. Damit das effizient in einem Schritt passiert, definieren wir eine Pipeline und lassen sie auf unseren Daten laufen:
from imblearn.pipeline import Pipeline
# Defining which resampling method and which ML model to use in the pipeline
resampling = SMOTE()
lr = LogisticRegression()
pipeline = Pipeline([('SMOTE', resampling), ('Logistic Regression', lr)])
pipeline.fit(X_train, y_train)
predictions = pipeline.predict(X_test)
print(pd.crosstab(y_test, predictions, rownames=['Actual Fraud'], colnames=['Flagged Fraud']))
Flagged Fraud 0.0 1.0
Actual Fraud
0.0 1496 9
1.0 1 9
In unserem Fall bringt SMOTE keinen Vorteil: Wir erkennen weiterhin 90% der Betrugsfälle, haben aber leicht mehr False Positives. Der Grund: Resampling führt nicht in allen Fällen zu besseren Ergebnissen. Wenn Betrugsfälle stark über die Daten verteilt sind, sind ihre nächsten Nachbarn nicht zwingend ebenfalls Betrugsfälle – SMOTE kann dadurch einen Bias einführen.
Fazit
Als nächsten Schritt können wir die Parameter der logistischen Regression feinjustieren, um die Genauigkeit zu steigern. Statt einer einfachen Teilung in Train/Test bietet sich auch K-Fold-Cross-Validation an. Außerdem lohnt es, andere Machine-Learning-Algorithmen (z. B. Entscheidungsbaum oder Random Forest) auszuprobieren und die Ergebnisse zu vergleichen.
Wenn du tiefer in die theoretischen und technischen Aspekte der Implementierung von Betrugserkennungsmodellen einsteigen möchtest, schau dir den Kurs Fraud Detection in Python an.


