Angka korelasi sudah tiga chapter menjadi alat kerja andalan kita — dipakai menemukan pita harga di analisis bivariat, lalu dibongkar perbaikannya saat variabel ketiga masuk. Sekarang saatnya membedah alat itu sendiri: apa yang sebenarnya dihitung oleh korelasi, kapan Pearson layak dipakai dan kapan harus pindah ke Spearman, bagaimana membaca matriks korelasi dalam bentuk heatmap, dan di mana batas tafsirnya. Pemahaman formal seperti ini penting karena korelasi adalah angka yang paling sering dikutip, dan sekaligus paling sering disalahartikan, dalam laporan data.

Rumus di Balik Angka Pearson #

Korelasi Pearson mengukur seberapa rapat pasangan nilai mengikuti satu garis lurus. Rumusnya bisa ditulis dalam bentuk skor-z: ubah setiap nilai menjadi jaraknya dari rata-rata, dalam satuan simpangan baku, lalu rata-ratakan hasil kali kedua skor:

text
z_x = (x - mean(x)) / std(x)
z_y = (y - mean(y)) / std(y)

r = jumlah(z_x * z_y) / (n - 1)

Intuisinya: pasangan yang sama-sama di atas rata-rata (atau sama-sama di bawah) menghasilkan hasil kali positif, sedangkan pasangan yang berlawanan menghasilkan negatif — r adalah rata-rata seluruh “suara” itu. Kita hitung manual untuk enam hari operasional Toko Kopi Kita:

python
import pandas as pd

hari = pd.DataFrame({
    "pengunjung": [120, 150, 180, 200, 230, 260],
    "gelas_terjual": [90, 110, 140, 150, 180, 200],
})

zx = (hari["pengunjung"] - hari["pengunjung"].mean()) / hari["pengunjung"].std()
zy = (hari["gelas_terjual"] - hari["gelas_terjual"].mean()) / hari["gelas_terjual"].std()
r_manual = (zx * zy).sum() / (len(hari) - 1)
r_pandas = hari["pengunjung"].corr(hari["gelas_terjual"])

print("z-x       :", zx.round(2).tolist())
print("z-y       :", zy.round(2).tolist())
print("r manual  :", round(r_manual, 3))
print("r pandas  :", round(r_pandas, 3))

Output yang Dihasilkan:

text
z-x       : [-1.36, -0.78, -0.19, 0.19, 0.78, 1.36]
z-y       : [-1.33, -0.85, -0.12, 0.12, 0.85, 1.33]
r manual  : 0.998
r pandas  : 0.998

Baris demi baris, kode di atas menurunkan rumus secara langsung: zx dan zy mengubah tiap kolom menjadi skor-z, (zx * zy).sum() menjumlahkan hasil kali tiap pasangan, dan pembagian (len(hari) - 1) merata-ratakannya — persis rumus pada blok text. Hasilnya identik dengan corr() dari pandas, karena pandas memakai simpangan baku sampel (n - 1) yang sama dengan perhitungan manual kita. Perhatikan pula pola kedua baris z: hari sepi ber-z negatif di kedua kolom, hari ramai ber-z positif di kedua kolom — hampir semua hasil kali bernilai positif, itulah sumber r yang mendekati 1.

Pearson untuk Garis Lurus, Spearman untuk Urutan #

Pearson punya satu syarat yang sering luput: hubungan yang diukurnya adalah hubungan garis lurus. Ketika hubungan nyata tetapi melengkung, Pearson menilai rendah. Data berikut mencatat delapan barista dan lamanya dilatih berbanding waktu rata-rata menyajikan satu pesanan — penurunan waktu paling deras terjadi di bulan-bulan awal, lalu melandai:

python
import pandas as pd
from scipy import stats

latihan = pd.DataFrame({
    "lama_latihan_bulan": [1, 2, 3, 4, 5, 6, 7, 8],
    "waktu_saji_menit": [9.0, 7.6, 6.5, 5.8, 5.3, 5.0, 4.9, 4.85],
})

r_pearson = latihan["lama_latihan_bulan"].corr(latihan["waktu_saji_menit"])
r_spearman = latihan["lama_latihan_bulan"].corr(latihan["waktu_saji_menit"], method="spearman")
print("pandas   : pearson", round(r_pearson, 3), "| spearman", round(r_spearman, 3))

