Data machine learning di dunia nyata jarang berbentuk array angka yang rapi; data datang sebagai tabel CSV dengan nama kolom, baris berlabel, dan tipe campuran — teks, angka, tanggal. Pandas dirancang persis untuk tabel semacam itu, dan hampir semua proyek machine learning dimulai dari DataFrame: memuat data, memeriksanya, menyaringnya, lalu menyerahkan hasilnya ke model sebagai matriks fitur X dan vektor target y. Chapter ini melatih alur tersebut pada tabel karyawan kecil yang kita bangun sendiri — tanpa file eksternal — mulai dari seleksi kolom hingga agregasi per kelompok, penggabungan tabel, dan deteksi data hilang.
DataFrame dan Series #
DataFrame adalah tabel dua dimensi: baris memiliki indeks, kolom memiliki nama, dan setiap kolom boleh bertipe berbeda (teks, bilangan bulat, desimal) — perbedaan utamanya dari ndarray yang harus homogen. Series adalah satu kolom DataFrame beserta indeksnya; memilih satu kolom menghasilkan Series, memilih beberapa kolom menghasilkan DataFrame baru. Struktur ini membuat kode terbaca: karyawan["gaji_juta"] lebih jelas daripada X[:, 3].
Fungsi df.info() adalah pemeriksaan pertama standar — fungsi tersebut mencetak jumlah baris, tipe tiap kolom, dan jumlah nilai terisi per kolom. File contoh di bawah mencetak ringkasan serupa secara manual agar keluarannya ringkas, lalu melanjutkan ke operasi inti: head() untuk mengintip data, seleksi kolom, penyaringan baris dengan kondisi boolean, pengurutan nlargest, pembuatan kolom baru, pembacaan CSV, dan describe() untuk statistik ringkas.
# DataFrame dasar: membangun, memilih kolom, menyaring, mengurutkan,
# membaca CSV dari teks, dan ringkasan statistik.
import io
import pandas as pd
karyawan = pd.DataFrame({
"nama": ["Budi", "Siti", "Dewi", "Andi", "Rina", "Fajar", "Lina", "Hendra"],
"departemen": ["Teknis", "Teknis", "Produksi", "Produksi",
"Pemasaran", "Pemasaran", "Teknis", "Produksi"],
"pengalaman_tahun": [2, 5, 3, 7, 1, 4, 6, 2],
"gaji_juta": [8.0, 12.5, 9.0, 15.0, 6.5, 10.0, 13.5, 8.5],
})
print("Lima baris pertama:")
print(karyawan.head())
print("\nInformasi ringkas:")
print("Jumlah baris :", len(karyawan))
print("Jumlah kolom :", karyawan.shape[1])
print("Nama kolom :", list(karyawan.columns))
# Seleksi kolom: satu kolom -> Series, banyak kolom -> DataFrame
print("\nDua kolom dipilih (DataFrame):")
print(karyawan[["nama", "gaji_juta"]].to_string(index=False))
# Penyaringan baris dengan kondisi boolean
senior_teknis = karyawan[(karyawan["departemen"] == "Teknis")
& (karyawan["pengalaman_tahun"] >= 5)]
print("\nKaryawan Teknis berpengalaman >= 5 tahun:")
print(senior_teknis.to_string(index=False))
# Pengurutan berdasarkan kolom
print("\nLima gaji tertinggi:")
print(karyawan.nlargest(5, "gaji_juta")[["nama", "departemen", "gaji_juta"]]
.to_string(index=False))
# Kolom baru hasil hitung antar kolom
karyawan["gaji_per_pengalaman"] = (karyawan["gaji_juta"]
/ karyawan["pengalaman_tahun"]).round(2)
print("\nKolom baru gaji_per_pengalaman:")
print(karyawan[["nama", "gaji_juta", "pengalaman_tahun", "gaji_per_pengalaman"]]
.to_string(index=False))
# Di proyek nyata data biasanya dibaca dari file CSV.
# Di sini isi CSV ditulis sebagai teks agar contoh tetap mandiri.
csv_teks = """nama,departemen,gaji_juta
Budi,Teknis,8.0
Siti,Teknis,12.5
Dewi,Produksi,9.0
Andi,Produksi,15.0
"""
df_csv = pd.read_csv(io.StringIO(csv_teks))
print("\nHasil pd.read_csv dari teks (4 baris):")
print(df_csv.to_string(index=False))
print("\nRingkasan statistik kolom numerik:")
print(karyawan[["pengalaman_tahun", "gaji_juta"]].describe().round(2))Output yang Dihasilkan:
Lima baris pertama:
nama departemen pengalaman_tahun gaji_juta
0 Budi Teknis 2 8.0
1 Siti Teknis 5 12.5
2 Dewi Produksi 3 9.0
3 Andi Produksi 7 15.0
4 Rina Pemasaran 1 6.5
Informasi ringkas:
Jumlah baris : 8
Jumlah kolom : 4
Nama kolom : ['nama', 'departemen', 'pengalaman_tahun', 'gaji_juta']
Dua kolom dipilih (DataFrame):
nama gaji_juta
Budi 8.0
Siti 12.5
Dewi 9.0
Andi 15.0
Rina 6.5
Fajar 10.0
Lina 13.5
Hendra 8.5
Karyawan Teknis berpengalaman >= 5 tahun:
nama departemen pengalaman_tahun gaji_juta
Siti Teknis 5 12.5
Lina Teknis 6 13.5
Lima gaji tertinggi:
nama departemen gaji_juta
Andi Produksi 15.0
Lina Teknis 13.5
Siti Teknis 12.5
Fajar Pemasaran 10.0
Dewi Produksi 9.0
Kolom baru gaji_per_pengalaman:
nama gaji_juta pengalaman_tahun gaji_per_pengalaman
Budi 8.0 2 4.00
Siti 12.5 5 2.50
Dewi 9.0 3 3.00
Andi 15.0 7 2.14
Rina 6.5 1 6.50
Fajar 10.0 4 2.50
Lina 13.5 6 2.25
Hendra 8.5 2 4.25
Hasil pd.read_csv dari teks (4 baris):
nama departemen gaji_juta
Budi Teknis 8.0
Siti Teknis 12.5
Dewi Produksi 9.0
Andi Produksi 15.0
Ringkasan statistik kolom numerik:
pengalaman_tahun gaji_juta
count 8.00 8.00
mean 3.75 10.38
std 2.12 2.97
min 1.00 6.50
25% 2.00 8.38
50% 3.50 9.50
75% 5.25 12.75
max 7.00 15.00Mari kita telaah baris-baris kode yang berperan penting:
- Baris 8–14 (
pd.DataFrame({...})): tabel dibangun dari dictionary — kunci menjadi nama kolom, nilai list menjadi isi kolom. Delapan karyawan fiktif kini punya empat kolom bertipe campuran. - Baris 16–22 (
headdan ringkasan):head()menampilkan lima baris pertama;len,shape, dancolumnsmemberi peta struktur tanpa mencetak seluruh data. - Baris 25–26 (seleksi kolom): daftar nama kolom di dalam kurung siku ganda menghasilkan DataFrame baru — hanya Budi sampai Hendra beserta gajinya yang tampil.
- Baris 29–32 (penyaringan): kondisi boolean pada kolom digabung dengan
&, persis pola mask NumPy; hasilnya hanya Siti dan Lina yang memenuhi kriteria Teknis berpengalaman lima tahun ke atas. - Baris 35–37 (
nlargest): pengurutan praktis lima gaji tertinggi tanpasort_valueslalu slicing manual. - Baris 40–44 (kolom baru): kolom
gaji_per_pengalamandihitung dari dua kolom lama dalam satu ekspresi vektor — pola dasar feature engineering. - Baris 48–56 (CSV dari teks):
pd.read_csvbiasanya membaca file; di sini string CSV dibungkusio.StringIOagar contoh mandiri tanpa file eksternal, dengan perilaku parsing yang identik. - Baris 58–59 (
describe): ringkasan count, mean, std, hingga kuartil — perpanjangan langsung dari statistika deskriptif Chapter sebelumnya, kini per kolom.
GroupBy: Ringkas per Kelompok #
Pertanyaan analitik hampir selalu berbentuk “per kelompok”: berapa rata-rata gaji per departemen, berapa jumlah transaksi per kota. GroupBy bekerja dalam tiga fase — split membagi baris menurut nilai kolom kunci, apply menjalankan agregasi (mean, count, max) pada tiap kelompok, combine menyatukan hasil menjadi tabel baru dengan kelompok sebagai indeks. File agregasi-groupby.py juga mendemonstrasikan merge untuk menggabungkan dua tabel lewat kolom kunci bersama — mekanisme yang sama dengan join pada SQL — serta deteksi data hilang dengan isna.
# GroupBy dan merge: ringkasan per departemen serta penggabungan tabel,
# ditutup deteksi data hilang dengan isna.
import pandas as pd
karyawan = pd.DataFrame({
"nama": ["Budi", "Siti", "Dewi", "Andi", "Rina", "Fajar", "Lina", "Hendra"],
"departemen": ["Teknis", "Teknis", "Produksi", "Produksi",
"Pemasaran", "Pemasaran", "Teknis", "Produksi"],
"pengalaman_tahun": [2.0, 5.0, 3.0, 7.0, 1.0, 4.0, 6.0, 2.0],
"gaji_juta": [8.0, 12.5, 9.0, 15.0, 6.5, 10.0, 13.5, 8.5],
})
# Rata-rata gaji per departemen, diurutkan dari yang tertinggi
rata_gaji = karyawan.groupby("departemen")["gaji_juta"].mean().round(2)
print("Rata-rata gaji per departemen (juta rupiah):")
print(rata_gaji.sort_values(ascending=False))
# Jumlah karyawan per departemen
print("\nJumlah karyawan per departemen:")
print(karyawan.groupby("departemen").size().sort_values(ascending=False))
# Beberapa agregasi sekaligus dengan named aggregation
ringkasan = karyawan.groupby("departemen").agg(
jumlah_karyawan=("nama", "count"),
gaji_rata_rata=("gaji_juta", "mean"),
gaji_tertinggi=("gaji_juta", "max"),
pengalaman_rata=("pengalaman_tahun", "mean"),
).round(2)
print("\nRingkasan banyak agregasi per departemen:")
print(ringkasan)
# Merge: gabungkan tabel bonus per departemen ke tabel karyawan
bonus = pd.DataFrame({
"departemen": ["Pemasaran", "Produksi", "Teknis"],
"bonus_juta": [0.8, 1.2, 1.0],
})
gabungan = karyawan.merge(bonus, on="departemen", how="left")
gabungan["total_juta"] = (gabungan["gaji_juta"] + gabungan["bonus_juta"]).round(2)
print("\nHasil merge dengan tabel bonus:")
print(gabungan[["nama", "departemen", "gaji_juta", "bonus_juta", "total_juta"]]
.to_string(index=False))
# Deteksi data hilang: satu nilai pengalaman sengaja dikosongkan
karyawan.loc[3, "pengalaman_tahun"] = float("nan")
print("\nJumlah nilai hilang per kolom:")
print(karyawan.isna().sum())
print("\nBaris yang memiliki nilai hilang:")
print(karyawan[karyawan["pengalaman_tahun"].isna()].to_string(index=False))Output yang Dihasilkan:
Rata-rata gaji per departemen (juta rupiah):
departemen
Teknis 11.33
Produksi 10.83
Pemasaran 8.25
Name: gaji_juta, dtype: float64
Jumlah karyawan per departemen:
departemen
Produksi 3
Teknis 3
Pemasaran 2
dtype: int64
Ringkasan banyak agregasi per departemen:
jumlah_karyawan gaji_rata_rata gaji_tertinggi pengalaman_rata
departemen
Pemasaran 2 8.25 10.0 2.50
Produksi 3 10.83 15.0 4.00
Teknis 3 11.33 13.5 4.33
Hasil merge dengan tabel bonus:
nama departemen gaji_juta bonus_juta total_juta
Budi Teknis 8.0 1.0 9.0
Siti Teknis 12.5 1.0 13.5
Dewi Produksi 9.0 1.2 10.2
Andi Produksi 15.0 1.2 16.2
Rina Pemasaran 6.5 0.8 7.3
Fajar Pemasaran 10.0 0.8 10.8
Lina Teknis 13.5 1.0 14.5
Hendra Produksi 8.5 1.2 9.7
Jumlah nilai hilang per kolom:
nama 0
departemen 0
pengalaman_tahun 1
gaji_juta 0
dtype: int64
Baris yang memiliki nilai hilang:
nama departemen pengalaman_tahun gaji_juta
Andi Produksi NaN 15.0Bedah kode di atas baris demi baris:
- Baris 15–17 (
groupby ... mean): baris dibagi tiga kelompok departemen, rata-ratagaji_jutadihitung per kelompok, lalusort_valuesmengurutkan Teknis (11,33) di depan Pemasaran (8,25). - Baris 20–21 (
size): menghitung anggota tiap kelompok — cara tercepat memeriksa class balance, kelak penting saat menangani data tidak seimbang. - Baris 24–31 (
aggbernama): satu panggilan menghasilkan empat kolom sekaligus; setiap kolom baru didefinisikan pasangan (kolom sumber, fungsi), hasilnya DataFrame ringkas per departemen. - Baris 34–42 (
merge): tabel bonus tiga baris digabungkan pada kolomdepartemen;how="left"menjaga seluruh baris karyawan tetap utuh. Kolomtotal_jutalalu dihitung dari hasil gabungan — pola umum saat melengkapi data dengan tabel referensi. - Baris 45–49 (
isna): satu nilai pengalaman dikosongkan;isna().sum()menghitung satu nilai hilang di kolom itu, dan penyaringanisna()menunjukkan baris Andi sebagai pemiliknya — langkah pertama sebelum memutuskan strategi imputasi.
Dari DataFrame ke X dan y #
Ujung seluruh operasi pandas pada alur machine learning adalah penyerahan data ke model. Pola bakunya ringkas: pilih kolom fitur sebagai X, pilih kolom target sebagai y — misalnya X = karyawan[["pengalaman_tahun", "gaji_juta"]] dan y = karyawan["departemen"]. scikit-learn menerima DataFrame secara langsung dan menjaga nama kolomnya pada pesan galat serta hasil feature_importances_; jika kita butuh array murni, metode .to_numpy() mengubahnya tanpa menyalin label. Dengan ini rantai lengkapnya tertutup: tabel berlabel → matriks fitur → model.
| Kebutuhan | Pola pandas | Hasil |
|---|---|---|
| Pilih kolom | df[["a", "b"]] | DataFrame baru |
| Saring baris | df[df["a"] > 5] | Baris yang memenuhi kondisi |
| Kolom baru | df["c"] = df["a"] / df["b"] | Kolom hasil hitung vektor |
| Ringkas per grup | df.groupby("g")["a"].mean() | Satu angka per kelompok |
| Gabung tabel | df1.merge(df2, on="k") | Kolom dari dua tabel tergabung |
| Deteksi hilang | df.isna().sum() | Jumlah NaN per kolom |
Tabel dan angka saja belum cukup untuk mengenal data — pola, sebaran, dan hubungan antar variabel paling cepat terlihat lewat gambar. Kita akan mempelajari caranya pada Chapter Matplotlib untuk Visualisasi Data.
Referensi Resmi #
- Getting started — pandas dokumentasi — pintu masuk resmi lengkap dengan panduan singkat.
- 10 minutes to pandas — pandas User Guide — tur cepat operasi inti DataFrame.
- Group by: split-apply-combine — pandas User Guide — penjelasan resmi mekanisme GroupBy.
- Merge, join, concatenate — pandas User Guide — penjelasan resmi penggabungan tabel.