33 minute read

Fraud Prediction

Problem Statement

💼 Fraud merupakan suatu tindakan penipuan pada transaksi keuangan. Transaksi ini bertujuan untuk memperoleh keuntungan dari suatu entitas lain dengan cara ilegal sehingga dapat menyebabkan kerugian.

Transaksi fraud sering terjadi di industri perbankan. Beberapa contoh transaksi fraud pada industri perbankan antara lain adalah pishing, skimming, penipuan kartu kredit, penipuan pinjaman, dll.

Efek negatif dari transaksi fraud adalah adanya kerugian finansial di kedua belah pihak baik customer maupun industri perbankan. Oleh karena itu diperlukan tindakan pencegahan dengan deteksi lebih dini terhadap potensi transaksi fraud.

Transaksi fraud dapat dideteksi lebih awal dengan cara membangun model machine learning dengan metode klasifikasi. Tugas kita pada project kali ini adalah membuat model klasifikasi untuk mendeteksi transaksi fraud agar dapat dilakukan action plan berikutnya

Rubrics Penilaian

Untuk menyelesaikan project ini, silahkan mengacu pada rubrics di bawah ini serta memberikan deskripsi dari proses yang Anda kerjakan untuk setiap bagian.

Data Preparation

(1 poin) Bagaimana melakukan persiapan data sebelum dilakukan pemodelan.

  • Metode apa saja yang yang dilakukan dalam proses persiapan data?
  • Apakah terdapat data yang missing atau duplicate, bagaimana cara mengatasi data tersebut? Referensi: dokumentasi pandas atau FAQ

(4 poin) Bagaimana cara untuk melakukan feature engineering ataupun pemilihan variabel dari data yang tersedia.

  • Apakah terdapat variable yang dihilangkan? Jika iya, kenapa?
  • Apakah terdapat variable yang ditambahkan? Jika iya, kenapa?

Exploratory Data Analysis

(2 poin) Exploratory Data Analysis

  • Berikan penjelasan informatif dari visualisasi dan/atau segala jenis hasil eksplorasi Anda.
  • Bagaimana distribusi data pada setiap variabel?
  • Apakah terdapat informasi menarik antara variable predictor dengan variable target?

Data Pre-processing and Model Fitting

(2 poin) Data Pre-processing

  • Apakah terdapat variabel yang harus di-encoding? Kalau ada, apa saja dan kenapa?
  • Bagaimana pembagian proporsi Data Train & Test?

(4 poin) Membuat model, pilih model berdasarkan model yang sudah diajarkan dikelas (logistic regression / knn)

  • Buatlah model yang dapat menjawab pertanyaan bisnis di atas.
  • Variable apa yang dirasa cukup penting dalam pembuatan model? Sertakan alasannya.
  • Metode evaluasi apa yang cocok digunakan untuk kasus ini? Jelaskan.

Prediction Performance

(1 poin) Metrics yang dipilih mencapai 60% pada data train (2 poin) Metrics yang dipilih mencapai 60% pada data test

Conclusion

(2 poin) Tuliskan kesimpulan dari project yang anda kerjakan.

  • Apakah model sudah dapat melakukan prediksi dengan baik? Jelaskan.
  • Apakah model sudah dapat menjawab pertanyaan bisnis yang ada? Jelaskan.
  • Action plan apa yang dapat dilakukan untuk tindakan preventif transaksi fraud?

Total Poin Capstone Project : 18

NOTE:

Apabila Anda sudah berhasil mendapatkan model yang baik dan berhasil menjawab seluruh rubric di atas, Anda diperkenankan untuk melakukan eksplorasi model menggunakan metode lain di luar yang diajarkan di kelas. Hasil model yang mendapatkan metrics pengukuran paling baik akan mendapatkan bonus nilai (di luar nilai capstone).

Penjelasan Dataset

Berikut adalah penjelasan setiap kolom yang terdapat pada dataset yang akan digunakan:

  • X: ID kartu
  • id_tanggal_transaksi_awal: ID tanggal transaksi dilakukan
  • tanggal_transaksi_awal: tanggal dilakukan transaksi (POSIX format)
  • tipe_kartu: tipe kartu yang bertransaksi
  • id_merchant: ID merchant kartu tersebut bertransaksi
  • nama_merchant: nama merchant kartu tersebut bertransaksi
  • tipe_mesin: tipe mesin yang digunakan untuk bertransaksi (ATM, EDC, dll)
  • tipe_transaksi: jenis transaksi
  • nama_transaksi: nama jenis transaksi
  • nilai_transaksi: nilai uang yang tercatat saat transaksi
  • id_negara: ID negara tempat terjadi transaksi
  • nama_negara: nama negara tempat terjadi transaksi
  • nama_kota: nama kota tempat terjadi transaksi
  • lokasi_mesin : lokasi mesin
  • pemilik_mesin: pemilik mesin
  • waktu_transaksi: waktu transaksi berlangsung
  • kuartal_transaksi: kuartal waktu transaksi berlangsung
  • kepemilikan_kartu: kepemilikan kartu
  • nama_channel: nama channel kartu tersebut bertransaksi
  • id_channel: ID channel kartu tersebut bertransaksi
  • flag_transaksi_finansial: jenis transaksi
  • status_transaksi: keberhasilan atau kegagalan transaksi
  • bank_pemilik_kartu: kepemilikan kartu yang dimiliki suatu bank
  • rata_rata_nilai_transaksi: rata - rata nilai transaksi
  • maksimum_nilai_transaksi: nilai maksimum transaksi
  • minimum_nilai_transaksi: nilai minimum transaksi
  • rata_rata_jumlah_transaksi: rata - rata jumlah transaksi
  • flag_transaksi_fraud: transaksi fraud (1) atau tidak fraud (0)

Data Preparation

(1 poin) Bagaimana melakukan persiapan data sebelum dilakukan pemodelan.

  • Metode apa saja yang yang dilakukan dalam proses persiapan data?
  • Apakah terdapat data yang missing atau duplicate, bagaimana cara mengatasi data tersebut? Referensi: dokumentasi pandas atau FAQu FAQ

Import Library yang dibutuhkan

import pandas as pd
import numpy as np
from datetime import datetime
import seaborn as sns
import matplotlib
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
import statsmodels.api as sm
from sklearn.metrics import recall_score, precision_score, accuracy_score
from sklearn.preprocessing import StandardScaler

Read Data

fraud = pd.read_csv('transaksi_fraud.csv')
fraud.head().T
0 1 2 3 4
X 4676 788 1520 9346 2914
id_tanggal_transaksi_awal 2457646 2457419 2457521 2457659 2457311
tanggal_transaksi_awal 2457726 2457507 2457612 2457746 2457385
tipe_kartu 111 111 2 103 0
id_merchant -2 -2 -2 75336 -2
nama_merchant 1798 1798 1798 249 1798
tipe_mesin 2605127 -3 -3 2806174 2334932
tipe_transaksi 26 156 156 58 26
nama_transaksi 10 12 12 6 10
nilai_transaksi 2200000.0 2500000.0 1200000.0 320000.0 150000.0
id_negara 96 96 96 96 96
nama_negara 5 5 5 5 5
nama_kota 265 121 101 239 69
lokasi_mesin 4137 1264 1283 7049 3425
pemilik_mesin 613 2196 2049 588 613
waktu_transaksi 193955 73140 140216 155117 143339
kuartal_transaksi 4 2 3 3 3
kepemilikan_kartu 2 1 1 2 2
nama_channel 1 5 5 2 1
id_channel 9 8 8 4 9
flag_transaksi_finansial False False False False False
status_transaksi 3 3 3 3 3
bank_pemilik_kartu 999 999 999 999 999
rata_rata_nilai_transaksi 1332292.784 1369047.619 15523460.4 711764.7059 617968.254
maksimum_nilai_transaksi 9750000.0 10000000.0 100000000.0 6884408.0 2500000.0
minimum_nilai_transaksi 10000.0 30000.0 41804.0 10000.0 100000.0
rata_rata_jumlah_transaksi 2.73 2.33 2.4 1.98 1.46
flag_transaksi_fraud 0 1 0 0 0

Cek keseimbangan fraudnya

fraud_asli = fraud.copy()
fraud_asli['flag_transaksi_fraud'].value_counts()
flag_transaksi_fraud
0    12215
1      910
Name: count, dtype: int64

Cek informasi sekilas dan tipe data

fraud.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13125 entries, 0 to 13124
Data columns (total 28 columns):
 #   Column                      Non-Null Count  Dtype  