stat_p, p_p = stats.pearsonr(latihan["lama_latihan_bulan"], latihan["waktu_saji_menit"])
stat_s, p_s = stats.spearmanr(latihan["lama_latihan_bulan"], latihan["waktu_saji_menit"])
print(f"scipy    : pearson r={stat_p:.3f} p={p_p:.2e}")
print(f"           spearman r={stat_s:.3f} p={p_s:.2e}")

Output yang Dihasilkan:

text
pandas   : pearson -0.924 | spearman -1.0
scipy    : pearson r=-0.924 p=1.03e-03
           spearman r=-1.000 p=0.00e+00

Tiga hal perlu dibaca dari output tersebut:

  1. Spearman sempurna (-1,0): Spearman tidak memakai nilai mentah, melainkan peringkat. Delapan barista tersusun monoton turun — setiap tambahan bulan latihan selalu mempercepat sajian — sehingga kesesuaian peringkatnya sempurna meski kurvanya melengkung.
  2. Pearson terpaut (-0,924): Pearson memakai nilai mentah dan “menghukum” pelandaian kurva — pasangan bulan-bulan akhir menjauh dari garis lurus terbaik, sehingga nilainya turun.
  3. p-value dari scipy: fungsi pearsonr dan spearmanr mengembalikan pasangan (r, p-value). p Pearson 1,03e-03 berarti peluang melihat hubungan seerat ini pada data yang sesungguhnya tak berhubungan hanya sekitar 0,1%; p Spearman tercetak 0,00e+00 — nilai yang telah jatuh di bawah presisi komputer. Makna p-value ini kita bedah tuntas pada chapter Pengujian Hipotesis dan p-value .

Pilihan praktisnya dirangkum pada tabel berikut:

Wujud hubunganUkuran yang tepatAlasannya
Dugaan garis lurus, data bersihPearsonmengukur keterikatan nilai mentah pada garis
Naik/turun teratur tetapi melengkungSpearmancukup urutannya konsisten, nilai boleh melengkung
Ada pencilan yang mencurigakanSpearmanperingkat menahan pengaruh satu nilai ekstrem

Matriks Korelasi dan Heatmap #

Untuk lebih dari dua kolom, korelasi berpasangan membentuk matriks. Data 12 hari berikut memuat suhu siang, jumlah pengunjung, gelas kopi susu, dan gelas teh tawar yang terjual:

python
import pandas as pd

cuaca = pd.DataFrame({
    "suhu": [26, 31, 24, 29, 33, 27, 25, 30, 28, 32, 26, 34],
    "pengunjung": [230, 250, 260, 220, 300, 210, 280, 240, 225, 285, 320, 310],
    "kopi_susu": [19, 27, 17, 25, 32, 22, 16, 28, 25, 31, 21, 34],
    "teh_tawar": [29, 20, 33, 23, 17, 32, 30, 23, 25, 19, 27, 15],
})

print(cuaca.corr(numeric_only=True).round(2))

Output yang Dihasilkan:

text
            suhu  pengunjung  kopi_susu  teh_tawar
suhu        1.00        0.31       0.98      -0.96
pengunjung  0.31        1.00       0.29      -0.43
kopi_susu   0.98        0.29       1.00      -0.94
teh_tawar  -0.96       -0.43      -0.94       1.00

Matriks ini simetris: nilai di sel (i, j) sama dengan (j, i), dan diagonal selalu 1,00. Tiga temuan menonjol: suhu dengan kopi_susu mencatat 0,98 dan dengan teh_tawar mencatat -0,96 — cuaca menggerakkan dua menu itu berlawanan arah; korelasi kopi_susu dengan teh_tawar (-0,94) hanyalah turunan dari dua hubungan tersebut; dan baris pengunjung nyaris pucat — kunjungan tidak mengikuti suhu, jadi penjualan dingin memang soal menu, bukan sekadar banyak orang. Matriks sebesar ini lebih cepat dibaca sebagai heatmap:

python
import matplotlib.pyplot as plt
import pandas as pd

cuaca = pd.DataFrame({
    "suhu": [26, 31, 24, 29, 33, 27, 25, 30, 28, 32, 26, 34],
    "pengunjung": [230, 250, 260, 220, 300, 210, 280, 240, 225, 285, 320, 310],
    "kopi_susu": [19, 27, 17, 25, 32, 22, 16, 28, 25, 31, 21, 34],
    "teh_tawar": [29, 20, 33, 23, 17, 32, 30, 23, 25, 19, 27, 15],
})

matriks = cuaca.corr(numeric_only=True)

