Vai al contenuto principale

Data Science nel banking: rilevamento delle frodi

Scopri come viene applicata la data science nel settore bancario esplorando uno dei casi d’uso più comuni: il rilevamento delle frodi.
Aggiornato 31 ago 2026  · 11 min leggi

Esplora con l'AI

ChatGPTClaudePerplexity

Illustrazione concettuale di fintech

Il banking è uno di quei settori fortunati in cui storicamente si raccolgono molti dati strutturati, ed è stato anche tra i primi ad adottare tecnologie di data science.

Come viene usata la data science nel banking? Oggi i dati sono diventati l’asset più prezioso in questo ambito. La data science è un requisito necessario per le banche che vogliono tenere il passo con i concorrenti, attrarre più clienti, aumentare la fedeltà di quelli esistenti, prendere decisioni più efficaci basate sui dati, potenziare il business, migliorare l’efficienza operativa, perfezionare servizi/prodotti esistenti e introdurne di nuovi, rafforzare la sicurezza e, di conseguenza, ottenere più ricavi. Non sorprende che la maggior parte della domanda di lavoro in data science provenga dal settore bancario.

La data science permette al settore bancario di svolgere con successo numerosi compiti, tra cui: 

  • analisi del rischio di investimento
  • previsione del valore del cliente nel tempo (CLV)
  • segmentazione della clientela
  • previsione del churn dei clienti
  • marketing personalizzato
  • analisi del sentiment dei clienti
  • assistenti virtuali e chatbot

Di seguito daremo un’occhiata più da vicino a uno dei casi d’uso più comuni della data science nel banking.

Caso d’uso di data science nel banking: rilevamento delle frodi 

Le attività fraudolente rappresentano un problema impegnativo non solo nel banking ma anche in molti altri ambiti, come pubblica amministrazione, assicurazioni, settore pubblico, vendite e sanità. Qualsiasi attività che gestisce un gran numero di transazioni online è esposta a un rischio significativo di frode. I crimini finanziari possono assumere varie forme, tra cui transazioni fraudolente con carte di credito, assegni bancari falsificati, evasione fiscale, riciclaggio di denaro, attacchi informatici, furto di account dei clienti, identità sintetiche, domande false e truffe.

Il rilevamento delle frodi è un insieme di misure proattive adottate per identificare e prevenire attività fraudolente e perdite finanziarie. Le sue principali tecniche analitiche si dividono in due gruppi:

  • Statistiche: calcolo di parametri statistici, regressione, distribuzioni di probabilità, data matching
  • Intelligenza artificiale (AI): data mining, machine learning, deep learning

Il machine learning è un pilastro essenziale per il rilevamento delle frodi. La sua cassetta degli attrezzi offre due approcci:

  • Metodi supervisionati: k-nearest neighbors, regressione logistica, support vector machines, decision tree, random forest, analisi delle serie temporali, reti neurali, ecc.
  • Metodi non supervisionati: analisi dei cluster, analisi dei collegamenti, self-organizing maps, analisi delle componenti principali, riconoscimento delle anomalie, ecc.

Non esiste un algoritmo di machine learning universale e affidabile per il rilevamento delle frodi. Nei casi d’uso reali, si testano di solito diverse tecniche o loro combinazioni, si calcola l’accuratezza predittiva del modello e si seleziona l’approccio ottimale.

La sfida principale per i sistemi di rilevamento delle frodi è adattarsi rapidamente ai pattern di frode e alle tattiche dei truffatori in costante evoluzione e scoprire tempestivamente schemi nuovi e sempre più elaborati. I casi di frode sono sempre una minoranza e sono ben nascosti tra le transazioni reali.

Preparare il dataset

Esploriamo un’implementazione di machine learning per il rilevamento delle frodi su carte di credito usando il linguaggio Python. Lavoreremo sul dataset creditcard_data, un campione modificato da un dataset Kaggle su Credit Card Fraud Detection. I dati originali rappresentano transazioni effettuate con carte di credito intestate a titolari europei in due giorni di settembre 2013.

Importiamo i dati e diamo un’occhiata veloce:

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 

Il dataset contiene le seguenti variabili:

  • Variabili codificate numericamene da V1 a V28 che sono le componenti principali ottenute da una trasformazione PCA. Per motivi di riservatezza, non sono state fornite informazioni di background sulle feature originali.
  • La variabile Amount rappresenta l’importo della transazione.
  • La variabile Class indica se la transazione è stata una frode (1) oppure no (0).

Per loro natura, i casi di frode sono per fortuna una minoranza estrema in qualsiasi elenco di transazioni. Tuttavia, gli algoritmi di machine learning in genere funzionano meglio quando le diverse classi contenute nel dataset sono più o meno ugualmente presenti.  In caso contrario, ci sono pochi dati da cui apprendere. Questo problema è detto squilibrio di classe.