---  ------                      --------------  -----  
 0   X                           13125 non-null  int64  
 1   id_tanggal_transaksi_awal   13125 non-null  int64  
 2   tanggal_transaksi_awal      13125 non-null  int64  
 3   tipe_kartu                  13125 non-null  int64  
 4   id_merchant                 13125 non-null  int64  
 5   nama_merchant               13125 non-null  int64  
 6   tipe_mesin                  13125 non-null  int64  
 7   tipe_transaksi              13125 non-null  int64  
 8   nama_transaksi              13125 non-null  int64  
 9   nilai_transaksi             13125 non-null  float64
 10  id_negara                   13125 non-null  int64  
 11  nama_negara                 13125 non-null  int64  
 12  nama_kota                   13125 non-null  int64  
 13  lokasi_mesin                13125 non-null  int64  
 14  pemilik_mesin               13125 non-null  int64  
 15  waktu_transaksi             13125 non-null  int64  
 16  kuartal_transaksi           13125 non-null  int64  
 17  kepemilikan_kartu           13125 non-null  int64  
 18  nama_channel                13125 non-null  int64  
 19  id_channel                  13125 non-null  int64  
 20  flag_transaksi_finansial    13125 non-null  bool   
 21  status_transaksi            13125 non-null  int64  
 22  bank_pemilik_kartu          13125 non-null  int64  
 23  rata_rata_nilai_transaksi   13104 non-null  float64
 24  maksimum_nilai_transaksi    13104 non-null  float64
 25  minimum_nilai_transaksi     13104 non-null  float64
 26  rata_rata_jumlah_transaksi  13104 non-null  float64
 27  flag_transaksi_fraud        13125 non-null  int64  
dtypes: bool(1), float64(5), int64(22)
memory usage: 2.7 MB

Berdasarkan deskripsi data sebelumnya dan fraud.info() maka beberapa kolom akan diubah ke tipe data lain.

  • object = [‘X’, ‘id_tanggal_transaksi_awal’, ‘nama_channel’, ‘id_channel’, ‘bank_pemilik_kartu’, ‘id_merchant’, ‘nama_merchant’, ‘nama_transaksi’]
  • category = [‘tipe_kartu’, ‘tipe_mesin’, ‘tipe_transaksi’, ‘id_negara’, ‘nama_negara’, ‘nama_kota’, ‘lokasi_mesin’, ‘pemilik_mesin’, ‘kepemilikan_kartu’, ‘status_transaksi’]
  • datetime = [‘tanggal_transaksi_awal’, ‘waktu_transaksi’]

Ubah datatype

obj_kolom = ['X', 'id_tanggal_transaksi_awal', 'nama_channel', 'id_channel', 'bank_pemilik_kartu', 'id_merchant', 'nama_merchant', 'nama_transaksi']
cat_kolom = ['kuartal_transaksi', 'tipe_kartu', 'tipe_mesin', 'tipe_transaksi', 'id_negara', 'nama_negara', 'nama_kota', 'lokasi_mesin', 'pemilik_mesin', 'kepemilikan_kartu', 'status_transaksi']
dt_kolom = ['tanggal_transaksi_awal', 'waktu_transaksi']
# -> object
fraud[obj_kolom] = fraud[obj_kolom].astype('object')
# -> category
fraud[cat_kolom] = fraud[cat_kolom].astype('category')
# -> datetime
fraud['tanggal_transaksi_awal'] = fraud['tanggal_transaksi_awal'].apply(lambda x : datetime.fromtimestamp(x))
fraud['waktu_transaksi'] = fraud['waktu_transaksi'].apply(lambda x : datetime.fromtimestamp(x))
fraud.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13125 entries, 0 to 13124
Data columns (total 28 columns):
 #   Column                      Non-Null Count  Dtype         
---  ------                      --------------  -----         
 0   X                           13125 non-null  object        
 1   id_tanggal_transaksi_awal   13125 non-null  object        
 2   tanggal_transaksi_awal      13125 non-null  datetime64[ns]
 3   tipe_kartu                  13125 non-null  category      
 4   id_merchant                 13125 non-null  object        
 5   nama_merchant               13125 non-null  object        
 6   tipe_mesin                  13125 non-null  category      
 7   tipe_transaksi              13125 non-null  category      
 8   nama_transaksi              13125 non-null  object        
 9   nilai_transaksi             13125 non-null  float64       
 10  id_negara                   13125 non-null  category      
 11  nama_negara                 13125 non-null  category      
 12  nama_kota                   13125 non-null  category      
 13  lokasi_mesin                13125 non-null  category      
 14  pemilik_mesin               13125 non-null  category      
 15  waktu_transaksi             13125 non-null  datetime64[ns]
 16  kuartal_transaksi           13125 non-null  category      
 17  kepemilikan_kartu           13125 non-null  category      
 18  nama_channel                13125 non-null  object        
 19  id_channel                  13125 non-null  object        
 20  flag_transaksi_finansial    13125 non-null  bool          
 21  status_transaksi            13125 non-null  category      
 22  bank_pemilik_kartu          13125 non-null  object        
 23  rata_rata_nilai_transaksi   13104 non-null  float64       
 24  maksimum_nilai_transaksi    13104 non-null  float64       
 25  minimum_nilai_transaksi     13104 non-null  float64       
 26  rata_rata_jumlah_transaksi  13104 non-null  float64       
 27  flag_transaksi_fraud        13125 non-null  int64         
dtypes: bool(1), category(11), datetime64[ns](2), float64(5), int64(1), object(8)
memory usage: 2.2+ MB

Cek deskripsi data numerik dan kategorik

# numerik
fraud.describe().T
count mean min 25% 50% 75% max std
tanggal_transaksi_awal 13125 1970-01-29 17:39:00.576761904 1970-01-29 17:35:03 1970-01-29 17:37:31 1970-01-29 17:39:03 1970-01-29 17:40:32 1970-01-29 17:42:34 NaN
nilai_transaksi 13125.0 1315218.824267 1.0 200000.0 570000.0 1250000.0 75000000.0 2838050.053336
waktu_transaksi 13125 1970-01-02 21:34:55.669638095 1970-01-01 07:00:47 1970-01-02 11:30:22 1970-01-02 22:05:07 1970-01-03 07:43:40 1970-01-04 00:31:54 NaN
rata_rata_nilai_transaksi 13104.0 1364131.826769 50000.0 568563.3893 1024239.017 1679777.627 24666666.67 1448583.095472
maksimum_nilai_transaksi 13104.0 12287602.944063 38000.0 2500000.0 6000000.0 15000000.0 100000000.0 16459046.159531
minimum_nilai_transaksi 13104.0 76519.328602 1.0 25000.0 36964.0 63200.0 75000000.0 676539.058057
rata_rata_jumlah_transaksi 13104.0 2.436182 1.0 1.68 2.1 2.79 19.78 1.389367
flag_transaksi_fraud 13125.0 0.069333 0.0 0.0 0.0 0.0 1.0 0.25403
# numerik
fraud.select_dtypes(include=['object', 'category']).describe().T
count unique top freq
X 13125 8793 2925 6
id_tanggal_transaksi_awal 13125 360 2457509 169
tipe_kartu 13125 14 111 4846
id_merchant 13125 1122 -2 11307
nama_merchant 13125 1105 1798 11307
tipe_mesin 13125 5341 -3 883
tipe_transaksi 13125 20 26 3575
nama_transaksi 13125 20 10 3575
id_negara 13125 13 96 13081
nama_negara 13125 12 5 13080
nama_kota 13125 229 128 5404
lokasi_mesin 13125 5814 600 21
pemilik_mesin 13125 1666 613 10418
kuartal_transaksi 13125 4 3 5224
kepemilikan_kartu 13125 2 2 12236
nama_channel 13125 5 1 10418
id_channel 13125 4 9 10418
status_transaksi 13125 1 3 13125
bank_pemilik_kartu 13125 1 999 13125

Cek missing atau duplicated

