Pertanyaan analisis sudah kita rumuskan; kini saatnya berkenalan dengan dataset yang akan menjawabnya. Kesalahan klasik pemula adalah langsung menghitung rata-rata tanpa memahami bentuk tabel terlebih dahulu — padahal salah membaca makna satu baris bisa merusak seluruh kesimpulan. Pada chapter ini kita membedah struktur data Toko Kopi Kita dengan alat inspeksi pandas: dimensi, nama kolom, tipe data, cuplikan baris, profil keunikan, hingga kunci yang menghubungkan dua tabel.
Makna Satu Baris: Observasi #
Aturan pertama memahami struktur: satu baris mewakili satu observasi — satu kejadian atau satu entitas yang dicatat. Kesadaran ini menentukan pertanyaan apa yang sah untuk diajukan. Pada tabel pelanggan, satu baris adalah satu pelanggan terdaftar, sehingga pertanyaan “siapa pelanggan dengan poin terbanyak?” sah. Sebaliknya, pada tabel transaksi, satu baris adalah satu pesanan, sehingga pertanyaan yang sama harus dijawab lewat penghitungan tambahan.
| Tabel | Satu baris mewakili | Contoh pertanyaan yang sah |
|---|---|---|
pelanggan | satu pelanggan terdaftar | Pelanggan siapa yang bergabung paling akhir? |
transaksi | satu pesanan pelanggan | Menu apa yang paling sering dipesan pekan ini? |
rekap_harian | satu hari operasional | Hari mana pendapatan terbesar bulan ini? |
Satu dataset yang sama bisa diringkas pada beberapa tingkat — transaksi mentah, rekap harian, rekap bulanan. Semakin tinggi tingkatnya, semakin sedikit barisnya dan semakin banyak detail yang menyatu di dalam satu angka. Sebelum membandingkan dua tabel, pastikan keduanya berada pada tingkat yang setara; membandingkan tabel transaksi dengan tabel rekap harian adalah resep kesimpulan yang keliru.
Kita memakai dua berkas kecil sepanjang chapter ini — tabel induk pelanggan:
id_pelanggan,nama,kota,poin
P01,Budi,Bandung,120
P02,Siti,Bandung,85
P03,Dewi,Surabaya,200
P04,Agus,Bandung,60
P05,Rani,Surabaya,95dan tabel transaksi yang mencatat pesanan dengan merujuk pelanggan lewat id_pelanggan:
tanggal,id_pelanggan,menu,total_ribu
2025-01-13,P01,kopi susu,48
2025-01-13,P02,teh tawar,20
2025-01-14,P03,matcha latte,56
2025-01-14,P01,kopi susu,24
2025-01-15,P05,teh tawar,40
2025-01-15,P04,matcha latte,28
2025-01-16,P02,kopi susu,72
2025-01-16,P03,teh tawar,40Memeriksa Dimensi, Kolom, dan Tipe Data #
Pemeriksaan pertama menjawab tiga hal: berapa ukuran tabel, kolom apa saja yang tersedia, dan tipe data apa yang dikandung tiap kolom. Ketiganya kita dapat dari shape, columns, dan dtypes:
import pandas as pd
pelanggan = pd.read_csv("pelanggan.csv")
print("Dimensi (baris, kolom):", pelanggan.shape)
print("Nama kolom:", pelanggan.columns.tolist())
print(pelanggan.dtypes)Output yang Dihasilkan:
Dimensi (baris, kolom): (5, 4)
Nama kolom: ['id_pelanggan', 'nama', 'kota', 'poin']
id_pelanggan object
nama object
kota object
poin int64
dtype: objectMari kita baca keluarannya satu per satu:
pelanggan.shapemengembalikan pasangan(5, 4): lima baris observasi dan empat kolom variabel. Ini ukuran tabel yang benar-benar terbaca — bukan ukuran berkas aslinya.pelanggan.columns.tolist()menampilkan nama kolom sebagai list Python. Di sinilah kita menguji pertanyaan analisis dari chapter sebelumnya: kolom yang tidak ada di list ini tidak bisa menjawab pertanyaan apa pun.pelanggan.dtypesmelaporkan tipe data tiap kolom. Kolom teks terbaca sebagaiobject, sedangkan kolom bilangan bulat sebagaiint64. Tipe menentukan operasi yang sah:poinbisa dihitung rata-ratanya,namahanya bisa dihitung frekuensinya.
Perhatikan pula bahwa id_pelanggan berisi kode P01 sampai P05 — label, bukan angka. Kolom semacam ini sengaja disimpan sebagai teks agar tidak ikut terseret ke dalam hitungan numerik; menjadikannya angka justru menyesatkan, karena P01 + P02 tidak punya arti.
Melihat Cuplikan Data: head, tail, dan sample #
Setelah tahu kerangkanya, kita mengintip isinya. Tiga method untuk itu: head() menampilkan baris teratas, tail() menampilkan baris terbawah, dan sample() mengambil baris secara acak:
import pandas as pd
pelanggan = pd.read_csv("pelanggan.csv")
print(pelanggan.head(3))
print()
print(pelanggan.tail(3))
print()
print(pelanggan.sample(3, random_state=42))Output yang Dihasilkan:
id_pelanggan nama kota poin
0 P01 Budi Bandung 120
1 P02 Siti Bandung 85
2 P03 Dewi Surabaya 200
id_pelanggan nama kota poin
2 P03 Dewi Surabaya 200
3 P04 Agus Bandung 60
4 P05 Rani Surabaya 95
id_pelanggan nama kota poin
1 P02 Siti Bandung 85
4 P05 Rani Surabaya 95
2 P03 Dewi Surabaya 200Ketiga cuplikan tersebut punya peran berbeda. head(3) memastikan berkas terbaca dengan benar — nama kolom cocok, nilai masuk akal. tail(3) mengecek ujung tabel, tempat baris rangkap atau catatan tambahan sering menempel. sample(3, random_state=42) mengambil tiga baris secara acak; argumen random_state=42 membekukan pilihan acaknya sehingga siapa pun yang menjalankan kode ini mendapat baris yang sama persis.
Profil Kolom: nunique dan info #
Pemeriksaan berikutnya memprofilkan tiap kolom: berapa banyak nilai uniknya, dan apakah ada sel yang kosong. Dua alatnya adalah nunique() dan info():
import pandas as pd
pelanggan = pd.read_csv("pelanggan.csv")
print("Jumlah nilai unik tiap kolom:")
print(pelanggan.nunique())
print()
pelanggan.info()Output yang Dihasilkan:
Jumlah nilai unik tiap kolom:
id_pelanggan 5
nama 5
kota 2
poin 5
dtype: int64
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id_pelanggan 5 non-null object
1 nama 5 non-null object
2 kota 5 non-null object
3 poin 5 non-null int64
dtypes: int64(1), object(3)
memory usage: 292.0+ bytesCara membaca keluaran tersebut:
nunique()menghitung nilai berbeda di tiap kolom. Kolomid_pelangganmemuat 5 nilai unik dari 5 baris — tanda kolom kunci. Kolomkotahanya memuat 2 nilai unik — tanda kolom kategorikal.RangeIndex: 5 entries, 0 to 4menegaskan 5 baris terindeks 0 sampai 4; tidak ada baris yang gagal terbaca.- Kolom
Non-Null Countmembandingkan jumlah nilai terisi dengan total baris. Seluruh kolom di sini mencatat5 non-null; kolom yang mencatat lebih sedikit mengandung missing values yang harus ditangani lebih dulu. dtypes: int64(1), object(3)merangkum komposisi tipe data, lalumemory usagememperkirakan pemakaian memori — angka yang mulai penting saat tabel membesar menjadi jutaan baris.
Kunci Penghubung antar Tabel #
Dunia nyata jarang menyimpan semua data dalam satu tabel. Toko Kopi Kita memisahkan tabel induk pelanggan dari tabel transaksi, dan keduanya dihubungkan kolom id_pelanggan — kolom kunci yang nilainya sama di kedua tabel. Pemisahan seperti ini menghemat ruang: nama dan kota pelanggan cukup disimpan sekali, tidak diulang di setiap transaksi.
Berikut cara kedua tabel tersebut disambungkan:
import pandas as pd
pelanggan = pd.read_csv("pelanggan.csv")
transaksi = pd.read_csv("transaksi.csv")
print("id_pelanggan di tabel pelanggan:", sorted(pelanggan["id_pelanggan"]))
print("id_pelanggan di tabel transaksi:", sorted(transaksi["id_pelanggan"].unique()))
print()
gabung = transaksi.merge(pelanggan[["id_pelanggan", "nama"]], on="id_pelanggan")
print(gabung)Output yang Dihasilkan:
id_pelanggan di tabel pelanggan: ['P01', 'P02', 'P03', 'P04', 'P05']
id_pelanggan di tabel transaksi: ['P01', 'P02', 'P03', 'P04', 'P05']
tanggal id_pelanggan menu total_ribu nama
0 2025-01-13 P01 kopi susu 48 Budi
1 2025-01-13 P02 teh tawar 20 Siti
2 2025-01-14 P03 matcha latte 56 Dewi
3 2025-01-14 P01 kopi susu 24 Budi
4 2025-01-15 P05 teh tawar 40 Rani
5 2025-01-15 P04 matcha latte 28 Agus
6 2025-01-16 P02 kopi susu 72 Siti
7 2025-01-16 P03 teh tawar 40 DewiBedah kode di atas:
sorted(pelanggan["id_pelanggan"])memastikan lima pelanggan tercatat lengkap;sorted(transaksi["id_pelanggan"].unique())memastikan setiap transaksi merujuk pelanggan yang memang ada. Kunci yang dirujuk tetapi tidak tercatat di tabel induk adalah foreign key yang menggantung — transaksi tanpa pemilik.pelanggan[["id_pelanggan", "nama"]]mengambil dua kolom saja dari tabel induk, sehingga tabel hasil penggabungan tidak membawa muatankotadanpoinyang tidak diperlukan..merge(..., on="id_pelanggan")menyandingkan tiap baris transaksi dengan baris pelanggan yang ber-id_pelanggansama. Hasilnya, tabel transaksi yang semula anonim kini memuat nama pelanggan — siap dipakai untuk analisis seperti “pelanggan mana yang paling sering memesan?”.
Rangkuman #
- Satu baris DataFrame mewakili satu observasi; makna ini menentukan pertanyaan mana yang sah untuk dijawab tabel tersebut.
shape,columns, dandtypesmemetakan kerangka tabel: ukuran, variabel yang tersedia, dan operasi yang sah untuk tiap kolom.head(),tail(), dansample(random_state=...)saling melengkapi sebagai cuplikan isi; cuplikan acak paling mewakili tabel yang terurut.nunique()daninfo()memprofilkan keunikan, kelengkapan, dan tipe kolom; kolom dengan nilai unik sebanyak barisnya adalah kolom kunci.merge(on=...)menyambungkan dua tabel lewat kolom kunci bersama — syaratnya pasangan kunci harus lengkap di kedua sisi.
Struktur sudah terpetakan, dan info() tadi memperlihatkan sekilas angka-angka di dalamnya. Pertanyaan berikutnya: bagaimana meringkas isi tabel itu menjadi angka-angka yang bermakna? Kita mulai dari kartu identitas dataset — describe() dan kawan-kawannya — pada chapter berikutnya, Ringkasan Dataset
.