Baris duplikat adalah masalah paling senyap di antara empat masalah data: nilainya terisi lengkap, tipenya benar, dan isna() tidak menemukan apa pun. Akibatnya baru terasa pada angka agregat; total penjualan menjadi dua kali lipat, rata-rata condong, dan laporan harian tidak cocok dengan pembukuan. Dataset pesanan kita sengaja memuat dua baris salinan identik plus satu id_pesanan ganda dengan isi berbeda. Chapter ini melatih dua method berpasangan untuk kasus tersebut: duplicated() yang menandai dan drop_duplicates() yang menyingkirkan.
Dua Bentuk Duplikat yang Berbeda #
Duplikat pertama adalah baris penuh: semua kolomnya identik dengan baris lain, biasanya hasil import dobel atau pengiriman formulir dua kali. Duplikat kedua adalah duplikat kunci: kolom kunci seperti id_pesanan sama, tetapi kolom lain berbeda, misalnya dua versi angka untuk pesanan yang sama. Keduanya perlu perlakuan berbeda, dan method pandas.DataFrame.duplicated
membedakannya lewat parameter subset. Konsep duplikasi pada label index, masalah yang sering berdampingan, dijelaskan terpisah pada halaman Duplicate labels
.
import pandas as pd
pesanan = pd.DataFrame(
{
"id_pesanan": [
"PSC-101", "PSC-102", "PSC-103", "PSC-104", "PSC-105",
"PSC-106", "PSC-101", "PSC-102", "PSC-103", "PSC-107",
],
"nama_pelanggan": [
"Budi", "Siti", "Dewi", "Andi", "Rina",
"Tono", "Budi", "Siti", "Dewi", "Sari",
],
"kota": [
"Jakarta", "Bandung", "Surabaya", "JAKARTA", "Bandung",
None, "Jakarta", "Bandung", "Surabaya", "Medan",
],
"umur": [29, 34, None, 41, 27, 38, 29, 34, None, 45],
"total_belanja": [
250000, 480000, 150000, None, 320000,
275000, 250000, 480000, 165000, 190000,
],
}
)
print("Jumlah baris awal :", len(pesanan))
print("Duplikat penuh :", pesanan.duplicated().sum())
print()
print(pesanan[pesanan.duplicated()])
print()
bersih = pesanan.drop_duplicates()
print("Setelah drop_duplicates():", len(bersih), "baris")
print("Duplikat id_pesanan :", pesanan.duplicated(subset=["id_pesanan"]).sum())
print()
terakhir = pesanan.drop_duplicates(subset=["id_pesanan"], keep="last")
print("Setelah dedup per id (keep='last'):", len(terakhir), "baris")
print(terakhir)Output yang Dihasilkan:
Jumlah baris awal : 10
Duplikat penuh : 2
id_pesanan nama_pelanggan kota umur total_belanja
6 PSC-101 Budi Jakarta 29.0 250000.0
7 PSC-102 Siti Bandung 34.0 480000.0
Setelah drop_duplicates(): 8 baris
Duplikat id_pesanan : 3
Setelah dedup per id (keep='last'): 7 baris
id_pesanan nama_pelanggan kota umur total_belanja
3 PSC-104 Andi JAKARTA 41.0 NaN
4 PSC-105 Rina Bandung 27.0 320000.0
5 PSC-106 Tono NaN 38.0 275000.0
6 PSC-101 Budi Jakarta 29.0 250000.0
7 PSC-102 Siti Bandung 34.0 480000.0
8 PSC-103 Dewi Surabaya NaN 165000.0
9 PSC-107 Sari Medan 45.0 190000.0Mari kita telaah peran setiap bagian skrip di atas:
- Baris 25-26:
len(pesanan)menyatakan 10 baris, sedangkanduplicated().sum()menandai 2 baris duplikat penuh. - Baris 28 (
pesanan[pesanan.duplicated()]): hanya baris 6 dan 7 yang tampil, yaitu salinan identik dari baris 0 (PSC-101) dan baris 1 (PSC-102). - Baris 30-31 (
bersih = pesanan.drop_duplicates()): baris penuh yang ganda dibuang dan jumlah berubah menjadi 8 baris. - Baris 32:
duplicated(subset=["id_pesanan"])menandai 3 baris; PSC-103 muncul dua kali dengantotal_belanjaberbeda, yaitu 150.000 dan 165.000, dan inilah duplikat kunci. - Baris 34-36:
drop_duplicates(subset=["id_pesanan"], keep="last")menyisakan 7 baris; PSC-103 yang bertahan adalah versi 165.000 karenakeep="last"menyimpan kemunculan terakhir.
Parameter keep dan subset #
| Parameter | Nilai | Efek |
|---|---|---|
keep | "first" (bawaan) | Kemunculan pertama dipertahankan, sisanya ditandai atau dibuang |
keep | "last" | Kemunculan terakhir yang dipertahankan |
keep | False | Semua kemunculan yang berduplikasi ditandai atau dibuang |
subset | List kolom | Definisi “sama” hanya melihat kolom yang disebut |
Pada duplicated(), parameter keep menentukan baris mana yang dianggap asli; nilai False berguna saat kita ingin menelaah semua anggota kelompok duplikat, misalnya pesanan[pesanan.duplicated(keep=False)] yang menampilkan 4 baris pada data kita. Pada drop_duplicates() dari halaman pandas.DataFrame.drop_duplicates
, pilihan keep=False menyisakan hanya 6 baris karena baris asli pun ikut dibuang. Pemilihan keep pada duplikat kunci menuntut keputusan bisnis; versi 150.000 atau 165.000 yang sah untuk PSC-103 hanya bisa dijawab oleh sumber data, bukan oleh pandas.
Mengurutkan Pembersihan Duplikat dan Pengisian #
duplicated() menganggap dua sel NaN yang seposisi sebagai sama, sehingga dua baris yang sama-sama kosong bisa terdeteksi sebagai duplikat. Karena itu urutan pembersihan berpengaruh: mendeteksi dan membuang duplikat lebih dulu mencegah kita menghabiskan waktu mengisi baris yang akhirnya dibuang. Sebaliknya, bila keputusan duplikat kunci bergantung pada kelengkapan data, misalnya versi yang lebih lengkap dianggap sah, mengisi kekosongan terlebih dahulu membantu perbandingan. Pada dataset latihan ini kita memilih pembersihan duplikat lebih dulu, sesuai alur Section ini.
Nilai kosong sudah bisa dihapus atau diisi, baris ganda sudah bisa dideteksi dan disingkirkan. Satu masalah tersisa pada dataset pesanan dan tidak terlihat dari isi sel: tipe data yang tidak tepat, seperti angka yang tersimpan sebagai teks. Chapter Memperbaiki Tipe Data menutup rangkaian pembersihan dasar ini dengan astype() dan pd.to_numeric().