fraud.isna().sum()
X                              0
id_tanggal_transaksi_awal      0
tanggal_transaksi_awal         0
tipe_kartu                     0
id_merchant                    0
nama_merchant                  0
tipe_mesin                     0
tipe_transaksi                 0
nama_transaksi                 0
nilai_transaksi                0
id_negara                      0
nama_negara                    0
nama_kota                      0
lokasi_mesin                   0
pemilik_mesin                  0
waktu_transaksi                0
kuartal_transaksi              0
kepemilikan_kartu              0
nama_channel                   0
id_channel                     0
flag_transaksi_finansial       0
status_transaksi               0
bank_pemilik_kartu             0
rata_rata_nilai_transaksi     21
maksimum_nilai_transaksi      21
minimum_nilai_transaksi       21
rata_rata_jumlah_transaksi    21
flag_transaksi_fraud           0
dtype: int64
fraud[fraud['rata_rata_nilai_transaksi'].isna()].T
610 1489 1829 3069 3752 3781 6185 6501 7655 7660 ... 7777 8719 8758 9147 10006 10374 10401 11142 11520 11797
X 1039 4020 14080 1335 8871 12852 8659 7518 2557 1813 ... 4192 2465 9504 342 5102 9641 14239 6907 8832 2409
id_tanggal_transaksi_awal 2457561 2457655 2457510 2457514 2457531 2457368 2457603 2457620 2457558 2457385 ... 2457331 2457592 2457524 2457526 2457517 2457593 2457429 2457308 2457468 2457536
tanggal_transaksi_awal 1970-01-29 17:40:07 1970-01-29 17:40:58 1970-01-29 17:38:41 1970-01-29 17:39:33 1970-01-29 17:40:10 1970-01-29 17:36:52 1970-01-29 17:40:43 1970-01-29 17:41:37 1970-01-29 17:39:26 1970-01-29 17:37:43 ... 1970-01-29 17:36:13 1970-01-29 17:40:45 1970-01-29 17:38:45 1970-01-29 17:40:21 1970-01-29 17:39:25 1970-01-29 17:40:16 1970-01-29 17:37:11 1970-01-29 17:35:48 1970-01-29 17:39:13 1970-01-29 17:39:51
tipe_kartu 93 103 93 111 111 111 93 111 93 111 ... 111 111 111 104 93 111 93 103 111 93
id_merchant -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 ... -2 -2 -2 -2 388748 -2 -2 -2 -2 -2
nama_merchant 1798 1798 1798 1798 1798 1798 1798 1798 1798 1798 ... 1798 1798 1798 1798 1574 1798 1798 1798 1798 1798
tipe_mesin -3 2330 185678 2344943 2805857 2337114 288963 -3 3186008 2393471 ... 1906758 2331560 181 -3 2383750 1752625 2489227 1478519 3166779 1180307
tipe_transaksi 156 147 159 26 26 148 26 156 238 26 ... 159 26 147 156 58 385 26 385 26 159
nama_transaksi 12 3 19 10 10 5 10 12 9 10 ... 19 10 3 12 6 11 10 11 10 19
nilai_transaksi 100000.0 1000000.0 6000000.0 500000.0 2500000.0 25000.0 600000.0 1200000.0 2150000.0 200000.0 ... 25000.0 400000.0 500000.0 200000.0 220130.0 1200000.0 350000.0 100000.0 200000.0 13918500.0
id_negara 96 96 96 96 96 96 96 96 96 96 ... 96 96 96 96 96 96 96 96 96 96
nama_negara 5 5 5 5 5 5 5 5 5 5 ... 5 5 5 5 5 5 5 5 5 5
nama_kota 128 128 101 141 128 265 57 101 128 128 ... 128 70 128 3 251 60 128 128 259 128
lokasi_mesin 1360 374 3988 3442 7852 3674 4759 7791 8414 3763 ... 2540 3489 2979 1213 7314 2162 8212 1486 8422 503
pemilik_mesin 1637 613 613 613 613 613 613 496 613 613 ... 613 613 613 1616 2309 613 613 613 613 613
waktu_transaksi 1970-01-02 17:28:42 1970-01-03 10:20:58 1970-01-02 22:08:43 1970-01-03 05:00:42 1970-01-03 07:10:21 1970-01-02 19:46:51 1970-01-03 04:43:42 1970-01-03 07:02:13 1970-01-02 11:36:56 1970-01-03 04:32:37 ... 1970-01-02 11:00:30 1970-01-02 01:12:28 1970-01-03 07:44:12 1970-01-02 05:20:54 1970-01-02 23:02:10 1970-01-02 17:51:54 1970-01-02 23:25:27 1970-01-02 00:59:10 1970-01-03 04:17:08 1970-01-02 12:20:14
kuartal_transaksi 3 4 3 3 3 3 3 3 2 3 ... 2 2 3 2 3 3 3 2 3 2
kepemilikan_kartu 1 2 2 2 2 2 2 1 2 2 ... 2 2 2 1 2 2 2 2 2 2
nama_channel 5 1 1 1 1 1 1 5 1 1 ... 1 1 1 5 2 1 1 1 1 1
id_channel 8 9 9 9 9 9 9 8 9 9 ... 9 9 9 8 4 9 9 9 9 9
flag_transaksi_finansial False False False False False False False False False False ... False False False False False False False False False False
status_transaksi 3 3 3 3 3 3 3 3 3 3 ... 3 3 3 3 3 3 3 3 3 3
bank_pemilik_kartu 999 999 999 999 999 999 999 999 999 999 ... 999 999 999 999 999 999 999 999 999 999
rata_rata_nilai_transaksi NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
maksimum_nilai_transaksi NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
minimum_nilai_transaksi NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
rata_rata_jumlah_transaksi NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
flag_transaksi_fraud 1 1 1 1 1 0 1 0 1 1 ... 0 1 1 1 1 1 1 0 1 1

28 rows × 21 columns

Saya akan coba menggunakan 2 metode dalam mengatasi missing value.

  1. Drop missing value karena missing value hanya 21 dan secara kumulatif hanya 0.16 % saja kehilangan data (prioritas karena mudah)
  2. Menggunakan imputasi (singular (mean,median) atau flexible imputation (KNNImputer atau IterativeImputer))
fraud = fraud.dropna()
fraud.isna().sum()
X                             0
id_tanggal_transaksi_awal     0
tanggal_transaksi_awal        0
tipe_kartu                    0
id_merchant                   0
nama_merchant                 0
tipe_mesin                    0
tipe_transaksi                0
nama_transaksi                0
nilai_transaksi               0
id_negara                     0
nama_negara                   0
nama_kota                     0
lokasi_mesin                  0
pemilik_mesin                 0
waktu_transaksi               0
kuartal_transaksi             0
kepemilikan_kartu             0
nama_channel                  0
id_channel                    0
flag_transaksi_finansial      0
status_transaksi              0
bank_pemilik_kartu            0
rata_rata_nilai_transaksi     0
maksimum_nilai_transaksi      0
minimum_nilai_transaksi       0
rata_rata_jumlah_transaksi    0
flag_transaksi_fraud          0
dtype: int64

Cek duplikat

fraud.duplicated().any()
False

Alhamdulillah tidak ada duplikat wkwkwkwkwk

(4 poin) Bagaimana cara untuk melakukan feature engineering ataupun pemilihan variabel dari data yang tersedia.

  • Apakah terdapat variable yang dihilangkan? Jika iya, kenapa?
  • Apakah terdapat variable yang ditambahkan? Jika iya, kenapa?
# numerik
fraud.select_dtypes(include=['object', 'category']).describe().T
count unique top freq
X 13104 8780 2925 6
id_tanggal_transaksi_awal 13104 360 2457509 169
tipe_kartu 13104 14 111 4835
id_merchant 13104 1121 -2 11287
nama_merchant 13104 1105 1798 11287
tipe_mesin 13104 5338 -3 880
tipe_transaksi 13104 20 26 3568
nama_transaksi 13104 20 10 3568
id_negara 13104 13 96 13060
nama_negara 13104 12 5 13059
nama_kota 13104 229 128 5394
lokasi_mesin 13104 5810 600 21
pemilik_mesin 13104 1665 613 10401
kuartal_transaksi 13104 4 3 5211
kepemilikan_kartu 13104 2 2 12218
nama_channel 13104 5 1 10401
id_channel 13104 4 9 10401
status_transaksi 13104 1 3 13104
bank_pemilik_kartu 13104 1 999 13104

Apakah terdapat variable yang dihilangkan? Jika iya, kenapa?

Iya, terutama variabel yang hanya menyangkut ID dan Nama yang memiliki nilai unik terlalu banyak akan dihilangkan seperti X, id_tanggal_transaksi_awal, id_merchant, nama_merchant, tipe_mesin, tipe_transaksi, nama_transaksi, id_negara, nama_negara,tipe_kartu, nama_kota, lokasi_mesin, pemilik_mesin lalu untuk status_transaksi dan bank_pemilik_kartu juga dihapus karena kategori yang tidak punya unique value

fraud[['nama_channel', 'id_channel']].corr()
nama_channel id_channel
nama_channel 1.000000 -0.376658
id_channel -0.376658 1.000000

Karena nama_channel dan id_channel tidak berkorelasi cukup kuat seperti asumsi saya diawal jadi dibiarkan saja

