Dolandırıcılık Tespiti – Kaggle Yarışması – Bölüm 1

Görsel Kaynak: https://www.exchangewire.com/

Bu yazımda sizlere Kaggle platformu üzerinden düzenlenen “IEEE-CIS Fraud Detection” başlıklı yarışmada ekipçe yaptığımız işlemleri, yarışmanın hikayesini, yol haritamızı ve kodlarımızı sizlerle paylaşacağım. Öncelikle yarışmaya 6.381 takım ve 7.416 kişi katıldı. Biz bu yarışmada 482. olduk ve %8’lik dilime girerek bronz madalya ile yarışmayı tamamladık. Utku Kubilay Çınar, Dr. Fırat Gönen, Ekrem Bayar ve Gökhan Çetinkaya ile beraber çıktığımız ve sonu güzel yolda yaşadıklarımızı, zorluklarımızı, zaman planlamamızı, hangi durumla karşılaştığımızda ne gibi kararlar aldığımızı sizlerle paylaşacağım. Veri seti hakkında bilgi vererek başlayalım o zaman…

Yarışmanın konusu kısaca fraud (dolandırıcı) olan kişileri belirlemekti ve test verisindeki hedef değişkenimizi 0-1 şeklinde sınıflandırmaktı. Uzaktan bakıldığında basit bir problem gibi gözüküyor… “Nasıl olsa sınıflandırma problemi !!!” gibi düşünsekte, veriyle uğraşmaya başladığımızda durumun bu kadar kolay olmadığını gördük. Final modeli oluşturmak için modeli eğitirken, eğitim ve test verilerinin toplam hacmi 5 GB’ ın üstündeydi. Tabloları birleştirip veriyi manipüle etmeye başladığımızda eğitim verimizde; 590.540 gözlem – 434 değişken, test verimizde ise 506.691 gözlem – 433 değişken vardı. Hedef değişkenimiz “TransactionID” ise 0-1 şeklindeydi. 3 ay süresi olan bu yarışma, veri bilimi ile ilgilenen ve meraklı kişiler için harika bir veri seti olduğunu düşünüyorum. Sizlere naçizane önerim, veri setini indirerek veriyi modellemeniz sizler için çok iyi olacaktır çünkü burada gerçek hayat problemine çok benzer bir veri seti ile karşılaşıyoruz. Veri setinde ciddi eksik veriler, yapı (pattern) yakalama, kural bazlı olaylar, önemli değişkenler ve birbirinden türetilecek dış kaynaklı verilerle modeli geliştireceğimiz durumlar vardı.

Yarışma süresi yaklaşık 3 aydı. Bu 3 ayın neredeyse 2.5 ayı keşifçi veri analizi, veri manipülasyonu, yeni değişkenler üretme ile geçti. Son 2-3 haftada sadece modeli geliştirme üzerine çalıştık (evet arkadaşlar, virgülden sonra 3. hane nasıl yükseltilir onunla uğraştık…) fakat yaptığımız her önemli işlemle modeller kurduk ve submit (sonuçları kaggle’a yükleme işlemi) ettik. Sıralamada 79. bile olduk. Virgülden sonra 2. / 3. değerler oynadığı için aşırı öğrenme (overfit) konusuna çok dikkat etmemiz gerekiyordu çünkü listenin 1. ile 1000. arasında yaklaşık %1.5-2’lik fark vardı.

