Profil tiap kolom kini kita pegang, tetapi keputusan hampir tidak pernah lahir dari satu kolom saja. Pengelola kafe bertanya apakah harga promosi menekan penjualan, apakah nilai transaksi berbeda antar menu, dan apakah menu tertentu dibayar dengan cara tertentu — semuanya pertanyaan tentang dua variabel sekaligus. Analisis bivariat adalah pemeriksaan hubungan antara tepat dua variabel, dan kuncinya ada pada satu disiplin: alat yang kita pilih harus mengikuti kombinasi tipe keduanya. Pada chapter ini kita kerjakan ketiga kombinasi itu satu per satu dengan prosedur yang baku.
Matriks Kombinasi Tipe Variabel #
Setiap analisis bivariat bermuara pada salah satu dari tiga kombinasi tipe, dan masing-masing punya pertanyaan pokok serta alat utama yang berbeda:
| Kombinasi | Pertanyaan pokok | Alat utama | Cara membaca hasil |
|---|---|---|---|
| Numerik vs numerik | apakah dua angka bergerak bersama? | scatter plot + korelasi | arah, kekuatan, bentuk pola |
| Kategorikal vs numerik | apakah angka berbeda antar kelompok? | groupby + rata-rata per kelompok | selisih rata-rata, sebaran tiap kelompok |
| Kategorikal vs kategorikal | apakah dua kategori seiring sejalan? | crosstab + proporsi | perbandingan proporsi antar baris |
Kita sudah mencicipi ketiganya secara lepas pada chapter Hubungan antar Variabel ; tugas kita sekarang menjalankannya sebagai prosedur utuh — dari memilih alat, membaca hasil, sampai melaporkannya dengan disiplin. Urutan pengerjaan mengikuti tabel di atas: mulai dari pasangan numerik yang paling ringkas, lalu naik ke pasangan yang melibatkan kategori.
Numerik vs Numerik: Seberapa Erat Dua Angka Bergerak Bersama #
Kasus pertama datang dari empat belas hari program promosi kopi susu di Toko Kopi Kita. Setiap hari kasir menurunkan harga jual pada rentang berbeda, lalu mencatat berapa gelas terjual — dua kolom numerik pada hari yang sama:
import pandas as pd
promo = pd.DataFrame({
"harga_promo": [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 22, 24, 26],
"gelas_terjual": [42, 40, 37, 35, 33, 30, 28, 26, 23, 21, 19, 31, 27, 24],
})
r = promo["harga_promo"].corr(promo["gelas_terjual"])
print("Korelasi harga promosi vs gelas terjual:", round(r, 3))Output yang Dihasilkan:
Korelasi harga promosi vs gelas terjual: -0.996Satu baris kode memberi dua informasi sekaligus. Tanda negatif membetulkan intuisi: hari dengan harga lebih tinggi adalah hari dengan penjualan lebih rendah. Magnitudonya, 0,996, berada di wilayah hubungan yang sangat kuat — harga dan penjualan bergerak hampir selalu berlawanan arah dengan rapat. Sebelum melaporkan angka sebesar itu, kita wajib melihat wujudnya:
import matplotlib.pyplot as plt
harga_promo = [18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 22, 24, 26]
gelas_terjual = [42, 40, 37, 35, 33, 30, 28, 26, 23, 21, 19, 31, 27, 24]
plt.scatter(harga_promo, gelas_terjual)
plt.xlabel("Harga promosi kopi susu (ribu rupiah)")
plt.ylabel("Gelas terjual per hari")
plt.title("Harga promosi vs penjualan harian, Toko Kopi Kita")
plt.show()Empat belas titik pada grafik menyusun pita yang menurun rapat dari kiri atas ke kanan bawah — tidak ada satu titik pun yang melompat jauh dari barisan. Inilah bentuk visual dari korelasi -0,996. Jika seandainya ada satu titik yang berdiri sendiri jauh dari pita, angka korelasi perlu diperiksa ulang karena satu pencilan saja sanggup menggelembungkan nilai r; bab alat ukurnya kita bedah tuntas pada chapter Analisis Korelasi .
Kategorikal vs Numerik: Membandingkan Angka antar Kelompok #
Kasus kedua memakai 30 transaksi yang mencatat tiga hal: menu yang dibeli, metode pembayaran, dan nilai transaksi (ribu rupiah). Nilai transaksi adalah numerik; menu adalah kategorikal — kombinasi yang dibaca lewat ringkasan per kelompok:
menu,metode,nilai_ribu
kopi susu,qris,22
kopi susu,tunai,25
kopi susu,qris,21
kopi susu,kartu,28
kopi susu,qris,24
kopi susu,tunai,22
kopi susu,qris,26
kopi susu,kartu,23
kopi susu,qris,21
kopi susu,tunai,27
kopi susu,qris,24
kopi susu,qris,25
kopi hitam,tunai,16
kopi hitam,qris,19
kopi hitam,tunai,17
kopi hitam,kartu,21
kopi hitam,tunai,18
kopi hitam,qris,16
kopi hitam,tunai,20
kopi hitam,kartu,17
kopi hitam,tunai,19
kopi hitam,qris,18
matcha latte,qris,32
matcha latte,kartu,36
matcha latte,qris,30
matcha latte,qris,38
matcha latte,kartu,33
matcha latte,qris,35
matcha latte,qris,31
matcha latte,qris,34Kita ringkas nilai transaksi per menu dengan tiga ukuran sekaligus — jumlah, rata-rata, dan simpangan baku:
import pandas as pd
penjualan = pd.read_csv("penjualan.csv")
ringkas = penjualan.groupby("menu")["nilai_ribu"].agg(["count", "mean", "std"]).round(2)
print(ringkas)Output yang Dihasilkan:
count mean std
menu
kopi hitam 10 18.10 1.66
kopi susu 12 24.00 2.30
matcha latte 8 33.62 2.67Cara membacanya menuntut dua perbandingan sekaligus:
- Antar kelompok: rata-rata naik teratur dari kopi hitam 18,10 ke kopi susu 24,00 ke matcha latte 33,62 — selisih antar menu jauh melampaui sebaran di dalam menu. Pola seperti ini menunjukkan kolom
menumembawa informasi nyata tentangnilai_ribu. - Di dalam kelompok:
stdtiap menu hanya sekitar 1,7 sampai 2,7, jauh lebih kecil daripada jarak antar rata-rata. Artinya menu hampir sepenuhnya menentukan lapisan harga, dan variasi sisanya berasal dari ukuran pesanan. countsebagai dasar hitung: rata-rata matcha latte dihitung dari delapan transaksi saja. Selisih sebesar itu tetap meyakinkan pada ukuran sampel kecil, tetapi kebiasaan melaporkancountmenyelamatkan kita saat kelompoknya timpang.
Kategorikal vs Kategorikal: Proporsi antar Kategori #
Kombinasi terakhir memasangkan dua kolom kategorikal: apakah cara membayar mengikuti menu yang dibeli? Tabulasi silang pd.crosstab() menghitung frekuensi setiap pasangan, lalu normalize="index" mengubahnya menjadi proporsi per baris agar antar menu bisa dibandingkan langsung:
import pandas as pd
penjualan = pd.read_csv("penjualan.csv")
jumlah = pd.crosstab(penjualan["menu"], penjualan["metode"])
proporsi = pd.crosstab(penjualan["menu"], penjualan["metode"], normalize="index").round(2)
print(jumlah)
print()
print(proporsi)Output yang Dihasilkan:
metode kartu qris tunai
menu
kopi hitam 2 3 5
kopi susu 2 7 3
matcha latte 2 6 0
metode kartu qris tunai
menu
kopi hitam 0.20 0.30 0.50
kopi susu 0.17 0.58 0.25
matcha latte 0.25 0.75 0.00Tabel frekuensi dan tabel proporsi dibaca berpasangan. Dari tabel frekuensi, QRIS memimpin secara keseluruhan dengan 16 dari 30 transaksi. Tabel proporsi per baris mempertajam cerita: pembeli matcha latte membayar QRIS pada 75% transaksi dan tidak sekali pun membayar tunai, sedangkan kopi hitam justru satu-satunya menu yang didominasi uang tunai — separuh transaksinya. Jika proporsi setiap baris mirip dengan proporsi keseluruhan, kedua kolom layak diduga saling bebas; pola yang bergelombang seperti di atas adalah petunjuk bahwa kedua kategori memang berjalan seiring, dengan kata kunci “petunjuk” — mengujinya secara formal dengan uji chi-square adalah materi chapter Analisis Data Kategorikal .
Rangkuman #
- Analisis bivariat memilih alat berdasarkan kombinasi tipe: scatter plot dan korelasi untuk numerik-numerik,
groupbydengancount/mean/stduntuk kategorikal-numerik, dancrosstabdengan proporsi untuk kategorikal-kategorikal. - Korelasi -0,996 pada kasus harga promosi hanya layak dilaporkan setelah scatter plot memastikan polanya memang berbentuk pita yang rapat.
- Perbandingan antar kelompok selalu dibaca dua arah: selisih rata-rata antar kelompok dan sebaran di dalam kelompok, dengan
countsebagai dasar hitung. crosstab(normalize="index")mengubah frekuensi menjadi proporsi per baris; arah normalisasi harus mengikuti pertanyaan analisis.
Dua variabel sesungguhnya baru cerita sebagian. Harga memengaruhi penjualan, tetapi pengaruhnya mungkin berbeda di tiap kota; menu menentukan nilai transaksi, tetapi mungkin juga berbeda antar jam sibuk. Ketika variabel ketiga masuk untuk memperjelas — atau justru mengubah — hubungan dua variabel, kita berpindah ke Analisis Multivariat .