fraud_clean = fraud.drop(columns=['X', 'id_tanggal_transaksi_awal', 'id_merchant', 'nama_merchant', 'tipe_mesin', 'tipe_transaksi', 'nama_transaksi', 'id_negara','tipe_kartu', 'nama_negara', 'nama_kota', 'lokasi_mesin', 'pemilik_mesin', 'status_transaksi', 'bank_pemilik_kartu'])
fraud_clean.head().T
0 1 2 3 4
tanggal_transaksi_awal 1970-01-29 17:42:06 1970-01-29 17:38:27 1970-01-29 17:40:12 1970-01-29 17:42:26 1970-01-29 17:36:25
nilai_transaksi 2200000.0 2500000.0 1200000.0 320000.0 150000.0
waktu_transaksi 1970-01-03 12:52:35 1970-01-02 03:19:00 1970-01-02 21:56:56 1970-01-03 02:05:17 1970-01-02 22:48:59
kuartal_transaksi 4 2 3 3 3
kepemilikan_kartu 2 1 1 2 2
nama_channel 1 5 5 2 1
id_channel 9 8 8 4 9
flag_transaksi_finansial False False False False False
rata_rata_nilai_transaksi 1332292.784 1369047.619 15523460.4 711764.7059 617968.254
maksimum_nilai_transaksi 9750000.0 10000000.0 100000000.0 6884408.0 2500000.0
minimum_nilai_transaksi 10000.0 30000.0 41804.0 10000.0 100000.0
rata_rata_jumlah_transaksi 2.73 2.33 2.4 1.98 1.46
flag_transaksi_fraud 0 1 0 0 0

Apakah terdapat variable yang ditambahkan? Jika iya, kenapa?

Sepertinya belum ada variable yang perlu ditambahkan dikarenakan belum diperlukannya. Namun ada kemungkinan penambahan variabel berdasarkan waktu seperti jam, hari, tanggal dan sebagainya. Beberapa dari variabel kategori atau objek akan ditambahkan untuk keperluan encoding agar input dapat dibaca oleh model. Namun akan dilakukan di cell lain. Lalu untuk variabel tanggal (tanggal_transaksi_awal, waktu_transaksi) akan diubah ke dalam bentuk timestamp agar dapat diproses model juga

Untuk analisis saya akan fokus menggunakan fraud_clean sedangkan untuk modelling akan menggunakan fraud_clean_enc

Exploratory Data Analysis

(2 poin) Exploratory Data Analyss-

Berikan penjelasan informatif dari visualisasi dan/atau segala jenis hasil eksplorasi An- da. Bagaimana distribusi data pada setiap varia- bel? Apakah terdapat informasi menarik antara variable predictor dengan variable target?

Multivariate analysis

matplotlib.rc('figure', figsize=(10, 5)) # Buat melebarkan gambar

sns.heatmap(fraud_clean.select_dtypes(include=['int64', 'float64']).corr(), # nilai korelasi
            annot=True,   # anotasi angka di dalam kotak heatmap
            fmt=".3f",    # format 3 angka dibelakang koma 
            cmap='Blues'); # warna heatmap

png

Terlihat insight menarik bahwa korelasi antar prediktor nilai_transaksi, rata_rata_nilai_transaksi, dan maksimum_nilai_transaksi cukup tinggi. Ini akan cukup mempengaruhi model karena redundansi yang tinggi. Mari kita lihat distribusi ketiga variabel tersebut

Distribusi nilai_transaksi terhadap flag_transaksi_fraud

sns.histplot(data=fraud_clean, x='nilai_transaksi', log_scale=True, kde=True, hue='flag_transaksi_fraud')
<Axes: xlabel='nilai_transaksi', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='nilai_transaksi', log_scale=True, hue='flag_transaksi_fraud')
<Axes: xlabel='nilai_transaksi'>

png

Distribusi rata_rata_nilai_transaksi terhadap flag_transaksi_fraud

sns.histplot(data=fraud_clean, x='rata_rata_nilai_transaksi', log_scale=True, kde=True, hue='flag_transaksi_fraud')
<Axes: xlabel='rata_rata_nilai_transaksi', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='rata_rata_nilai_transaksi', log_scale=True, hue='flag_transaksi_fraud')
<Axes: xlabel='rata_rata_nilai_transaksi'>

png

Distribusi maksimum_nilai_transaksi terhadap flag_transaksi_fraud

sns.histplot(data=fraud_clean, x='maksimum_nilai_transaksi', log_scale=True, kde=True, hue='flag_transaksi_fraud')
<Axes: xlabel='maksimum_nilai_transaksi', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='maksimum_nilai_transaksi', log_scale=True, hue='flag_transaksi_fraud')
<Axes: xlabel='maksimum_nilai_transaksi'>

png

Distribusi minimum_nilai_transaksi terhadap flag_transaksi_fraud

sns.histplot(data=fraud_clean, x='minimum_nilai_transaksi', log_scale=True, kde=True, hue='flag_transaksi_fraud')
<Axes: xlabel='minimum_nilai_transaksi', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='minimum_nilai_transaksi', log_scale=True, hue='flag_transaksi_fraud')
<Axes: xlabel='minimum_nilai_transaksi'>

png

Distribusi rata_rata_jumlah_transaksi terhadap flag_transaksi_fraud

sns.histplot(data=fraud_clean, x='rata_rata_jumlah_transaksi', log_scale=True, kde=True, hue='flag_transaksi_fraud')
<Axes: xlabel='rata_rata_jumlah_transaksi', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='rata_rata_jumlah_transaksi', log_scale=True, hue='flag_transaksi_fraud')
<Axes: xlabel='rata_rata_jumlah_transaksi'>

png

Kesimpulan yang didapat pada data kontinu

  • Terdapat persebaran yang sangat luas pada nilai_transaksi dan minimum_nilai_transaksi.
  • Untuk rata_rata_nilai_transaksi distribusinya cukup normal
  • Untuk maksimum_jumlah_transaksi dan rata_rata_jumlah_transaksi mempunyai skewness yang berlawanan
  • Untuk rata_rata_jumlah_transaksi mempunyai skala yang berbeda dengan yang lain (karena hanya menghitung banyaknya transaksi jadi tidak banyak nilainya dibanding yang lain
  • Melihat dari boxplot, sepertinya rata_rata_jumlah_transaksi dan nilai_transaksi bisa menjadi prediktor yang baik untuk memprediksi target

Analysis tanggal dan transaksi fraud

sns.histplot(data=fraud_clean, x='tanggal_transaksi_awal', hue='flag_transaksi_fraud')
<Axes: xlabel='tanggal_transaksi_awal', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='tanggal_transaksi_awal', hue='flag_transaksi_fraud')
<Axes: xlabel='tanggal_transaksi_awal'>

png

Kesimpulan dari sini fraud lebih banyak terjadi waktu di waktu yang lebih sore/malam

sns.histplot(data=fraud_clean, x='waktu_transaksi', hue='flag_transaksi_fraud')
<Axes: xlabel='waktu_transaksi', ylabel='Count'>

png

sns.boxplot(data=fraud_clean, x='waktu_transaksi', hue='flag_transaksi_fraud')
<Axes: xlabel='waktu_transaksi'>

png

Analysis kategorikal data dengan target

non_num_kolom
['kuartal_transaksi', 'kepemilikan_kartu', 'nama_channel', 'id_channel']
sns.barplot(data=fraud_clean, x='kuartal_transaksi', y='flag_transaksi_fraud' )
<Axes: xlabel='kuartal_transaksi', ylabel='flag_transaksi_fraud'>

png

Dapat dilihat bahwa transaksi fraud lebih condong ke awal awal kuartal transaksi

sns.barplot(data=fraud_clean, x='kepemilikan_kartu', y='flag_transaksi_fraud' )
<Axes: xlabel='kepemilikan_kartu', ylabel='flag_transaksi_fraud'>

png

Lalu untuk kepemilikan_kartu = 1 lebih condong melakukan fraud

sns.barplot(data=fraud_clean, x='nama_channel', y='flag_transaksi_fraud' )
<Axes: xlabel='nama_channel', ylabel='flag_transaksi_fraud'>

png

Lalu untuk nama_channel 3 dan 5 lebih condong fraud dibanding yang lain

sns.barplot(data=fraud_clean, x='id_channel', y='flag_transaksi_fraud' )
<Axes: xlabel='id_channel', ylabel='flag_transaksi_fraud'>

png

Lalu untuk id_channel 8 lebih condong fraud dibanding yang lain

Data Pre-processing and Model Fitting