Bu yarışmada bence dereceye girilecek, daha doğrusu büyük farklar yaracak kısım “keşifçi veri analizi” ve “patern yakalama” bölümleriydi. Yarışmada değişkenler açıklanmıştı ama çok yetersizdi ve gerekli iş bilgisi (alan bilgisi / know how) yeterince olmadığı için veriyi çok iyi anlamamız, kredi kartlarından detay bilgi bilmemiz ve kural bazlı yapıları görmemiz gerekiyordu. Bu sebeplerle keşifçi veri analizi ve yapıları görme konusuna çok zaman harcadık. Örneğin modelimizde mail adresin, kart numarasının ilk 4 rakamı, kredi kartı ile adres bilgisinin tekilleştirilmesi gibi oluşturulan değişkenler, hedef değişken üzerinde açıklayıcılığı ve önemi çok fazlaydı. Muhtemelen ekibimizde bankacılık ya da telekomünikasyon alanlarında tecrübeli biri olsaydı alan bilgimiz daha fazla olacağından daha farklı bir sonuç alarak, daha başarılı modeller kurabilirdik. Aslında gerçek hayat problemlerinde de durum bu şekilde olduğu için sizlere bu veri ile uğraşmanızı öneriyorum. Öncelikle yol haritamızı sizlerle paylaşmak istiyorum. Aşağı yukarı “Uçtan Uca Makine Öğrenmesi Örneği: Titanik Gemi Kazası Uygulaması” yazımda da paylaştığım gibi ( yazıma buradan ulaşabilirsiniz bkz) süreci böldük. Yol haritamız ve veriye yaklaşımımız aynıydı fakat buradaki farklılık ise veriyi anlamlandırmamız çok uzun sürdü.

Yol Haritası

  • Her şeyden önce ekip arkadaşlarını gazlamak, motivasyonu yüksek tutmak ve sonuçta bir yarışma olduğu için mutlu sona inanmak 🙂 (Burası önemli) (sen yaparsın olum, sen kralsın olum vs.)
  • Veriyi açtıktan sonra, genel bir inceleme sonrasında ciddi bir şekilde literatürü araştırmak. Literatürde gördüğümüz modelleri, üretilen değişkenleri incelemek ve yapılabilirliğine bakmak.
  • Dosya hacmini küçültmek .
  • Nasıl bir dış kaynak veri ile modeli modeli zenginleştirdik? (biz 3-4 farklı dış kaynak veri kullandık)
  • Eksik verileri – uç değerleri – korelasyonları basit düzeyde incelemek.
  • Hangi değişkenler numerik? Hangi değişkenler kategorik?
  • Değişkenlerin dağılımını incelemek.
  • Kategorik verilerin kırılımında numerik ve hedef değişkeni incelemek.
  • Bu incelemeler sırasında önemli gördüğümüz değişkenli not etmek ve gelecekte parametre mühendisliği için kullanmak.
  • Keşifçi veri analizi ile değişken üretimi, dağılım incelemesi, test ve eğitim verisi arasındaki dağılım farklılıklarını incelemek (son 2 madde bizim için çok uzun sürdü ve ciddi düzeyde modeli iyileştirdi). Verideki beklenmeyen durumları belirlemek, eksik verileri ortanca-otalama gibi değerlerle doldurmak.
  • Anlamlı değişkenler üretmek.
  • Tüm bu işlemler sonunda korelasyonları inceleyerek 0.85-0.90 üstü korelasyonlu olan değişkenlerin birini veri setinden çıkarmak (regresyon problemi için çoklu doğrusal bağlantıyı engellemek).
  • Hangi modeller kullanılacağını belirlemek.
  • En uygun model belirleyerek parametre ayarlamalarını yapmak, modeli geliştirmek.
  • Gerekli ise veri manipülasyonu ve tekrar modelin kurulması

Yarışma sürecindeki 3 ayımız hemen hemen yukarıdaki maddeler ile özetleyebilirim. Bu yarışmada gördük ki veriyi, değişkenlerin ne olduğunu anlayan ve ona göre model kuran kişiler yarışmada daha iyi sonuç alıyorlar. Bu sebeple keşifçi veri analizi ve parametre üretme kısımlarını çok uzun süreyle çalıştık.

Bazı Keşifçi Veri Analizleri Görselleri

Eksik Veriler

Eksik veriler bizim için çok büyük bir problemdi. Veri setinde çok fazla eksik veri vardı. Numerik değişkenlerin analizlerine ve eksik veri doldurmaya başlamadan önce veri setinde eksiklik dağılımına baktık ve %60’ ın üstünü tamamen sildik. Kategorik tüm değişkenlerde ise karar bazlı-komşuluk bazlı eksik veri doldurduk, karar veremediğimiz ve veriye yanlılık katmamak için kategorik değişkenlere “missing” değerini koyduk. Eksik verinin tanımını doğru yapmak gerekir. Eksik veriler belli bir düzene göre mi eksik yoksa rastlantısal olarak mı eksik kalmış ? Bu sorunun cevabı önemlidir. Tamamıyla Rastlantısal Olarak Kayıp Veriler (TROK)(bkz: Missing Completely at Random, MCAR) olarak adlandırılan eksik veriler, başka bir parametrenin etkisiyle doğrudan ya da dolaylı olarak eksilmeyen, veri setinde tamamen rastlantısal (rastgele) olarak dağılmış eksik verilerdir.

