Forensic Analytics dengan Pandas – The Number Duplication Test

Kode Lima Detik

import pandas as pd

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

largenumber = df[df['Amount'] >= 10][['ID', 'Amount']]
data = laargenumber.groupby('Amount', as_index=False).count()
data.rename(columns={'ID': 'Count'}, inplace=True)
data.sort_values(by='Count', ascending=False, inplace=True)
data['FirstTwo'] = data['Amount'].astype(str).str[:2].astype('int64')
data.head(15)[['Count', 'Amount', 'FirstTwo']]

Pengantar

Menggunakan Benford’s Law kita dapat gambaran angka berapa saja yang frekuensi kemunculannya “tidak lazim”. Langkah selanjutnya adalah melihat lebih rinci angka-angka tersebut.

Namun jangkauan angka tersebut bisa jadi masih terlalu jauh. Contohnya jika kita menggunakan data invoices paid yang didiskusikan pada tulisan sebelumnya, first two-digit test menginformasikan angka 50 yang tidak lazim banyaknya. Namun angka 50 tersebut dapat berarti 50, 500, 5.000, 50.000 atau angka berawalan 50 lainnya.

The number duplication test membantu kita lebih fokus karena hasil dari pengujian ini adalah frekuensi masing-masing nilai.


The Number Duplication Test

Tujuan

Kita akan mereproduksi tabel dari Figure 8.5 Forensic Analytics yang berisi frekuensi kemunculan angka, diurutkan berdasarkan frekuensi terbanyak.

Tabel di atas adalah tabel frekuensi untuk nilai \geq 10. Sedang untuk nilai 0 \leq n < 10 adalah seperti ini.

Urgensi

Menurut Pak Nigrini metode ini membantu kita mendapatkan beberapa hal seperti (Forensic Analytics, p. 154 dengan penyesuaian):

  • Banyak data yang merupakan nilai yang berhubungan dengan hasil pengujian Benford’s Law. Seperti angka 50 yang banyak ditemukan, kita akan menemukan bahwa nilai yang mengandung angka tersebut memang banyak ditemukan pada data.
  • Frekuensi tinggi pada nilai di bawah angka psikologis. untuk kondisi di Indonesia, misal angka 90-an akan banyak ditemukan karena umumnya transaksi menghindari nilai Rp1juta sehingga banyak digunakan nilai Rp900ribuan.
  • Banyak ditemukan angka yang dibulatkan, misal transaksi dibulatkan menjadi 100ribu, 1juta dan lainnya.
  • Nilai “aneh” yang banyak ditemukan.
  • Nilai yang muncul lebih sering ketimbang nomor lain.
  • Nilai yang terasosiasi dengan inefisiensi. Bisa jadi kita menemukan banyak transaksi bernilai kecil yang mengancam efisiensi karena, katakanlah, lebih besar biaya pemrosesan daripada nilai tersebut.

Langkah Kerja

Data invoices paid dapat diunduh di sini. Data diuji adalah tabel Amount bernilai \geq 10 dan yang bernilai 0 \leq n < 10.

Langkah pertama tentu saja me-load library dan data.

import pandas as pd

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

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

Nilai Lebih Besar Sama Dengan 10

Filter kolom Amount bernilai \geq 10, buat sebagai variabel baru bernama largenumber.

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

Menggunakan fungsi groupby gabungkan nilai Amount yang sama dan hitung banyaknya kemunculan.

data = largenumber.groupby('Amount', as_index=False).count()

Kolom ID berisi jumlah kemunculan nilai Amount yang sama, agar lebih informatif, kolom ID kita ganti nama menjadi Count menggunakan fungsi rename.

data.rename(columns={'ID': 'Count'}, inplace=True)

Agar lebih mudah dicerna, data diurutkan berdasarkan kolom Count dari banyak ke kecil. Pandas sudah menyediakan fungsi sort_values untuk itu.

data.sort_values(by='Count', ascending=False, inplace=True)

Langkah selanjutnya adalah menambahkan kolom FirstTwo yang berisi dua angka pertama dari kolom Amount.

data['FirstTwo'] = data['Amount'].astype(str).str[:2].astype('int64')

Kolom terakhir yang ditambahkan adalah kolom Rank. Karena pada saat ini dataframe telah urut berdasarkan kolom, kita dapat mengisi kolom Rank dengan angka urut dari 1 sampai sebanyak data (64.579 baris). Pandas menyediakan fungsi shape yang akan menginformasikan jumlah baris dan kolom dari dataframe, kita gunakan itu untuk mendapatkan banyak data.

data['Rank'] = range(1, data.shape[0] + 1)

Langkah terakhir adalah mereset index agar urut seperti kolom Rank, dalam dataframe kita, index adalah angka berwarna tebal di sebelah kiri kolom Amount. Langkah ini opsional, hanya untuk kepentingan estetika saja.

data.reset_index(inplace=True)

Sekarang kita dapat menampilkan tabel yang sama dengan buatan Pak Nigrini. Pandas menyediakan fungsi head untuk menampilkan data n teratas.

data.head(20)[['Rank', 'Count', 'Amount', 'FirstTwo']]

Nilai antara 0 sampai 9,99

Karena kita sudah berhasil membuat kode untuk kolom Amount bernilai \geq 10 maka membuatnya untuk nilai 0 \leq n < 10 menjadi lebih mudah. Kita rangkum saja kode di atas, ubah 2 baris teratas.

smallnumber = df[(df['Amount'] > 0) & (df['Amount']< 10)][['ID', 'Amount']]
data = smallnumber.groupby('Amount', as_index=False).count()

data.rename(columns={'ID': 'Count'}, inplace=True)
data.sort_values(by='Count', ascending=False, inplace=True)
data['FirstTwo'] = data['Amount'].astype(str).str[:1].astype('int64')
data['Rank'] = range(1, data.shape[0] + 1)
data.reset_index(inplace=True)
data.head(20)[['Rank', 'Count', 'Amount', 'FirstTwo']]

Selanjutnya

Sekarang kita tahu angka 50, 10 dan 11 mana yang menyebabkan data invoices paid tidak patuh pada Benford’s Law. Alih-alih menjadikan sampel semua nilai dengan angka awal 50, 10 dan 11, sekarang kita tahu yang patut menjadi fokus adalah 50, 1.083,45 dan 1.153,35

Di sisi nilai kurang dari 10, kita tahu banyak transaksi berawalan 5, salah satu penyebab angka tersebut muncul saat first-digits test. Selain itu bukankah transaksi bernilai USD0,sekian sepertinya terlalu kecil, apakah tidak lebih efisien jika manajemen melakukan sesuatu terhadap jenis transaksi sebesar itu?


Notebook dapat diakses di sini.

Cover Image by Pexels on Pixabay

Leave a Reply

Your email address will not be published. Required fields are marked *