0% encontró este documento útil (0 votos)
9 vistas77 páginas

Tfm-2024 Tamarit Domã - Nguez, Jesã - S

Este trabajo de fin de máster presenta un modelo de inteligencia artificial diseñado para detectar fraude en transacciones con tarjetas de crédito, utilizando un conjunto de datos previamente procesado. Se llevó a cabo un análisis gráfico para identificar características relevantes y se entrenó el modelo ajustando sus parámetros para optimizar su rendimiento. Finalmente, se sugieren métodos para mejorar y ampliar el proyecto mediante diversas técnicas y procedimientos.

Cargado por

joviqui8
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
9 vistas77 páginas

Tfm-2024 Tamarit Domã - Nguez, Jesã - S

Este trabajo de fin de máster presenta un modelo de inteligencia artificial diseñado para detectar fraude en transacciones con tarjetas de crédito, utilizando un conjunto de datos previamente procesado. Se llevó a cabo un análisis gráfico para identificar características relevantes y se entrenó el modelo ajustando sus parámetros para optimizar su rendimiento. Finalmente, se sugieren métodos para mejorar y ampliar el proyecto mediante diversas técnicas y procedimientos.

Cargado por

joviqui8
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Trabajo Fin de Máster

Máster en Ingeniería Electrónica, Robótica y


Automática

Inteligencia artificial para la detección de fraude


en transacciones realizadas con tarjetas de crédito

Autor: Jesús Tamarit Domínguez


Tutor: Rubén Martín Clemente

Equation Chapter 1 Section 1

Dpto. Teoría de la Señal y Comunicaciones


Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2021
Dpto. Ingeniería de Sistemas y Automática
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2019
Trabajo Fin de Máster
Máster en Ingeniería Electrónica, Robótica y Automática

Inteligencia artificial para la detección de fraude


en transacciones realizadas con tarjetas de
crédito

Autor:
Jesús Tamarit Domínguez

Tutor:
Rubén Martín Clemente
Profesor titular

Dpto. Teoría de la Señal y Comunicaciones


Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2021
Trabajo Fin de Máster:
Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de
crédito

Autor: Jesús Tamarit Domínguez

Tutor: Rubén Martín Clemente

El tribunal nombrado para juzgar el Trabajo arriba indicado, compuesto por los siguientes
miembros:

Presidente:

Vocales:

Secretario:

Acuerdan otorgarle la calificación de:

Sevilla, 2021

El Secretario del Tribunal


A mi familia
A mis maestros
Resumen

En este proyecto se ha abordado el problema de la detección de fraude en transacciones


bancarias utilizando un modelo de inteligencia artificial ajustado y entrenado con un conjunto
de datos relativos a dichas transacciones que se ha procesado anteriormente. Estos datos
contienen información sobre cada transacción y su emisor y se han cargado usando librerías
de manejo de datos y reduciendo tanto su uso de memoria como su dimensionalidad para
mejorar el entrenamiento del modelo. Por otro lado, se ha realizado un análisis gráfico de las
distintas características a fin de denotar las más importantes.
Posteriormente, se ha realizado el entrenamiento de un modelo de Inteligencia Artificial con
estos datos. Además, se ha realizado un ajuste de los parámetros de dicho modelo para
conseguir los mejores resultados, los cuales se han analizado.
Finalmente, se han propuesto diferentes formas de mejorar y extender el proyecto utilizando
distintas técnicas y procedimientos.

Abstract
In this project, the problem of detecting fraud in banking transactions has been addressed
using an artificial intelligence model adjusted and trained with a set of data related to said
transactions that has been previously processed. This data contains information about each
transaction and its issuer and has been loaded using data management libraries and reduced
its memory usage and dimensionality to improve model training. On the other hand, a
graphic analysis of the different characteristics has been carried out in order to denote the
most important ones.
Subsequently, the training of an Artificial Intelligence model with these data has been carried
out. In addition, an adjustment of the parameters of said model has been carried out to
achieve the best results, which have been analyzed.
Finally, different ways to improve and extend the project have been proposed using different
techniques and procedures.
Índice

Resumen 8
Índice 9
Índice de Figuras 11
1 Introducción 1
1.1 Modelos de Inteligencia Artificial 2
1.2 Objetivos y Estructura de la memoria 3
2 Preparación y Carga de Datos 5
2.1 Preparación del entorno 5
2.2 Importación de los datos 10
2.3.1 Usando Google Drive 11
2.3.2 Usando archivos locales 11
2.3 Procesamiento inicial 13
2.4 Reducción de tamaño 14
3 Análisis de los Datos 17
3.1 Identificación de columnas 17
3.2 Análisis gráfico de variables 19
3.2.1 Proveedor, Tipo de tarjeta y Tipo de dispositivo (isFraud, card4, card6 y DeviceType) 21
3.2.2 Proveedor de correo electrónico del emisor (P_emaildomain) 22
3.2.3 Sistema Operativo (Id_30) 23
3.2.4 Navegador Web (Id_31) 24
3.3 Análisis en el tiempo 25
4 Técnicas de Reducción de la Dimensionalidad 27
4.1 Missing Value Ratio 28
4.2 Low Variance Filter 28
4.3 High Correlation Filter 29
4.4 Principal Component Analysis 29
4.5 Random Forests 30
4.6 Linear Discriminant Analysis 31
4.7 Autoencoder 32
4.8 t-distributed Stochastic Neighbor Embedding (t-SNE) 32
4.9 Aplicación de estas técnicas al algoritmo 33
5 Preparación de los Datos para el Modelo 35
5.1 Codificación de variables categóricas 35
5.2 División de los datos 36
5.3 Almacenamiento de los datos 38
6 Creación y Entrenamiento del Modelo 39
6.1 Función de evaluación del modelo 39
6.2 Modelos de clasificación 43
6.3 Creación del modelo 43
6.4 Elección de hiperparámetros 47
6.5 Entrenamiento del modelo y resultados 52
6.5.1 Importancia de las características 55
6.5.2 Curva ROC 56
6.5.3 Diagrama de árbol 57
6.5.4 Cálculo de fraudes totales detectados 57
6.6 Almacenamiento de resultados en un archivo externo 59
6.6.1 Subida a Kaggle 59
7 Desarrollos futuros y Conclusiones 61
Referencias 63
Glosario 64
ÍNDICE DE F IGURAS

Figura 1-1. Fraudes con tarjetas de crédito en EE. UU. 1


Figura 1-2. Comparación entre pagos en efectivo y con tarjeta (Billones de £) 2
Figura 1-3. Esquema general de una red neuronal 2
Figura 2-1. Logo de Python 5
Figura 2-2. Logo de Visual Studio Code 6
Figura 2-3. Comparación entre Matplotlib y Seaborn 6
Figura 2-4. Ejemplo de un Pairplot 7
Figura 2-5. Paquetes de SKLearn 8
Figura 2-6. Ejemplo de un diagrama de grafos 9
Figura 2-7. Primeras filas del dataset train_transaction 12
Figura 2-8. Primeras filas del dataset train_identity 12
Figura 2-9. Comparación entre datasets train y test 13
Figura 2-10. Columnas del dataset test renombradas 14
Figura 2-11. Primeras filas del dataset train 16
Figura 3-1. Logo de Seaborn 17
Figura 3-2. Relación entre cantidad monetaria y fraude 19
Figura 3-3. Distribución Fraude/No Fraude en card4 (Proveedor), card6 (Tipo de tarjeta) y
DeviceType 21
Figura 3-4. Distribución Fraude/No Fraude en P_emaildomain 22
Figura 3-5. Distribución Fraude/No Fraude en id_30 23
Figura 3-6. Distribución Fraude/No Fraude en id_31 24
Figura 3-7. Histograma de la variable TransactionDT 25
Figura 3-8. División de datos usando TimeSeriesSplit() 26
Figura 4-1. Técnicas de reducción de la dimensionalidad 27
Figura 4-2. Correlación entre algunas de las variables 29
Figura 4-3. Ejemplo de Principal Component Analisys 30
Figura 4-4. Ejemplo del cálculo de la importancia de las características 30
Figura 4-5. Ejemplo de Linear Discriminant Analisys 31
Figura 4-6. Diagrama de un Autoencoder 32
Figura 4-7. Resultado de t-SNE en el dataset "MNIST" (Dataset de imágenes de números)
33
Figura 5-1. Ejemplo del uso de un LabelEncoder() 36
Figura 5-2. División de datasets 37
Figura 6-1. Entrenamiento y uso del modelo 39
Figura 6-2. Curva ROC 40
Figura 6-3. Diversos puntos en la ROC 40
Figura 6-4. Diversos puntos en la ROC invertidos 41
Figura 6-5. Valor AUC según la curva ROC 41
Figura 6-6. Algoritmo de entrenamiento 47
Figura 6-7. Combinaciones de valores de parámetros 49
Figura 6-8. Puntuaciones obtenidas en cada Fold 54
Figura 6-9. Puntuaciones obtenidas en cada Fold en Entrenamiento 54
Figura 6-10. Importancia de las características en el modelo entrenado 55
Figura 6-11. Curva ROC 56
Figura 6-12. Porción del diagrama de grafos del modelo 57
Figura 6-13. Valores de las predicciones en X_test (Recortada en el eje Y) 58
Figura 6-14. Primeras filas del archivo CSV 59
Figura 6-15. Puntuación final conseguida en Kaggle 59
1 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

1 INTRODUCCIÓN
“La inteligencia artificial va a
tener un impacto mayor que el
descubrimiento del fuego”
- Sundar Pichai -

E n las últimas décadas hemos podido asistir y observar el auge y la implantación de la


digitalización en las transacciones financieras. La tecnología ha avanzado tanto que
incluso ya se pueden realizar pagos con tarjetas de crédito utilizando un teléfono móvil
o incluso un “wearable”.
Estas tecnologías mejoran la experiencia del usuario y le aportan comodidad y rapidez, pero,
junto a las numerosas ventajas que tienen este tipo de operaciones, también aparecen algunas
desventajas y la principal es el aumento de los fraudes en estas transacciones.

Figura 1-1. Fraudes con tarjetas de crédito en EE. UU.

En los últimos años ha habido un gran incremento del número de transacciones totales con
tarjetas de crédito. Además, este número se espera que se incremente cada vez más. Debido a
esto, las entidades bancarias necesitan desarrollar una tecnología de seguridad adicional a las
ya existentes que se encargue de analizar las transacciones que se realicen a fin de detectar las
Introducción 2

que puedan ser fraudulentas.

Figura 1-2. Comparación entre pagos en efectivo y con tarjeta (Billones de £)

1.1 Modelos de Inteligencia Artificial


Para la detección del fraude en las transacciones con tarjetas de crédito se va a entrenar y
utilizar un modelo de Inteligencia Artificial. Este modelo seguirá el esquema de una red
neuronal, en la cual existirán un determinado número de entradas, capas de nodos ocultos y
salidas.

Figura 1-3. Esquema general de una red neuronal


Las entradas del modelo se corresponderán a las características que se vayan a utilizar como
características en el entrenamiento. Ya que el objetivo del entrenamiento es la detección de
fraude en transacciones con tarjetas de crédito, las características que se usarán estarán
3 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

relacionadas con los datos de las tarjetas (Número, fabricante, etc.) y los datos relativos al
dispositivo emisor de la transacción (Sistema operativo, tipo de dispositivo, etc.). Además,
cada transacción tendrá relacionado un número de identificación (TransactionID) y una
variable de tiempo (TransactionDT). Estas características se verán con más detalle en el
Apartado 3.1.
Los nodos ocultos se organizan en capas de tamaño variable y se encargarán de realizar los
distintos cálculos y relaciones entre las diferentes entradas, asignando a cada nodo un peso
distinto durante el entrenamiento.
Finalmente, los nodos de salida agrupan todas las relaciones anteriores y, en el caso de un
sistema clasificador como el que se tiene, asignará a cada clase de salida una probabilidad de
predicción.
Como en este caso las únicas salidas posibles a predecir van a ser “fraude” y “no fraude” se
dice que estamos ante un sistema de clasificación binario.
Utilizando un modelo con un esquema similar al de la Figura 1-3, entrenándolo usando los
datos de entrada procesados y ajustando los parámetros del entrenamiento del modelo se
conseguirá obtener un sistema que detecte el fraude con buena precisión.
Por último, se utilizarán los datos del dataset de prueba para realizar la predicción del fraude
con sus datos y exportar esas predicciones a la web Kaggle. En esta web se evaluará de forma
online el rendimiento de este modelo de predicción respecto al de otras personas.

1.2 Objetivos y Estructura de la memoria


Entre los objetivos del proyecto se destacan:
 Carga y procesamiento correcto de los datos disponibles.
 Realización de un análisis de los datos disponibles para una mejor comprensión de
ellos.
 Implementación del modelo de Inteligencia Artificial para su entrenamiento con los
datos.
 Búsqueda de los parámetros del modelo más adecuados para el entrenamiento.
 Entrenamiento del modelo y análisis de los resultados obtenidos.
 Subida de las predicciones con el dataset de prueba a Kaggle y obtención de un buen
resultado.
La memoria se compone de 7 capítulos mediante los cuáles se irán ampliando y comentando
más detalladamente estos objetivos y cómo se han llevado a cabo para llegar finalmente a las
conclusiones de estos.
Introducción 4
5 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

2 PREPARACIÓN Y CARGA DE DATOS

E
l primer paso para el desarrollo del proyecto va a consistir en la preparación del entorno
Python que se va a utilizar importando todos los módulos necesarios así como los datos
disponibles sobre las transacciones monetarias. Posteriormente se hará una observación
de los datos disponibles con el fin de observar qué características van a ser las mejores para
entrenar a la inteligencia artificial para que ofrezca los mejores resultados posibles.

2.1 Preparación del entorno


Como ya se ha comentado, el proyecto va a estar escrito en el lenguaje de programación
Python. Python es un lenguaje de programación interpretado, multiparadigma, dinámico y
multiplataforma. Posee una licencia de código abierto y desde 1991 se ha ido desarrollando en
múltiples versiones. En este proyecto concreto se va a utilizar la versión 3.9.4 del lenguaje.

Figura 2-1. Logo de Python