İstatistikte eksik verilerin rastlantısal olarak dağılmasını isteriz. Bunun için “missing value analysis” yapılır ve bu analizi yaparken t – Testi (başka testler de mevcuttur) kullanılır. Hipotezimiz ise kayıp veriler rastlantısal dağılıp-dağılmadığıdır ve araştırmacı, kayıp verilerin rastlantısal olarak dağılmasını amaçlar ve test eder.

“Missing” değerini koymamızın sebebi eksik veriler gözle görülür şekilde belli bir düzenle silinmişti (örneğin her 1.000 gözlemden 3. sütündan 20 gözlemi ardışık sil) (t testi yapılan eksik veri analizleri, bkz. MCAR). Bunu farkedince karar bazlı doldurduğumuz verileri tekrar inceledik ve kategorik verilere eksik verileri doldurmak yerine “missing” yazmak daha mantıklı geldi. Belki bu kısımı biraz daha geliştirebilirdik fakat bu süreç yaklaşık 3 hafta sürdüğü için “yapabildiğimiz kadarını yapalım gerisini bu şekilde dolduralım” şeklinde ilerledik.

Yarışmada sıralamaya baktığımızda insanlar virgülden sonra 3. hane ile yüzlerce sıra atlıyor ya da düşüyordu. Bu sebeple eksik veri doldurma işlemi son derece kritik ve yanlılık eklememe konusunda çok önemliydi. Veri manipülasyonu işlemlerinde istatistik teorilerini bilmenin avantajları yadsınamaz bir gerçektir. Eksik veriyi, yansız tamamlamak ciddi bir bilgi birikimi gerektirir ama cankurtaran görevi gören istatistik bilimi sayesinde, işimiz kolaylaşmaktadır. Eksik verilerle mücadele kapsamında, istatistik teorileriyle geliştirilen birçok algoritma mevcuttur. Araştırmacı, bu algoritmaları kullanarak eksik veri problemini büyük ölçüde giderebilir.

Eksik veriyi doldurmak için tabi birden fazla algoritmalar ve yöntemler mevcuttur ama veriyi doldururken (imputasyon) yapılırken yansız(unbias) doldurmak önemlidir. Verinin karakterini bozmadan, bize söylediği bilgileri ve doğruları kaçırmadan eksik veriyi doldurmak önemlidir. Sonuçta verinin karakteri ile oynuyor-değiştiriyorduk (eksik veri doldurma yazıma bu link üzerinden ulaşabilirsiniz).

Görselden de göreceğiniz üzere, numerik değişkenlerin yaklaşık 50 tanesini eksik veriden dolayı sildik. Bu bizim sütün bazlı yaptığımız eleme yöntemiydi. Satır bazlı eksik gözlemler incelediğimizde, satırdaki gözlemin %80’i eksik olma durumunda eğitim verisinden çıkartılmasını kararlaştırdık.

Feature Engineering (Parametre Mühendisliği / Yeni Değişkenler)

Çalışmada (özellikle keşifçi veri analizi kısmında) yüzlerce belki binlerce satır kod olduğu için hepsini burada paylaşamayacağım fakat bazılarının görsellerini koyacağım. Tüm bu işlemlerin amacı veriyi daha iyi anlamak, hedef (bağımlı değişkeni) daha iyi modelleyebilmek, eğer karar bazlı bir model kurulacaksa kırılımları daha iyi gösterebilmekti. Keşifçi veri analizi yazıma ulaşmak için bu linke gidebilirsiniz. Bir veri bilimi projesinde veri manipülasyonu ve keşifçi veri analizleri süreçleri en uzun süren ve en kritik rol oynayan süreçtir çünkü “No Free Lunch Theorem”e göre tüm modeller birbirine eşit (daha doğru bir açıklamayla, her problem için hiçbir model, diğerinden üstünlüğü bulunmamaktadır, veriye göre başarılı model değişkenlik gösterir şeklinde açıklanabilir). Şuraya varmak istiyorum; “Model kurulur abi, sen modele neleri sokacağına(input) odaklan.”

