Pular para o conteúdo principal

Data science no setor bancário: detecção de fraude

Aprenda como a data science é aplicada no setor bancário explorando um dos casos de uso mais comuns: detecção de fraude.
Atualizado 31 de ago. de 2026  · 11 min lido

Explorar com IA

ChatGPTClaudePerplexity

Ilustração de conceito de fintech

O setor bancário é um dos poucos que historicamente coletam grandes volumes de dados estruturados e também um dos primeiros a adotar tecnologias de data science.

Como a data science é usada em bancos? Hoje, os dados se tornaram o ativo mais valioso nessa área. A data science é essencial para que os bancos acompanhem os concorrentes, atraiam mais clientes, aumentem a fidelidade dos atuais, tomem decisões mais eficientes baseadas em dados, impulsionem o negócio, ganhem eficiência operacional, aprimorem serviços e produtos existentes e lancem novos, reforcem a segurança e, como resultado de tudo isso, aumentem a receita. Não é surpresa que a maior parte da demanda por profissionais de data science venha do setor bancário.

A data science permite que a indústria bancária execute com sucesso diversas tarefas, incluindo: 

  • análise de risco de investimento
  • previsão de valor do ciclo de vida do cliente (CLV)
  • segmentação de clientes
  • previsão de churn de clientes
  • marketing personalizado
  • análise de sentimento do cliente
  • assistentes virtuais e chatbots

A seguir, vamos detalhar um dos casos de uso mais comuns de data science em bancos.

Caso de uso de data science em bancos: detecção de fraude 

Atividades fraudulentas são um desafio não só no setor bancário, mas também em áreas como governo, seguros, setor público, vendas e saúde. Qualquer negócio que lide com um grande volume de transações online corre um risco significativo de fraude. Crimes financeiros podem assumir várias formas, como transações fraudulentas com cartão de crédito, cheques bancários falsificados, sonegação fiscal, lavagem de dinheiro, ataques cibernéticos, roubo de contas de clientes, identidades sintéticas, aplicações falsas e golpes.

A detecção de fraude é um conjunto de medidas proativas para identificar e prevenir atividades fraudulentas e perdas financeiras. Suas principais técnicas analíticas podem ser divididas em dois grupos:

  • Estatísticas: cálculo de parâmetros estatísticos, regressão, distribuições de probabilidade, correspondência de dados
  • Inteligência artificial (IA): mineração de dados, machine learning, deep learning

O machine learning é um pilar essencial na detecção de fraudes. Seu conjunto de ferramentas oferece duas abordagens:

  • Métodos supervisionados: k-vizinhos mais próximos, regressão logística, máquinas de vetor de suporte, árvore de decisão, random forest, análise de séries temporais, redes neurais, etc.
  • Métodos não supervisionados: análise de clusters, análise de vínculos, mapas auto-organizáveis, análise de componentes principais, reconhecimento de anomalias, etc.

Não existe um algoritmo universal e infalível de machine learning para detecção de fraude. Em casos reais de data science, normalmente testamos várias técnicas ou combinações delas, calculamos a acurácia preditiva do modelo e escolhemos a melhor abordagem.

O grande desafio dos sistemas de detecção de fraude é se adaptar rapidamente a padrões e táticas que mudam o tempo todo e identificar com agilidade esquemas novos e cada vez mais elaborados. Casos de fraude são sempre minoria e ficam bem ocultos entre as transações legítimas.

Preparando o dataset

Vamos explorar uma implementação de detecção de fraude em cartão de crédito usando a linguagem Python. Vamos trabalhar com o dataset creditcard_data, que é uma amostra modificada de um conjunto do Kaggle sobre Credit Card Fraud Detection. Os dados originais representam transações feitas em cartões de crédito de clientes europeus durante dois dias de setembro de 2013.

Vamos importar os dados e dar uma olhada rápida:

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 

O dataset contém as seguintes variáveis:

  • Variáveis numericamente codificadas de V1 a V28, que são componentes principais obtidos por uma transformação PCA. Por questões de confidencialidade, não há informações de contexto sobre as variáveis originais.
  • A variável Amount representa o valor da transação.
  • A variável Class indica se a transação foi fraudulenta (1) ou não (0).

Por natureza, ocorrências de fraude felizmente são uma minoria extrema em qualquer lista de transações. Porém, algoritmos de machine learning tendem a funcionar melhor quando as classes no dataset estão mais ou menos igualmente representadas. Caso contrário, há poucos dados para aprender. Esse problema é conhecido como desbalanceamento de classes.

