Tujuan Praktikum
Setelah menyelesaikan praktikum ini, mahasiswa mampu:
- Mendiagnosis masalah kualitas data: nilai kosong, duplikat, dan inkonsistensi.
-
Menangani missing value dengan strategi yang tepat per
kolom (
fillnaataudropna). -
Mendeteksi dan menghapus data duplikat dengan
drop_duplicates. - Melakukan transformasi data: standardisasi teks dan konversi tipe data.
- Menyimpan hasil pembersihan menjadi dataset bersih yang siap dianalisis.
Persiapan
Kebutuhan praktikum:
- Akun Google
- Google Colab
- Koneksi internet
- Dataset penjualan_kotor.csv (data sengaja dibuat "kotor" untuk latihan)
Buat notebook baru bernama
Pertemuan03_NamaAnda.ipynb. Bagian ini sekaligus
mengulang keterampilan import CSV dari Pertemuan 02
— pilih salah satu cara berikut untuk menyediakan datanya.
Opsi A - Membuat file langsung (paling aman)
Jalankan cell ini. File penjualan_kotor.csv akan
dibuat otomatis di runtime sehingga praktikum bisa langsung
dilanjutkan:
data_kotor = """tanggal,produk,kategori,qty,harga
2025-01-01,laptop,Elektronik,2,8500000
2025-01-01, Mouse ,Aksesoris,5,150000
2025-01-02,KEYBOARD,Aksesoris,3,250000
2025-01-02,Monitor,Elektronik,2,
2025-01-03,Printer,elektronik,1,1500000
2025-01-03,Mouse,Aksesoris,,150000
2025-02-01,Laptop,Elektronik,1,8500000
2025-02-01,Laptop,Elektronik,1,8500000
2025-02-02,Keyboard,,4,250000
2025-02-03,monitor,Elektronik,3,2000000
2025-02-03,Mouse,Aksesoris,6,150000
"""
with open("penjualan_kotor.csv", "w") as f:
f.write(data_kotor)
print("File penjualan_kotor.csv siap digunakan.")
Opsi B - Mengunduh dari tautan (review import CSV)
Pandas dapat membaca CSV langsung dari URL. Ganti
URL_DATASET dengan tautan yang dibagikan dosen:
import pandas as pd
URL_DATASET = "https://contoh-domain/penjualan_kotor.csv" # ganti dengan tautan dari dosen
df = pd.read_csv(URL_DATASET)
df.head()
Opsi C - Mengunggah file dari komputer
Jika dosen membagikan file untuk diunduh ke komputer terlebih dahulu:
from google.colab import files
uploaded = files.upload() # klik "Choose Files", pilih penjualan_kotor.csv
Setelah salah satu opsi dijalankan, semua langkah berikutnya
dimulai dengan
df = pd.read_csv("penjualan_kotor.csv").
Konsep Singkat
Data cleaning (pembersihan data) adalah proses memperbaiki data yang bermasalah sebelum dianalisis. Ini adalah tahap yang sering memakan waktu paling banyak dalam pekerjaan data, tetapi paling menentukan: analisis dan grafik secanggih apa pun akan menyesatkan jika datanya kotor. Prinsipnya dikenal sebagai garbage in, garbage out — sampah masuk, sampah keluar.
Tiga masalah kualitas data yang paling umum, beserta contohnya pada dataset kita:
1. Missing Value (Nilai Kosong)
Sel yang tidak terisi. Pandas menandainya sebagai
NaN (Not a Number). Contoh pada data kita:
kolom harga kosong pada satu transaksi Monitor,
qty kosong pada satu transaksi Mouse, dan
kategori kosong pada satu transaksi Keyboard.
Dampak: perhitungan seperti sum() atau
mean() bisa keliru, dan kolom angka yang mengandung
NaN otomatis berubah menjadi tipe desimal
(float).
2. Duplicate Data (Data Ganda)
Baris yang tercatat lebih dari satu kali, biasanya akibat kesalahan input. Contoh pada data kita: transaksi Laptop pada 2025-02-01 tercatat dua kali. Jika tidak dibuang, total penjualan akan terhitung berlebih.
3. Inkonsistensi (Perlu Transformasi)
Data yang sama ditulis dengan format berbeda sehingga dianggap
berbeda oleh komputer. Contoh pada data kita: laptop,
Laptop, dan LAPTOP dianggap tiga produk
berbeda; ada spasi tersembunyi pada
" Mouse "; kategori ditulis
elektronik dan Elektronik. Termasuk pula
tipe data yang salah (angka terbaca sebagai teks atau desimal).
Alur Kerja
Pola yang akan kita ikuti:
Diagnosa → Perbaiki (missing, duplikat, transformasi) → Verifikasi → Simpan
Langkah 1 - Memuat dan Mendiagnosis Data
Sebelum memperbaiki, kita potret dulu semua masalahnya. Jangan langsung membersihkan tanpa tahu apa yang salah.
import pandas as pd
df = pd.read_csv("penjualan_kotor.csv")
df
Output:
tanggal produk kategori qty harga
0 2025-01-01 laptop Elektronik 2.0 8500000.0
1 2025-01-01 Mouse Aksesoris 5.0 150000.0
2 2025-01-02 KEYBOARD Aksesoris 3.0 250000.0
3 2025-01-02 Monitor Elektronik 2.0 NaN
4 2025-01-03 Printer elektronik 1.0 1500000.0
5 2025-01-03 Mouse Aksesoris NaN 150000.0
6 2025-02-01 Laptop Elektronik 1.0 8500000.0
7 2025-02-01 Laptop Elektronik 1.0 8500000.0
8 2025-02-02 Keyboard NaN 4.0 250000.0
9 2025-02-03 monitor Elektronik 3.0 2000000.0
10 2025-02-03 Mouse Aksesoris 6.0 150000.0
Periksa ukuran, tipe data, jumlah nilai kosong, dan jumlah duplikat:
print("Ukuran:", df.shape)
print("\nNilai kosong per kolom:")
print(df.isna().sum())
print("\nJumlah baris duplikat:", df.duplicated().sum())
Output:
Ukuran: (11, 5)
Nilai kosong per kolom:
tanggal 0
produk 0
kategori 1
qty 1
harga 1
dtype: int64
Jumlah baris duplikat: 1
Perhatikan: kolomqtydanhargabertipe desimal (2.0,8500000.0) padahal seharusnya bilangan bulat. Ini terjadi karena adanyaNaN. Tipe akan kita perbaiki setelah nilai kosong ditangani.
Langkah 2 - Menangani Missing Value
Kunci penting: tidak semua kolom ditangani dengan cara yang sama. Pembersihan butuh penilaian.
Lihat baris mana saja yang punya nilai kosong:
df[df.isna().any(axis=1)]
Output:
tanggal produk kategori qty harga
3 2025-01-02 Monitor Elektronik 2.0 NaN <- harga kosong
5 2025-01-03 Mouse Aksesoris NaN 150000.0 <- qty kosong
8 2025-02-02 Keyboard NaN 4.0 250000.0 <- kategori kosong
Strategi yang dipilih:
| Kolom | Keputusan | Alasan |
|---|---|---|
harga |
Isi (fillna) |
Harga satuan tiap produk diketahui dari tabel referensi |
kategori |
Isi (fillna) |
Kategori bisa ditentukan dari nama produk |
qty |
Buang (dropna) |
Jumlah barang tidak bisa ditebak; menebak qty berisiko keliru |
Mengisi harga dan kategori
menggunakan tabel referensi produk (map):
peta_harga = {
"Laptop": 8500000, "Mouse": 150000, "Keyboard": 250000,
"Monitor": 2000000, "Printer": 1500000
}
peta_kategori = {
"Laptop": "Elektronik", "Monitor": "Elektronik", "Printer": "Elektronik",
"Mouse": "Aksesoris", "Keyboard": "Aksesoris"
}
df["harga"] = df["harga"].fillna(df["produk"].map(peta_harga))
df["kategori"] = df["kategori"].fillna(df["produk"].map(peta_kategori))
Membuang baris yang qty-nya kosong:
df = df.dropna(subset=["qty"])
Verifikasi tidak ada lagi nilai kosong:
print(df.isna().sum().sum(), "nilai kosong tersisa")
Output:
0 nilai kosong tersisa
fillnamengisi sel kosong;dropna(subset=[...])membuang baris yang kolom tertentunya kosong. Memilih di antaranya bergantung pada apakah nilai yang hilang bisa diperkirakan dengan aman.
Langkah 3 - Menangani Duplicate Data
Lihat baris yang terduplikasi:
df[df.duplicated()]
Output:
tanggal produk kategori qty harga
7 2025-02-01 Laptop Elektronik 1.0 8500000.0
Hapus duplikat dan cek perubahan ukuran:
print("Sebelum:", df.shape)
df = df.drop_duplicates()
print("Sesudah:", df.shape)
Output:
Sebelum: (10, 5)
Sesudah: (9, 5)
duplicated()menandai baris yang merupakan salinan dari baris sebelumnya;drop_duplicates()membuangnya dan menyisakan satu. Selalu periksashapesebelum/sesudah agar yakin jumlah yang terhapus masuk akal.
Langkah 4 - Transformasi Data
Tahap ini menyeragamkan format agar data konsisten dan bertipe benar.
Standardisasi Teks
Buang spasi berlebih dengan str.strip() dan
seragamkan kapitalisasi dengan str.title():
df["produk"] = df["produk"].str.strip().str.title()
df["kategori"] = df["kategori"].str.strip().str.title()
print(df["produk"].unique())
print(df["kategori"].unique())
Output:
['Laptop' 'Mouse' 'Keyboard' 'Monitor' 'Printer']
['Elektronik' 'Aksesoris']
Sekarang laptop, KEYBOARD,
monitor, dan " Mouse " sudah
seragam.
Konversi Tipe Data
Setelah nilai kosong hilang, ubah qty dan
harga menjadi bilangan bulat, dan
tanggal menjadi tipe tanggal:
df["qty"] = df["qty"].astype(int)
df["harga"] = df["harga"].astype(int)
df["tanggal"] = pd.to_datetime(df["tanggal"])
df.dtypes
Output:
tanggal datetime64[ns]
produk object
kategori object
qty int64
harga int64
dtype: object
Konversiastype(int)hanya berhasil bila kolom tidak lagi mengandungNaN. Itulah sebabnya missing value ditangani lebih dulu.
Langkah 5 - Verifikasi dan Menyimpan
Lakukan pemeriksaan akhir, lalu simpan data bersih ke file baru.
print("Ukuran akhir :", df.shape)
print("Nilai kosong :", df.isna().sum().sum())
print("Baris duplikat :", df.duplicated().sum())
print("Jumlah produk :", df["produk"].nunique())
df.head()
Output:
Ukuran akhir : (9, 5)
Nilai kosong : 0
Baris duplikat : 0
Jumlah produk : 5
Simpan ke penjualan_bersih.csv (parameter
index=False agar nomor baris tidak ikut tertulis):
df.to_csv("penjualan_bersih.csv", index=False)
print("Data bersih tersimpan sebagai penjualan_bersih.csv")
File penjualan_bersih.csv inilah yang akan dipakai
untuk visualisasi pada pertemuan berikutnya.
Referensi Fungsi Penting
Bagian ini merangkum fungsi-fungsi Pandas yang relevan untuk
data cleaning beserta variasinya, agar mahasiswa dapat
bereksperimen lebih jauh dari sekadar langkah praktikum di atas.
Semua perintah dapat langsung disalin dan dicoba pada
df.
Mendeteksi Missing Value
Pada Langkah 1 dan 2 kita memakai
df[df.isna().any(axis=1)]. Baris itu sebenarnya
gabungan beberapa fungsi kecil:
-
df.isna()menghasilkan tabelTrue/False—Trueberarti sel kosong. (df.isnull()adalah nama lain yang identik.) -
.any(axis=1)mengecek per baris: bernilaiTruebila ada minimal satu sel kosong di baris itu. -
df[ ... ]lalu menampilkan baris-baris yang terdeteksi.
Memahami axis (sering membingungkan, jadi ingat
baik-baik):
axis=0 → arah ke bawah (memproses antar-baris, hasil per KOLOM)
axis=1 → arah ke samping (memproses antar-kolom, hasil per BARIS)
| Perintah | Fungsi |
|---|---|
df.isna() |
Tabel True/False,
True = kosong
|
df.notna() |
Kebalikan dari isna() (True =
terisi)
|
df.isna().sum() |
Jumlah nilai kosong per kolom |
df.isna().sum().sum() |
Total nilai kosong seluruh tabel |
df.isna().any() |
Kolom mana yang memiliki nilai kosong |
df.isna().any(axis=1) |
Baris mana yang memiliki nilai kosong |
df["harga"].isna() |
Cek nilai kosong pada satu kolom |
df.info() |
Ringkasan jumlah data terisi per kolom |
df.isna().sum() # berapa kosong tiap kolom
df.isna().sum().sum() # total kosong seluruh tabel
df[df.isna().any(axis=1)] # tampilkan baris yang punya kosong
df[df["harga"].isna()] # tampilkan baris yang harganya kosong saja
Menangani Missing Value
Pada Langkah 2 kita memakai
df.dropna(subset=["qty"]) dan
fillna(...). Keduanya punya banyak variasi.
Membuang dengan dropna:
| Perintah | Efek |
|---|---|
df.dropna() |
Buang baris yang punya kosong di kolom mana pun |
df.dropna(subset=["qty"]) |
Buang baris hanya bila kolom qty kosong |
df.dropna(how="all") |
Buang baris hanya bila semua kolomnya kosong |
df.dropna(thresh=3) |
Pertahankan baris yang punya minimal 3 nilai terisi |
df.dropna(axis=1) |
Buang kolom (bukan baris) yang mengandung kosong |
Mengisi dengan fillna dan kerabatnya:
| Perintah | Efek |
|---|---|
df["x"].fillna(0) |
Isi dengan nilai tetap (mis. 0) |
df["x"].fillna(df["x"].mean())
|
Isi dengan rata-rata kolom |
df["x"].fillna(df["x"].median())
|
Isi dengan nilai tengah (median) |
df["x"].fillna(df["x"].mode()[0])
|
Isi dengan nilai terbanyak (modus) — cocok untuk kategori |
df["x"].ffill() |
Isi dengan nilai dari baris atas-nya |
df["x"].bfill() |
Isi dengan nilai dari baris bawah-nya |
df["x"].fillna(df["kunci"].map(peta))
|
Isi dari tabel referensi (seperti di Langkah 2) |
df["harga"] = df["harga"].fillna(df["harga"].median()) # isi dengan median
df["kategori"] = df["kategori"].fillna("Tidak Diketahui") # isi dengan teks tetap
df = df.dropna(subset=["qty"]) # buang baris qty kosong
Pilihannya selalu sama: isi bila nilai bisa diperkirakan dengan aman, buang bila tidak.
Menangani Duplikat
Pada Langkah 3 kita memakai df[df.duplicated()] dan
df.drop_duplicates(). Parameter keep dan
subset membuatnya fleksibel.
df.duplicated() menandai baris yang sama dengan baris
sebelumnya. Parameter
keep menentukan kemunculan mana yang
tidak dihitung sebagai duplikat:
Nilai keep |
Arti |
|---|---|
"first" (default) |
Tandai semua kembaran kecuali yang pertama |
"last" |
Tandai semua kembaran kecuali yang terakhir |
False |
Tandai semua baris yang kembar |
| Perintah | Fungsi |
|---|---|
df.duplicated() |
Tandai baris duplikat (True/False)
|
df.duplicated().sum() |
Hitung jumlah duplikat |
df[df.duplicated()] |
Tampilkan baris yang duplikat |
df[df.duplicated(keep=False)] |
Tampilkan semua baris kembar |
df.duplicated(subset=["tanggal",
"produk"])
|
Anggap duplikat berdasar kolom tertentu saja |
df.drop_duplicates() |
Hapus duplikat, sisakan satu |
df.drop_duplicates(subset=["tanggal",
"produk"], keep="last")
|
Hapus berdasar kolom tertentu, simpan kemunculan terakhir |
df.duplicated().sum() # ada berapa duplikat
df[df.duplicated(keep=False)] # lihat semua baris yang kembar
df = df.drop_duplicates() # hapus, sisakan satu
Standardisasi Teks dan Tipe
Pelengkap untuk tahap Transformasi (Langkah 4):
| Perintah | Fungsi |
|---|---|
df["x"].str.strip() |
Hapus spasi di awal/akhir teks |
df["x"].str.lower() /
.str.upper()
|
Ubah ke huruf kecil / besar |
df["x"].str.title() |
Awali tiap kata dengan huruf besar |
df["x"].str.replace("a",
"b")
|
Ganti potongan teks |
df["x"].astype(int) /
.astype(float)
|
Ubah tipe data angka |
pd.to_datetime(df["x"]) |
Ubah teks menjadi tipe tanggal |
df["x"].unique() /
.nunique()
|
Lihat nilai unik / jumlah nilai unik |
df["x"].value_counts() |
Hitung frekuensi tiap nilai |
df["produk"].value_counts() # lihat sebaran & ejaan nilai
df["produk"] = df["produk"].str.strip().str.title()
df["produk"].unique() # pastikan sudah seragam
Pengujian
Pastikan hasil pembersihan memenuhi seluruh kriteria berikut:
df.shapemenghasilkan(9, 5).-
df.isna().sum().sum()bernilai0(tidak ada nilai kosong). -
df.duplicated().sum()bernilai0(tidak ada duplikat). -
df["produk"].nunique()bernilai5dandf["kategori"].nunique()bernilai2(teks konsisten). -
df.dtypesmenunjukkanqtydanhargabertipeint64, sertatanggalbertipedatetime64[ns].
Verifikasi cepat secara otomatis:
assert df.shape == (9, 5)
assert df.isna().sum().sum() == 0
assert df.duplicated().sum() == 0
assert df["produk"].nunique() == 5
print("Semua pengujian lolos. Data sudah bersih.")
Troubleshooting
| Masalah | Penyebab | Solusi |
|---|---|---|
ValueError: cannot convert ... NaN saat
astype(int)
|
Masih ada nilai kosong di kolom | Tangani missing value lebih dulu (Langkah 2) |
SettingWithCopyWarning |
Memodifikasi hasil filter, bukan DataFrame asli |
Tambahkan .copy() saat membuat subset, atau
gunakan .loc
|
Teks masih dianggap berbeda setelah title()
|
Ada spasi tersembunyi di awal/akhir |
Jalankan str.strip() sebelum
str.title()
|
map justru memunculkan NaN baru
|
Kunci pada peta tidak cocok (beda ejaan/kapital) | Samakan dulu teks, atau periksa isi peta |
| Duplikat tidak terhapus | Ada perbedaan tak terlihat (spasi/kapital) |
Bersihkan teks dulu, baru drop_duplicates()
|
Tugas Praktikum
Buat laporan (format PDF) yang berisi:
- Identitas: Nama dan NIM.
- Ringkasan diagnosis awal: jumlah nilai kosong per kolom dan jumlah duplikat.
- Penjelasan singkat strategi yang dipilih untuk tiap kolom yang bermasalah.
- Bukti data sudah bersih (output Pengujian).
-
Analisis ulang dari data bersih: hitung kembali
produk terlaris dan total penjualan menggunakan teknik dari
Pertemuan 02 (
groupby), lalu bandingkan — apakah hasilnya akan berbeda jika data tidak dibersihkan? Jelaskan mengapa.
Tips: ekspor notebook ke PDF melalui menu File → Print → Save as PDF.
Kesimpulan
Pada pertemuan ini mahasiswa belajar bahwa kualitas analisis sangat bergantung pada kualitas data. Mahasiswa mendiagnosis tiga masalah utama — missing value, duplicate data, dan inkonsistensi — lalu menanganinya dengan strategi yang tepat: mengisi atau membuang nilai kosong sesuai konteks, menghapus duplikat, menyeragamkan teks, dan mengoreksi tipe data. Hasil akhirnya adalah dataset bersih yang tersimpan dan siap dipakai. Keterampilan ini menjadi fondasi wajib sebelum melangkah ke visualisasi data pada pertemuan berikutnya, karena grafik yang dibuat dari data kotor hanya akan menghasilkan kesimpulan yang menyesatkan.