Hoppa till huvudinnehållet

Data science inom bank: bedrägeriupptäckt

Lär dig hur data science används i banksektorn genom att utforska ett av de vanligaste användningsområdena: bedrägeriupptäckt.
Uppdaterad 31 aug. 2026  · 11 min läsa

Utforska med AI

ChatGPTClaudePerplexity

Illustration av fintech-koncept

Bank är ett av de lyckligt lottade områdena där det historiskt har samlats in mycket strukturerad data, och också ett av de första där data science-tekniker tillämpades.

Hur används data science i bank? Idag har data blivit den mest värdefulla tillgången inom detta område. Data science är ett nödvändigt krav för banker för att hålla jämna steg med sina konkurrenter, attrahera fler kunder, öka lojaliteten hos befintliga kunder, fatta mer effektiva datadrivna beslut, stärka verksamheten, höja den operativa effektiviteten, förbättra befintliga tjänster/produkter och introducera nya, förstärka säkerheten och, som ett resultat av allt detta, öka intäkterna. Det är inte förvånande att majoriteten av all efterfrågan på data science-jobb kommer från banksektorn.

Data science gör det möjligt för banksektorn att framgångsrikt utföra många uppgifter, bland annat: 

  • analys av investeringsrisk
  • prognos av kundens livstidsvärde
  • kundsegmentering
  • prognos av kundbortfall
  • personanpassad marknadsföring
  • analys av kundsentiment
  • virtuella assistenter och chattbotar

Nedan tittar vi närmare på ett av de vanligaste användningsfallen för data science i bank.

Användningsfall för data science i bank: upptäcka bedrägerier 

Bedrägliga aktiviteter är ett svårt problem inte bara inom bank utan även inom många andra områden, som offentlig förvaltning, försäkring, offentlig sektor, försäljning och sjukvård. Alla verksamheter som hanterar ett stort antal onlinetransaktioner löper betydande bedrägeririsk. Finansiella brott kan ta olika former, inklusive bedrägliga kreditkorts­transaktioner, förfalskade bankcheckar, skatteflykt, penningtvätt, cyberattacker, kapning av kundkonton, syntetiska identiteter, falska ansökningar och bedrägerier.

Bedrägeriupptäckt är en uppsättning proaktiva åtgärder för att identifiera och förhindra bedrägliga aktiviteter och finansiella förluster. Dess viktigaste analytiska tekniker kan delas in i två grupper:

  • Statistiska: beräkning av statistiska parametrar, regression, sannolikhetsfördelningar, datamatchning
  • Artificiell intelligens (AI): datautvinning, maskininlärning, djupinlärning

Maskininlärning är en grundpelare för bedrägeriupptäckt. Verktygslådan erbjuder två angreppssätt:

  • Övervakade metoder: k-närmaste grannar, logistisk regression, supportvektormaskiner, beslutsträd, random forest, tidsserieanalys, neurala nätverk etc.
  • Oövervakade metoder: klusteranalys, länkanalys, självorganiserande kartor, huvudkomponentanalys, avvikelseigenkänning etc.

Det finns ingen universell och helt tillförlitlig algoritm för maskininlärning vid bedrägeriupptäckt. I stället testas vanligtvis flera tekniker eller kombinationer av dem i verkliga användningsfall inom data science, modellernas prediktiva noggrannhet beräknas och det optimala angreppssättet väljs.

Den största utmaningen för system för bedrägeriupptäckt är att snabbt anpassa sig till ständigt föränderliga bedrägarmönster och bedragarnas taktiker samt snabbt avslöja nya och allt mer sofistikerade upplägg. Bedrägerifall är alltid i minoritet och är väl dolda bland de verkliga transaktionerna.

Förbereda datasetet

Låt oss utforska en implementering av maskininlärning för upptäckt av kreditkortsbedrägerier med programmeringsspråket Python. Vi arbetar med datasetet creditcard_data, som är ett modifierat urval från ett Kaggle-dataset om Credit Card Fraud Detection. De ursprungliga uppgifterna representerar transaktioner som gjorts med kreditkort ägda av europeiska kortinnehavare under två dagar i september 2013.

Låt oss importera datan och titta snabbt på den:

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 

Datasetet innehåller följande variabler:

  • Numeriskt kodade variabler V1 till V28 som är huvudkomponenterna från en PCA-transformering. På grund av sekretessfrågor gavs ingen bakgrundsinformation om de ursprungliga variablerna.
  • Variabeln Amount representerar transaktionsbeloppet.
  • Variabeln Class visar om transaktionen var ett bedrägeri (1) eller inte (0).

Till sin natur är bedrägerihändelser tack och lov en extrem minoritet i alla transaktionslistor. Maskininlärningsalgoritmer fungerar dock oftast bäst när de olika klasserna i datasetet är mer eller mindre lika representerade.  Annars finns det för lite data att lära av. Detta problem kallas klassobalans.

