Luiz Felipe P. Figueiredo
  • Home
  • Tech Skills
  • Skill Sets
  • Work Experience
  • Projects
  • Dashboards
  • Blog
  • About me

Detecção de transações fraudulentas com Cartões de Crédito

  • Mostrar o código
  • Esconder o código

  • Ver o código fonte
Python
Machine Learning
Desenvolvimento de modelo de Machine Learning para detecção de fraudes em cartões.
Autor

Luiz Felipe P. Figueiredo

Data de Publicação

03/12/2023

Objetivo

Este projeto tem como objetivo, desenvolver um modelo de aprendizado de maquina a fim de detectar transações fraudulentas envolvendo cartões de crédito. Isso será alcançado por meio da exploração e aplicação de vários algoritmos de aprendizado de máquina, seguidos pela avaliação e comparação de métricas de desempenho com o objetivo de selecionar o modelo mais eficaz.

Descrição dos Dados

Os dados que serão utilizado neste projeto, foram retirados do kaggle. Trata-se de uma base de dados que contém transações feitas por cartões de créditos europeus em setembro de 2013. Além disso a base de dados contém 28 variáveis ou colunas que foram anonimizadas a fim de proteger a sigilosidade dos dados em questão.

Descrição das variáveis

  • Time - Segundos que se passaram entre cada transação e a primeira transação no dataset;
  • V1 a V28 - Variáveis anonimizadas devido a confidencialidade dos dados, essa variáveis foram transformadas utilizando Análise de Componentes Principais;
  • Amount - Valor de cada transação;
  • Class - Variável resposta, onde 1 equivale a uma compra fraudulenta e 0 com não fraudulenta.
Código
# bibliotecas utilizadas
import numpy as np
import pandas as pd
import plotly.io as pio
pio.renderers.default = "notebook_connected"
import plotly.colors as colors
import plotly.express as px
import plotly.graph_objects as go
from sklearn.preprocessing import RobustScaler

Verificação dos Dados

Código
# preview do dataset
df = pd.read_csv("C:/Users/luisf/Desktop/DATACAMP/Portfolio/datasets/credit_card_fraud/creditcard.csv")
df.head()
Time V1 V2 V3 V4 V5 V6 V7 V8 V9 ... V21 V22 V23 V24 V25 V26 V27 V28 Amount Class
0 0.0 -1.359807 -0.072781 2.536347 1.378155 -0.338321 0.462388 0.239599 0.098698 0.363787 ... -0.018307 0.277838 -0.110474 0.066928 0.128539 -0.189115 0.133558 -0.021053 149.62 0
1 0.0 1.191857 0.266151 0.166480 0.448154 0.060018 -0.082361 -0.078803 0.085102 -0.255425 ... -0.225775 -0.638672 0.101288 -0.339846 0.167170 0.125895 -0.008983 0.014724 2.69 0
2 1.0 -1.358354 -1.340163 1.773209 0.379780 -0.503198 1.800499 0.791461 0.247676 -1.514654 ... 0.247998 0.771679 0.909412 -0.689281 -0.327642 -0.139097 -0.055353 -0.059752 378.66 0
3 1.0 -0.966272 -0.185226 1.792993 -0.863291 -0.010309 1.247203 0.237609 0.377436 -1.387024 ... -0.108300 0.005274 -0.190321 -1.175575 0.647376 -0.221929 0.062723 0.061458 123.50 0
4 2.0 -1.158233 0.877737 1.548718 0.403034 -0.407193 0.095921 0.592941 -0.270533 0.817739 ... -0.009431 0.798278 -0.137458 0.141267 -0.206010 0.502292 0.219422 0.215153 69.99 0

5 rows × 31 columns

Verificação de Valores Faltantes e dados desbalanceados.

Código
# Verificação de valores faltantes
n_valores_faltantes = int(df[df.columns[df.isnull().any()]].isnull().sum().sum())
print(f'Existe um total de {n_valores_faltantes} valores faltantes nesta base de dados')
Existe um total de 0 valores faltantes nesta base de dados
Código
# Verificando Dados Desbalanceados
dist_class = pd.DataFrame({'Class':df['Class'].map({0:'Fraude', 1:'Não Fraude'}).value_counts().index, 
                           'Contagem':df['Class'].map({0:'Fraude', 1:'Não Fraude'}).value_counts().values})

fig = px.bar(dist_class, x='Class', y= 'Contagem', log_y=True ,title = 'Distribuição da Variável Class', labels=dict(x='Class', y='Frequência'))
fig.show()

Acima, pode-se se verificar que não existem valores faltantes neste dataset, além disso, estes dados são extremamente desbalanceados, a variável resposta Class contem 284.315 compras legitimas e somente 492 compras fraudulentas, deste modo, será necessário implementar técnicas para tratar este desbalanceamento, pois, implementar um modelo de aprendizado de maquina seria um problema e com certeza geraria um modelo com desempenho ruim.

Tratamento De Dados

Como as variáveis Time e Amount não foram dimensionadas, é preciso realizar a transformação dessas variáveis, utilizando o sklearn.preprocessing.RobustScaler já que esse “scaler” é robusto para outliers [1].

Código
# Dimensionamento das variáveis Time e Amount
#robust_scaler = RobustScaler()

#df['Dim_Amount'] = robust_scaler.fit_transform(df['Amount'].values.reshape(-1, 1))
#df['Dim_Time'] = robust_scaler.fit_transform(df['Time'].values.reshape(-1, 1))
#df.drop(['Time','Amount'], axis=1, inplace=True)
Código
# Supondo que 'df' seja o seu DataFrame
holder = pd.DataFrame()

# Atribuir as colunas 'Amount', 'Time' e 'Class' a variáveis separadas
holder['Amount'] = df['Amount']
holder['Time'] = df['Time']
holder['Class'] = df['Class']