plt.imshow(matriks, cmap="RdBu_r", vmin=-1, vmax=1)
plt.colorbar(label="Korelasi")
plt.xticks(range(len(matriks.columns)), matriks.columns, rotation=20)
plt.yticks(range(len(matriks.columns)), matriks.columns)
for i in range(len(matriks)):
    for j in range(len(matriks)):
        plt.text(j, i, f"{matriks.iloc[i, j]:.2f}", ha="center", va="center")
plt.title("Heatmap matriks korelasi, 12 hari operasional")
plt.show()

Heatmap yang tergambar adalah kisi 4x4 dengan dua arah warna: merah pekat untuk korelasi mendekati +1 dan biru pekat untuk mendekati -1, sementara nilai dekat nol tampil nyaris putih. Diagonalnya tersusun kotak merah gelap bertuliskan 1,00; blok suhu-kopi_susu menyala merah terang, blok suhu-teh_tawar menyala biru, dan baris pengunjung tampak pucat dihiasi angka kecil. Dengan sekali lirik, mata langsung mendaratkan perhatian pada pasangan yang kuat dan mengabaikan yang lemah — itulah fungsi heatmap pada laporan eksplorasi.

Korelasi Semu dan Batas Tafsir #

Sekarang contoh yang mengingatkan kita akan batas. Toko Kopi Kita mencatat total penjualan kopi susu per tahun selama delapan tahun, dan pada periode yang sama harga tiket masuk museum kota naik berkali-kali:

python
import pandas as pd

tahunan = pd.DataFrame({
    "tahun": [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023],
    "kopi_susu_ribu": [120, 135, 150, 170, 190, 215, 240, 270],
    "tiket_museum": [5.0, 5.5, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0],
})

r = tahunan["kopi_susu_ribu"].corr(tahunan["tiket_museum"])
print("Korelasi penjualan kopi susu vs harga tiket museum:", round(r, 3))

Output yang Dihasilkan:

text
Korelasi penjualan kopi susu vs harga tiket museum: 0.996

Korelasinya 0,996 — setinggi hubungan harga-promosi pada chapter sebelumnya. Tetapi tidak ada mekanisme yang masuk akal menghubungkan keduanya: pengunjung museum tidak membeli puluhan ribu gelas kopi susu saat tiketnya naik, dan kafe tidak menaikkan tiket museum. Kedua deret menanjak karena sama-sama menunggangi tren yang lebih besar — pertumbuhan kota dan kenaikan harga umum — sehingga waktu menjadi confounder yang tak terlihat pada tabel. Korelasi seperti ini disebut korelasi semu (spurious correlation): angkanya tinggi, hubungannya kosong.

Sebelum menutup, mari kita tetapkan batas tafsir dengan satu daftar pengecekan. Temuan korelasi tinggi hanya membuktikan bahwa dua variabel bergerak bersama. Penjelasannya bisa salah satu dari empat: X memengaruhi Y, Y memengaruhi X, variabel ketiga memengaruhi keduanya (seperti kota pada chapter multivariat dan waktu pada contoh museum), atau kebetulan belaka. Memilah keempatnya menuntut desain eksperimen atau metode kausal tersendiri — bukan angka korelasi yang lebih tinggi.

Rangkuman #

  • Pearson adalah rata-rata hasil kali skor-z kedua variabel; corr() pandas menghitungnya dari nilai mentah dan paling tepat untuk hubungan garis lurus.
  • Spearman bekerja pada peringkat, sehingga tetap sempurna untuk hubungan monoton yang melengkung dan lebih tahan terhadap pencilan.
  • scipy.stats.pearsonr dan spearmanr melengkapi r dengan p-value — peluang melihat hubungan seerat itu bila data sebenarnya tak berhubungan.
  • Matriks korelasi dibaca simetris dengan diagonal 1,00; heatmap memetakan kekuatan ke warna sehingga pasangan kuat langsung terlihat.
  • Korelasi tinggi bisa lahir dari confounder atau kebetulan — korelasi semu — dan tidak pernah dengan sendirinya membuktikan sebab-akibat.

Korelasi menjawab “seberapa erat dua variabel bergerak bersama”, tetapi pertanyaan bisnis sering menuntut lebih: berapa gelas tambahan yang terjual bila harga turun 1.000 rupiah? Berapa perkiraan penjualan pekan depan? Untuk menjawab “berapa”, kita butuh model yang menempatkan hubungan itu pada satu garis — pekerjaan Regresi Linear .

Referensi #

  1. SciPy — Statistical Functions (stats)
  2. pandas — User Guide
  3. Matplotlib — pyplot Summary