Con la instalación base de Python se puede programar utilizando la línea de comandos,
aunque es bastante poco práctico. Para ello se utilizará el software Visual Studio Code como
IDE o Entorno de desarrollo integrado que actuará tanto como editor de código como
intérprete de este y terminal de salida de la ejecución del código.
Este software pertenece a Microsoft y cuenta con gran cantidad de extensiones y diferentes
opciones de configuración que permiten utilizarlo en la mayoría de los lenguajes de
programación existentes con gran comodidad.
Una vez se tengan instalados los programas anteriores se procederá a instalar los módulos o
librerías de Python que se van a utilizar para el desarrollo del proyecto. Se van a comentar
las características y funciones de las librerías más importantes:
 Pandas: Se trata de una librería para el manejo de datos. Con ella se puede realizar
Preparación y Carga de Datos 6

desde la importación de los datos desde una gran cantidad de formatos hasta la
transformación de los datos en sí. Para ello almacena los datos en “dataframes” en los
que guarda la información de las diferentes columnas y filas. Con ellos se pueden
realizar funciones como ordenar, transformar, cambiar tamaños, cambiar tipos, pintar
gráficas, etc. Estos “dataframes” se pueden utilizar directamente en el resto de las
funciones de otras librerías ya que Pandas se encuentra bastante extendido y es de uso
común.

Figura 2-2. Logo de Visual Studio Code


 Numpy: Esta librería es una de las más importantes de Python y de ella dependen la
mayoría de las librerías que se usan en el proyecto. Numpy proporciona a Python
numerosas funciones matemáticas de alto nivel, permitiendo además la creación de
matrices y vectores de grandes dimensiones. Esta librería se creó debido a que Python
no fue diseñado inicialmente para la computación numérica y con la librería Numpy se
consigue un rendimiento mucho mayor que con Python base tanto en rapidez de
escritura del código como en la ejecución.

Figura 2-3. Comparación entre Matplotlib y Seaborn


 Matplotlib: Se trata de otra de las principales librerías de Python que se usa para la
creación de visualizaciones de datos tanto estáticas como animadas o interactivas. Una
de sus mayores ventajas es que permite un control total de la personalización de los
7 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

gráficos, pudiendo elegir entre diferentes colores, tipos de líneas, personalización de


leyendas y ejes, etc. Los gráficos se realizan de forma rápida y sencilla y pueden ser
exportados como imágenes o guardados en un archivo local.
 Seaborn: Es una librería de visualización de datos en Python. Está basada en
Matplotlib y sirve como su extensión. Sirve como una integración entre Matplotlib y
Pandas ya que ayuda a explorar y entender los datos utilizando gráficos más
avanzados e informativos. Por ejemplo, en Seaborn se pueden crear “pairplots” que
relacionen características de un “dataframe” entre sí.

Figura 2-4. Ejemplo de un Pairplot


 Os: Este módulo de Python viene incluido en la instalación base del lenguaje y se usa
para utilizar las funcionalidades del sistema operativo desde el propio código. En este
Preparación y Carga de Datos 8

proyecto se va a utilizar para modificar el “path”.


 Sklearn: Esta librería de código abierto contiene funciones relacionadas con la
inteligencia artificial. Está diseñada para operar con Pandas y Numpy y añade
algoritmos de clasificación, regresión y “clustering” además de otros algoritmos como
k-medias, máquinas de vectores de soporte (SVM), bosques aleatorios de predictores o
técnicas de potenciación del gradiente. Contiene varios paquetes de funciones, como
ejemplo se muestran los siguientes:
o Metrics: Contiene distintas funciones relacionadas con mediciones y cálculos de
distintos errores, medias y varianzas como por ejemplo el MAE o la curva
ROC.
o Preprocessing: Las funciones que contiene este paquete están relacionadas con
el preprocesamiento de los datos antes de usarlos para el entrenamiento del
modelo. Por ejemplo, contiene los LabelEncoder y OneHotEncoder para
codificar variables categóricas.
o Model_Selection: En este paquete se encuentran funciones relacionadas con
los modelos de sklearn. Algunas de ellas se utilizan para realizar la división
entre el set de entrenamiento y el de prueba, para realizar optimización de los
parámetros o para realizar divisiones de los datos de entrenamiento para
mejorar la generalización.

Figura 2-5. Paquetes de SKLearn


9 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

 Lightgbm: Se trata de uno de los muchos modelos entrenables creados a partir del
algoritmo de potenciación del gradiente en árbol de decisión (GBDT). En esta
implementación del algoritmo se incluyen mejoras respecto al resto de modelos que le
permiten mantener la misma precisión que el resto mientras disminuye el tiempo de
entrenamiento del modelo hasta 20 veces. En el Apartado 5 se tratará con mayor
profundidad este modelo.
 Time/Datetime: Estos dos módulos de Python se incluyen con su instalación base y
se pueden utilizar para acceder a la hora y fecha del sistema. En este proyecto se
utilizarán para calcular el tiempo que tardán los algoritmos en ejecutarse.
 GC: Se trata del módulo Garbage Collector incluido con la instalación de Python y
que permitirá reunir variables u otro tipo de información que se ha quedado guardada
en memoria y eliminarla para reducir el consumo de la memoria RAM del ordenador.
 Warnings/Logging: Los módulos warnings y logging está incluidos en Python base y
se utilizan para ajustar el nivel de información que queremos que aparezca a través de
la consola. En este caso Warnings se usará para filtrar los mensajes menos importantes
y Logging se utilizará para eliminar los mensajes menos importantes de un paquete en
concreto.
 Graphviz: Este módulo consiste en un generador de diagramas de grafos de código
abierto. Con él se pueden generar diagramas de todo tipo, modificarlos de forma
personalizada e incluso guardarlos en un archivo local o exportarlos a un archivo de
imagen. En este caso se va a utilizar para generar diagramas de grafos del modelo ya
entrenado, en el cuál se van a poder observar todos los nodos intermedios del modelo,
así como sus entradas y salidas.

Figura 2-6. Ejemplo de un diagrama de grafos


Preparación y Carga de Datos 10

El código relacionado con la preparación del entorno es el siguiente:

Código 2.1 – Preparación del entorno


import numpy as np
import pandas as pd
import seaborn as sns
import os

import matplotlib.pyplot as plt


from sklearn.metrics import mean_absolute_error, roc_curve

import lightgbm as lgb


import time
import datetime

from sklearn.preprocessing import LabelEncoder


from sklearn.model_selection import StratifiedKFold, KFold, RepeatedKFold,
GroupKFold, GridSearchCV, train_test_split, TimeSeriesSplit
from sklearn import metrics

import gc
import warnings
warnings.filterwarnings("ignore")

import graphviz

import logging
logging.getLogger('googleapicliet.discovery_cache').setLevel(logging.ERROR)

2.2 Importación de los datos


En siguiente paso en el proceso es la carga de los datos. Estos datos están almacenados en
varios archivos CSV o de variables separadas por comas. Los archivos que se van a utilizar en
este proyecto se encuentran alojados en la web en la página “Kaggle” y son en total cuatro
archivos, dos archivos relacionados con los datos de entrenamiento y otros dos archivos
relacionados con los datos de prueba. Los nombres completos de los archivos son los
siguientes:
 train_transaction.csv
 train_identity.csv
 test_transaction.csv
 test_identity.csv
La estructura de estos archivos se analizará posteriormente en el Apartado 3.1. Existen dos
opciones a la hora de importar estos archivos, las cuales se van a analizar a continuación.
11 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

2.3.1 Usando Google Drive

La primera de las opciones disponibles para cargar los datos consiste en la utilización de
varios módulos de Python para cargar los archivos alojados en Google Drive. Para ello será
necesario una cuenta de Google con la cual se realizará la autentificación y realizar la subida
de los archivos previamente.
Una vez subidos los archivos se obtendrán sus números de identificación públicos que se
utilizarán junto a los módulos “PyDrive”, “Google Colab” y “OAuth2Client” para descargar
los archivos de la web y guardarlos en una variable de tipo dataframe de la librería Pandas.
La principal ventaja de este método consiste en la gran portabilidad del código, ya que no va
a depender de la existencia de los archivos en la máquina local. En cambio, el proceso es
mucho más lento al depender de la conexión a la red.
El código relacionado con la carga de datos desde Google Drive es el siguiente:

Código 2.2 – Carga mediante Google Drive


!pip install -U -q PyDrive2
from pydrive2.auth import GoogleAuth
from pydrive2.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials

# Autenticacion y creacion de variables


auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)

# Links de los archivos compartidos en Drive