Beräkna bedrägeri i datasetet

Låt oss beräkna andelen bedrägliga transaktioner av det totala antalet transaktioner i vårt dataset:

round(creditcard_data['Class'].value_counts()*100/len(creditcard_data)).convert_dtypes()
0    99
1     1
Name: Class, dtype: Int64

och skapa ett diagram för att visualisera datapunkterna för bedrägeri respektive icke-bedrägeri:

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)

Bedrägliga transaktioner

Använda SMOTE för att återbalansera data 

Vi kan nu bekräfta att andelen bedrägliga transaktioner är mycket låg och att vi har ett fall av klassobalans. För att åtgärda detta kan vi återbalansera våra data med hjälp av den syntetiska minoritetsöversamplings­tekniken (SMOTE). Till skillnad från slumpmässig översampling är SMOTE något mer sofistikerat eftersom det inte bara skapar exakta kopior av observationer. I stället använder det egenskaper hos närmaste grannar till bedrägerifall för att skapa nya, syntetiska prover som liknar de befintliga observationerna i minoritetsklassen. Låt oss tillämpa SMOTE på våra kreditkortsdata:

from imblearn.over_sampling import SMOTE

method = SMOTE()
X_resampled, y_resampled = method.fit_resample(X, y)
plot_data(X_resampled, y_resampled)

SMOTE-diagram

Som vi ser ger SMOTE oss plötsligt fler observationer av minoritetsklassen. För att se resultaten av detta angreppssätt ännu tydligare jämför vi dem med originaldatan:

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

Graf för SMOTE-metod

Följaktligen har SMOTE-metoden balanserat våra data helt, och minoritetsklassen är nu lika stor som majoritetsklassen.

Vi återkommer snart till den praktiska tillämpningen av SMOTE-metoden, men låt oss nu gå tillbaka till originaldatan och försöka upptäcka bedrägerifallen. Enligt det "+old-school+"-sättet måste vi skapa vissa regler för att fånga bedrägeri. Sådana regler kan till exempel röra ovanliga platser för transaktioner eller misstänkt frekventa transaktioner. Tanken är att definiera tröskelvärden baserat på vanlig statistik, ofta på medelvärden av observationer, och använda dessa trösklar på våra variabler för att upptäcka bedrägeri.

print(creditcard_data.groupby('Class').mean().round(3)[['V1', 'V3']])
        V1     V3
Class             
0      0.035  0.037
1     -4.985 -7.294

I vårt specifika fall tillämpar vi följande villkor: V1 < -3 och V3 < -5. För att sedan uppskatta hur väl detta angreppssätt fungerar jämför vi de flaggade bedrägerifallen med de faktiska:

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

Tillämpa logistisk regression 

Vi upptäckte 22 av 50 bedrägerifall, men missade de övriga 28, och fick 16 falska positiva. Låt oss se om användning av maskininlärning kan slå de resultaten.

Nu implementerar vi en enkel klassificeringsalgoritm med logistisk regression på våra kreditkortsdata för att identifiera bedrägliga händelser och visualiserar sedan resultaten i en konfusionsmatris:

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

Det är viktigt att notera att vi här har färre observationer i konfusionsmatrisen eftersom vi bara använder testmängden för att beräkna modellens resultat, dvs. endast 30% av hela datasetet.

Vi fångade en högre andel bedrägerifall: 90% (9 av 10), jämfört med det tidigare resultatet 44% (22 av 50). Vi fick också betydligt färre falska positiva än tidigare, så det är en förbättring.

Låt oss nu återvända till problemet med klassobalans som diskuterades tidigare och undersöka om vi kan förbättra prediktionsresultaten ytterligare genom att kombinera den logistiska regressionsmodellen med SMOTE-återsampling. För att göra det effektivt och i ett enda steg behöver vi definiera en pipeline och köra den på våra data:

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

Som vi ser gav SMOTE i vårt fall inga förbättringar: vi fångade fortfarande 90% av bedrägerifallen och dessutom har vi något fler falska positiva. Förklaringen är att återsampling inte nödvändigtvis leder till bättre resultat i alla fall. När bedrägerifallen är mycket utspridda i datan är deras närmaste grannar inte nödvändigtvis också bedrägerifall, så användning av SMOTE kan introducera en bias.

Slutsats 

Som en möjlig väg framåt, för att öka noggrannheten i den logistiska regressionsmodellen, kan vi finjustera vissa av algoritmens parametrar. K-faldig korsvalidering kan också övervägas i stället för att bara dela datasetet i två delar. Slutligen kan vi prova andra maskininlärningsalgoritmer (t.ex. beslutsträd eller random forest) och se om de ger bättre resultat. 

Om du vill lära dig mer om de teoretiska och tekniska aspekterna av implementering av modeller för bedrägeriupptäckt kan du utforska materialet i kursen Fraud Detection in Python.

Ämnen
Data science
Maskininlärning