(2 poin) Data Pre-processing

  • Apakah terdapat variabel yang harus di-encoding? Kalau ada, apa saja dan kenapa?

Ada yaitu data-data yang masih bersifat kategorikal dan boolean. Alasannya adalah karena model tidak dapat membaca data yang bersifat object atau categorical (untuk boolean masih diperdebatkan karena terkadang ada beberapa model yang bisa membaca boolean sebagai 1 atau 0).

Untuk kolom yang perlu di encoding adalah kuartal_transaksi, kepemilikan_kartu, nama_channel, id_channel, flag_transaksi_finansial

Oh iya jangan lupa datetimens[64] juga terkadang tidak bisa dibaca mode makanya sebaiknya diubah lagi dalam bentuk timestamp

fraud_asli['flag_transaksi_finansial'].value_counts()
flag_transaksi_finansial
False    13125
Name: count, dtype: int64
# Ternyata False semua WKWKWKWKWKWWKK
fraud_clean = fraud_clean.drop(columns='flag_transaksi_finansial')

Dikarenakan variabel nama_channel dan id_channel nilai encoding nya punya korelasi tinggi maka salah satu kolom dihapus dan diambillah id_channel. Lalu untuk tanggal_transaksi_awal karena banyak sekali keanehan saat dalam bentuk datettimens(64) (cuma 1 hari) maka di drop untuk menghindari kesalahan data

non_num_kolom = ['kuartal_transaksi', 'kepemilikan_kartu', 'id_channel'] 
fraud_clean_enc = pd.get_dummies(fraud_clean,columns=non_num_kolom,drop_first=True,dtype='int')
fraud_clean_enc[dt_kolom] = fraud_asli[dt_kolom]
fraud_clean_enc = fraud_clean_enc.drop(columns=['tanggal_transaksi_awal', 'nama_channel'])
fraud_clean_enc.head().T
0 1 2 3 4
nilai_transaksi 2200000.000 2.500000e+06 1200000.0 3.200000e+05 150000.000
waktu_transaksi 193955.000 7.314000e+04 140216.0 1.551170e+05 143339.000
rata_rata_nilai_transaksi 1332292.784 1.369048e+06 15523460.4 7.117647e+05 617968.254
maksimum_nilai_transaksi 9750000.000 1.000000e+07 100000000.0 6.884408e+06 2500000.000
minimum_nilai_transaksi 10000.000 3.000000e+04 41804.0 1.000000e+04 100000.000
rata_rata_jumlah_transaksi 2.730 2.330000e+00 2.4 1.980000e+00 1.460
flag_transaksi_fraud 0.000 1.000000e+00 0.0 0.000000e+00 0.000
kuartal_transaksi_2 0.000 1.000000e+00 0.0 0.000000e+00 0.000
kuartal_transaksi_3 0.000 0.000000e+00 1.0 1.000000e+00 1.000
kuartal_transaksi_4 1.000 0.000000e+00 0.0 0.000000e+00 0.000
kepemilikan_kartu_2 1.000 0.000000e+00 0.0 1.000000e+00 1.000
id_channel_4 0.000 0.000000e+00 0.0 1.000000e+00 0.000
id_channel_8 0.000 1.000000e+00 1.0 0.000000e+00 0.000
id_channel_9 1.000 0.000000e+00 0.0 0.000000e+00 1.000

(4 poin) Membuat model, pilih model berdasarkan model yang sudah diajarkan dikelas (logistic regression / knn)

  • Buatlah model yang dapat menjawab pertanyaan bisnis di atas. : Untuk Capstone, saya akan mencoba menggunakan kedua model Logit() dan KNN

  • Variable apa yang dirasa cukup penting dalam pembuatan model? Sertakan alasannya. : Untuk model Logit() saya akan mencoba menggunakan semua data yang ada, namun ada beberapa prediktor kategorikal akan dihapus karena memiliki korelasi tinggi. Lalu untuk KNN, saya mencoba menggunakan semua nilai numerik yang ada dan melakukan scaling

  • Metode evaluasi apa yang cocok digunakan untuk kasus ini? Jelaskan. : Evaluasi yang digunakan adalah precision karena target tidak seimbang dan dalam business case ini difokuskan untuk mencari True Positive dengan menurunkan dan menghindari False Positive sebanyak mungkin

Uji coba menggunakan Logistic Regression

Train Test split

X = sm.add_constant(fraud_clean_enc.drop(columns='flag_transaksi_fraud'))
y = fraud_clean_enc['flag_transaksi_fraud']
X.info()
<class 'pandas.core.frame.DataFrame'>
Index: 13104 entries, 0 to 13124
Data columns (total 14 columns):
 #   Column                      Non-Null Count  Dtype  
---  ------                      --------------  -----  
 0   const                       13104 non-null  float64
 1   nilai_transaksi             13104 non-null  float64
 2   waktu_transaksi             13104 non-null  int64  
 3   rata_rata_nilai_transaksi   13104 non-null  float64
 4   maksimum_nilai_transaksi    13104 non-null  float64
 5   minimum_nilai_transaksi     13104 non-null  float64
 6   rata_rata_jumlah_transaksi  13104 non-null  float64
 7   kuartal_transaksi_2         13104 non-null  int32  
 8   kuartal_transaksi_3         13104 non-null  int32  
 9   kuartal_transaksi_4         13104 non-null  int32  
 10  kepemilikan_kartu_2         13104 non-null  int32  
 11  id_channel_4                13104 non-null  int32  
 12  id_channel_8                13104 non-null  int32  
 13  id_channel_9                13104 non-null  int32  
dtypes: float64(6), int32(7), int64(1)
memory usage: 1.1 MB
# X = X.iloc[:, :12]
X.corr()
const nilai_transaksi waktu_transaksi rata_rata_nilai_transaksi maksimum_nilai_transaksi minimum_nilai_transaksi rata_rata_jumlah_transaksi kuartal_transaksi_2 kuartal_transaksi_3 kuartal_transaksi_4 kepemilikan_kartu_2 id_channel_4 id_channel_8 id_channel_9
const NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
nilai_transaksi NaN 1.000000 -0.019857 0.419086 0.219751 0.025245 0.092394 0.018400 0.002426 -0.022916 -0.019989 -0.095767 0.020400 0.069391
waktu_transaksi NaN -0.019857 1.000000 -0.026441 -0.019929 -0.004055 0.000056 -0.661371 0.152606 0.725364 0.028756 0.081363 -0.027334 -0.051648
rata_rata_nilai_transaksi NaN 0.419086 -0.026441 1.000000 0.674542 0.183931 0.223442 0.021902 -0.003942 -0.021849 -0.015058 -0.052375 0.015319 0.035389
maksimum_nilai_transaksi NaN 0.219751 -0.019929 0.674542 1.000000 0.045452 0.309681 0.016373 -0.008148 -0.009549 0.005384 -0.015978 -0.004986 0.016988
minimum_nilai_transaksi NaN 0.025245 -0.004055 0.183931 0.045452 1.000000 -0.003797 -0.001714 0.007160 -0.006077 -0.008944 -0.010199 0.008779 0.003161
rata_rata_jumlah_transaksi NaN 0.092394 0.000056 0.223442 0.309681 -0.003797 1.000000 -0.005349 0.002426 0.002915 0.012259 -0.024747 -0.011278 0.028744
kuartal_transaksi_2 NaN 0.018400 -0.661371 0.021902 0.016373 -0.001714 -0.005349 1.000000 -0.561865 -0.394363 -0.013247 -0.081556 0.012598 0.061437
kuartal_transaksi_3 NaN 0.002426 0.152606 -0.003942 -0.008148 0.007160 0.002426 -0.561865 1.000000 -0.463386 0.002069 0.037197 -0.001212 -0.030486
kuartal_transaksi_4 NaN -0.022916 0.725364 -0.021849 -0.009549 -0.006077 0.002915 -0.394363 -0.463386 1.000000 0.022208 0.050322 -0.021943 -0.029200
kepemilikan_kartu_2 NaN -0.019989 0.028756 -0.015058 0.005384 -0.008944 0.012259 -0.013247 0.002069 0.022208 1.000000 0.108045 -0.996364 0.528240
id_channel_4 NaN -0.095767 0.081363 -0.052375 -0.015978 -0.010199 -0.024747 -0.081556 0.037197 0.050322 0.108045 1.000000 -0.107652 -0.787051
id_channel_8 NaN 0.020400 -0.027334 0.015319 -0.004986 0.008779 -0.011278 0.012598 -0.001212 -0.021943 -0.996364 -0.107652 1.000000 -0.526319
id_channel_9 NaN 0.069391 -0.051648 0.035389 0.016988 0.003161 0.028744 0.061437 -0.030486 -0.029200 0.528240 -0.787051 -0.526319 1.000000