ids = [["1aHWZA-O3r3JRV6N95ix_5r_GRh-
BpTwr","train_identity"],["1ZBg64Zrh_X4tLPdL51wfVeza1jdqNgLs","train_transact
ion"],["1_qW7biLaKpZppjq4czcHLZILvERV8OyX","test_identity"],["1OHHiJ9HH5kyw76
A5-46tcXXhdIBdbhvc","test_transaction"]]
for id, name in ids:
print ("Cargando archivo con id: " + str(id) + " y nombre: " + str(name))
downloaded = drive.CreateFile({'id':id})
downloaded.GetContentFile('Filename.csv')
globals()[name] = pd.read_csv('Filename.csv')

# Limpieza de variables
del gauth, drive, ids, downloaded

2.3.2 Usando archivos locales

La segunda opción disponible para realizar la carga de los datos es la lectura de los archivos
con extensión CSV que se encuentren alojados directamente de forma local en el ordenador.
Este proceso es mucho más sencillo de realizar que la carga mediante Google Drive ya que la
propia librería Pandas contiene funciones dedicadas a la carga de archivos CSV como por
ejemplo la función read_csv(). Además, estas funciones permiten la detección automática de
Preparación y Carga de Datos 12

los nombres de las columnas y ordenan los datos introduciéndolos en una variable de tipo
dataframe.
Como este método utiliza archivos locales es necesario previamente obtener esos archivos,
aunque, una vez obtenidos, se realiza la lectura de estos de forma bastante rápida.
El código relacionado con la carga de datos desde archivos locales es el siguiente:

Código 2.3 - Carga mediante archivos locales


print("Cargando datos...")
train_transaction = pd.read_csv("train_transaction.csv")
train_identity = pd.read_csv("train_identity.csv")
test_transaction = pd.read_csv("test_transaction.csv")
test_identity = pd.read_csv("test_identity.csv")
print("Datos cargados correctamente")

Una vez importados los datos que se van a utilizar en sus respectivos dataframes se pueden
utilizar los métodos asociados a este objeto. Uno de ellos es el método head() que permite
mostrar por pantalla las primeras filas de la variable asociada.
Por tanto, podemos observar la forma que van a tener las distintas primeras filas de los datos
de entrenamiento:

Figura 2-7. Primeras filas del dataset train_transaction

Figura 2-8. Primeras filas del dataset train_identity


13 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

2.3 Procesamiento inicial


Como se ha comentado anteriormente, los archivos están divididos en dos tipos según su uso:
los archivos “train” estarán relacionados con los datos que se van a utilizar en el
entrenamiento del modelo y los archivos “test” estarán relacionados con los datos que se van
a utilizar para la prueba del modelo final.
A su vez estos archivos se encuentran divididos en otros dos tipos. Los archivos “transaction”
van a contener información sobre las transacciones bancarias y los archivos “identity” van a
contener información sobre la identidad de los emisores que han realizado esas transacciones.
No todas las transacciones van a tener información asociada sobre su emisor.
El punto común entre los dos archivos va a ser la columna “TransactionID” ya que en ella se
almacena un número de identificación único para cada transacción. Por ello, se pueden unir
las dos variables relacionadas con el entrenamiento usando el valor de “TransactionID” para
relacionarlas.
La unión se va a realizar utilizando las siguientes funciones:

Código 2.4 – Unión de los datos


train = pd.merge(train_transaction, train_identity, on='TransactionID',
how='left')
# Limpieza de variables
del train_identity, train_transaction

test = pd.merge(test_transaction, test_identity, on='TransactionID',


how='left')
# Limpieza de variables
del test_identity, test_transaction

print(f'Train tiene {train.shape[0]} filas y {train.shape[1]} columnas.')


print(f'Test tiene {test.shape[0]} filas y {test.shape[1]} columnas.')

Train tiene 590540 filas y 434 columnas.


Test tiene 506691 filas y 433 columnas.

Ahora que se tienen los datos organizados en dos datasets llamados “train” y “test” se pueden
comparar utilizando de nuevo la función head():

Figura 2-9. Comparación entre datasets train y test


Preparación y Carga de Datos 14

Como se puede observar en la imagen anterior, las columnas con las claves con formato
“id_XX” que existen en el dataset “train” tienen un formato distinto en el dataset “test” ya
que utilizan guiones (-) en lugar de usar guiones bajos (_). Para solucionar esta discordancia
se renombran las columnas correspondientes usando el método rename() en el dataset “test”
de la siguiente forma:

Código 2.5 – Renombramiento de columnas


test = test.rename(columns=lambda s: s.replace("-","_"))
test['TransactionAmt'].round(2)

Estas columnas hacen referencia a unos parámetros de identificación propios de los emisores
de las transacciones (como pueden ser su IP o su huella digital) pero que han sido codificados
por la compañía que ha generado los datos para mantener la privacidad de los emisores. La
mayoría de transacciones no van a tener una información de identidad asociada por lo que va
a existir gran cantidad de valores NaN.
De esta manera, el dataset “test” resultante es el siguiente:

Figura 2-10. Columnas del dataset test renombradas

2.4 Reducción de tamaño


Uno de los mayores desafíos que se pueden presentar a la hora de trabajar con una cantidad
tan grande de datos es la limitación de la capacidad de la memoria RAM. En este caso los
datasets “train” y “test” contienen gran cantidad de información y van a ocupar bastante
memoria por lo que se va a proceder a crear una función que reduzca la memoria que utilizan.
Para ello se debe observar con más detenimiento los datos y el tipo de sus variables. Pandas
asigna por defecto un tipo de variable de gran capacidad al leer los datos desde un archivo
CSV con el método read_csv(), como puede ser por ejemplo int64 o float64.
Pero en realidad no se necesita tanta memoria asignada ya que el valor de los datos no va a
tomar valores muy grandes. Por ello se va a ir recorriendo cada columna del dataset
observando el tipo de variable que se usa y cuáles son los valores máximos y mínimos que se
15 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

dan en cada columna para, según estos valores, proceder a modificar el tipo de la variable a
un unsigned int, un int o un float de menor número de bits.
Antes de realizar este procedimiento se debe asegurar la sustitución de los valores infinitos
por NaN para evitar problemas. Además, se van a ignorar las columnas que tienen variables
categóricas, que se tratarán más adelante.

Código 2.6 – Reducción de tamaño de los datasets


cat_cols = ['ProductCD', 'card4', 'card6','P_emaildomain', 'R_emaildomain',
'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8', 'M9',
'id_12','id_15','id_16','id_23','id_27', 'id_28', 'id_29',
'id_30', 'id_31', 'id_32', 'id_33', 'id_34', 'id_35', 'id_36', 'id_37',
'id_38',
'DeviceType', 'DeviceInfo']

def reduce_size(dataset, cat_cols):


orig_size = dataset.memory_usage().sum() / 1024**2
print("El tamaño original del dataset es de " + str(orig_size) + " MB.",\
end = '\n')

# Reemplazamiento de infinitos por NaN


dataset.replace([np.inf, -np.inf] , np.nan)

for col in dataset.columns:


if col not in cat_cols:
# Variables usadas
integ = False
max = dataset[col].max()
min = dataset[col].min()

# Probamos si se puede convertir a entero


conv = dataset[col].fillna(0).astype(np.int64) # Quitamos decimales
result = (dataset[col] - conv) # En resultado quedaria la parte
result = result.sum() # decimal de los números
if abs(result) == 0: # Si no tiene decimales es un int
integ = True

# En el caso de que haya un valor NaN no se puede convertir, tiene


que quedarse como float
if dataset[col].isna().any():
integ = False

# Conversion de tipos segun los tamaños y el tipo inicial


if integ:
if min >= 0:
if max < (2^8-1):
dataset[col] = dataset[col].astype('uint8')
elif max < (2^16-1):
dataset[col] = dataset[col].astype('uint16')
elif max < (2^32-1):
dataset[col] = dataset[col].astype('uint32')
else:
dataset[col] = dataset[col].astype('uint64')
else:
if min > np.iinfo('int8').min and max < np.iinfo('int8').max:
dataset[col] = dataset[col].astype('int8')
elif min > np.iinfo('int16').min and max < np.iinfo('int16').max:
dataset[col] = dataset[col].astype('int16')
elif min > np.iinfo('int32').min and max < np.iinfo('int32').max:
Preparación y Carga de Datos 16

dataset[col] = dataset[col].astype('int32')
else:
dataset[col] = dataset[col].astype('int64')
else:
dataset[col] = dataset[col].astype('float16')

final_size = dataset.memory_usage().sum() / 1024**2


print("El tamaño final del dataset es de " + str(final_size) + " MB.",
end = '\n')
print("El tamaño final es un " + str(100*final_size/orig_size) + " % del
original.", end = '\n')

# Reducimos el tamaño de los datasets


print("------ Reduciendo tamaño del dataset TRAIN ------", end = '\n')
reduce_size(train, cat_cols)
print("------ Reduciendo tamaño del dataset TEST ------", end = '\n')
reduce_size(test, cat_cols)

------ Reduciendo tamaño del dataset TRAIN ------


El tamaño original del dataset es de 1959.8762512207031 MB.
El tamaño final del dataset es de 656.1079978942871 MB.
El tamaño final es un 33.47701149425287 % del original.
------ Reduciendo tamaño del dataset TEST ------
El tamaño original del dataset es de 1677.7335662841797 MB.
El tamaño final del dataset es de 551.3519582748413 MB.
El tamaño final es un 32.86290322580645 % del original.

Gracias al procesamiento anterior se ha conseguido reducir el tamaño ocupado por los datos
en la memoria, de forma que ahora ocupan aproximadamente un 30% del tamaño ocupado
originalmente.
Además, se puede observar utilizando de nuevo el método head() que el valor de los datos
sigue siendo el mismo:

Figura 2-11. Primeras filas del dataset train


17 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

3 ANÁLISIS DE LOS DATOS

P ara continuar con el desarrollo del proyecto se va a realizar un análisis de los datos
disponibles con el fin de identificar la funcionalidad de las diferentes columnas de los
datos. De esta manera se puede tener un mayor conocimiento de la estructura de los
datos para determinar qué columnas es necesario mantener y cuáles eliminar.
Para ello se van a analizar algunas de las columnas más importantes y, posteriormente, se
realizará un análisis gráfico usando las herramientas disponibles en los módulos de Python
Matplotlib y Seaborn.

Figura 3-1. Logo de Seaborn

3.1 Identificación de columnas


Primeramente, se va a proceder a la identificación de las columnas más importantes de los
datos utilizando la observación y el análisis lógico. Las principales columnas de los datos son
las siguientes:
 TransitionID: Número de identificación de cada transacción que permite relacionar la
información de la transacción del archivo “transaction” con la de la identidad del
emisor contenida en el archivo “identity” así como identificar cada fila con un número
único.
 TransitionDT: Momento de tiempo en el que se realiza la transacción, por lo que se
puede decir que los datos se encuentran repartidos en una serie temporal.
 isFraud: Variable binaria que marcará si una determinada transacción es fraudulenta
o no, por lo que cuando se usen los nuevos datos contenidos en el dataset de prueba
esta variable vendrá dada por la salida del modelo predictor ya entrenado.
 TransactionAmt: Cantidad monetaria transferida en cada transacción monetaria. Al
no disponer de unidades se va a suponer que su valor viene dado en dólares ($).
 ProductCD: Tipo de producto asociado a la transacción bancaria.
Análisis de los Datos 18

 card1 y card2: Valor numérico relacionado con el número de la tarjeta.


 card4: Empresa proveedora de la tarjeta involucrada en la transacción monetaria.
 card6: Tipo de tarjeta (crédito o débito).
 addr1: Correo electrónico del emisor codificado numéricamente por privacidad.
 P_emaildomain: Proveedor de servicio de la dirección de correo electrónico asociada
al emisor de la transferencia monetaria.
 R_emaildomain: Proveedor de servicio de la dirección de correo electrónico asociada
al receptior de la transferencia monetaria.
 id_30: Versión del sistema operativo del emisor.
 id_31: Navegador web desde el que se realiza la operación.
 id_33: Resolución del dispositivo desde el que se realiza la transacción.
 DeviceType: Tipo del dispositivo.
 DeviceInfo: Información disponible del dispositivo.
Va a existir una gran cantidad de filas en las cuales las columnas anteriores van a tener
valores nulos o “NaN”. Otras, van a contener variables categóricas de tipo “string” que deben
marcarse individualmente al igual que se realizó anteriormente en el Apartado 2.4. Por
último, existe otro tipo de variables que solo van a tomar tres valores posibles (incluyendo el
valor nulo), por lo que se dice que son variables binarias.
Como ya se ha comentado anteriormente, la principal división que se puede realizar entre los
datos de las columnas consiste en el tipo de variable que contienen. Para ello, se van a buscar
las variables categóricas para marcarlas en una variable nueva. Por ejemplo, algunas de las
columnas que van a pertenecer a este tipo son las columnas “card4”, “card6” o “ProductCD”.
Es importante marcar y separar las variables categóricas ya que éstas necesitarán un
preprocesado que convierta los datos de palabras a números, para lo cuál se usarán los
métodos LabelEncoder() o OneHotEncoder() de la librería SKLearn. Este preprocesado se
realizará posteriormente en el Apartado 5.1.
Las columnas con variables categóricas que se han identificado observando los datos son las
siguientes:

Código 3.1 – Definición de variables categóricas


cat_cols = ['ProductCD', 'card4', 'card6','P_emaildomain', 'R_emaildomain',
'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8',
'M9','id_12','id_15','id_16','id_23','id_27', 'id_28', 'id_29', 'id_30',
'id_31', 'id_32', 'id_33', 'id_34', 'id_35', 'id_36', 'id_37',
'id_38','DeviceType', 'DeviceInfo']
19 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

3.2 Análisis gráfico de variables


Para realizar un mejor análisis de las variables anteriores se va a proceder a la creación de
distintos histogramas y otro tipo de gráficos usando las funciones de las librerías Matplotlib,
Seaborn y Pandas.
Por ejemplo, se puede observar la relación entre la cantidad monetaria usada en la
transacción y el fraude utilizando el siguiente código:

Código 3.2 – Relación entre “TransactionAmt” y “isFraud”


plt.style.use('seaborn')
plt.figure(figsize=(20,5))
plt.subplot(121)
plt.hist(train['TransactionAmt'].where(train['isFraud'] == 0), 500,
rwidth=0.85)
plt.axis([min(train['TransactionAmt']),3000,0,50000])
plt.title('Histograma de TransactionAmt | NO FRAUDE')
plt.xlabel("Cantidad")
plt.ylabel("Nº Veces")
plt.subplot(122)
plt.hist(train['TransactionAmt'].where(train['isFraud'] == 1), 100,
rwidth=0.85)
plt.axis([min(train['TransactionAmt']),3000,0,7000])
plt.title('Histograma de TransactionAmt | FRAUDE')
plt.xlabel("Cantidad")
plt.ylabel("Nº Veces")
plt.show()

Figura 3-2. Relación entre cantidad monetaria y fraude


Análisis de los Datos 20

Como se puede observar en el gráfico anterior, la mayoría de las transacciones fraudulentas se


van a producir en aquellas que conllevan una cantidad monetaria inferior a 400 dólares, al
igual que la mayoría de las transacciones no fraudulentas son por debajo de esa cantidad. Sin
embargo, parece que existe una distribución ligeramente más concentrada en las cantidades
por debajo de 200 dólares en las transacciones no fraudulentas (83.17%) que en las
fraudulentas (77.90%).
Para acelerar el proceso de creación de los gráficos se va a crear una función llamada
plot_prop() que se va a encargar de pintar las variables que se le indiquen a través de los
argumentos utilizando para ello funciones contenidas en Matplotlib y Pandas. Además, esta
función también se encargará de calcular el porcentaje de fraude cometido para cada valor
posible que tomen las variables indicadas.
El código relacionado con la creación de esta función es el siguiente:

Código 3.3 – Función para representar gráficamente las variables


def plot_prop (variable, head_value = None, title = None, xlabel =
'Cuenta'):
if title is None:
title = variable
plt.title(title)
plt.xlabel(xlabel)
if head_value is None:
train[variable].where(train['isFraud'] == 0)\
.value_counts().plot.barh()
train[variable].where(train['isFraud'] == 1)\
.value_counts().plot.barh(color = 'red')
p1 = train[variable].where(train['isFraud'] == 0).value_counts()
p2 = train[variable].where(train['isFraud'] == 1).value_counts()
else:
train[variable].where(train['isFraud'] == 0)|
.value_counts().head(head_value).plot.barh()
train[variable].where(train['isFraud'] == 1)\
.value_counts().head(head_value).plot\
.barh(color = 'red')
p1 = train[variable].where(train['isFraud'] == 0)\
.value_counts().head(head_value)
p2 = train[variable].where(train['isFraud'] == 1)\
.value_counts().head(head_value)

plt.legend(['NO FRAUDE','FRAUDE'])
prop = p2*100/(p1+p2)
print("---Porcentaje de fraude---")
print(prop)
print("--------------------------")

Una vez escrita, la función se puede utilizar para el análisis de las siguientes variables de una
forma más rápida.
21 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

3.2.1 Proveedor, Tipo de tarjeta y Tipo de dispositivo (isFraud, card4, card6 y


DeviceType)

El gráfico se crea de la siguiente forma. “Cuenta” hace referencia al número de transacciones.

Código 3.4 – Representación variables “isFraud”, “card4”, “card6” y “DeviceType”


plt.figure(figsize=(20,10))
plt.subplot(221)
plt.title('isFraud')
plt.xlabel("Cuenta")
train['isFraud'].value_counts().plot.barh()
plt.subplot(222)
plot_prop('card4')
plt.subplot(223)
plot_prop('card6')
plt.subplot(224)
plot_prop('DeviceType')
plt.show()
---Porcentaje de fraude---
american express 2.869836695485111
discover 7.728161178770110
mastercard 3.433095334985757
visa 3.475609914571676
Name: card4, dtype: float64
---Porcentaje de fraude---
charge card NaN
credit 6.678479857167788
debit 2.426250971727834
debit or credit NaN
Name: card6, dtype: float64
---Porcentaje de fraude---
desktop 6.521458345564493
mobile 10.166232365890915
Name: DeviceType, dtype: float64

Figura 3-3. Distribución Fraude/No Fraude en card4 (Proveedor), card6 (Tipo de tarjeta) y
DeviceType
Análisis de los Datos 22

Como se puede observar en el gráfico anterior en las variables relativas al proveedor de las
tarjetas se puede apreciar que la mayoría de ellas pertenecen a visa o mastercard y que las
transacciones fraudulentas y no fraudulentas se reparten aproximadamente de la misma
forma entre los dos proveedores (3.4%). Sin embargo, las tarjetas del proveedor discover
tienen un porcentaje mayor de fraude (7.7 %).
Además, observando el tipo de tarjeta, las tarjetas de crédito tienen un porcentaje de fraude
(6.68 %) mucho mayor que el de las tarjetas de débito (2.43 %).
De la misma forma, observando el tipo de dispositivo se puede concluir que la mayoría de los
dispositivos son de tipo mobile y que tienen un porcentaje de fraude (10.2%) mayor que el de
los dispositivos de tipo desktop (6.5%).

3.2.2 Proveedor de correo electrónico del emisor (P_emaildomain)

El gráfico se ha generado de la siguiente forma:

Código 3.5 – Representación variable “P_emaildomain”


plt.figure(figsize=(10,7))
plot_prop('P_emaildomain', 5 ,'Servidor de correo del
emisor(P_emaildomain)')
plt.show()
---Porcentaje de fraude---
anonymous.com 2.321747121466025
aol.com 2.181059775884620
gmail.com 4.354185369271529
hotmail.com 5.295027624309392
yahoo.com 2.275744545940912
Name: P_emaildomain, dtype: float64
--------------------------

Figura 3-4. Distribución Fraude/No Fraude en P_emaildomain


23 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

Observando el gráfico anterior se puede concluir que la gran mayoría de los proveedores de
correo electrónico usados en las transacciones son Hotmail.com o Gmail.com. Debido a esto,
también se encuentran más extendidos entre los que generan las transacciones fraudulentas y
estos dos proveedores son los que tienen un mayor porcentaje de transacciones fraudulentas
(5.29% y 4.35%, respectivamente).
Otra de las posibilidades por las que los que generan transacciones fraudulentas utilizan los
proveedores Hotmail.com y Gmail.com puede ser debido a que están más extendidos entre la
población general.

3.2.3 Sistema Operativo (Id_30)

El gráfico se genera utilizando las siguientes funciones:

Código 3.6 - Representación variable “id_30”


plt.figure(figsize=(10,7))
plot_prop('id_30', 5 ,'Sistema Operativo usado (id_30)')
plt.show()
---Porcentaje de fraude---
Android 7.0 5.781957506095437
Windows 10 3.105648782793666
Windows 7 3.295194508009153
iOS 11.1.2 NaN
iOS 11.2.1 4.916711445459431
iOS 11.2.5 NaN
Name: id_30, dtype: float64
--------------------------

Figura 3-5. Distribución Fraude/No Fraude en id_30


Análisis de los Datos 24

Si se observa el gráfico anterior se puede concluir que la mayoría de los sistemas operativos
usados para las transacciones bancarias son Windows. El resto de los sistemas operativos que
se utilizan en estas transacciones están diseñados para teléfonos móviles, como por ejemplo
iOS 11 o Android.
Estos sistemas operativos relacionados con dispositivos móviles van a tener un porcentaje de
fraude mayor que el SO Windows (5% frente a 3.2%).

3.2.4 Navegador Web (Id_31)

Este gráfico se ha generado utilizando el siguiente código:

Código 3.7 - Representación variable “id_31”


plt.figure(figsize=(10,7))
plot_prop('id_31', 5 ,'Navegador Web usado (id_31)')
plt.show()
---Porcentaje de fraude---
chrome 63.0 6.831818181818182
chrome 65.0 NaN
chrome generic NaN
ie 11.0 for desktop NaN
mobile safari 11.0 6.272815316993221
mobile safari generic 9.987798500958689
safari generic NaN
Name: id_31, dtype: float64
--------------------------

Figura 3-6. Distribución Fraude/No Fraude en id_31


25 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

Esta variable se encuentra relacionada con el navegador web usado en las transacciones.
Observando el gráfico anterior se puede deducir que la mayoría de los navegadores web que
han sido utilizados en las transacciones pertenecen a las familias de Chrome o Safari, teniendo
esta última un porcentaje de fraude ligeramente mayor que la anterior (6.83% frente a un
10%).
Todos los datos anteriores van a ser interpretados por el modelo de clasificación en su etapa
de entrenamiento. En este entrenamiento el modelo asignará mayor o menor peso en la
predicción a una determinada variable dependiendo del porcentaje de fraude, de su
concentración, de su correlación con otras variables, etc.

3.3 Análisis en el tiempo


Por último, se va a proceder al análisis de la variable TransactionDT. La variable
TransactionDT va a indicar el momento de tiempo en el que se realiza cada transacción.
Para realizar un análisis correcto de esta variable se va a mostrar en un histograma los
momentos de tiempos que se encuentran en los dataset "train" y "test" utilizando el siguiente
fragmento de código:

Código 3.8 - Representación variable temporal “TransactionDT”


plt.figure(figsize=(10,5))
plt.hist(train['TransactionDT'], label='train')
plt.hist(test['TransactionDT'], label='test')
plt.legend()
plt.title('Histograma de la variable TransactionDT')
plt.show()

Figura 3-7. Histograma de la variable TransactionDT


Análisis de los Datos 26

En el eje de la abcisas se ha representado el tiempo a partir de un instante de tiempo inicial


t=0 que hace referencia a una marca de tiempo sin definir en los datos que se proporcionan.
Este tiempo se encuentra representado en segundos y, por tanto, en total se tienen datos de
aproximadamente un año repartidos entre los datos “train” y “test”.
Si se observa la imagen anterior se puede apreciar que los momentos de tiempo de los dos
dataset no se solapan entre sí en el tiempo. Esto significa que se podrá usar la función
TimeSeriesSplit() de la librería sklearn para realizar la validación cruzada del modelo.
Esta función dividirá los datos en grupos de intervalos fijos de tiempo en vez de hacerlo de
forma aleatoria e irá realizando la validación cruzada avanzando en esos grupos, usando los
grupos anteriores como "train" y el siguiente como "test" en cada iteración del algoritmo. El
progreso del algoritmo en cada iteración se muestra en la siguiente imagen:

Figura 3-8. División de datos usando TimeSeriesSplit()


En la imagen anterior se puede observar que el algoritmo coge en la primera iteración el
primer set como entrenamiento y el segundo como prueba y realiza la validación cruzada. En
la siguiente iteración se escoge como prueba el tercer set y los anteriores como entrenamiento.
De esta forma se avanza hasta realizar la validación cruzada con todos los sets de datos.
27
Inteligencia artificial para la detección de fraude en transacciones rea
crédito

4 TÉCNICAS DE R EDUCCIÓN DE LA
DIMENSIONALIDAD

E n los datos existe gran cantidad de información que es irrelevante o redundante. Hay
muchas columnas en las que la mayoría de sus valores son nulos. Otras, en cambio,
tienen un solo valor con mucho mayor porcentaje de aparición que el resto de los
valores posibles o incluso un único valor para todas las filas. Por último, existirán columnas
que estén altamente correladas entre sí y que no aportan información nueva al modelo más
allá de la información que ha aportado la columna correlada correspondiente.
Esto ocurrirá tanto en el dataset "train" como en el dataset "test". Por ello se procederá a
buscar las columnas que cumplan las condiciones anteriormente mencionadas en los dos
datasets y a eliminarlas de ellos para disminuir la cantidad de información irrelevante, lo que
ayudará a mejorar la precisión del modelo y a reducir la carga computacional necesaria al
entrenarlo. Con ello se conseguirá además una mejora en el tiempo que necesita el
entrenamiento del modelo.
En primer lugar, se va a realizar un análisis y presentación de las técnicas de reducción de la
dimensionalidad más importantes.

Figura 4-1. Técnicas de reducción de la dimensionalidad


28
Técnicas de Reducción de la Dimensionalidad

4.1 Missing Value Ratio


Se trata de la eliminación de las columnas cuyo porcentaje de filas con valores nulos o “NaN”
sea mayor de un determinado porcentaje objetivo, ya que estas columnas no aportan ningún
tipo de información nueva en el conjunto general de los datos, sino que solo aportan
información de las pocas filas que tienen esos valores no nulos. El resto de valores NaN los
tratará directamente el modelo.
En este caso se ha optado por eliminar las columnas con un porcentaje de valores nulos
mayor o igual al 60%.

Código 4.1 – Ejemplo de columna con muchos NaN


train['D14'].isnull().value_counts(normalize = True)
True 0.894695
False 0.105305
Name: D14, dtype: float64

Por ejemplo, si se observa la columna “D14” (Relacionada con el tiempo de la transacción) de


los datos de entrenamiento se puede observar que el 89.46% de sus valores son nulos.

4.2 Low Variance Filter


Esta técnica consiste en la eliminación de las columnas que tengan una varianza muy baja en
los valores de sus filas. Es decir, se van a eliminar aquellas columnas en las que un gran
porcentaje de los valores de sus filas sean de un valor único y, por tanto, no aportan
información útil al entrenamiento del modelo.
Se ha optado por eliminar las columnas que tengan un porcentaje de valores iguales mayor o
igual al 75%.

Código 4.2 – Ejemplo de columna con muchos valores iguales


train['card3'].value_counts(normalize = True)
150.0 0.885075
185.0 0.095668
106.0 0.002667
146.0 0.002126
144.0 0.002126
...
228.0 0.000002
139.0 0.000002
114.0 0.000002
164.0 0.000002
221.0 0.000002
Name: card3, Length: 114, dtype: float64

En el código anterior se puede observar cómo el 88.50% de los valores de la columna “card3”
(Relacionada con el banco emisor de la tarjeta) tienen un valor de 150.0.
29 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

4.3 High Correlation Filter


Esta técnica implementa un filtro de reducción de características que va a calcular la
correlación existente entre las diferentes características de los datos y eliminará aquellas
características que tengan una alta correlación entre sí. Por tanto, de cada par de
características altamente correladas entre sí habrá que elegir una de ellas para su eliminación.
Para ello, se va a eliminar de cada par aquella que tenga menos correlación con el objetivo
(isFraud). Se va a consider características altamente correladas entre sí aquellas que tienen
una correlación mayor o igual a 0.7.

Figura 4-2. Correlación entre algunas de las variables

4.4 Principal Component Analysis


Se trata de una técnica utilizada para describir el conjunto de los datos que se tienen
utilizando un nuevo conjunto de datos con variables no correladas entre sí. Estas nuevas
variables se llamarán “componentes principales” y se ordenan según la cantidad de varianza
del “dataset” que consiguen describir. Es decir, el primer componente va a conseguir
representar un alto porcentaje de los datos, el segundo representará un porcentaje menor, etc.
De esta forma, utilizando solo los primeros componentes se puede conseguir alcanzar a la
mayoría de los datos que se tienen. El resto de los componentes se ignorarán ya que
representan una parte muy pequeña de los datos.
La utilización de esta técnica conlleva una transformación del sistema de coordenadas de
nuevo que las nuevas coordenadas del espacio de los datos van a venir dadas por los
componentes. Debido a esto, se pierde la posibilidad de interpretar cada característica por
separado ya que los componentes serán combinaciones de características y, además, es
necesario realizar todo el procesado de los datos previamente a este método.
30
Técnicas de Reducción de la Dimensionalidad

Figura 4-3. Ejemplo de Principal Component Analisys


Pese a todo lo anterior, este método cuenta con numerosas ventajas. La primera de ellas como
ya se ha comentado será la eliminación de la correlación entre variables lo que aumentará el
rendimiento del algoritmo (con lo que no sería necesario usar High Correlation Filter). Otras
de las ventajas son la reducción del sobreentrenamiento al reducir el número de variables en
el dataset y la mejora en la visualización de los datos disponibles que, al transformarse, se
pueden visualizar en un diagrama de dos dimensiones.

4.5 Random Forests


Esta técnica utiliza los bosques aleatorios que se utilizan como un clasificador de datos. Los
bosques aleatorios constituyen una técnica bastante útil para la selección de características ya
que son rápidos de entrenar y van a seleccionar automáticamente las mejores características
del conjunto de los datos. Para ello, se entrena cada árbol que forma parte del algoritmo
utilizando una pequeña fracción de los atributos. Si uno de los atributos se selecciona
normalmente como el mejor, va a representar una característica que interesa retener.

Figura 4-4. Ejemplo del cálculo de la importancia de las características


31 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

El cálculo de la importancia de las características que se observa en la imagen anterior se


realiza internamente en el modelo RandomForestClassifier de la librería sklearn. Un número
mayor de puntuación de importancia en una característica indica que el modelo ha dado más
peso a esa característica respecto al resto.
El siguiente paso del algoritmo consiste en la representación numérica de las puntuaciones de
las características contando el número de veces que cada característica ha sido seleccionada
como la mejor.
Finalmente, se repiten los pasos anteriores, pero ordenando aleatoriamente la columna
objetivo (en este caso la columna “isFraud”). Los resultados con la columna aleatoria van a
crear una línea base que marcará el nivel medio de las puntuaciones. Los valores de
puntuaciones que, utilizando la columna original, se desmarquen de esta línea y tengan un
valor de puntuación mucho mayor van a ser los correspondientes a las características más
representativas de los datos. Por ejemplo, si se observa la Figura 4-4, las características que
van a ser más representativas de los datos son “A”, “B” y “C”. Además, también se observa
la línea base comentada de color rojo.

4.6 Linear Discriminant Analysis


Se trata de una de las técnicas más extendidas. Al igual que el análisis de componentes
principales es una técnica de transformación lineal. Sin embargo, la mayor diferencia entre
ellas radica en que LDA es una técnica de entrenamiento supervisado mientras que PCA es
una técnica de entrenamiento no supervisado. Esto quiere decir que PCA no tiene en cuenta
las distintas clases que pueden existir en los datos. LDA proyecta los datos en la dirección en
la que la separación entre clases es máxima, así consigue reducir la dimensión de los datos.

Figura 4-5. Ejemplo de Linear Discriminant Analisys


En este caso, como se tiene un sistema binario, solo van a existir las clases “Fraude” y “No
Fraude”. En sistemas multiclase se trata de una técnica realmente útil ya que permite
maximizar la separación entre clases.
32
Técnicas de Reducción de la Dimensionalidad

4.7 Autoencoder
Otra de las últimas técnicas creadas para la reducción de la dimensionalidad es el
“Autoencoder”. Consiste en una red neuronal formada por un número n de entradas y salidas
y una capa oculta de menor tamaño con m nodos. Por tanto, tiene dos etapas principalmente.
La primera de ellas es conocida como el codificador y consiste en la reducción de las n
entradas en un espacio de m unidades utilizando los nodos de la capa oculta.
La segunda de las etapas es la reconstrucción de los datos utilizando el decodificador y
tranformando los datos contenidos en m nodos de la capa oculta en las n salidas.

Figura 4-6. Diagrama de un Autoencoder


Este modelo se entrena en un equilibrio de forma que la salida sea lo más parecida posible a
la entrada dada para perder la menor información posible y, a su vez, se consiga eliminar de
los datos la información considerada menos relevante o “ruido”. De esta forma se conseguiría
reducir la dimensionalidad de los datos.

4.8 t-distributed Stochastic Neighbor Embedding (t -SNE)


La t-SNE es un método estadístico usado para visualizar conjuntos de datos de alta
dimensionalidad que le da a cada punto concreto un lugar en un espacio de dos o tres
dimensiones. Este algoritmo se desarrolla en dos pasos.
En primer lugar, se construye una distribución de probabilidad en parejas de muestras del
espacio original. Las muestras semejantes van a tener mayor posibilidad de ser elegidas en la
pareja basándose en un criterio de vecindad por cercanía en el espacio de los puntos.
En segundo lugar, el algoritmo transforma los puntos del espacio original de alta
33 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

dimensionalidad a uno de menor dimensionalidad de forma aleatoria definiendo una nueva


distribución de probabilidad. Posteriormente, minimizando la divergencia Kullback-Leibler
(medida de similitud entre dos distribuciones), el algoritmo intenta reproducir la distribución
de probabilidad que existía en el espacio original.

Figura 4-7. Resultado de t-SNE en el dataset "MNIST" (Dataset de imágenes de números)


Este proceso es similar al desarrollado por el “Autoencoder” pero con un algoritmo de más
complejidad. Por tanto, su principal función va a ser la representación de la información más
relevante para así poder eliminar la información menos relevante o “ruido” en una etapa
posterior.

4.9 Aplicación de estas técnicas al algoritmo


Finalmente se van a aplicar algunas de las técnicas anteriormente vistas a los datos de las
transacciones que se tienen en los datasets “train” y “test”. Las técnicas que se van a aplicar
son el filtro de baja varianza, el filtro de alta correlación y la eliminación de columnas con
alto porcentaje de valores nulos.
El resto de las técnicas no se van a aplicar ya que son más complejas que las anteriores y al
realizar su implementación incrementaban en gran medida el tiempo de ejecución del
programa.
Las técnicas se han aplicado en el siguiente código:

Código 4.3 – Aplicación de la reducción de la dimensionalidad


# Dataset TRAIN
print("Reduciendo dimensionalidad en el dataset TRAIN")

null_cols_train = [col for col in train.columns if train[col]\


.isnull().sum() / train.shape[0] > 0.6]
big_value_cols_train = [col for col in train.columns if train[col]\
.value_counts(normalize=True).values[0] > 0.75]

train_corr = train.corr()
34
Técnicas de Reducción de la Dimensionalidad

train_cols = train.columns
train_high_corr = [ ]

for col1 in train_cols:


for col2 in train_cols:
if col1 != col2 and col2 not in train_high_corr and\
train_corr[col1][col2] > 0.7 and train_corr['isFraud'][col1] <\
train_corr['isFraud'][col2]:
train_high_corr.append(col1)
print("La columna " + str(col1) +\
" se elimina por alta corr. con " + str(col2) + ".")

# Dataset TEST
print("Reduciendo dimensionalidad en el dataset TEST")

# Se unen pero asegurandonos que la columna isFraud no este en ellas


cols_drop = list(set(null_cols_train + big_value_cols_train +\
train_high_corr))
cols_drop.remove('isFraud')

print("Se han eliminado " + str(len(cols_drop)) + " columnas.")

# Finalmente se eliminan esas columnas


train = train.drop(cols_drop, axis=1)
test = test.drop(cols_drop, axis=1)

# Limpieza de variables
del cols_drop, null_cols_train, big_value_cols_train, train_high_corr

Reduciendo dimensionalidad en el dataset TRAIN


Reduciendo dimensionalidad en el dataset TEST
La columna ProductCD se elimina por alta corr. con id_15.
La columna C1 se elimina por alta corr. con C2.
La columna C4 se elimina por alta corr. con C1.
La columna C6 se elimina por alta corr. con C1.
La columna C7 se elimina por alta corr. con C1.
(...)
La columna id_35 se elimina por alta corr. con ProductCD.
La columna id_36 se elimina por alta corr. con id_12.
La columna id_37 se elimina por alta corr. con id_12.
La columna id_38 se elimina por alta corr. con id_12.
Se han eliminado 355 columnas.
35 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

5 PREPARACIÓN DE LOS DATOS PARA


EL M ODELO

E
n este apartado se terminará de procesar los datos utilizando un “LabelEncoder” para
codificar de forma numérica las columnas categóricas. Además, se guardarán los datos
ya procesados en una variable de extensión “pickle” (.pkl) para no tener que repetir el
procesamiento de los datos cada vez que se quiera arrancar el entrenamiento del modelo.

5.1 Codificación de variables categóricas


Como ya se comentó anteriormente, las columnas con variables categóricas (variables que sólo
pueden tomar un valor concreto de un grupo limitado y fijo de valores) se tratarán usando un
“LabelEncoder”. En otro caso en el que los datos contuvieran un menor número de
características se podría utilizar el método “OneHotEncoder”. Este último método crea una
nueva columna por cada valor único en la columna original y rellena estas columnas con ceros
y unos según el valor determinado que tome cada fila. Así se consigue aumentar la precisión
del modelo final, pero se añade una columna por cada valor que pueda tomar cada variable
categórica, lo que en este caso aumentaría bastante el tamaño de los datos.

Código 5.1 – Definición de variables categóricas


cat_cols = ['ProductCD', 'card4', 'card6','P_emaildomain', 'R_emaildomain',
'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8',
'M9','id_12','id_15','id_16','id_23','id_27', 'id_28', 'id_29', 'id_30',
'id_31', 'id_32', 'id_33', 'id_34', 'id_35', 'id_36', 'id_37',
'id_38','DeviceType', 'DeviceInfo']

LabelEncoder() consiste en una herramienta contenida en la librería SKLearn que permite


codificar variables categóricas transformando el valor categórico contenido en una palabra en
números de forma que a cada posible valor le asigna un número entero entre 0 y n_valores-1.
Esta codificación añade el problema de la secuenciación numérica. El codificador va a asignar
a cada posible valor categórico un número según el orden de aparición de cada valor. Es decir,
primero va a asignar como valor el cero, después el uno, etc. A la hora de entrenar el modelo,
éste puede encontrar un patrón entre el valor numérico asignado y el resto de los datos. De
esta forma, el modelo puede asignar diferentes pesos según este número. Pero realmente no
existe ningún tipo de relación entre el número y el valor categórico.
36
Preparación de los Datos para el Modelo

El método OneHotEncoder() eliminaría este problema de secuenciación numérica pero al


añadir tantas columnas es preferible usar LabelEncoder().

Figura 5-1. Ejemplo del uso de un LabelEncoder()


En el siguiente fragmento de código se puede observar la implementación y utilización del
LabelEncoder():

Código 5.2 – Utilización del LabelEncoder


labelencoder = LabelEncoder()
count = 0

for col in cat_cols:


if col in train.columns:
count += 1
# Nos aseguramos de que utiliza todas las clases existentes en ambos
datasets en el entrenamiento
# Para ello se entrena el labelencoder con los dos datasets
labelencoder.fit(list(train[col].astype(str).values) +\
list(test[col].astype(str).values))
# Convertimos las columnas
train[col] = labelencoder\
.transform(list(train[col].astype(str).values))
test[col] = labelencoder.transform(list(test[col].astype(str).values))

# Limpieza de variables
del labelencoder

print("Se han codificado " + str(count) + " columnas.")

Se han codificado 26 columnas.

5.2 División de los datos


Finalmente, se deben reconfigurar y dividir los datos que se van a usar en el entrenamiento
del modelo. Para ello se crearán los siguientes nuevos datasets:
37 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

 El dataset X_train se compondrá de los datos de entrada del modelo a utilizar en el


entrenamiento y se conseguirá ordenando en el tiempo (según la variable
TransactionDT) las filas del dataset “train” que sirven como datos de entrada.
Además, es necesario eliminar del dataset las columnas que no se van a usar como
datos de entrenamiento, las cuales son las columnas “isFraud”, “TransactionDT” y
“TransactionID”.
 El dataset X_train_ID será la salida objetivo del modelo para cada fila X
correspondiente. En este caso se compondrá con la columna binaria “isFraud”.
 El dataset X_test se va a formar con los datos de entrada del modelo a utilizar en la
etapa de predicción final y se conseguirá ordenando en el tiempo (según la variable
TransactionDT) las columnas del dataset “test”. Al igual que con el dataset X, es
necesario eliminar las columnas “TransactionDT” y “TransactionID”.
 El dataset X_test_ID se va a usar simplemente a efectos prácticos para su uso en
representaciones gráficas y en el archivo con extensión .csv en el que se guardarán las
predicciones una vez realizadas.

Figura 5-2. División de datasets


Por tanto, los datasets “train” y “test” se dividirán usando los criterios anteriores:

Código 5.3 – División de los datos


X_train = train.sort_values('TransactionDT')\
.drop(['isFraud','TransactionDT','TransactionID'], axis=1)

X_train_ID = train.sort_values('TransactionDT')['isFraud']

X_test = test.sort_values('TransactionDT')\
.drop(['TransactionDT','TransactionID'], axis=1)

X_test_ID = test.sort_values('TransactionDT')['TransactionID']

# Limpieza de variables
del train, test

# Limpieza de variables utilizando el limpiador de Python (Modulo Garbage


Collector)
obj = gc.collect()
38
Preparación de los Datos para el Modelo

print("Se han limpiado " + str(obj) + " objetos.")

Se han limpiado 396 objetos.

5.3 Almacenamiento de los datos


Con el procesamiento que se ha realizado desde la carga de los datos hasta este punto ya se
tienen listos los datos para su utilización en el entrenamiento del modelo. Sin embargo, puede
ser bastante útil la exportación de estos datos a un archivo local.
De esta forma, los datasets procesados van a quedar guardados externamente y podrán ser
importados siempre que se necesiten. Esto simplificará y aumentará la rapidez de ejecuciones
posteriores del proceso de entrenamiento o uso del modelo.
El manejo de estos datos se realizará mediante un tipo de archivo contenido en la librería
Pandas. Estos archivos tienen un formato denominado “pickle” y una extensión “.pkl”. Este
formato implementa protocolos binarios para serializar o deserializar estructuras de objetos de
Python, de manera que los objetos son convertidos en un stream de bytes o viceversa.
La exportación de los datos se realizará mediante un método que contienen los objetos de tipo
dataset denominado .to_pickle() con el siguiente código:

Código 5.4 – Guardado de datos en archivo “Pickle”


X_train.to_pickle("X_train.pkl")
X_train_ID.to_pickle("X_train_ID.pkl")

X_test.to_pickle("X_test.pkl")
X_test_ID.to_pickle("X_test_ID.pkl")

Cada vez que se quiera realizar el proceso contrario, es necesario utilizar la función
read_pickle() incluida en la librería Pandas junto con la dirección del archivo que se va a
importar. En este caso, se tendría que utilizar de la siguiente forma:

Código 5.5 – Carga de datos desde un archivo “Pickle”


X_train = pd.read_pickle("X_train.pkl")
X_train_ID = pd.read_pickle("X_train_ID.pkl")

X_test = pd.read_pickle("X_test.pkl")
X_test_ID = pd.read_pickle("X_test_ID.pkl")

Otra opción sería la exportación a un archivo CSV que, aunque ocupa una mayor cantidad de
memoria, tienen una compatibilidad más extendida.
39 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

6 CREACIÓN Y ENTRENAMIENTO DEL


M ODELO

E
n este apartado se procederá a la creación del modelo y a su entrenamiento para, más
tarde, utilizarlo para predecir los resultados del dataset “test”. Para ello, se van a
utilizar diversas técnicas y algoritmos para el entrenamiento del modelo, así como para
la medición de distintos parámetros del modelo.
Primeramente, se va a crear una función que monitorice la efectividad del modelo durante su
entrenamiento. Posteriormente, se realizará una comparación entre los distintos tipos de
modelos de clasificación que existen en varias librerías diferentes. Además, una vez elegido el
modelo que se va a utilizar es necesario ajustar sus parámetros. Finalmente, se realizará el
entrenamiento del modelo y se observarán sus resultados.

Figura 6-1. Entrenamiento y uso del modelo

6.1 Función de evaluación del modelo


Para la evaluación del modelo se va a definir la función que se utilizará para realizar el
cálculo del “Área Bajo la Curva Característica Operativa del Receptor” (AUC-ROC). Este
factor será utilizado por el modelo durante el entrenamiento para la evaluación de su
efectividad (en lugar de su precisión) ya que se tiene un modelo de tipo binario en el que se
calculan probabilidades de que la salida sea 0 o 1 (Fraude o No Fraude).
La curva ROC es una representación de la sensibilidad frente a la especificidad en un sistema
40
Creación y Entrenamiento del Modelo

clasificador binario según varía el umbral de discriminación. Dicho de otro modo, es la


relación entre el TPR (Ratio de positivos verdaderos) y el FPR (Ratio de falsos positivos)
según varía el umbral de discriminación. El umbral se utiliza en este caso ya que el modelo va
a predecir las probabilidades de que una cierta entrada produzca cada salida (Fraude o No
Fraude) y se debe fijar un umbral de probabilidad a partir del cual se considera que el modelo
ha asignado esa salida a una de las dos. Según se va variando ese umbral se van tomando los
puntos que se consiguen y de esa forma se crea una curva, la curva ROC.

Figura 6-2. Curva ROC


Para obtener los puntos que forman la curva ROC se deben tener en cuenta las dos variables
que la forman, el TPR y el FPR:
 El ratio de verdaderos positivos (TPR) o sensibilidad se conseguirá con la siguiente
fórmula: TPR = TP / (TP + FN)
 El ratio de falsos positivos (FPR) o 1 - especificidad se conseguirá con la siguiente
fórmula: FPR = FP / (FP + TN)
Con ello se conseguirán diversos puntos. Por ejemplo, algunos de ellos pueden ser los
siguientes:

Figura 6-3. Diversos puntos en la ROC


41 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

Como se puede observar en la representación anterior, la zona superior izquierda representa


un TPR cercano a 1, mientras que el FPR sería cercano a 0, por lo que la clasificación será
casi perfecta. La zona central corresponde a una equivalencia entre TPR y FPR, lo que
indicaría que el modelo clasificaría los puntos de forma aleatoria.
En el diagrama se puede observar que el punto A obtiene aparentemente mejores resultados
que el punto B que se encuentra en la zona por debajo de la línea de clasificación aleatoria.
En esta zona hay una mayor cantidad de clasificaciones incorrectas que correctas. Pero ésto
no tiene por qué ser malo, ya que al estar ante un clasificador binario bastaría con invertir los
resultados. De esta forma, la mayoría de las veces que el clasificador asigna una clase el
resultado real sería el contrario como se puede apreciar en el siguiente diagrama:

Figura 6-4. Diversos puntos en la ROC invertidos


Al invertir los resultados del punto B se obtiene el punto B’, el cual se puede observar que
mantiene una simetría inversa respecto a la línea central y, finalmente, estaría más cerca de la
clasificación perfecta ideal que el punto A.
Por tanto, el área bajo la curva ROC (AUC) se creará con los puntos anteriores y tomará un
valor entre 0 y 1. Mientras más cercano sea el valor a 1, mejor va a predecir el modelo:

Figura 6-5. Valor AUC según la curva ROC


42
Creación y Entrenamiento del Modelo

Esta nueva función para el cálculo de la AUC-ROC se ha creado debido a que la función que
la librería SKLearn incluye por defecto realiza los cálculos de forma mucho más lenta y, para
un dataset del tamaño que se está manejando en este caso, el entrenamiento tomaría una
gran cantidad de tiempo. Con la nueva función se consigue reducir este tiempo
significativamente.
La función que calcula la AUC-ROC es la siguiente:

Código 6.1 – Funciones para el cálculo de la AUC-ROC


def fast_auc(y_true, y_prob):
# Basado en: https://www.kaggle.com/c/microsoft-malware-
prediction/discussion/76013
y_true = np.asarray(y_true)
y_true = y_true[np.argsort(y_prob)]
nfalse = 0
auc = 0
n = len(y_true)
for i in range(n):
y_i = y_true[i]
nfalse += (1 - y_i)
auc += y_i * nfalse
auc /= (nfalse * (n - nfalse))
return auc

def eval_auc(y_true, y_pred):


return 'auc', fast_auc(y_true, y_pred), True

Finalmente, se crea otra función que se encargue de representar gráficamente la curva AUC-
ROC utilizando para ello la función roc_curve() de SKLearn para obtener el ratio de
verdaderos y falsos positivos:

Código 6.2 – Función para la representación gráfica de la curva ROC


def plot_roc_curve(scores, y, oof):
# Plot curva ROC
plt.figure(figsize=(6,6))

fpr, tpr, thres = roc_curve(y, oof)


plt.plot(fpr, tpr, color='b')
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 1.05])
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('Curva ROC')

Además de la ROC, el modelo usará internamente otras medidas como la precisión y la “F1-
Score” (Que se calcula usando la precisión y la sensibilidad), que se encuentran en
sklearn.metrics.
43 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

6.2 Modelos de clasificación


En el contexto del machine learning existen una gran cantidad de técnicas y algoritmos de
clasificación que se han ido perfeccionando durante años. Por ello, hay una gran diversidad y
disponibilidad a la hora de escoger un modelo para utilizar para la clasificación del fraude en
transacciones monetarias.
Los métodos que se pueden usar para el proyecto utilizan todos ellos un algoritmo de
"Gradient Boosting". El Gradiente representa la pendiente de la tangente de la función de
pérdidas (lo que quiere decir que a menor gradiente mejores resultados va a tener el modelo).
Además, durante cada etapa del entrenamiento, se pasará a la siguiente etapa del algoritmo
de entrenamiento la información de los datos con mayor gradiente y con ello se conseguirá
que el algoritmo invierta más tiempo en entrenar las zonas con mayor gradiente para
ajustarlas mejor. A este proceso se le denomina Boosting.
En este caso se tienen una gran cantidad de datos que procesar y el tiempo de procesamiento
se puede alargar en gran medida. Debido a ello se ha optado por utilizar el algoritmo de
LightGBM ya que dispone de un equilibrio entre rapidez de entrenamiento y de ajuste de
hiperparámetros y una precisión de predicción buena.
El modelo LightGBM (Que utiliza la función LGBMClassifier()) utiliza una técnica de
gradiente de muestreo unilateral (GOSS) en la que se toman instancias de los datos con
mayores gradientes en cada iteración y un porcentaje de muestreo aleatorio del resto de
datos. Con esto se consigue que el entrenamiento y el ajuste de hiperparámetros sea rápido.
Otra ventaja de este método es que acepta variables categóricas con un algoritmo rápido y
tiene una precisión buena.

6.3 Creación del modelo


Teniendo las funciones anteriores creadas se puede proceder a crear otra función que lo
agrupará todo y se encargará del entrenamiento del modelo según los parametros que se le
proporcionen. El objetivo de esta función será el entrenamiento del modelo utilizando
X_train para luego realizar la predicción de la salida en el dataset de prueba X_test. Este
resultado se exportará a un archivo CSV y se subirá a Kaggle. La función va a tener varios
argumentos que se definen de la siguiente forma:
 X_train: Dataset que va a ser usado en el entrenamiento.
 X_test: Dataset que va a ser usado en la etapa de prueba.
 X_train_ID: Columna de datos que va a ser utilizada como salida del modelo en la
etapa de entrenamiento. Es decir, mientras el modelo se esté entrenando éste será el
objetivo que se debe conseguir a la salida.
 Params: Estructura de parámetros que se van a pasar al modelo para ajustarlo
44
Creación y Entrenamiento del Modelo

correctamente y mejorar sus resultados. Estos parámetros se explicarán con más


detalle y se realizará una función para su elección en el Apartado 6.4.
 Folds: Modelo de división de datos que se va a utilizar en el algoritmo. Como se
comentó en el Apartado 3.3, se va a utilizar la función TimeSeriesSplit() para realizar
una división de datos en el tiempo con 5 divisiones (folds). Este modelo se crea de la
siguiente forma:

Código 6.3 – División de datos en el tiempo


folds = TimeSeriesSplit(n_splits=5)

 Plot_feature_importance: Flag que le indica al modelo si se quiere representar la


importancia que el modelo le da a cada característica en un gráfico al utilizar la
función.
 Model: Argumento por el que se puede utilizar otra función de modelo para el
entrenamiento. Si no se indica nada, se utiliza el modelo LGBMClassifier().
 Verbose: Este argumento le indica al modelo cada cuántas iteraciones debe mostrar
las puntuaciones medias que se han calculado en ese intervalo.
 Early_stopping_rounds: Este argumento hace referencia al número de iteraciones
que deben ocurrir para que se active la técnica de parada anticipada del
entrenamiento. Esta técnica va a detener el entrenamiento del modelo cuando no se
mejoren los resultados obtenidos durante el número de rondas indicado, lo que ayuda
a prevenir el sobreentrenamiento.
 N_estimators: Número de estimadores que se van a utilizar en el modelo, es decir,
número de árboles que se van a entrenar.
 N_folds: Número de divisiones que se han utilizado en el modelo de división de datos.
Debe ser igual que el argumento de la función del parámetro Folds.
 N_jobs: Número de núcleos del procesador que se van a utilizar en el entrenamiento
del modelo. Si es igual a -1, utiliza todos los núcleos posibles.
El código relacionado con la creación de esta función es el siguiente:

Código 6.4 – Función para el entrenamiento del modelo


def train_model_classification(X_train, X_test, X_train_ID, params, folds,
plot_feature_importance=False, model=None, verbose=500,
early_stopping_rounds=200, n_estimators=5000, n_folds=5, n_jobs=-1):

# Inicializacion de variables:
columns = X_train.columns
n_splits = n_folds # Número de divisiones
X_test = X_test[columns]
45 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

result_dict = {} # Resultados
# Predicciones fuera del fold (out-of-fold). Guarda las predicciones
oof = np.zeros((len(X_train), 1)) # en la etapa de validación.
# Predicciones
prediction = np.zeros((len(X_test), 1))
# Puntuaciones de cada fold
scores = []
feature_importance = pd.DataFrame()

# Division y entrenamiento de cada fold:


# Se utiliza la función Split() de folds para dividir el dataset de
# entrenamiento inicial entre un dataset de entrenamiento y un dataset
# de validación utilizando las 5 divisiones del Apartado 3.3.
for fold_n,(train_index,valid_index)in enumerate(folds.split(X_train)):
print(f'Fold {fold_n + 1} comenzada en {time.ctime()}')

# Split() devuelve los índices de los datos. Se usa iloc para


# obtener los datos de esos índices.
X_train, X_valid = X_train[columns].iloc[train_index],\
X_train[columns].iloc[valid_index]
y_train, y_valid = X_train_ID.iloc[train_index],
X_train_ID.iloc[valid_index]

# Se crea el modelo LightGBM con los parámetros ya vistos.


model = lgb.LGBMClassifier(**params, n_estimators=n_estimators,\
n_jobs = n_jobs)

# Con la función fit() se comienza el entrenamiento que utiliza


# el dataset de entrenamiento y el de validación que se han
# creado junto al resto de parámetros.
model.fit(X_train, y_train, eval_set=[(X_train, y_train),\
(X_valid, y_valid)], eval_metric=eval_auc,\
verbose=verbose,\
early_stopping_rounds=early_stopping_rounds)

# Con el modelo entrenado se usa predict_proba() para realizar


# la predicción de la salida en validación y también con el
# dataset de prueba con la mejor puntuación del modelo.
y_pred_valid = model.predict_proba(X_valid)[:, 1]
y_pred = model.predict_proba(X_test,\
num_iteration=model.best_iteration_)[:, 1]

# Almacenamiento de variables de cada fold.


oof[valid_index] = y_pred_valid.reshape(-1, 1)
# La puntuación se calcula con la ROC-AUC entre la salida real
# del modelo y la predicha.
scores.append(metrics.roc_auc_score(y_valid, y_pred_valid))
prediction += y_pred.reshape(-1, 1)

if plot_feature_importance:
# Se guarda la importancia de cada caracteristica
fold_importance = pd.DataFrame()
fold_importance["feature"] = columns
# El modelo calcula automáticamente las características más
# importantes.
fold_importance["importance"] = model.feature_importances_
# Se guarda el número de fold (Del 1 al 5).
fold_importance["fold"] = fold_n + 1
feature_importance = pd.concat([feature_importance,\
fold_importance], axis=0)
46
Creación y Entrenamiento del Modelo

print("---------------------------------------------")

# La predicción final será la media de las predicciones en todos los


# folds:
prediction /= n_splits

print('Puntuacion Cross-Validation | mean: {0:.4f}, std: {1:.4f}.'\


.format(np.mean(scores), np.std(scores)))

# Almacenamiento de variables finales.


result_dict['oof'] = oof
result_dict['prediction'] = prediction
result_dict['scores'] = scores

# Plot Curva AUC ROC (Código 6.2).


plot_roc_curve(scores, y, oof)

# Plot importancia de caracteristicas


if plot_feature_importance:

# Se hace la media de las puntuaciones:


feature_importance["importance"] /= n_splits

# Se eligen las 25 mejores características:


cols = feature_importance[["feature", "importance"]]\
.groupby("feature").mean()\
.sort_values(by="importance", ascending=False)[:25].index

best_features = feature_importance\
.loc[feature_importance.feature.isin(cols)]

# Plot figures
plt.figure(figsize=(16, 12))
sns.barplot(x="importance", y="feature",\
data=best_features.sort_values(by="importance", ascending=False))
plt.title('Caracteristicas LGB (Media de los folds)')

# Almacenamiento de variables finales.


result_dict['feature_importance'] = feature_importance
result_dict['top_columns'] = cols

# Creación del gráfico del modelo utilizando el módulo GraphViz, como


# ya se ha comentado en el Apartado 2.1. Create_tree_diagraph() crea
# un diagrama en árbol.
viz = lgb.create_tree_digraph(model, tree_index=0, show_info=None,\
precision=3, orientation='horizontal')

# Se guarda la visualización en un archivo externo


viz.save(filename = 'viz.gv')

# Devuelve la variable con todos los resultados almacenados.


# Principalmente interesa “prediction” que es donde se tienen
# almacenadas las predicciones del dataset de prueba.
return result_dict
47 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

Figura 6-6. Algoritmo de entrenamiento

6.4 Elección de hiperparámetros


Finalmente, se deben definir los parámetros que se van a usar con el modelo. Estos
parámetros dependerán del tipo de modelo que se vaya a usar y para cada uno de ellos va a
existir una gran cantidad de ellos, por lo que solo se van a comentar los más importantes y
utilizados generalmente.
En este caso se ha elegido un modelo de tipo LGB, por lo que los parámetros que se deben
definir son los siguientes:
 Número de hojas (num_leaves): Define el número de hojas que va a tener cada
diagrama de árbol del modelo. Debe ser menor que 2^max_depth para que no se
produzca "overfitting". Se buscará su mejor valor.
48
Creación y Entrenamiento del Modelo

 Muestra mínima de cada hijo (min_child_samples): Representa el número de datos


necesarios en un hijo (hoja). Debe estar en un valor correcto para no producir
"underfitting" u "overfitting". Para ello, se debe tener en cuenta el tamaño del dataset
de entrenamiento y el parámetro num_leaves. Se ha elegido un valor igual a 79.
 Objetivo (objective): Especifica el objetivo que va a buscar el modelo. En este caso se
está usando un clasificador que organizará las predicciones en unos (Fraude) o ceros
(No Fraude) por lo que el objetivo será "binario".
 Máxima profundidad (max_depth): Número máximo de niveles de profundidad que
va a tener el diagrama en árbol que se va a crear. Se han elegido 13 niveles de
profundidad.
 Factor de aprendizaje (learning_rate): Ajusta el nivel de aprendizaje que va a tener
el modelo conforme vaya avanzando en los valores del dataset "train". Es decir, a
mayor factor de aprendizaje más variarán los pesos asignados a cada rama del
diagrama en cada iteración. Se ha elegido un valor de 0.03 para que entrene
lentamente.
 Tipo de Boosting (boosting_type): Tipo de algoritmo que se va a utilizar en el
entrenamiento y optimización del modelo. En este caso se ha optado por "Gradient
Boosting Decision Tree" (gbdt) ya que es la técnica más utilizada y ofrece buenos
resultados.
 Muestra (subsample): Porcentaje de los datos que se va a usar para entrenar cada
árbol en cada iteración, lo que ayudará a mejorar la generalización del modelo. Se ha
escogido el 90% de los datos.
 Frecuencia de la muestra (subsample_freq): Frecuencia de actualización de la
muestra en número de iteraciones. Normalmente se encuentra entre 1 y 5. Se ha
elegido un valor de 3.
 Semilla de muestreo (bagging_seed): Semilla aleatoria para el muestreo. Por
ejemplo, se ha escogido el valor 11.
 Muestra de columnas (colsample_bytree): Ratio de columnas usado en cada
subgrupo cuando se construye cada árbol del diagrama. Se ha escogido el 90% de los
datos.
 Métrica (metric): Métrica de evaluación del modelo. Como ya se ha comentado
anteriormente se va a utilizar la AUC.
 Verbosidad (verbosity): Define el nivel de importancia de los mensajes que se van a
escribir en pantalla. Con el nivel -1 sólo aparecerán errores fatales. En el caso en el que
se quier mostrar más información se escogería el valor 1.
49 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

 Alpha (reg_alpha): Término usado en los pesos en la regularización L1 (Lasso). Suele


encontrarse en un valor entre 0.1 y 0.5. Se buscará su mejor valor.
 Lambda (reg_lambda): Término usado en los pesos en la regularización L2 (Ridge).
Suele encontrarse en un valor entre 0.1 y 0.5. Se buscará su mejor valor.
A continuación, se definen algunos de los parámetros anteriores en un diccionario de Python
para más tarde pasarlos a la función que se va a encargar de la búsqueda del valor óptimo del
resto de los parámetros. Esta función se apoya en el uso de “GridSearchCV”, un algoritmo de
la librería SKLearn que irá probando las distintas combinaciones de parámetros que se le
indiquen y buscará la mejor combinación de ellos utilizando un método de validación cruzada.
Los parámetros que se buscarán con esta función van a ser num_leaves, reg_alpha y
reg_lambda y se probarán las distintas combinaciones de los distintos valores:

Figura 6-7. Combinaciones de valores de parámetros


Ya que existen tres parámetros a ajustar con tres valores distintos cada uno, en total
existirán 27 combinaciones posibles. El resto de los parámetros ya están definidos con los
valores que se han indicado al inicio de este mismo apartado. El código utilizado para la
búsqueda de los valores de los hiperparámetros que maximizan la precisión del modelo en
validación es el siguiente:

Código 6.5 – Ajuste de hiperparámetros


from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report

# Parámetros ya ajustados
params = {'min_child_samples': 79,
'objective': 'binary',
'max_depth': 13,
'learning_rate': 0.03,
"boosting_type": "gbdt",
"subsample": 0.9,
"subsample_freq": 3,
"bagging_seed": 11,
'colsample_bytree': 0.9,
"metric": 'auc',
"verbosity": -1,
}
50
Creación y Entrenamiento del Modelo

# Parametros que se van a ajustar


tuned_parameters = [{'num_leaves': [32, 64, 128],
'reg_alpha': [0.2, 0.3, 0.4],
'reg_lambda': [0.2, 0.3, 0.4],}]

# Division de datos utilizando la función train_test_split() con una


# division del 80% entrenamiento / 20% validación
X_train, X_valid, y_train, y_valid = train_test_split(X_train, X_train_ID,\
test_size=0.2, random_state=11)

# Modelo en entrenamiento
model = lgb.LGBMClassifier(**params, n_estimators=500, n_jobs = -1)

print("# Buscando hiperparametros usando la roc_auc")


print()

# Función de Cross Validation. Esta función se encargará de realizar la


# validación cruzada del modelo calculando para cada combinación de
# parámetros la puntuación que se le indique (roc_auc en este caso).
# Se entrenan CV = 10 modelos para cada combinación.
clf = GridSearchCV(model, tuned_parameters, cv=10, n_jobs = n_jobs,\
verbose=10, scoring='roc_auc')

# El modelo de Cross-Validation se entrena:


clf.fit(X_train, y_train)

print("Mejores parametros encontrados:")


print()
print(clf.best_params_)
print()
print("Puntuaciones:")
print()

# Los resultados de la CV se guardan en cv_results


means = clf.cv_results_['mean_test_score']
stds = clf.cv_results_['std_test_score']

# Print de las puntuaciones


for mean, std, params in zip(means, stds, clf.cv_results_['params']):
print("%0.3f (+/-%0.03f) for %r" % (mean, std * 2, params))

# Con la función classification_report() se genera a partir de la salida


# del modelo real y la predicha un informe en el que se indican datos
# relativos a la precisión y puntuaciones del modelo.
print()
print()
y_true, y_pred = y_valid, clf.predict(X_valid)
print(classification_report(y_true, y_pred))
print()
# Buscando hiperparametros usando la roc_auc
Fitting 10 folds for each of 27 candidates, totalling 270 fits
[CV 1/10; 1/27] START num_leaves=32, reg_alpha=0.2, reg_lambda=0.2...............
[CV 3/10; 1/27] START num_leaves=32, reg_alpha=0.2, reg_lambda=0.2...............
[CV 2/10; 1/27] START num_leaves=32, reg_alpha=0.2, reg_lambda=0.2...............
[CV 5/10; 1/27] START num_leaves=32, reg_alpha=0.2, reg_lambda=0.2...............
51 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

(...)
[CV 6/10; 27/27] END num_leaves=128, reg_alpha=0.4, reg_lambda=0.4; total time=
1.8min
[CV 7/10; 27/27] END num_leaves=128, reg_alpha=0.4, reg_lambda=0.4; total time=
1.9min
[CV 8/10; 27/27] END num_leaves=128, reg_alpha=0.4, reg_lambda=0.4; total time=
2.0min
[CV 10/10; 27/27] END num_leaves=128, reg_alpha=0.4, reg_lambda=0.4; total time=
1.8min
[CV 9/10; 27/27] END num_leaves=128, reg_alpha=0.4, reg_lambda=0.4; total time=
1.8min

Mejores parametros encontrados:


{'num_leaves': 128, 'reg_alpha': 0.4, 'reg_lambda': 0.2}

Puntuaciones:
0.927 (+/-0.002) for {'num_leaves': 32, 'reg_alpha': 0.2, 'reg_lambda': 0.2}
0.926 (+/-0.003) for {'num_leaves': 32, 'reg_alpha': 0.2, 'reg_lambda': 0.3}
0.926 (+/-0.002) for {'num_leaves': 32, 'reg_alpha': 0.2, 'reg_lambda': 0.4}
0.927 (+/-0.002) for {'num_leaves': 32, 'reg_alpha': 0.3, 'reg_lambda': 0.2}
0.927 (+/-0.003) for {'num_leaves': 32, 'reg_alpha': 0.3, 'reg_lambda': 0.3}
0.926 (+/-0.003) for {'num_leaves': 32, 'reg_alpha': 0.3, 'reg_lambda': 0.4}
0.927 (+/-0.002) for {'num_leaves': 32, 'reg_alpha': 0.4, 'reg_lambda': 0.2}
0.927 (+/-0.002) for {'num_leaves': 32, 'reg_alpha': 0.4, 'reg_lambda': 0.3}
0.927 (+/-0.003) for {'num_leaves': 32, 'reg_alpha': 0.4, 'reg_lambda': 0.4}
0.941 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.2, 'reg_lambda': 0.2}
0.940 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.2, 'reg_lambda': 0.3}
0.940 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.2, 'reg_lambda': 0.4}
0.941 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.3, 'reg_lambda': 0.2}
0.940 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.3, 'reg_lambda': 0.3}
0.940 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.3, 'reg_lambda': 0.4}
0.941 (+/-0.004) for {'num_leaves': 64, 'reg_alpha': 0.4, 'reg_lambda': 0.2}
0.941 (+/-0.003) for {'num_leaves': 64, 'reg_alpha': 0.4, 'reg_lambda': 0.3}
0.940 (+/-0.004) for {'num_leaves': 64, 'reg_alpha': 0.4, 'reg_lambda': 0.4}
0.951 (+/-0.003) for {'num_leaves': 128, 'reg_alpha': 0.2, 'reg_lambda': 0.2}
0.950 (+/-0.003) for {'num_leaves': 128, 'reg_alpha': 0.2, 'reg_lambda': 0.3}
0.950 (+/-0.003) for {'num_leaves': 128, 'reg_alpha': 0.2, 'reg_lambda': 0.4}
0.951 (+/-0.003) for {'num_leaves': 128, 'reg_alpha': 0.3, 'reg_lambda': 0.2}
0.951 (+/-0.004) for {'num_leaves': 128, 'reg_alpha': 0.3, 'reg_lambda': 0.3}
0.950 (+/-0.003) for {'num_leaves': 128, 'reg_alpha': 0.3, 'reg_lambda': 0.4}
0.951 (+/-0.004) for {'num_leaves': 128, 'reg_alpha': 0.4, 'reg_lambda': 0.2}
0.951 (+/-0.004) for {'num_leaves': 128, 'reg_alpha': 0.4, 'reg_lambda': 0.3}
0.950 (+/-0.003) for {'num_leaves': 128, 'reg_alpha': 0.4, 'reg_lambda': 0.4}
52
Creación y Entrenamiento del Modelo