Denediğimiz farklı modeller sonucunda LGBM modelini kullanmaya karar verdik. Bunun asıl sebebi ise hızlı çalışması, gradyan tabanlı ve karar bazlı bir model olmasıydı. Sonuç olarak final modelimizde LGBM modelini kullanmaya karar verdik. Lokal bilgisayarımızda K-fold, groupfold, tabakalı (stratified fold) cross validation setleriyle modeli eğittik. Kullandığımız bilgisayarın özellikleri ise CPU: 1xsingle core hyper threaded (1 core, 2 threads), Xeon Processors @2.3Ghz, 46MB Cache, 16 GB RAM. Yaklaşık eğitim süresi ise kısaca gece yatmadan önce çalıştır uyanınca bitiyor formatındaydı.

Değişkenlerimizden bazıları kredi kartı numaralarının dörder hanelik numaralarıydı. Biz burada card1 ve card2 değişkenlerini birleştirerek, yeni bir değişken ürettik ve bu değişken modelimiz için önemliydi. Her bir gözlem kart için harcanan dolar cinsinden tutar vardı.

Karta göre oluşturduğumuz değişkenlerimizden biri de kart limitiydi. Ortalama ve standart sapmaya göre (dağılımları incelenerek) kategorik bir aralık belirledik ve buna olası kredi kart limiti gibi bir değişken ürettik. Hedef değişken kırılım dağılımında incelediğimizde güzel bir değişken olduğunu düşündük ve modele ekledik. Ayrıca dolandırıcı olma olasılığı gibi değişkenler de ürettik.

Hadi şimdi kodlayalım…

Yarışmada hem R hem de Python programlarını kullandık. R için kullanılan kütüphaneler;

library(tidyverse) 
library(magrittr) 
library(DataExplorer) 
library(vroom) 
library(e1071) 
library(lubridate) 
library(GGally) 
library(gridExtra) 
library(stringr) 
library(rvest)

Python’da kullanılan kütüphaneler;

import os 
import gc 
import time 
import keras 
import random 
import warnings 
import datetime 
import numpy as np 
import pandas as pd 
import xgboost as xgb 
import seaborn as sns 
from math import sqrt 
import lightgbm as lgb 
import tensorflow as tf 
import keras.backend as K 
from keras.models import Model 
import matplotlib.pyplot as plt 
from lightgbm import LGBMRegressor 
from scipy.optimize import minimize 
from keras.callbacks import Callback 
from xgboost import XGBRegressor,xgb 
from sklearn.decomposition import PCA 
from catboost import CatBoostRegressor 
from keras.optimizers import Adam, Nadam 
from sklearn.preprocessing import LabelEncoder 
from keras.utils.generic_utils import get_custom_objects 
from keras.layers import Dense, Input, Dropout, BatchNormalization, Activation 
from sklearn.metrics import roc_auc_score, mean_absolute_error,confusion_matrix 
from sklearn.model_selection import StratifiedKFold, KFold, RepeatedKFold, GroupKFold, GridSearchCV, train_test_split, TimeSeriesSplit, cross_val_score 
 
warnings.filterwarnings("ignore") 
%matplotlib inline

Veri seti hacim anlamında büyük olduğu için öncelikle veriyi küçülmemiz gerekti. Piyasada buna “Memory Reduction” deniyor. Burada aslında çok basit veritabanı mantığı ile verinin boyutunu yarı yarıya düşürdük. Verinin tipini değiştirerek dosya boyutunda ciddi bir azaltma yaptık. Bu işlemle beraber eğitim verisini %66.2, test verini ise %65.6 oranında azaltmış olduk böylelikle eğitim verimiz 669 MB, test verimiz de 584 MB boyutuna inmiş oldu.

