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 .

python
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:

text
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.0

Mari kita telaah peran setiap bagian skrip di atas:

  1. Baris 25-26: len(pesanan) menyatakan 10 baris, sedangkan duplicated().sum() menandai 2 baris duplikat penuh.
  2. 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).
  3. Baris 30-31 (bersih = pesanan.drop_duplicates()): baris penuh yang ganda dibuang dan jumlah berubah menjadi 8 baris.
  4. Baris 32: duplicated(subset=["id_pesanan"]) menandai 3 baris; PSC-103 muncul dua kali dengan total_belanja berbeda, yaitu 150.000 dan 165.000, dan inilah duplikat kunci.
  5. Baris 34-36: drop_duplicates(subset=["id_pesanan"], keep="last") menyisakan 7 baris; PSC-103 yang bertahan adalah versi 165.000 karena keep="last" menyimpan kemunculan terakhir.

Parameter keep dan subset #

ParameterNilaiEfek
keep"first" (bawaan)Kemunculan pertama dipertahankan, sisanya ditandai atau dibuang
keep"last"Kemunculan terakhir yang dipertahankan
keepFalseSemua kemunculan yang berduplikasi ditandai atau dibuang
subsetList kolomDefinisi “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().