precision recall f1-score support


0 0.98 1.00 0.99 114012
1 0.92 0.51 0.66 4096
accuracy 0.98 118108
macro avg 0.95 0.75 0.82 118108
weighted avg 0.98 0.98 0.98 118108

Como se puede observar en la salida por terminal del código anterior el valor óptimo de los
parámetros es: num_leaves = 128, reg_alpha = 0.4 y reg_lambda = 0.2.
Una vez determinados los valores óptimos de los parámetros anteriores se agrupan todos en el
diccionario de parámetros:

Código 6.6 – Conjunto de parámetros finales


params = {'min_child_samples': 79,
'objective': 'binary',
'max_depth': 13,
'learning_rate': 0.03,
"boosting_type": "gbdt",
"subsample": 0.9,
"subsample_freq": 3,
"bagging_seed": 11,
'colsample_bytree': 0.9,
"metric": 'auc',
"verbosity": -1,
'num_leaves': 128,
'reg_alpha': 0.4,
'reg_lambda': 0.2,
}

6.5 Entrenamiento del modelo y resultados


Una vez que se ha creado la función encargada del entrenamiento del modelo, se tienen los
datos correctamente procesados y se han determinado los hiperparámetros óptimos se puede
usar la función de entrenamiento del modelo proporcionándole todos los datos necesarios
como argumentos y se observan los resultados:

Código 6.7 – Entrenamiento del modelo


result_lgb = train_model_classification(X_train=X_train, X_test=X_test,\
X_train_ID=X_train_ID, params=params, folds=folds,\
plot_feature_importance=True, verbose=500,\
early_stopping_rounds=200, n_estimators=5000,\
n_folds=5, n_jobs=-1)

Fold 1 comenzada en Thu Jun 17 17:59:53 2021


Training until validation scores don't improve for 200 rounds
Early stopping, best iteration is:
[195] training's auc: 0.994318 valid_1's auc: 0.886762
53 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

---------------------------------------------
Fold 2 comenzada en Thu Jun 17 18:06:17 2021
Training until validation scores don't improve for 200 rounds
[500] training's auc: 0.996968 valid_1's auc: 0.903799
Early stopping, best iteration is:
[437] training's auc: 0.995574 valid_1's auc: 0.904611
---------------------------------------------
Fold 3 comenzada en Thu Jun 17 18:22:58 2021
Training until validation scores don't improve for 200 rounds
[500] training's auc: 0.991698 valid_1's auc: 0.8945
Early stopping, best iteration is:
[363] training's auc: 0.98602 valid_1's auc: 0.895842
---------------------------------------------
Fold 4 comenzada en Thu Jun 17 18:41:06 2021
Training until validation scores don't improve for 200 rounds
[500] training's auc: 0.986012 valid_1's auc: 0.91735
[1000] training's auc: 0.99612 valid_1's auc: 0.918434
Early stopping, best iteration is:
[904] training's auc: 0.995131 valid_1's auc: 0.918952
---------------------------------------------
Fold 5 comenzada en Thu Jun 17 19:26:33 2021
Training until validation scores don't improve for 200 rounds
[500] training's auc: 0.98192 valid_1's auc: 0.917863
Early stopping, best iteration is:
[684] training's auc: 0.988344 valid_1's auc: 0.918342
---------------------------------------------
Puntuacion Cross-Validation | mean: 0.9049, std: 0.0126.

