Latar Belakang Masalah
Sebuah perusahaan e-commerce menemukan masalah dalam database pelanggan mereka:
- Rekaman pelanggan ganda karena sistem registrasi bermasalah
- Data pelanggan yang sama dengan ID berbeda dari berbagai channel (website, mobile app, marketplace)
- Perbedaan penulisan nama dan alamat yang sama
Dampak yang Terjadi:
- Pengiriman promo ganda ke pelanggan yang sama
- Analisis perilaku pelanggan tidak akurat
- Laporan jumlah pelanggan membengkak
Dataset Contoh
Data pelanggan_duplikat.csv:
customer_id,email,nama,telepon,alamat,join_date,last_purchase 1,andi@mail.com,Andi Wijaya,0812345678,Jl. Merdeka No.1,2022-01-01,2023-05-15 2,budi@mail.com,Budi Santoso,0856789012,Jl. Sudirman No.45,2022-02-10,2023-06-20 3,andi@mail.com,Andi W.,0812345678,Jl. Merdeka 1,2022-01-01,2023-05-18 4,cici@mail.com,Cici Liana,0878123456,Jl. Gatot Subroto 22,2022-03-05,2023-04-10 5,budi.s@mail.com,Budi,0856789012,Jl. Sudirman 45,2022-02-10,2023-06-22
Solusi Deduplikasi
1 Identifikasi Duplikat
import pandas as pd # Membaca data df = pd.read_csv('pelanggan_duplikat.csv') # Cek duplikat berdasarkan email print("Duplikat berdasarkan email:") print(df[df.duplicated(subset=['email'], keep=False)]) # Cek duplikat berdasarkan telepon print("\nDuplikat berdasarkan telepon:") print(df[df.duplicated(subset=['telepon'], keep=False)])
Output:
Duplikat berdasarkan email: customer_id email nama telepon alamat join_date last_purchase 0 1 andi@mail.com Andi Wijaya 0812345678 Jl. Merdeka No.1 2022-01-01 2023-05-15 2 3 andi@mail.com Andi W. 0812345678 Jl. Merdeka 1 2022-01-01 2023-05-18 Duplikat berdasarkan telepon: customer_id email nama telepon alamat join_date last_purchase 0 1 andi@mail.com Andi Wijaya 0812345678 Jl. Merdeka No.1 2022-01-01 2023-05-15 1 2 budi@mail.com Budi Santoso 0856789012 Jl. Sudirman No.45 2022-02-10 2023-06-20 2 3 andi@mail.com Andi W. 0812345678 Jl. Merdeka 1 2022-01-01 2023-05-18 4 5 budi.s@mail.com Budi 0856789012 Jl. Sudirman 45 2022-02-10 2023-06-22
2 Strategi Deduplikasi
Kami akan menggunakan pendekatan bertahap:
- Deduplikasi eksak pada email
- Deduplikasi pada nomor telepon
- Fuzzy matching untuk nama dan alamat
# Langkah 1: Deduplikasi email (keep record terbaru berdasarkan last_purchase) df_clean = df.sort_values('last_purchase').drop_duplicates(subset=['email'], keep='last') # Langkah 2: Deduplikasi telepon untuk sisa record no_email_dup = df[~df['customer_id'].isin(df_clean['customer_id'])] df_clean = pd.concat([ df_clean, no_email_dup.sort_values('last_purchase').drop_duplicates(subset=['telepon'], keep='last') ]) # Langkah 3: Fuzzy matching untuk nama+alamat from fuzzywuzzy import fuzz def check_similarity(row1, row2): # Gabungkan nama dan alamat untuk perbandingan str1 = f"{row1['nama']} {row1['alamat']}" str2 = f"{row2['nama']} {row2['alamat']}" return fuzz.ratio(str1.lower(), str2.lower()) # Identifikasi kemiripan tinggi (>85%) potential_dups = [] for i in range(len(df_clean)): for j in range(i+1, len(df_clean)): similarity = check_similarity(df_clean.iloc[i], df_clean.iloc[j]) if similarity > 85: potential_dups.append((i, j, similarity)) print("\nPasangan dengan kemiripan tinggi:") for dup in potential_dups: print(f"Record {dup[0]} dan {dup[1]} - Similarity: {dup[2]}%") print(df_clean.iloc[[dup[0], dup[1]]])
3 Penyelesaian Duplikat
# Membuat keputusan untuk record duplikat final_ids = set(df_clean['customer_id']) # Hapus record dengan ID 3 (duplikat Andi) final_ids.discard(3) # Hapus record dengan ID 5 (duplikat Budi) final_ids.discard(5) # Hasil akhir df_final = df_clean[df_clean['customer_id'].isin(final_ids)].sort_values('customer_id') print("\nData setelah deduplikasi:") print(df_final)
Output:
Data setelah deduplikasi: customer_id email nama telepon alamat join_date last_purchase 0 1 andi@mail.com Andi Wijaya 0812345678 Jl. Merdeka No.1 2022-01-01 2023-05-15 1 2 budi@mail.com Budi Santoso 0856789012 Jl. Sudirman No.45 2022-02-10 2023-06-20 3 4 cici@mail.com Cici Liana 0878123456 Jl. Gatot Subroto 22 2022-03-05 2023-04-10
Validasi Hasil
1 Metrik Evaluasi
original_count = len(df) final_count = len(df_final) dup_removed = original_count - final_count print(f"Total record awal: {original_count}") print(f"Total record akhir: {final_count}") print(f"Duplikat dihapus: {dup_removed} ({dup_removed/original_count:.1%})") # Cek distribusi data print("\nDistribusi join date sebelum dan sesudah:") print(pd.DataFrame({ 'Sebelum': pd.to_datetime(df['join_date']).dt.year.value_counts(), 'Sesudah': pd.to_datetime(df_final['join_date']).dt.year.value_counts() }))
2 Visualisasi Perubahan
import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 2, figsize=(12,5)) # Sebelum dedup df['is_dup'] = df.duplicated(subset=['email', 'telepon'], keep=False) ax[0].scatter( x=pd.to_datetime(df['join_date']).dt.year, y=df['customer_id'], c=df['is_dup'].map({True: 'red', False: 'blue'}), alpha=0.6 ) ax[0].set_title('Sebelum Deduplikasi') # Sesudah dedup ax[1].scatter( x=pd.to_datetime(df_final['join_date']).dt.year, y=df_final['customer_id'], color='green', alpha=0.6 ) ax[1].set_title('Sesudah Deduplikasi') plt.tight_layout() plt.show()
Dokumentasi Proses
Laporan Deduplikasi:
PROSES DEDUPLIKASI PELANGGAN ============================ Tanggal: 2023-07-15 Dataset: pelanggan_duplikat.csv METODE: 1. Deduplikasi eksak pada email (keep last_purchase terbaru) 2. Deduplikasi pada nomor telepon untuk record tersisa 3. Fuzzy matching nama+alamat (threshold 85%) HASIL: - Total record awal: 5 - Total record akhir: 3 - Duplikat dihapus: 2 (40.0%) DETAIL DUPLIKAT YANG DIHAPUS: 1. customer_id 3 (Andi W.) - duplikat dari customer_id 1 2. customer_id 5 (Budi) - duplikat dari customer_id 2 REKOMENDASI: 1. Perbaiki sistem registrasi untuk mencegah duplikat 2. Implementasi validasi real-time untuk email dan telepon 3. Jadwalkan deduplikasi berkala setiap 3 bulan