Forensic Analytics dengan Pandas – The Last-Two Digits Test

Kode Lima Detik

import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

pd.options.display.float_format = '{:,.2f}'.format

df = pd.read_excel('Chapter4_Figure4pt4_DataOnly.xlsx')

data = df[df['Amount'] >= 10][['ID', 'Amount']]
data['Amount100'] = data['Amount'] * 100
new = data['Amount100'].astype(str).str.split('.', n=1, expand=True)
data['LastTwo'] = new[0].str[-2:].astype('int64')

data2 = data[['LastTwo', 'ID']].groupby('LastTwo', as_index=False).count()
data2.rename(columns={'ID': 'Count'}, inplace=True)
data2['proportion'] = data2['Count'] / data2['Count'].sum() * 100

sns.set(style='whitegrid') # garis horizontal tiap 0.05
a4_dims = (11.7, 8.27) # ukuran grafik
plt.figure(figsize=a4_dims)
ax = sns.barplot(y="proportion", x="LastTwo", data=data2)
ax.xaxis.set_major_locator(ticker.MultipleLocator(5)) # Label x akan diberikan tiap 5
ax.xaxis.set_major_formatter(ticker.ScalarFormatter())
ax.set(xlabel='Last-Two Digits', ylabel='Proportion') # Title pada x dan y
ax.axhline(1, color='blue') # garis horizontal pada nilai y 1 (0.01)
plt.yticks(ax.get_yticks(), ax.get_yticks() / 100) # label y akan dibagi 100
plt.show()

Pengantar

Ada kondisi dimana angka sebaiknya “cukup teratur” sehingga kita memerlukan alat untuk menguji keteraturan tersebut. Misalnya produk yang dijual berharga kelipatan Rp100 tentu akan janggal bila data penjualan menunjukkan terdapat transaksi berakhiran Rp50 atau bahkan “keriting” seperti Rp50.475.

The last-two digits test dapat menjawab pertanyaan, apakah tidak terdapat angka “aneh” pada data?


The Last-Two Digits Test

Sesuai namanya metode ini menguji dua angka terakhir pada data. Tidak seperti Benford’s Law yang memiliki “harapan” akan frekuensi kemunculan suatu angka, the last-two digits test tidak berharap apapun. Dugaannya hanya bahwa tiap angka memiliki porsi yang sama banyak, sehingga pada angka 00 sampai 99 sama-sama muncul sebanyak 1% dari populasi.

Tujuan

Masih sama seperti tulisan sebelumnya, kita akan mereproduksi grafik dari Buku Forensic Analytics-nya Pak Nigrini, kali ini dari Figure 8.22 di halaman 171.

Urgensi

Metode ini ampuh untuk mendeteksi nilai belakang yang tidak seharusnya ada. Penulis menyarankan untuk melakukan pengujian ini terutama di saat data seharusnya tidak memiliki nilai di belakang koma (desimal).


Langkah Kerja

Masih akan menggunakan invoices paid data yang dapat diunduh dari sumbernya langsung di sini. Data yang diproses adalah yang lebih besar atau sama dengan 10. Jika tidak ingin mengetik, notebook dapat diakses di sini.

Kode

Load library dan data.

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

pd.options.display.float_format = '{:,.2f}'.format

df = pd.read_excel('Chapter4_Figure4pt4_DataOnly.xlsx')

Buat sebuah variabel baru bernama data, berisi hanya data dengan nilai Amount lebih besar atau sama dengan 10 dan hanya berisi kolom ID dan Amount.

data = df[df['Amount'] >= 10][['ID', 'Amount']]

Buat kolom baru bernilai 100 x kolom Amount. Langkah ini untuk memastikan angka desimal (dua angka di belakang koma) menjadi angka bulat dan akan diambil pada proses selanjutnya.

data['Amount100'] = data['Amount'] * 100

Buat sebuah kolom baru, berisi dua angka terakhir dari kolom Amount100.

new = data['Amount100'].astype(str).str.split('.', n=1, expand=True)
data['LastTwo'] = new[0].str[-2:].astype('int64')

Buat variabel baru bernama data2 yang hanya berisi kolom LastTwo dan jumlah kemunculannya.

data2 = data[['LastTwo', 'ID']].groupby('LastTwo', as_index=False).count()
data2.rename(columns={'ID': 'Count'}, inplace=True)

Buat sebuah kolom berisi proporsi (persentase) masing-masing jumlah LastTwo.

data2['proportion'] = data2['Count'] / data2['Count'].sum() * 100

Langkah terakhir adalah membuat grafik.

sns.set(style='whitegrid') # garis horizontal tiap 0.05
a4_dims = (11.7, 8.27) # ukuran grafik
plt.figure(figsize=a4_dims)
ax = sns.barplot(y="proportion", x="LastTwo", data=data2)

ax.xaxis.set_major_locator(ticker.MultipleLocator(5)) # Label x akan diberikan tiap 5
ax.xaxis.set_major_formatter(ticker.ScalarFormatter())

ax.set(xlabel='Last-Two Digits', ylabel='Proportion') # Title pada x dan y

ax.axhline(1, color='blue') # garis horizontal pada nilai y 1 (0.01)

plt.yticks(ax.get_yticks(), ax.get_yticks() / 100) # label y akan dibagi 100

plt.show()

Selanjutnya

Garis biru pada grafik sebelumnya menunjukkan dugaan bahwa semua angka dari 0 sampai 99 porsinya hanya 1%. Terlihat angka 0 memiliki porsi >20%, hal ini wajar mengingat angka yang diproses adalah nilai kolom Amount yang dikalikan 100 sehingga dua angka di belakang koma akan menjadi angka bulat. Harapan kita memang dua angka dibelakang koma tersebut adalah angka 00.

Karena sedang menghadapi data dalam mata uang Dolar Amerika maka tingginya proporsi angka 50 menjadi cukup wajar karena ada nominal setengah dolar sehingga dimungkinkan terdapat transaksi dengan dua angka terakhir 50.

Yang “janggal” adalah tingginya proporsi angka 34, apakah angka tersebut terdiri dari kumpulan bilangan bulat berakhiran 34 atau merupakan desimal. Jika desimal tentu lebih mengherankan lagi. Sehingga perlu dikonsultasikan kepada sesiapa yang lebih mengenal “perilaku” transaksi yang menghasilkan kumpulan angka tersebut.

Sekali lagi, pembacaan hasil pengujian ini sangat terpengaruh dari “keteraturan” yang diharapkan. Jika angka dari suatu kejadian diharapkan selalu bulat tanpa desimal, misal hasil cacah jiwa, maka keteraturan yang diharapkan adalah tingginya proporsi angka 0 pada grafik, kemunculan angka lain diharapkan dari angka bulat dari 1 sampai 99, bukan dari angka desimal.


Cover Image by falco from Pixabay

Leave a Reply

Your email address will not be published.