Los resultados del algoritmo anterior se han guardado en la variable de tipo diccionario
result_lgb. Este diccionario cuenta con las siguientes claves en su interior:
 Oof: En esta clave del diccionario se han ido almacenando las distintas predicciones
que el modelo ha ido realizando en la etapa de validación en cada fold de la división.
 Prediction: Esta clave del diccionario almacena las predicciones que se han realizado
utilizando como entrada el dataset de prueba (X_test). Es decir, estas predicciones
son las que luego se utilizarán para extraerlas a un archivo CSV y subirlo a la página
web Kaggle.
 Scores: Su función es el almacenamiento de las puntuaciones que se han ido
consiguiendo en cada fold del entrenamiento del modelo. En este caso, almacenará el
resultado de la puntuación de la ROC_AUC.
 Feature_importance: En esta clave se guarda el valor de la importancia que el
modelo ha asignado a cada una de las características durante el entrenamiento. El
cálculo de este valor se va a tratar en el siguiente apartado.
 Top_columns: Esta clave almacena los índices de las columnas de las 25
características con mayor valor de importancia del modelo. De esta forma, puede
usarse en una etapa posterior para disponer directamente de estas características o
para generar gráficas.
Es necesario recordar que, al estar los datos divididos en 5 folds distintos, los valores de las
claves del diccionario “Oof”, “Prediction”, “Scores” y “Feature_importance” deben dividirse
por el número de folds para obtener su valor real.
54
Creación y Entrenamiento del Modelo