def reduce_mem_usage(df, verbose=True):
    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
    start_mem = df.memory_usage().sum() / 1024**2    
    for col in df.columns:
        col_type = df[col].dtypes
        if col_type in numerics:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)  
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)    
    end_mem = df.memory_usage().sum() / 1024**2
    if verbose: print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, 100 * (start_mem - end_mem) / start_mem))
    return df

train = reduce_mem_usage(train)
test  = reduce_mem_usage(test)

Veri setinden türettiğimiz ilk değişken, Kart Limitiydi.

cardlimit <- limit_max %>% mutate(Limit = if_else(max_spend < 500, 500, 
                                           if_else(max_spend < 1200, 1500,
                                                   if_else(max_spend < 2200, 3500,
                                                           if_else(max_spend < 4500, 5000,
                                                                   if_else(max_spend < 7000, 9000, 
                                                                           if_else(max_spend < 10000, 14000,
                                                                                   if_else(max_spend < 15000, 20000,
                                                                                           if_else(max_spend < 20000, 30000,
                                                                                                   if_else(max_spend < 30000, 40000,
                                                                                                           if_else(max_spend < 50000,60000,
                                                                                                                   if_else(max_spend < 90000, 120000,
                                                                                                                           if_else(max_spend < 140000, 180000,
                                                                                                                                   if_else(max_spend < 200000, 250000,
                                                                                                                                           if_else(max_spend < 260000, 300000,
                                                                                                                                                   if_else(max_spend < 320000, 360000,
                                                                                                                                                           if_else(max_spend < 390000, 450000, 600000)))))))))))))))))

Buna bağlı olarak diğer ürün parametresine (ProductCD) göre de aynı işlemi yaptık. Kredi kartı numaraları ile oluşturduğumuz ve modelimiz için önemli olan değişkenlerin bir diğeri ise tüm kredi kartı numaralarını birleştirerek bunları kategorikleştirme işlemiydi.

Veri setimizde DeviceInfo ve id_30 adında iki değişken vardı. Bununla gözlemin bilgisayarın ya da telefonun sürümü gibi bilgiler içeriyordu. Buraya dış kaynak veri kullanarak Ios ve Windows gibi özelliklerine göre çeşitli değişkenleri birleştirdik. Güncellenme tarihi, sürümü ve türü gibi değişkenlere ulaşmış olduk.

train <- train  %>% 
    mutate(OpSystem = if_else(
        str_sub(id_30, start = 1, end = 3) %in% "Mac", "Mac",
        if_else(is.na(id_30), "other",
                if_else(str_sub(id_30, start = 1, end = 7) %in% "Windows", "Windows",
                        if_else(str_sub(id_30, start = 1, end = 7) %in% "Android", "Android",
                                if_else(str_sub(id_30, start = 1, end = 3) %in% "iOS", "iOS",
                                        if_else(id_30 %in% "Linux", "Linux",
                                                if_else(id_30 %in% "func", "other", "other")
                                               )))))))

Veri setimizde diğer değişkenlerden biri de gözlemin sahip olduğu mail uzantısıydı. Buradan biz ülkeye ulaştık ve bunu yeni bir değişken yaptık.

Yazımın ilk kısmını burada bitiriyorum. Okunması daha kolay olabilmesi için yazımı iki bölüme böldüm. İkinci bölümde daha çok kodlar olacak. 2. bölümde Parametre Mühendisliğinden devam edeceğim ve son olarak modelimizi oluşturacağız. Serinin devamı olan ikinci yazımda buluşma dileğiyle. Yazımın 2. kısmına bu linkten ulaşabilirsiniz.

Saygılarımla,

Varsayımlarınızın sağlanması dileğiyle,

Veri ile kalın, Hoşça kalın..

Utku Kubilay Çınar – Makine Öğrenmesi ve Yapay Zeka Çözümleri Takımında Data Scientist @ DoğuşTeknoloji

Yazar Hakkında
Toplam 21 yazı
Utku Kubilay ÇINAR
Utku Kubilay ÇINAR
YTÜ - Doktora - Veri Bilimi - Alghanim Industries - Data Scientist
Yorumlar (Yorum yapılmamış)

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

×

Bir Şeyler Ara