Membuat kolom dengan korelasi tinggi

X.head()
const nilai_transaksi waktu_transaksi rata_rata_nilai_transaksi maksimum_nilai_transaksi minimum_nilai_transaksi rata_rata_jumlah_transaksi kuartal_transaksi_2 kuartal_transaksi_3 kuartal_transaksi_4 kepemilikan_kartu_2 id_channel_4 id_channel_8 id_channel_9
0 1.0 2200000.0 193955 1.332293e+06 9750000.0 10000.0 2.73 0 0 1 1 0 0 1
1 1.0 2500000.0 73140 1.369048e+06 10000000.0 30000.0 2.33 1 0 0 0 0 1 0
2 1.0 1200000.0 140216 1.552346e+07 100000000.0 41804.0 2.40 0 1 0 0 0 1 0
3 1.0 320000.0 155117 7.117647e+05 6884408.0 10000.0 1.98 0 1 0 1 1 0 0
4 1.0 150000.0 143339 6.179683e+05 2500000.0 100000.0 1.46 0 1 0 1 0 0 1
fraud_clean_enc.describe().T
count mean std min 25% 50% 75% max
nilai_transaksi 13104.0 1.314923e+06 2.837644e+06 1.0 2.000000e+05 572575.000 1.251524e+06 7.500000e+07
waktu_transaksi 13104.0 1.389062e+05 4.788674e+04 47.0 1.026220e+05 140707.000 1.754315e+05 2.359140e+05
rata_rata_nilai_transaksi 13104.0 1.364132e+06 1.448583e+06 50000.0 5.685634e+05 1024239.017 1.679778e+06 2.466667e+07
maksimum_nilai_transaksi 13104.0 1.228760e+07 1.645905e+07 38000.0 2.500000e+06 6000000.000 1.500000e+07 1.000000e+08
minimum_nilai_transaksi 13104.0 7.651933e+04 6.765391e+05 1.0 2.500000e+04 36964.000 6.320000e+04 7.500000e+07
rata_rata_jumlah_transaksi 13104.0 2.436182e+00 1.389367e+00 1.0 1.680000e+00 2.100 2.790000e+00 1.978000e+01
flag_transaksi_fraud 13104.0 6.822344e-02 2.521386e-01 0.0 0.000000e+00 0.000 0.000000e+00 1.000000e+00
kuartal_transaksi_2 13104.0 3.234890e-01 4.678254e-01 0.0 0.000000e+00 0.000 1.000000e+00 1.000000e+00
kuartal_transaksi_3 13104.0 3.976648e-01 4.894342e-01 0.0 0.000000e+00 0.000 1.000000e+00 1.000000e+00
kuartal_transaksi_4 13104.0 2.454212e-01 4.303531e-01 0.0 0.000000e+00 0.000 0.000000e+00 1.000000e+00
kepemilikan_kartu_2 13104.0 9.323871e-01 2.510901e-01 0.0 1.000000e+00 1.000 1.000000e+00 1.000000e+00
id_channel_4 13104.0 1.386600e-01 3.456045e-01 0.0 0.000000e+00 0.000 0.000000e+00 1.000000e+00
id_channel_8 13104.0 6.715507e-02 2.502999e-01 0.0 0.000000e+00 0.000 0.000000e+00 1.000000e+00
id_channel_9 13104.0 7.937271e-01 4.046441e-01 0.0 1.000000e+00 1.000 1.000000e+00 1.000000e+00
X_train, X_test, y_train, y_test = train_test_split(X, 
                                                   y, # kolom target
                                                   test_size = 0.2, # 80% training and 20% test
                                                   random_state = 10,
                                                   stratify=y)
X_train.dtypes
const                         float64
nilai_transaksi               float64
waktu_transaksi                 int64
rata_rata_nilai_transaksi     float64
maksimum_nilai_transaksi      float64
minimum_nilai_transaksi       float64
rata_rata_jumlah_transaksi    float64
kuartal_transaksi_2             int32
kuartal_transaksi_3             int32
kuartal_transaksi_4             int32
kepemilikan_kartu_2             int32
id_channel_4                    int32
id_channel_8                    int32
id_channel_9                    int32
dtype: object

Modelling menggunakan Logistic Regression

model_logit = sm.Logit(y_train, X_train)
model_logit.fit().summary()
Warning: Maximum number of iterations has been exceeded.
         Current function value: 0.209745
         Iterations: 35