El algoritmo ha ido entrenando los distintos folds y aprendiendo de forma que se ha


conseguido ir mejorando la puntuación conseguida en validación en cada uno de ellos. Esto
también es debido a que en cada fold sucesivo se tienen en cuenta una mayor cantidad de
datos para realizar el entrenamiento, lo que ha supuesto también un mayor tiempo de
procesamiento como se puede observar en las marcas de tiempo de la salida por terminal
anterior.
Se ha representado en un gráfico la puntuación conseguida en validación en cada fold y, para
el cálculo de la puntuación final, se ha utilizado la media de estas puntuaciones:

Figura 6-8. Puntuaciones obtenidas en cada Fold


Como se puede observar en la gráfica anterior, la puntuación de precisión en validación media
entre todos los Folds que se ha conseguido es de un 90.49%, el cual es un valor bastante
bueno en este caso que se tiene gran cantidad de características.
También resulta interesante la visualización de las puntuaciones conseguidas en la evaluación
del dataset de entrenamiento para ver si el modelo ha terminado con un ajuste deficiente
(“underfitting”) o sobreajustado (“overfitting”):

Figura 6-9. Puntuaciones obtenidas en cada Fold en Entrenamiento


55 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

Observando el gráfico se observa que el modelo en general está altamente ajustado a los datos
de entrenamiento, con lo que se ha conseguido una puntuación media de los Folds en
entrenamiento de un 99.19%.
Por tanto, se tiene finalmente un modelo entrenado que está ligeramente sobreajustado ya
que, aunque esté bastante ajustado a los datos de entrenamiento, generaliza de forma correcta
y consigue una buena puntuación en la etapa de validación.