df= df.drop(['Time', 'Amount', 'Class'], axis=1)
Código
holder
Amount Time Class
0 149.62 0.0 0
1 2.69 0.0 0
2 378.66 1.0 0
3 123.50 1.0 0
4 69.99 2.0 0
... ... ... ...
284802 0.77 172786.0 0
284803 24.79 172787.0 0
284804 67.88 172788.0 0
284805 10.00 172788.0 0
284806 217.00 172792.0 0

284807 rows × 3 columns

Tratando Dados Desbalanceados

Uma técnica que é amplamente utilizada é a Synthetic Minority Over-sampling Technique também conhecida como SMOTE, trata-se de uma técnica que gera dados sintéticos com base na classe de minoria, neste projeto, denotada como fraude ou Class = 0, a fim de balancear a distribuição da variável em questão. Esta técnica atua criando novas instâncias sintéticas que são combinações das instâncias existentes da classe minoritária da variável resposta [2,3].

Outra técnica que pode ser utilizada, é a Fuzzy C-Means

Código
data=df

c=5

import skfuzzy as fuzz

cntr, u, u0, d, jm, p, fpc= fuzz.cmeans(data.T, c, m=2, error=0.005, maxiter=1000)
Código
labels = np.argmax(u, axis=0)
df['Amount'] = holder['Amount']
df['Time'] = holder['Time']
df['Class'] = holder['Class']
df['Cluster'] = labels
Código
df[df['Cluster']==3]['Class'].value_counts()
0    45
Name: Class, dtype: int64
Código
df['Class'].value_counts()
0    284315
1       492
Name: Class, dtype: int64
Código
def extrai_dataset_balanceado(df = pd.DataFrame(), ratios=tuple):
    temp_df = pd.DataFrame()
    # entro no primeiro cluster
    for cluster in range(0, 5):
        center = round(len(df[df['Cluster']==cluster])/2) # encontro o index do meio
        if df[df['Cluster']==cluster]['Class'].iloc[center] == 0: # se o index for uma fraude
            temp_df = pd.concat([temp_df, df[df['Cluster'] == cluster].iloc[center:center+1]])
        else:
            for i in range(0, center]):
                if df[df['Cluster']==cluster]['Class'].iloc[center - i] == 0:
                    temp_df = pd.concat([temp_df, df[df['Cluster'] == cluster].iloc[center:center+1-i]])
                for j in range(df[df['Cluster']==cluster]):
                    if df[df['Cluster']==cluster]['Class'].iloc[center + i] == 0:   


Código
cluster = 0
center = round(len(df[df['Cluster']==cluster])/2)
novo_df = pd.DataFrame()
pd.concat([novo_df, df[df['Cluster'] == cluster].iloc[center:center+1]])
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 ... V23 V24 V25 V26 V27 V28 Amount Time Class Cluster
141127 -0.748337 1.352324 1.21948 0.001557 -0.321504 -0.940654 0.385059 0.323884 -0.663196 -0.553007 ... 0.021669 0.383776 -0.148222 0.071436 0.144934 0.059351 1.79 84137.0 0 0

1 rows × 32 columns

Código
df[df['Cluster'] == cluster].iloc[center]
V1            -0.748337
V2             1.352324
V3             1.219480
V4             0.001557
V5            -0.321504
V6            -0.940654
V7             0.385059
V8             0.323884
V9            -0.663196
V10           -0.553007
V11           -0.432604
V12            0.465073
V13            0.756511
V14            0.325729
V15            0.735773
V16            0.288397
V17           -0.262055
V18           -0.396918
V19            0.004576
V20            0.026471
V21           -0.178891
V22           -0.550972
V23            0.021669
V24            0.383776
V25           -0.148222
V26            0.071436
V27            0.144934
V28            0.059351
Amount         1.790000
Time       84137.000000
Class          0.000000
Cluster        0.000000
Name: 141127, dtype: float64

Referências

  • 1 - Scikit-learn developers. RobustScaler. Scikit-learn: machine learning in Python. Disponível em: link. Acesso em: 05 dez. 2023.
  • 2 - BROWNLEE, Jason. SMOTE for Imbalanced Classification with Python. Machine Learning Mastery, 2020. Disponível em: <1>. Acesso em: 05 dez. 2023.
  • 3 - GENESIS. SMOTE: Synthetic Minority Oversampling Technique. From The GENESIS, 2018. Disponível em: <1>. Acesso em: 05 dez. 2023.
Código
teste = pd.read_excel('/Users/luisf/Desktop/Planilha sem título.xlsx')
teste.columns
Index(['ANO ', 'LOJA', 'JANEIRO', 'FEVEREIRO', 'MARÇO', 'ABRIL', 'MAIO ',
       'JUNHO ', 'JULHO ', 'AGOSTO', 'SETEMBRO', 'OUTUBRO', 'NOVEMBRO ',
       'DEZEMBRO'],
      dtype='object')
Código
# Reestruturando os dados para o formato "long" para usar com Plotly Express
teste_melted = teste.melt(id_vars=["ANO ", "LOJA"], var_name="Mês", value_name="Vendas")

# Criando o gráfico de linhas com Plotly Express
fig = px.line(teste_melted[teste_melted['ANO ']==2018], x="Mês", y="Vendas", color="LOJA",
              title='Vendas Mensais por Loja', markers=True)

# Mostrando o gráfico
fig.show()
Código
help(pd.melt)

ADASYN TOMEK Links SMOTE Under e Oversampling

Hibridos

Código
240 - 200
40
Código
40/20
2.0
This work is licensed under CC BY-SA 4.0
Designed and Developed collaboratively by
Jose C. S. Junior & Luiz F. P. Figueiredo
Built with Quarto