C:\Users\SaltFarmer\miniconda3\envs\algoritma\lib\site-packages\statsmodels\base\model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  warnings.warn("Maximum Likelihood optimization failed to "
Logit Regression Results
Dep. Variable: flag_transaksi_fraud No. Observations: 10483
Model: Logit Df Residuals: 10469
Method: MLE Df Model: 13
Date: Thu, 11 Jan 2024 Pseudo R-squ.: 0.1576
Time: 15:02:23 Log-Likelihood: -2198.8
converged: False LL-Null: -2610.0
Covariance Type: nonrobust LLR p-value: 2.158e-167
coef std err z P>|z| [0.025 0.975]
const -19.0997 8660.347 -0.002 0.998 -1.7e+04 1.7e+04
nilai_transaksi 8.383e-08 1.15e-08 7.266 0.000 6.12e-08 1.06e-07
waktu_transaksi -1.875e-06 2.53e-06 -0.741 0.459 -6.83e-06 3.08e-06
rata_rata_nilai_transaksi -1.908e-08 3.87e-08 -0.492 0.622 -9.5e-08 5.69e-08
maksimum_nilai_transaksi -1.298e-09 3.82e-09 -0.340 0.734 -8.79e-09 6.19e-09
minimum_nilai_transaksi 1.112e-06 2.02e-07 5.505 0.000 7.16e-07 1.51e-06
rata_rata_jumlah_transaksi -0.2769 0.050 -5.553 0.000 -0.375 -0.179
kuartal_transaksi_2 -0.4941 0.250 -1.974 0.048 -0.985 -0.004
kuartal_transaksi_3 -0.4149 0.356 -1.166 0.244 -1.112 0.283
kuartal_transaksi_4 -0.5087 0.475 -1.071 0.284 -1.440 0.422
kepemilikan_kartu_2 11.3593 nan nan nan nan nan
id_channel_4 5.4534 nan nan nan nan nan
id_channel_8 19.7843 8660.347 0.002 0.998 -1.7e+04 1.7e+04
id_channel_9 5.9059 nan nan nan nan nan

Prediction Performance

  • (1 poin) Metrics yang dipilih mencapai 60% pada data train (2 poin) Metrics yang dipilih mencapai 60% pada data test

Hasil metric data train

logit_pred_tr = model_logit.fit().predict(X_train)
logit_pred_tr
Warning: Maximum number of iterations has been exceeded.
         Current function value: 0.209745
         Iterations: 35


C:\Users\SaltFarmer\miniconda3\envs\algoritma\lib\site-packages\statsmodels\base\model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  warnings.warn("Maximum Likelihood optimization failed to "





11191    0.037380
1027     0.056526
10908    0.057065
4404     0.057710
5958     0.027605
           ...   
3071     0.380087
4977     0.050986
574      0.048985
1717     0.049682
203      0.048698
Length: 10483, dtype: float64
pred_label_tr = logit_pred_tr.apply(lambda x: 1 if x > 0.5 else 0)
pred_label_tr.value_counts()
0    10416
1       67
Name: count, dtype: int64
print(f'Accuracy score: {accuracy_score(y_train, pred_label_tr)}')
print(f'Recall score: {recall_score(y_train, pred_label_tr)}')
print(f'Precision score: {precision_score(y_train, pred_label_tr)}')
Accuracy score: 0.9311265859009825
Recall score: 0.04195804195804196
Precision score: 0.44776119402985076

Karena Precision belum lebih dari 60% maka saya atur lagi thresholdnya

pred_label_tr = logit_pred_tr.apply(lambda x: 1 if x > 0.8 else 0)
pred_label_tr.value_counts()
0    10470
1       13
Name: count, dtype: int64
print(f'Accuracy score: {accuracy_score(y_train, pred_label_tr)}')
print(f'Recall score: {recall_score(y_train, pred_label_tr)}')
print(f'Precision score: {precision_score(y_train, pred_label_tr)}')
Accuracy score: 0.9322712963846227
Recall score: 0.012587412587412588
Precision score: 0.6923076923076923

Sudah ditemukan threshold yang tepat untuk Data Train melebihi nilai threshold 60%

Hasil metric data Test

logit_pred = model_logit.fit().predict(X_test)
logit_pred
Warning: Maximum number of iterations has been exceeded.
         Current function value: 0.209745
         Iterations: 35


C:\Users\SaltFarmer\miniconda3\envs\algoritma\lib\site-packages\statsmodels\base\model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  warnings.warn("Maximum Likelihood optimization failed to "





12431    0.057628
4523     0.049031
8211     0.011157
4172     0.048879
5746     0.389036
           ...   
11842    0.048245
9454     0.046732
2449     0.055409
3865     0.036163
5465     0.051302
Length: 2621, dtype: float64
pred_label = logit_pred.apply(lambda x: 1 if x > 0.5 else 0)
pred_label.value_counts()
0    2602
1      19
Name: count, dtype: int64
print(f'Accuracy score: {accuracy_score(y_test, pred_label)}')
print(f'Recall score: {recall_score(y_test, pred_label)}')
print(f'Precision score: {precision_score(y_test, pred_label)}')
Accuracy score: 0.9320869896985883
Recall score: 0.055865921787709494
Precision score: 0.5263157894736842

Saya coba atur sedikit threshold nya agar mendapatkan nilai presisi yang diinginkan

pred_label = logit_pred.apply(lambda x: 1 if x > 0.8 else 0)
pred_label.value_counts()
0    2619
1       2
Name: count, dtype: int64
print(f'Accuracy score: {accuracy_score(y_test, pred_label)}')
print(f'Recall score: {recall_score(y_test, pred_label)}')
print(f'Precision score: {precision_score(y_test, pred_label)}')
Accuracy score: 0.9324685234643266
Recall score: 0.0111731843575419
Precision score: 1.0

Melihat hasil metric dari data train dan data test maka model bisa dianggap undefitting (hasil train < hasil test)

Angka Haram

Hasil dengan presisi 1 dan terbaik

# fraud_asli = fraud_asli.dropna()
# X = sm.add_constant(fraud_asli.drop(columns='flag_transaksi_fraud')[['nilai_transaksi', 'waktu_transaksi', 'rata_rata_nilai_transaksi', 'maksimum_nilai_transaksi', 'minimum_nilai_transaksi', 'rata_rata_jumlah_transaksi']])
# y = fraud_asli['flag_transaksi_fraud']
# X_train, X_test, y_train, y_test = train_test_split(X, 
#                                                    y, # kolom target
#                                                    test_size = 0.2, # 80% training and 20% test
#                                                    random_state = 10,
#                                                    stratify=y)
# X_train
const nilai_transaksi waktu_transaksi rata_rata_nilai_transaksi maksimum_nilai_transaksi minimum_nilai_transaksi rata_rata_jumlah_transaksi
11191 1.0 1250000.0 155818 5.527200e+06 75000000.0 50000.0 2.40
1027 1.0 2500000.0 142017 1.303347e+06 9000000.0 33500.0 1.84
10908 1.0 100000.0 102021 3.992588e+05 2500000.0 22400.0 1.11
4404 1.0 2500000.0 172626 8.525882e+05 7000000.0 50000.0 1.66
5958 1.0 498813.0 154446 5.185913e+05 4318765.0 21200.0 2.24
... ... ... ... ... ... ... ...
3071 1.0 1300000.0 151541 1.184368e+06 10000000.0 25000.0 2.08
4977 1.0 1250000.0 171957 1.275961e+06 7000000.0 50000.0 1.73
574 1.0 2499000.0 102907 2.917987e+06 7328969.0 500000.0 2.50
1717 1.0 1000000.0 133843 6.063348e+05 3500000.0 31700.0 2.00
203 1.0 300000.0 195601 5.033857e+05 1000000.0 100000.0 1.40

10483 rows × 7 columns

# model_logit2 = sm.Logit(y_train, X_train)
# model_logit2.fit().summary()
Optimization terminated successfully.
         Current function value: 0.240125
         Iterations 7
Logit Regression Results
Dep. Variable: flag_transaksi_fraud No. Observations: 10483
Model: Logit Df Residuals: 10476
Method: MLE Df Model: 6
Date: Thu, 11 Jan 2024 Pseudo R-squ.: 0.03554
Time: 12:11:09 Log-Likelihood: -2517.2
converged: True LL-Null: -2610.0
Covariance Type: nonrobust LLR p-value: 2.302e-37
coef std err z P>|z| [0.025 0.975]
const -1.7497 0.153 -11.472 0.000 -2.049 -1.451
nilai_transaksi 7.637e-08 1.05e-08 7.274 0.000 5.58e-08 9.7e-08
waktu_transaksi -3.296e-06 8.14e-07 -4.047 0.000 -4.89e-06 -1.7e-06
rata_rata_nilai_transaksi -3.895e-10 3.67e-08 -0.011 0.992 -7.24e-08 7.16e-08
maksimum_nilai_transaksi -2.108e-09 3.59e-09 -0.588 0.557 -9.14e-09 4.92e-09
minimum_nilai_transaksi 1.101e-06 2.02e-07 5.447 0.000 7.05e-07 1.5e-06
rata_rata_jumlah_transaksi -0.2684 0.047 -5.669 0.000 -0.361 -0.176
# logit_pred2 = model_logit2.fit().predict(X_test)
# logit_pred2
Optimization terminated successfully.
         Current function value: 0.240125
         Iterations 7





12431    0.075937
4523     0.082749
8211     0.015727
4172     0.065997
5746     0.081120
           ...   
11842    0.062634
9454     0.071733
2449     0.072522
3865     0.049655
5465     0.078226
Length: 2621, dtype: float64
# pred_label2 = logit_pred2.apply(lambda x: 1 if x > 0.5 else 0)
# pred_label2.value_counts()
0    2618
1       3
Name: count, dtype: int64
# print(f'Accuracy score: {accuracy_score(y_test, pred_label2)}')
# print(f'Recall score: {recall_score(y_test, pred_label2)}')
# print(f'Precision score: {precision_score(y_test, pred_label2)}')
Accuracy score: 0.9320869896985883
Recall score: 0.0111731843575419
Precision score: 0.6666666666666666

Coba KNN

KNN_model = KNeighborsClassifier(n_neighbors=10)
scaler = StandardScaler()
KNN_model
KNeighborsClassifier(n_neighbors=10)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
fraud_clean_num = fraud_clean_enc.iloc[:, :6]
fraud_clean_num
nilai_transaksi waktu_transaksi rata_rata_nilai_transaksi maksimum_nilai_transaksi minimum_nilai_transaksi rata_rata_jumlah_transaksi
0 2200000.0 193955 1.332293e+06 9750000.0 10000.0 2.73
1 2500000.0 73140 1.369048e+06 10000000.0 30000.0 2.33
2 1200000.0 140216 1.552346e+07 100000000.0 41804.0 2.40
3 320000.0 155117 7.117647e+05 6884408.0 10000.0 1.98
4 150000.0 143339 6.179683e+05 2500000.0 100000.0 1.46
... ... ... ... ... ... ...
13120 100000.0 140547 2.917987e+06 7400000.0 26500.0 2.57
13121 2500000.0 172446 1.914437e+06 20000000.0 100000.0 2.73
13122 1250000.0 141836 3.417045e+05 1000000.0 100000.0 1.33
13123 500000.0 71451 7.644508e+05 3000000.0 25000.0 1.62
13124 300000.0 175350 8.483696e+05 6375000.0 25000.0 1.79

13104 rows × 6 columns

# prediktor
X = fraud_clean_num
# target
y = fraud_clean_enc['flag_transaksi_fraud']

# Split dataset
X_train, X_test, y_train, y_test = train_test_split(X, # kolom prediktor
                                                   y, # kolom target
                                                   test_size = 0.2, # 80% training and 20% test
                                                   random_state = 10,
                                                   stratify = y)

Scaling

cols = X_train.columns

scaler.fit(X_train)

X_train_scale = scaler.transform(X_train)
X_test_scale = scaler.transform(X_test)
KNN_model.fit(X_train_scale, y_train)
pred_knn_tr = KNN_model.predict(X_train_scale)
print(f'Accuracy score: {accuracy_score(y_train, pred_knn_tr)}')
print(f'Recall score: {recall_score(y_train, pred_knn_tr)}')
print(f'Precision score: {precision_score(y_train, pred_knn_tr)}')
Accuracy score: 0.9324620814652295
Recall score: 0.013986013986013986
Precision score: 0.7692307692307693

Precision score dari KNN sudah cukup memuaskan karena sudah diatas 60%

KNN_model.fit(X_train_scale, y_train)
pred_knn_label = KNN_model.predict(X_test_scale)
print(f'Accuracy score: {accuracy_score(y_test, pred_knn_label)}')
print(f'Recall score: {recall_score(y_test, pred_knn_label)}')
print(f'Precision score: {precision_score(y_test, pred_knn_label)}')
Accuracy score: 0.9328500572300649
Recall score: 0.01675977653631285
Precision score: 1.0

Didapatkan score precisision dari Data Test yang lebih tinggi lagi sehingga dianggap modelnya underfitting (hasil train < hasil test)

Conclusion

(2 poin) Tuliskan kesimpulan dari project yang anda kerjakan.

  • Apakah model sudah dapat melakukan prediksi dengan baik? Jelaskan

Sudah cukup baik karena memenuhi pertanyaan bisnis untuk metric precision diatas 60%. Untuk kedua model Logit() dan KNN() sudah cukup memuaskan dengan hasil KNN() yang lebih baik pada Data Test. Kedua model tersebut juga perlu dilakukan tuning parameter seperti threshold di logit dan n_neighbor di KNN agar mendapatkan hasil yang diinginkan

  • Apakah model sudah dapat menjawab pertanyaan bisnis yang ada? Jelaskan.

Sudah, karena pertanyaan bisnisnya mendeteksi fraud sebaik mungkin. Dikarenakan ketidakseimbangan jumlah target, maka metric yang digunakan pun harus tepat untuk fokus melihat True Positive sebaik mungkin dan melihat False Negative sesedikit mungkin. Dari hasil diatas, model Logit dan KNN sudah bekerja dengan baik sudah memenuhi standar presisi yang diinginkan.

  • Action plan apa yang dapat dilakukan untuk tindakan preventif transaksi fraud?

Berdasarkan hasil dari model Logit, maka perlu diwaspadai saat ada momen nilai_transaksi, minimum_nilai_transaksi, tinggi serta mempunyai kepemilikan_kartu 2 dan melakukan id_channel selain 3 dikarenakan variabel - variabel ber koefisiensi positive terhadap model dalam memberikan peluang positif Fraud

Freestyle SMOTE dan XGBoost

fraud_clean_enc
Index(['nilai_transaksi', 'waktu_transaksi', 'rata_rata_nilai_transaksi',
       'maksimum_nilai_transaksi', 'minimum_nilai_transaksi',
       'rata_rata_jumlah_transaksi', 'flag_transaksi_fraud',
       'kuartal_transaksi_2', 'kuartal_transaksi_3', 'kuartal_transaksi_4',
       'kepemilikan_kartu_2', 'id_channel_4', 'id_channel_8', 'id_channel_9'],
      dtype='object')
from imblearn.combine import SMOTEENN

sme = SMOTEENN(random_state=10)
X_0 = fraud_clean_enc.drop(columns='flag_transaksi_fraud')
y_0 = fraud_clean_enc['flag_transaksi_fraud']
X_res, y_res = sme.fit_resample(X_0, y_0)
y_res.value_counts()
flag_transaksi_fraud
1    10106
0     8553
Name: count, dtype: int64
X_res.shape
(18659, 13)
fraud_clean_enc['flag_transaksi_fraud'].value_counts()
flag_transaksi_fraud
0    12210
1      894
Name: count, dtype: int64
from xgboost import XGBClassifier

xgb = XGBClassifier(random_state=10)
X_train, X_test, y_train, y_test = train_test_split(X_res, # kolom prediktor
                                                   y_res, # kolom target
                                                   test_size = 0.2, # 80% training and 20% test
                                                   random_state = 10,
                                                   stratify = y_res)
xgb.fit(X_train, y_train)
XGBClassifier(base_score=None, booster=None, callbacks=None,
              colsample_bylevel=None, colsample_bynode=None,
              colsample_bytree=None, device=None, early_stopping_rounds=None,
              enable_categorical=False, eval_metric=None, feature_types=None,
              gamma=None, grow_policy=None, importance_type=None,
              interaction_constraints=None, learning_rate=None, max_bin=None,
              max_cat_threshold=None, max_cat_to_onehot=None,
              max_delta_step=None, max_depth=None, max_leaves=None,
              min_child_weight=None, missing=nan, monotone_constraints=None,
              multi_strategy=None, n_estimators=None, n_jobs=None,
              num_parallel_tree=None, random_state=10, ...)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
pred_tr = xgb.predict(X_train)
pred_tr
array([0, 1, 0, ..., 1, 1, 0])
print(f'Accuracy score: {accuracy_score(y_train, pred_tr)}')
print(f'Recall score: {recall_score(y_train, pred_tr)}')
print(f'Precision score: {precision_score(y_train, pred_tr)}')
Accuracy score: 0.9952435184564883
Recall score: 0.9922077922077922
Precision score: 0.9990037359900373
pred_ts = xgb.predict(X_test)
pred_ts
array([1, 1, 1, ..., 0, 0, 1])
print(f'Accuracy score: {accuracy_score(y_test, pred_ts)}')
print(f'Recall score: {recall_score(y_test, pred_ts)}')
print(f'Precision score: {precision_score(y_test, pred_ts)}')
Accuracy score: 0.964898177920686
Recall score: 0.9609104403760514
Precision score: 0.9739217652958877
model_logit3 = sm.Logit(y_train, X_train)
model_logit3.fit().summary()
Warning: Maximum number of iterations has been exceeded.
         Current function value: 0.290377
         Iterations: 35


C:\Users\SaltFarmer\miniconda3\envs\algoritma\lib\site-packages\statsmodels\base\model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  warnings.warn("Maximum Likelihood optimization failed to "
Logit Regression Results
Dep. Variable: flag_transaksi_fraud No. Observations: 14927
Model: Logit Df Residuals: 14914
Method: MLE Df Model: 12
Date: Thu, 11 Jan 2024 Pseudo R-squ.: 0.5790
Time: 14:25:01 Log-Likelihood: -4334.5
converged: False LL-Null: -10295.
Covariance Type: nonrobust LLR p-value: 0.000
coef std err z P>|z| [0.025 0.975]
nilai_transaksi 2.549e-07 1.37e-08 18.650 0.000 2.28e-07 2.82e-07
waktu_transaksi 4.549e-05 1.14e-06 39.752 0.000 4.32e-05 4.77e-05
rata_rata_nilai_transaksi 6.933e-08 3.18e-08 2.182 0.029 7.07e-09 1.32e-07
maksimum_nilai_transaksi -1.684e-08 2.85e-09 -5.909 0.000 -2.24e-08 -1.13e-08
minimum_nilai_transaksi 2.725e-06 2.21e-07 12.346 0.000 2.29e-06 3.16e-06
rata_rata_jumlah_transaksi -0.0988 0.024 -4.099 0.000 -0.146 -0.052
kuartal_transaksi_2 -2.9516 0.095 -31.185 0.000 -3.137 -2.766
kuartal_transaksi_3 -5.2644 0.138 -38.187 0.000 -5.535 -4.994
kuartal_transaksi_4 -8.5689 0.202 -42.511 0.000 -8.964 -8.174
kepemilikan_kartu_2 19.4428 2287.246 0.009 0.993 -4463.477 4502.362
id_channel_4 -23.9954 2287.246 -0.010 0.992 -4506.915 4458.924
id_channel_8 -0.3650 0.106 -3.455 0.001 -0.572 -0.158
id_channel_9 -22.4858 2287.246 -0.010 0.992 -4505.405 4460.434
logit_pred_tr2 = model_logit3.fit().predict(X_train)
logit_pred_tr2
Warning: Maximum number of iterations has been exceeded.
         Current function value: 0.290377
         Iterations: 35


C:\Users\SaltFarmer\miniconda3\envs\algoritma\lib\site-packages\statsmodels\base\model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
  warnings.warn("Maximum Likelihood optimization failed to "





4595     0.475110
15122    0.978847
5773     0.342949
10132    0.853132
18484    0.757783
           ...   
2803     0.415036
14465    0.998638
12002    0.999722
12342    0.887879
3115     0.110515
Length: 14927, dtype: float64
pred_label = logit_pred_tr2.apply(lambda x: 1 if x > 0.5 else 0)
pred_label.value_counts()
0    7604
1    7323
Name: count, dtype: int64
print(f'Accuracy score: {accuracy_score(y_train, pred_label)}')
print(f'Recall score: {recall_score(y_train, pred_label)}')
print(f'Precision score: {precision_score(y_train, pred_label)}')
Accuracy score: 0.8929456689220875
Recall score: 0.8540507111935683
Precision score: 0.9429195684828622

Leave a comment