6.5.1 Importancia de las características

Resulta interesante analizar cuáles son las características a las que el modelo ha dado más
importancia en el entrenamiento. Esta importancia se ha calculado utilizando los flujos de los
árboles de decisión (Se verán posteriormente en el Apartado 6.5.3). Cada hoja del árbol va a
tener un valor de predicción asociado y unos nodos padres anteriores en el flujo que también
tienen un valor de predicción esperado.
Por tanto, según las características que influyen en ese flujo y el cambio entre el valor de
predicción esperado y el real al pasar de un nodo padre a hijo, se puede calcular la
contribución de cada característica al entrenamiento del modelo.
La función utilizada en el cálculo es 𝑰𝒎𝒑𝒐𝒓𝒕𝒂𝒏𝒄𝒊𝒂 𝒇(𝒙) = 𝒑𝒊𝒏𝒊 + ∑𝑲 𝒌 𝟏 𝒄𝒐𝒏𝒕𝒓𝒊𝒃(𝒙, 𝒌) donde
“p_ini” es la predicción inicial y “contrib(x,k)” es la diferencia que genera la característica k
en el vector de características x.

Figura 6-10. Importancia de las características en el modelo entrenado


56
Creación y Entrenamiento del Modelo

Como se puede observar en la gráfica anterior, algunas de las características a las que el
clasificador les asigna más peso en la predicción del fraude son aquellas que ya se denotaron
como importantes en el Apartado 2, ya que son de las características principales de las
transacciones analizadas.
Por ejemplo, las cuatro características más importantes para la detección del fraude han sido
“card1” y “card2” (Valores numéricos relacionados con las tarjetas), “TransactionAmt”
(Cantidad monetaria transferida) y “addr1” (Dirección de correo electrónico codificada en un
número por privacidad).
Sin embargo, algunas de ellas que parecían ser importantes a simple vista (como “card4” -
Proveedor y “card6” – Tipo de tarjeta) no han resultado tan importantes en el entrenamiento
final del modelo.

6.5.2 Curva ROC

Figura 6-11. Curva ROC


Esta representación y su curva asociada se han generado como ya se comentó en el Apartado
6.1. En el esquema anterior se observa que la curva ROC tiene un valor de AUC cercano a 1,
por lo que el clasificador va a tener una precisión buena.
57 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

6.5.3 Diagrama de árbol

Como se comentó anteriormente, se puede utilizar el módulo Graphviz para observar el


diagrama de grafos del modelo. Debido a la gran cantidad de características y nodos que se
tienen en este modelo se genera un diagrama de gran tamaño.
Este diagrama se ha generado utilizando la función Create_tree_digraph() que se encuentra
dentro de la función de entrenamiento train_model_clasification(). Solo se muestra a
continuación una pequeña parte del diagrama total: [9]

Figura 6-12. Porción del diagrama de grafos del modelo


Observando el diagrama anterior, se puede ver que el modelo cuenta con dos tipos de nodos:
 Los nodos intermedios son aquellos que dividen el flujo de la predicción según una
condición. En este caso, las condiciones para elegir un camino u otro es el valor de una
cierta característica determinada. Estos valores o pesos son determinados por el
modelo en la etapa de entrenamiento.
 El segundo tipo de nodo es el nodo hoja (“leaf”). Este tipo de nodo es un nodo final o
sumidero que define el valor de la predicción que van a tener los datos que sigan la
ruta hasta él. Como se denotó en el Código 6.4, es necesario dividir este valor por el
número de folds utilizados (5 en este caso) para obtener el valor real de la predicción.
Debido a la gran cantidad de datos y características que se tienen, se va a generar un
diagrama con una gran cantidad de nodos de ambos tipos.

6.5.4 Cálculo de fraudes totales detectados

Para contar el número de fraudes que se han detectado en total en los datos de prueba se
pueden analizar las probabilidades encontradas, que se encuentran almacenadas en la variable
result_lgb[‘prediction’]. Por ejemplo, se pueden tomar como fraudes las predicciones con una
probabilidad mayor de 0.5, con lo que se tendría el siguiente código:
58
Creación y Entrenamiento del Modelo

Código 6.8 – Cálculo del número de fraudes totales


res = pd.DataFrame(result_lgb['prediction'], columns=['isFraud'])

frauds = len(res.where(res >= 0.5).dropna()\


.sort_values(by=['isFraud'], ascending = False))

print("Se han predecido en total " + str(frauds) +\


" fraudes en el dataset \"test\"")

Se han predecido en total 6361 fraudes en el dataset "test"

Figura 6-13. Valores de las predicciones en X_test (Recortada en el eje Y)


Al observar el histograma anterior se puede ver que la mayoría de las predicciones se sitúan
en las zonas de predicción menor a 0.3 (No Fraude) y predicción mayor a 0.8 (Fraude). Existe
también una zona intermedia en la cuál el valor de la predicción oscila entre 0.3 y 0.8 y que
tiene alrededor de 500 predicciones por cada franja de valores.
Por defecto se toma el umbral en un valor de 0.5 para determinar el valor que tomará una
predicción y en este caso parece que es un valor correcto ya que cae en la zona intermedia y
la mayoría de las predicciones quedan agrupadas a su izquierda o derecha. Con ello se han
detectado finalmente 6361 fraudes en el dataset de prueba (X_test).
59 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

6.6 Almacenamiento de resultados en un archivo externo


Los resultados de las predicciones se pueden guardar en un archivo de tipo “CSV”. De esta
forma, pueden consultarse en cualquier momento, utilizarse más tarde con otro tipo de código
y subirse a la web de Kaggle.
El guardado de los resultados se ha realizado utilizando el siguiente código:

Código 6.9 – Guardado de las predicciones en un archivo “CSV”


res = pd.DataFrame(result_lgb['prediction'], columns=['isFraud'])

# X_test_ID son los identificadores TransactionID del dataset X_test


sub = pd.concat([X_test_ID, res], axis=1)

sub.to_csv('submission.csv', index=False)

El resultado es el archivo “submission.csv” y se muestran sus primeras filas a continuación:

Figura 6-14. Primeras filas del archivo CSV

6.6.1 Subida a Kaggle

Por último, se ha procedido a la subida del archivo CSV a la página web de Kaggle, que
evaluará el rendimiento de la predicción en el dataset de prueba. La puntuación conseguida es
la siguiente:

Figura 6-15. Puntuación final conseguida en Kaggle


60
Creación y Entrenamiento del Modelo

Finalmente, se ha obtenido una puntuación de 90.95% en la predicción con el dataset X_test,


un valor bueno y similar al obtenido en validación.
61 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

7 DESARROLLOS FUTUROS Y
CONCLUSIONES

C
omo ya se ha comentado anteriormente, las tecnologías relacionadas con la Inteligencia
Artificial se encuentran en constante evolución ya que continuamente se están
desarrollando nuevas técnicas y tipos de modelo que mejoran el rendimiento del
sistema, su velocidad, el uso de memoria y procesador que necesitan, etc.
Gracias a esto, el proyecto se va a poder ampliar o integrar con otros proyectos ya existentes
de forma conveniente. Para ello se podrían modificar desde los propios datos, su
procesamiento y su análisis hasta el tipo de modelo que se usa y los parámetros asociados a
él.
A continuación, se presentan distintas ideas de mejora o integración de este proyecto con
otros similares:
 Creación de un algoritmo que realice la búsqueda de los mejores hiperparámetros de
un modelo y lo entrene con ellos automáticamente.
 Integración de un mayor número de técnicas de reducción de la dimensionalidad como
las comentadas en el Apartado 4.
 Utilización de otro tipo de proceso de extracción de datos que puedan ser más útiles
en un caso práctico real, como la lectura de los datos directamente desde una base de
datos con SQL.
Para concluir el desarrollo del proyecto se puede realizar un balance de los resultados que se
han obtenido, comparándolos con los inicialmente planteados para comprobar si se han
cumplido con éxito los objetivos marcados al inicio del proyecto.
Inicialmente se tenían los datos almacenados en distintos archivos de extensión CSV que se
han cargado correctamente y procesado de forma que los datos estén disponibles en variables
que ocupen el menor espacio en memoria posible. Además, estas variables se han procesado
con técnicas de reducción de la dimensionalidad para disminuir la cantidad de información
irrelevante que contienen.
Los datos se han analizado denotando las columnas más relevantes que contienen y realizando
análisis gráficos de ellos que permitieron observar la relación entre los valores de las variables
y la salida del modelo deseada. También se ha realizó un análisis en el tiempo de manera que
se conociera la función de división de los datos que se necesitaba usar.
62
Desarrollos futuros y Conclusiones

Posteriormente, se realizó una comparativa entre una parte de los distintos modelos que se
encontraban disponibles para usar en el proyecto. Se optó por utilizar el modelo LightGBM
ya que era el que ofrecía mejores resultados con la mejor relación entre la precisión ofrecida y
el coste de computación necesario.
El modelo elegido para el entrenamiento de los datos necesitaba de la definición de ciertos
parámetros. Para realizar la búsqueda de estos parámetros se realizó una función
personalizada que se encargaba del entrenamiento de un modelo variando los parámetros en
cada instancia y presentaba los resultados al finalizar, mostrando a su vez los parámetros que
maximizaban la precisión del modelo en validación.
Finalmente, se ha realizado el entrenamiento del modelo con los parámetros determinados y
se ha observado que el modelo ha obtenido un buen valor de precisión en la etapa de
validación: 90.49%. Además, gracias al resto de gráficas generadas sobre el modelo se ha
podido comprobar cúales han sido las características a las que el modelo ha ofrecido más
importancia.
Por último, se guardaron los resultados de la utilización del modelo en la predicción en el
conjunto de datos de prueba en un archivo de tipo CSV para su almacenamiento y uso en
cualquier proyecto posterior y se subió este archivo a la web de Kaggle para comprobar su
puntuación con el dataset de prueba. La puntuación conseguida ha sido de un 90.95%.
El proyecto ha avanzado favorablemente y se han cumplido los objetivos inicialmente
marcados, desde la carga y procesado de los datos hasta el entrenamiento y uso del modelo.
Además, aunque no fuese uno de los objetivos iniciales del proyecto, se han mostrado y
utilizado técnicas de reducción de la dimensionalidad en el conjunto de los datos.
Desde el punto de vista personal ha sido un proyecto bastante gratificador ya que se ha
profundizado en el uso y aprendizaje de técnicas de Machine Learning y en el procesado de
datos, las cuáles son de las herramientas que más se utilizan en la industria, lo que supone
una gran ganancia de experiencia en el ámbito profesional.
63 Inteligencia artificial para la detección de fraude en transacciones realizadas con tarjetas de crédito

R EFERENCIAS

[1] Kaggle, «IEEE-CIS Fraud Detection | Kaggle» [En línea]. Disponible:


https://www.kaggle.com/c/ieee-fraud-detection/data. [Último acceso: Mayo 2021].

[2] Pandas, «API Reference - pandas 1.2.4 documentation» [En línea]. Disponible:
https://pandas.pydata.org/docs/reference/index.html. [Último acceso: Mayo 2021].

[3] Scikit, «API Reference - scikit-learn 0.24.2 documentation» [En línea]. Disponible:
https://scikit-learn.org/stable/modules/classes.html. [Último acceso: Mayo 2021].

[4] Vidhya, «Dimensionality Reduction Techniques | Python» [En línea]. Disponible:


https://www.analyticsvidhya.com/blog/2018/08/dimensionality-reduction-techniques-
python/ [Último acceso: Mayo 2021].

[5] Raschka, Sebastian, «What is the difference between LDA and PCA for dimensionality
reduction?» [En línea]. Disponible: https://sebastianraschka.com/faq/docs/lda-vs-
pca.html. [Último acceso: Mayo 2021].

[6] Medium, «Understanding AUC-ROC Curve | by Sarang Narkhede | Towards Data


Science» [En línea]. Disponible: https://towardsdatascience.com/understanding-auc-roc-
curve-68b2303cc9c5. [Último acceso: Mayo 2021].

[7] LightGBM, «lightgbm.LGBMClassifier - LightGBM 3.2.1.99 documentation» [En línea].


Disponible:
https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html.
[Último acceso: Mayo 2021].

[8] XGBoost, «Python API Reference - xgboost 1.5.0-SNAPSHOT documentation» [En


línea]. Disponible:
https://xgboost.readthedocs.io/en/latest/python/python_api.html#module-
xgboost.sklearn. [Último acceso: Mayo 2021].
64
Glosario

[9] Diagrama Graphviz al completo: https://i.imgur.com/Ncldiok.png

[10] ETSI, «Formatos de Publicación» [En línea]. Disponible:


https://www.etsi.us.es/publicaciones/formatos. [Último acceso: Mayo 2021].

G LOSARIO

AUC
Area Under the Curve 39
CSV
Comma-Separated Values 10
FPR
False Positive Rate 40
GBDT
Gradient Boosting Decision Tree 9
IDE
Integrated Development Environment 5
LDA
Linear Discriminant Analysis 31
MAE
Mean Absolute Error 8
PCA
Principal Component Analysis 31
ROC
Receiver Operating Characteristic 8
SVM
Support Vector Machine 8
TPR
True Positive Rate 40

También podría gustarte