Calculando a taxa de fraude no dataset

Vamos calcular a porcentagem de transações fraudulentas em relação ao total de transações no nosso dataset:

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

e criar um gráfico para visualizar os pontos de dados de fraude versus não fraude:

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)

Transações fraudulentas

Usando SMOTE para reequilibrar os dados 

Agora conseguimos confirmar que a proporção de transações fraudulentas é muito baixa e que temos um caso de desbalanceamento de classes. Para corrigir, podemos reequilibrar os dados usando a técnica de oversampling da minoria sintética (SMOTE). Diferente do oversampling aleatório, o SMOTE é um pouco mais sofisticado, pois não cria apenas cópias exatas das observações. Em vez disso, usa características dos vizinhos mais próximos dos casos de fraude para gerar novas amostras sintéticas, bastante semelhantes às observações existentes na classe minoritária. Vamos aplicar SMOTE aos nossos dados de cartão de crédito:

from imblearn.over_sampling import SMOTE

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

Gráfico SMOTE

Como podemos ver, o uso do SMOTE passa a gerar mais observações da classe minoritária. Para enxergar ainda melhor os resultados, vamos compará-los com os dados originais:

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

Gráfico do método SMOTE

Ou seja, o método SMOTE balanceou completamente nossos dados, e a classe minoritária agora tem o mesmo tamanho da classe majoritária.

Voltaremos em breve à aplicação prática do SMOTE, mas por enquanto vamos retomar os dados originais e tentar detectar casos de fraude. Seguindo a abordagem "old school", precisamos criar algumas regras para capturar fraudes. Essas regras podem considerar, por exemplo, locais incomuns de transações ou frequência suspeita de compras. A ideia é definir valores de corte com base em estatísticas comuns, muitas vezes nas médias das observações, e usar esses limites nas features para detectar fraude.

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

No nosso caso específico, vamos aplicar as seguintes condições: V1 < -3 e V3 < -5. Em seguida, para estimar o desempenho dessa abordagem, vamos comparar os casos de fraude sinalizados com os reais:

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

Aplicando regressão logística 

Detectamos 22 de 50 casos de fraude, mas deixamos 28 passarem e ainda tivemos 16 falsos positivos. Vamos ver se técnicas de machine learning conseguem superar esses resultados.

Agora vamos implementar um algoritmo simples de classificação por regressão logística nos nossos dados de cartão de crédito para identificar ocorrências fraudulentas e, em seguida, visualizar os resultados em uma matriz de confusão:

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 notar que temos menos observações na matriz de confusão porque estamos usando apenas o conjunto de teste para calcular os resultados do modelo, isto é, somente 30% do dataset.

Capturamos uma porcentagem maior de casos de fraude: 90% (9 de 10), comparado ao resultado anterior de 44% (22 de 50). Também tivemos bem menos falsos positivos do que antes, o que já é uma melhoria.

Agora, vamos voltar ao problema de desbalanceamento de classes discutido anteriormente e verificar se conseguimos aumentar ainda mais a qualidade das previsões combinando o modelo de regressão logística com o método de reamostragem SMOTE. Para fazer isso de forma eficiente e de uma vez só, precisamos definir um pipeline e executá-lo nos dados:

from imblearn.pipeline import Pipeline

# Definindo qual método de reamostragem e qual modelo de ML usar no 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

Como podemos ver, neste caso o SMOTE não trouxe melhorias: ainda capturamos 90% das ocorrências de fraude e, além disso, tivemos um número um pouco maior de falsos positivos. A explicação é que a reamostragem nem sempre leva a melhores resultados. Quando os casos de fraude estão muito dispersos nos dados, seus vizinhos mais próximos nem sempre são fraudes; assim, o SMOTE pode introduzir viés.

Conclusão 

Como próximos passos para aumentar a acurácia da regressão logística, podemos ajustar alguns parâmetros do algoritmo. Também vale considerar K-fold cross-validation em vez de simplesmente dividir o dataset em duas partes. Por fim, podemos experimentar outros algoritmos de machine learning (por exemplo, árvore de decisão ou random forest) e avaliar se trazem resultados melhores. 

Se você quiser se aprofundar nos aspectos teóricos e técnicos da implementação de modelos de detecção de fraude, explore o curso Fraud Detection in Python.

Tópicos
Ciência de dados
Aprendizado de máquina