Calcolare le frodi nel dataset

Calcoliamo la percentuale di transazioni fraudolente sul numero totale di transazioni nel nostro dataset:

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

e creiamo un grafico per visualizzare i punti dati di frode rispetto a quelli non fraudolenti:

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)

Transazioni fraudolente

Usare SMOTE per riequilibrare i dati 

Possiamo ora confermare che la percentuale di transazioni fraudolente è molto bassa e che ci troviamo di fronte a un problema di squilibrio di classe. Per risolverlo, possiamo riequilibrare i dati usando la tecnica di oversampling della minoranza sintetica (SMOTE). Diversamente dall’oversampling casuale, SMOTE è leggermente più sofisticato perché non crea semplici copie identiche delle osservazioni. Invece, usa le caratteristiche dei vicini più prossimi dei casi di frode per creare nuovi campioni sintetici abbastanza simili alle osservazioni esistenti nella classe minoritaria. Applichiamo SMOTE ai nostri dati sulle carte di credito:

from imblearn.over_sampling import SMOTE

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

Grafico SMOTE

Come si vede, usando SMOTE otteniamo improvvisamente più osservazioni della classe minoritaria. Per vedere ancora meglio i risultati di questo approccio, li confronteremo con i dati originali:

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

Grafico del metodo SMOTE

Quindi, il metodo SMOTE ha bilanciato completamente i nostri dati e la classe minoritaria ora è pari in dimensioni alla classe maggioritaria.

Torneremo presto all’applicazione pratica di SMOTE, ma per il momento riprendiamo i dati originali e proviamo a rilevare i casi di frode. Seguendo il metodo “old school”, dobbiamo creare alcune regole per intercettare le frodi. Tali regole possono riguardare, ad esempio, luoghi insoliti delle transazioni o una frequenza sospettamente elevata di transazioni. L’idea è definire valori soglia basati su statistiche comuni, spesso sulle medie delle osservazioni, e usare tali soglie sulle nostre feature per rilevare le frodi.

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

Nel nostro caso specifico, applichiamo le seguenti condizioni: V1 < -3 e V3 < -5. Poi, per stimare le prestazioni di questo approccio, confronteremo i casi di frode segnalati con quelli effettivi:

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

Applicare la regressione logistica 

Abbiamo rilevato 22 casi di frode su 50, ma non riusciamo a intercettare gli altri 28 e abbiamo ottenuto 16 falsi positivi. Vediamo se l’uso di tecniche di machine learning può superare questi risultati.

Ora implementeremo un semplice algoritmo di classificazione con regressione logistica sui nostri dati delle carte di credito per individuare le occorrenze fraudolente e poi visualizzeremo i risultati su una matrice di confusione:

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

È importante notare che qui abbiamo meno osservazioni nella matrice di confusione perché usiamo solo il test set per calcolare i risultati del modello, cioè solo il 30% dell’intero dataset.

Abbiamo intercettato una percentuale più alta di casi di frode: 90% (9 su 10), rispetto al risultato precedente del 44% (22 su 50). Abbiamo anche molti meno falsi positivi rispetto a prima, quindi è un miglioramento.

Torniamo ora al problema dello squilibrio di classe discusso in precedenza ed esploriamo se possiamo migliorare ulteriormente i risultati di previsione combinando il modello di regressione logistica con il metodo di campionamento SMOTE. Per farlo in modo efficiente e in un colpo solo, dobbiamo definire una pipeline ed eseguirla sui nostri dati:

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

Come si vede, nel nostro caso SMOTE non ha portato miglioramenti: abbiamo comunque intercettato il 90% delle occorrenze di frode e, per di più, abbiamo un numero leggermente più alto di falsi positivi. La spiegazione è che il ricampionamento non porta necessariamente a risultati migliori in tutti i casi. Quando i casi di frode sono molto dispersi nei dati, i loro vicini più prossimi non sono necessariamente anch’essi casi di frode, quindi usare SMOTE può introdurre bias.

Conclusione 

Come possibile passo successivo, per aumentare l’accuratezza del modello di regressione logistica possiamo ottimizzare alcuni parametri dell’algoritmo. Si può anche considerare la k-fold cross-validation invece di dividere semplicemente il dataset in due parti. Infine, possiamo provare altri algoritmi di machine learning (ad esempio, decision tree o random forest) e vedere se producono risultati migliori. 

Se vuoi approfondire gli aspetti teorici e tecnici dell’implementazione di modelli di rilevamento delle frodi, puoi esplorare i materiali del corso Fraud Detection in Python.

Argomenti
Data Science
Machine Learning
Correlato

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

Mostra AltroMostra Altro