Statistik JS: Chap. 7

Riky Perdana
36 min readDec 27, 2022
Photo by Nadir sYzYgY on Unsplash

7. How Things Happen

“Holmes, ia kabur dan membuang barang bukti ke sungai itu”

“Tenang Watson, ikut aku” Sherlock dan Watson pergi ke bendungan dan menemukan pistol tersangka “Bagaimana kau tau barang itu bisa ditemukan disini, Holmes”

“Ia bisa kabur dari aku, tapi tidak akan bisa kabur dari logika, tuan Watson. Ingat kausalitas”

Berkat gravitasi, semua barang akan cenderung jatuh kebawah, bukan ke atas. Dengan deduksi kecepatan arus sungai, alur belokan sungai, dan ukuran objek yang dicari, Holmes tau kemana barang yang dia cari “kemungkinan” akan didapat. Apa yang terjadi dalam kepala Holmes bukan statistik, melainkan intuisi, pengalaman, dan logika. Bagaimana kalau tidak semua orang seperti Holmes? Tidak punya cukup pengalaman, tidak punya jaket detektif, dan tidak punya rekanan seperti Dr. Watson. Hanya berbekal data dan statistik, bisakah kita menganalisis hubungan antara hal-hal, antar variabel? Jawabannya bisa, dengan statistik inferensial.

7.1. Corelation

Photo by Patrick Hendry on Unsplash

Ketika Anda menyaksikan sebuah fenomena yang dapat diukur dalam 2 variabel (=hal berubah) atau lebih, kemungkinan besar Anda akan klaim bahwa iya kedua variabel tersebut berhubungan. Mari kita ambil contoh antara termometer raksa dan temperatur ruangan. Kita bisa mengamati bahwa air raksa perlahan naik saat cuaca semakin panas, dan kembali turun saat sudah gelap. Apakah kenaikan raksa pada termometer yang menyebabkan cuaca diluar jadi panas, atau sebaliknya? Pada kasus tadi tentu lebih mudah untuk melihat apa yang menyebabkan apa. Tapi pada kebanyakan kasus, agak buram siapa yang menjadi penyebab dan siapa yang menjadi akibat. Sebagai contoh, ketika Anda pulang hujan-hujanan, biasanya Anda akan demam, meriang, atau minimal flu. Orang yang naif akan dengan mudah mengambil kesimpulan bahwa hujanlah yang menyebabkan demam. Sedikit yang menyadari yang membuat dia flu bukan molekul air dalam hujan yang menyebabkan demam, melainkan virus yang sudah standby menunggu saat imun tubuh Anda turun, dan kebetulan setelah hujan-hujanan. Karena kita tidak bisa berasumsi kausalitas pada setiap situasi yang kita hadapi, apakah kita punya cara untuk melihat hubungan antara 2 variabel dalam 1 fenomena melalui statistik? Jawabannya adalah korelasi.

Korelasi tidak menjustifikasi siapa yang melakukan apa duluan, dan menjadi penyebab terjadinya sesuatu pada sesuatu yang lain. Kalau kita terjemahkan dalam bahasa statistik, kalaupun kita belum bisa mengetahui hubungan kausalitas antara X dan Y, setidaknya kita bisa tahu secara kuantitatif apakah X dan Y bergerak bersama (maju/mundur, turun/naik). Konsep korelasi sendiri sudah lama dalam praktik matematika selama ratusan tahun. Pada peradaban Arab dan China, para cendekiawan sudah bisa menggunakan “statistik purba” untuk melihat keterkaitan antara 2 kejadian yang dapat diukur secara matematis. Contohnya dengan menghitung selisih antara setiap eksperimen, selisih hitung 2 sampel, tapi ya cukup sampai disitu saja, mereka belum bisa menghasilkan sebuah koefisien atau konstanta yang dalam statistik modern lebih reliabel. Untuk itu beberapa ilmuan Eropa mencetuskan ide mereka masing-masing tentang cara menghitung korelasi secara akurat. Dalam bab ini Anda akan banyak mendengar nama seperti Pearson, Spearman, and the gang.

7.1.1. Korelasi Pearson

Korelasi Pearson adalah model matematis statistik yang dikembangkan oleh Pearson (orang) yang dapat menghasilkan sebuah angka indeks seberapa kuat/lemah dan positif/negatif hubungan antara 2 variabel. Bentuk formula matematisnya adalah sebagai berikut:

Rumus: Nilai korelasi antara 2 variabel
Rumus: Nilai determinan korelasi 2 variabel

Yang jika dikonversi menjadi kode JS, maka bentuknya seperti berikut:

corelation = (x, y) => (
x.length * sum(x.map((i, j) => i * y[j])) -
sum(x) * sum(y)
) / pow(1/2)(
(
x.length * sum(x.map(pow(2))) -
pow(2)(sum(x))
) * (
x.length * sum(y.map(pow(2))) -
pow(2)(sum(y))
)
)

corelation(
[3, 6, 9, 10, 13],
[12, 23, 24, 26, 28]
) // get 0.9149

determination = (x, y) => pow(2)(corelation(x, y))

determination(
[3, 6, 9, 10, 13],
[12, 23, 24, 26, 28]
) // get 0.8370

corelation adalah fungsi yang bisa menerima 2 deret angka yang berbeda, sebut saja variabel x dan variabel y (terlepas dari siapa yang mempengaruhi siapa). Cara kerja fungsi ini cukup sederhana, hanya melibatkan aritmatika dasar, perpangkatan dan pengakaran. Pada contoh diatas ketika fungsi corelation dipanggil untuk mengerjakan data:

[ 3,  6,  9, 10, 13],
[12, 23, 24, 26, 28]

Secara intuitif Anda bisa lihat sendiri bahwa terlepas dari berapapun besaran angka X dan Y, mereka selalu bergerak bersama secara positif. Dan angka yang dikeluarkan oleh fungsi corelation untuk data ini adalah sebesar +0.9149, artinya ada korelasi positif antara variabel X dan Y dengan kekuatan hubungan yang sangat mendekati +1.0(= nilai korelasi sempurna). Sekarang coba Anda karang data sendiri dengan nilai pada deret X dan Y yang besar kecilnya acak, bisa jadi Anda tidak akan mendapati nilai korelasi yang setinggi itu.

Batas maksimal nilai korelasi yang bisa dihasilkan oleh fungsi ini adalah +1.0 dan -1.0, dan batas minimal yang dimungkinkan adalah 0.0. Kalau Anda mendapati suatu angka semakin mendekati +1.0 maka dapat dianggap kedua variabel tersebut berkorelasi positif, bila mendekati 0 maka semakin kecil korelasinya, dan bila pas di 0 maka dapat dianggap mereka tidak berkorelasi sama sekali. Sementara bila nilainya mengandung tanda negatif maka berarti kedua variabel tersebut memiliki tendensi untuk saling menjauh atau berkebalikan. Pada kasus nilai mendekati -1.0 berarti kedua variabel tersebut dapat dianggap hampir berkebalikan sempurna. Joke: Jadi kalau Anda ingin tes pengetahuan teman Anda tentang korelasi, coba bilang “nilai korelasinya bagus ya, lebih dari 10”. Tergantung reaksi dia, Anda tahu dia paham atau tidak.

Determination kata dasarnya determine yang artinya “menentukan”. Maksudnya seberapa besar kemungkinan diketahuinya kondisi sebuah variabel dapat menjelaskan kondisi variabel lain yang dianggap telah berkorelasi tadi. Proses perhitungannya cukup sederhana, hanya meng-kuadratkan hasil output corelation, tapi justru dengan ini kita akan selalu memperoleh nilai yang relatif lebih kecil dari nilai korelasi dasarnya. Pada contoh diatas pemanggilan kode determination menghasilkan nilai 0.8370, berarti ada kemungkinan 83.7% kondisi pada variabel X dapat menjelaskan kondisi variabel Y. Tapi hanya mengetahui kekuatan hubungan saja tidak cukup, kita juga perlu mengetahui hal-hal lain yang terkait dengan persamaan untuk prediksi nilai ketika salah satu variabel diketahui, khusus untuk itu kita akan butuh model statistik yang lebih canggih dari ini. Karena negatif kuadrat akan selalu positif, maka seberapa negatif pun hasil nilai korelasi, nilai determinasi akan tetap positif.

Kelebihan korelasi Pearson:

  1. Cara matematis yang relatif sederhana tapi efektif untuk memperoleh sebuah indeks korelasi

Kekurangan korelasi Pearson:

  1. Korelasi hanya menggambarkan 2 variabel itu bergerak searah atau tidak, bukan sebab-akibat

Bedah Kode: Korelasi Pearson

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

corelation = (x, y) => (
// fungsi ini menerima deret x deret y, harus sama panjang
x.length * sum(x.map((i, j) => i * y[j])) -
// panjang x dikali jumlah dari item x dikali item y
sum(x) * sum(y)
// dikurangi penjumlahan deret x dikali penjumlahan deret y
) / pow(1/2)(
// pangkatkan setengah, alias diakarkan
(
x.length * sum(x.map(pow(2))) -
// panjang x dikali penjumlahan dari pangkat 2 setiap x
pow(2)(sum(x))
// dikurangi dengan pangkat 2 dari penjumlahan x
) * (
x.length * sum(y.map(pow(2))) -
// panjang x dikali penjumlahan dari pangkat 2 dari semua y
pow(2)(sum(y))
// dikurangi pangkat 2 penjumlahan y
)
)

7.1.2. Korelasi Ranking ala Spearman

Rumus korelasi Pearson hanya bisa digunakan bila data Anda adalah data interval atau skala, sementara bila datanya berupa ranking maka korelasi Pearson sama sekali tidak bisa digunakan. Korelasi Spearman khusus untuk menangani perhitungan korelasi dimana data yang tersedia hanya dalam bentuk ranking, bukan nilai sebenarnya. Contoh kecilnya dalam suatu balap 1000cc, Valentino Rossi juara 1 dengan finishing lap di 15 menit, 40 detik, 32 milidetik. Marquez menyelesaikan dalam 15 menit, 40 detik, 31 milidetik. Dan Lorenzo menyelesaikan dalam 28 menit, 17 detik, 20 milidetik. Anda bisa bayangkan bahwa Rossi dan Marquez menyelesaikan garis finish pada waktu yang sepersekian detik hampir bersamaan, sementara Lorenzo lumayan jauh tertinggal di belakang dan mendaptkan juara 3, tapi urutannya hanya 1 ranking setelah Marquez. Dengan pemeringkatan, kita berpotensi kehilangan kesempatan untuk memperbandingkan selisih “sebenarnya” dari objek yang diamati. Walau demikian bukan berarti tidak ada alat statistik yang bisa menanganinya, itulah Spearman Rank Corelation. Mari kita lihat sebuah contoh kasus:

Tabel: Contoh 2 set data ranking yang diduga berkorelasi

Pada tabel diatas terdapat 10 orang siwa yang masing-masing mereka ikut ajang kompetisi akbar olahraga dan musik yang diikuti oleh 100 orang peserta. Sayangnya tidak satupun murid-murid menang membawa lencana juara, malahan bisa dibilang ranking rendah semua. Kedua guru olah raga dan seni saling menunjukkan hasil evaluasi ranking masing-masing anak tersebut dan mendapati susunannya seperti tabel di atas. Mereka berasumsi bahwa anak yang jago dalam olahraga mungkin akan bisa bagus dalam bidang seni. Hanya mereka tidak bisa sekedar berasumsi bahwa hal itu benar dan mendadak menerapkannya ke sekolah. Mereka butuh bukti matematis bahwa kedua set data ini memang berkorelasi. Sayangnya kedua guru tersebut hanya jago di bidang masing-masing dan kurang mengenal statistik. Andapun hadir di tengah mereka dengan wajah sumringah, “Mana datanya?”.

Rumus: Korelasi Data Ranking oleh Spearman

Yang jika dikonversi menjadi kode JS maka bentuknya seperti ini:

ranking = arr => withAs(sort([...arr]), sorted =>
arr.map(i => 1 + sorted.findIndex(j => j == i))
)

ranking([82, 75, 85, 70, 77, 60, 63, 66, 80, 89])
// get [8, 5, 9, 4, 6, 1, 2, 3, 7, 10]
ranking([79, 80, 89, 65, 67, 62, 61, 68, 81, 84])
// get [6, 7, 10, 3, 4, 2, 1, 5, 8, 9]
corelationRank = (x, y) => withAs(
makeArray(x.length).map(i =>
ranking(x)[i] - ranking(y)[i]
), diff => 1 - (6 * sum(diff.map(pow(2)))
/ (pow(3)(x.length) - x.length))
)
corelationRank(
[82, 75, 85, 70, 77, 60, 63, 66, 80, 89],
[79, 80, 89, 65, 67, 62, 61, 68, 81, 84]
) // get 0.866

ranking adalah fungsi yang ketika diberikan sebuah deret angka, maka ia akan mengembalikan deret angka dengan panjang yang sama tapi isinya adalah daftar ranking sesuai indeks data aslinya. Pada contoh diatas ketika fungsi ranking dipanggil dengan data [82, 75, 85, 70, 77, 60, 63, 66, 80, 89] ia akan mengembalikan [8, 5, 9, 4, 6, 1, 2, 3, 7, 10]. Artinya apa? Ranking 1 diperoleh oleh nilai 60, karena dia adalah angka terendah dalam deret ini, sementara yang dapat ranking 10 adalah angka tertinggi yaitu 89, masuk akal bukan? Bisa saja penulis meniru buku statistik lain dengan menggunakan angka rendah seperti [2, 1, 3, 5, 4, ...] tapi justri disini peneliti menggunakan deret angka besar, agar Anda paham bahwa untuk menggunakan Spearman Rank Corelation, Anda bahkan tidak harus memperoleh semua data peserta pemenang tadi, cukup sampel yang bisa Anda peroleh, selagi kelengkapan variabelnya konsisten. Coba Anda tes buat deret angka baru dengan isian angka yang kecil/besar-nya jauh berbeda, Anda akan tetap memperoleh hasil ranking yang logis:

ranking([293847, 98, 12, 57493])
// get [4, 2, 1, 3]

Perhatikan pada contoh pemanggilan fungsi ranking pada 2 deret ranking yang berbeda, dimana deret pertama adalah daftar ranking peserta lomba Sport, dan deret kedua adalah daftar peserta lomba Music. Masing-masing deret tersebut memperoleh output yang berbeda, nah!, data yang sudah dinormalisasi inilah yang akan dibandingkan oleh Spearman Rank Corelation.

corelationRank adalah fungsi yang ketika menerima 2 deret angka (x & y) maka ia akan mengembalikan sebuah angka dalam rentang -1 s/d +1 untuk menunjukkan 1) apakah hubungan mereka berdua positif atau negatif, 2) apakah hubungan tersebut lemah atau kuat. Pada contoh pemanggilan fungsi diatas kita memperoleh hasil 0.866. Kalau mendekat ke 0 itu lemah dan mendekat ke 1 itu kuat, berarti nilai yang kita peroleh ini menunjukkan adanya korelasi kuat antara performa Sport dan Music pada para pelajar yang ikut kompetisi tadi. Walaupun kita tidak bisa menunjukkan apakah mereka jadi jago Sport karena Music, atau jago Music karena Sport, setidaknya kita tahu bahwa pelajar yang jago salah satu maka kemungkinan akan jago juga pada hal yang satunya lagi.

Selain dalam konteks sekolah, kemana lagi kita bisa manfaatkan model “SuPEARMAN” yang super ini? Bila Anda browsing internet dan menemukan sesuatu yang bentuknya daftar ranking, Anda bisa cari daftar ranking lain yang deretnya mengandung anggota pada daftar ranking yang pertama. Sebagai contoh, daftar ranking “Best Action Movies” lalu cari daftar ranking “Big Budget Movies”. Kalau Anda bisa menyusun daftar film action yang muncul pada “Best Action Movies” DAN “Big Budget Movies”, lalu masukkan ranking mereka dalam deret X dan deret Y. Dengan bermodal fungsi corelationRank Anda bisa tahu apakah film action dengan budget besar akan masuk ke daftar film action terbaik. Atau sebaliknya, daftar film action terbaik kemungkinan memiliki budget besar. Silahkan coba!

Selain urusan ranking sekolah dan film blockbusters, kemana lagi bisa dimanfaatkan? Jika Anda perhatikan pada situs informasi harga saham, Anda akan sering menemukan beberapa nama perusahaan yang sama pada daftar yang berbeda. Bisa saja Anda membandingkan antara daftar harga saham perusahaan teknologi, daftar saham volatil, daftar saham blue chip, daftar saham red chip. Silahkan coba.

Kelebihan metode Spearman Rank Corelation:

  1. Sangat cocok untuk perbandingan data ranking, walau kita tidak tahu nilai aslinya
  2. Tetap bisa digunakan pada sebagian sampel, tidak harus dari ranking 1 sampai akhir

Kelemahan metode Spearman Rank Corelation:

  1. Sangat tidak disarankan untuk digunakan pada data skala/interval

Bedah Kode: Korelasi Ranking

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

ranking = arr => withAs(sort([...arr]), sorted =>
// fungsi ini menerima deret angka untuk diubah
// buat deret baru yang telah diurut, sebut saja sorted
arr.map(i => 1 + sorted.findIndex(j => j == i))
// rubah setiap angka pada data menjadi nilai rankingnya
)

corelationRank = (x, y) => withAs(
// fungsi ini menerima deret x dan deret y
makeArray(x.length).map(i =>
// buat deret baru sepanjang x, lalu urai
ranking(x)[i] - ranking(y)[i]
// cari selisih ranking antara item x dan item y
), diff => 1 - (6 * sum(diff.map(pow(2)))
/ (pow(3)(x.length) - x.length))
// tiru rumus aslinya dalam kode JS
)

7.1.3. Korelasi Data Distribusi

Akan ada masanya dimana Anda menghadapi data dalam jumlah yang sangat besar dan untuk menyederhanakan data besar tersebut, datanya diubah menjadi distribusi frekuensi. Silahkan lihat lagi bagian distribusi frekuensi bila Anda lupa apa tujuannya. Kalau panjang data yang Anda olah itu masih dalam range 100, 500, 1000, atau 1500, aplikasi statistik yang Anda gunakan mungkin masih bisa menanganinya. Dan kalau Anda gunakan kode JS ini untuk menghitung korelasi data besar, kapasitasnya sanggup untuk mengolah hingga 200.000 hingga 500.000 data (tergantung PCnya). Bagaimana bila data tersebut tembus 1 juta data, 3 juta data, atau 15 juta data. Bagi yang bekerja di perkantoran, menghitung korelasi pada data pegawai yang jumlahnya sekitar 65 orang mungkin belum butuh korelasi data distribusi. Tapi bila Anda bekerja di perusahaan teknologi informasi yang mengumpulkan database dalam jumlah banyak, batas 1 juta data itu dapat dilampaui dengan mudah. Contohnya seperti database jejaring sosial, lab uji mesin mobil balap F1 yang mengukur efisiensi pembakaran 1/1000 detik, bahkan pergerakan harga saham semua perusahaan per detik selama 24 jam. Apakah teknologi akan membatasi kita untuk mencari tahu apa yang ingin kita tahu? Atau kita punya alat yang bisa menangani korelasi data besar itu? Jawabannya ada, yaitu korelasi data distribusi.

Sebagaimana yang telah Anda ketahui di sub-bab data distribusi, bentuk dari data distribusi itu selalu mengandung informasi seperti kelas, interval, range, top, bottom, cumulative, ogive, dan semacamnya. Tabel distribusi frekuensi untuk tujuan korelasi memiliki bentuk yang khusus, contohnya seperti ini:

Tabel: Korelasi pada DF (Sumber: Hasan, 2012)

Dapat dilihat pada tabel tersebut, setiap kolom menjadi interval bagi data X dan setiap baris menjadi interval bagi data Y. Setiap data sel (= persilangan kolom dan baris) adalah angka yang menunjukkan berapa kali sebuah data muncul yang nilai X dan Y-nya jatuh dalam interval mereka berdua. Tidak harus menunggu tembus 1 juta data dulu agar kita bisa menggunakan tabel distribusi frekuensi korelasi ini. Anda bisa latihan membuat dalam Spreadsheet (Excel, dsb), pola yang mirip seperti pada tabel contoh di atas.

Jika Anda ingin tahu, bagaimana formula matematis statistik yang bisa mengkonversi tabel tadi menjadi sebuah angka korelasi, bentuknya seperti fungsi berikut:

Rumus: Korelasi pada data distribusi frekuensi berkelompok

Yang jika dikonversi menjadi kode JS, maka bentuknya adalah sebagai berikut:

distCorelation = arrays => withAs({
n: sum(arrays.flat()),
fy: arrays.map(sum),
fx: arrays[0].map((i, j) => sum(arrays.map(k => k[j]))),
uy: middleIndex(arrays.length).reverse(),
ux: middleIndex(arrays[0].length)
}, ({n, fy, fx, uy, ux}) => withAs({
fyuy: sum(fy.map((i, j) => i * uy[j])),
fyuy2: sum(fy.map((i, j) => i * pow(2)(uy[j]))),
fyuyux: sum(arrays.map((i, j) => sum(
i.map((k, l) => k * uy[j] * ux[l])
))),
fxux: sum(fx.map((i, j) => i * ux[j])),
fxux2: sum(fx.map((i, j) => i * pow(2)(ux[j]))),
fxuxuy: sum(arrays[0].map((i, j) => sum(
arrays.map((k, l) => k[j] * ux[j] * uy[l])
))),
}, ({fyuy, fyuy2, fyuyux, fxux, fxux2, fxuxuy}) =>
(n * fxuxuy - fxux * fyuy) / pow(1/2)(
(n * fxux2 - pow(2)(fxux)) *
(n * fyuy2 - pow(2)(fyuy))
)
))

distCorelation([
[3, 5, 4, 0, 0, 0],
[3, 6, 6, 2, 0, 0],
[1, 4, 9, 5, 2, 0],
[0, 0, 5,10, 8, 1],
[0, 0, 1, 4, 6, 5],
[0, 0, 0, 2, 4, 4]
]) // get -0.7685

distCorelation adalah fungsi yang ketika menerima sebuah set data dengan beberapa deret angka (pastikan sama jumlah kolom dan jumlah baris), maka ia akan mengembalikan hasil hitung korelasi data distribusi frekuensi tersebut. Harus penulis akui, mengkonversi rumus diatas menjadi seperti pada contoh kode bukan tantangan yang mudah, tapi berkat ini Anda tidak perlu lagi menghitung manual dan cukup hanya memanggil fungsi distCorelation pada data yang sudah Anda siapkan.

Bedah Kode: Korelasi Distribusi Frekuensi

Silahkan baca bagian ini bagi yang berminat mengetahui cara kerja fungsi ini dengan detail.

distCorelation = arrays => withAs({
// fungsi korelasi distribusi menerima suatu set himpunan-himpunan
n: sum(arrays.flat()),
// semua angka diratakan dalam 1 deret dan dijumlahkan
fy: arrays.map(sum),
// daftar penjumlahan dari setiap baris
fx: arrays[0].map((i, j) => sum(arrays.map(k => k[j]))),
// penjumlahan dari setiap kolom
uy: middleIndex(arrays.length).reverse(),
// middle indeks dari suatu baris
ux: middleIndex(arrays[0].length)
// middle index dari suatu kolom
}, ({n, fy, fx, uy, ux}) => withAs({
fyuy: sum(fy.map((i, j) => i * uy[j])),
// hasil kali index dengan frekuensi baris
fyuy2: sum(fy.map((i, j) => i * pow(2)(uy[j]))),
// hasil kali fyuy dan uy
fyuyux: sum(arrays.map((i, j) => sum(
i.map((k, l) => k * uy[j] * ux[l])
))),
fxux: sum(fx.map((i, j) => i * ux[j])),
// hasil kali index dengan frekuensi kolom
fxux2: sum(fx.map((i, j) => i * pow(2)(ux[j]))),
// hasil kali fxux dan ux
fxuxuy: sum(arrays[0].map((i, j) => sum(
arrays.map((k, l) => k[j] * ux[j] * uy[l])
))),
}, ({fyuy, fyuy2, fyuyux, fxux, fxux2, fxuxuy}) =>
// kumpulkan semua bahan perhitungan
(n * fxuxuy - fxux * fyuy) / pow(1/2)(
(n * fxux2 - pow(2)(fxux)) *
(n * fyuy2 - pow(2)(fyuy))
) // buat kode yang meniru rumus aslinya
))

Sekarang mari kita buat sebuah contoh sederhana, dengan data yang tidak terlalu besar, tapi cukup untuk menggambarkan cara kerja dan hasil perhitungan korelasi distribusi frekuensinya. Dalam sebuah angkatan di fakultas ekonomi terdapat 100 orang mahasiswa yang masing-masing mereka telah menjalankan tes matemetika dan sejarah. Kedua data ini disandingkan dan didapatlah 2 kolom (matematika dan sejarah) dan 100 baris yang mewakili setiap nama mahasiswa/i-nya. Setelah Anda susun dalam bentuk kode JS, maka bentuknya seperti ini:

distCorelation([
[3, 5, 4, 0, 0, 0],
[3, 6, 6, 2, 0, 0],
[1, 4, 9, 5, 2, 0],
[0, 0, 5,10, 8, 1],
[0, 0, 1, 4, 6, 5],
[0, 0, 0, 2, 4, 4]
]) // get -0.7685

Disini kita memperoleh nilai -0.7685, bila kita bandingkan dalam range -1 s/d +1 kita dapat melihat bahwa hubungannya bertolak belakang. Dan nilai 0.76 itu menunjukkan kekuatan hubungan yang bertolak belakang tadi cukup kuat (Info: data ini hanya karangan untuk contoh saja).

Kelebihan metode Korelasi Distribusi Frekuensi:

  1. Sangat cocok untuk data besar
  2. Hasil keluaran hampir seakurat korelasi pada data tunggal

Kekurangan metode Korelasi Distribusi Frekuensi:

  1. Mungkin tidak seakurat korelasi pada data tunggal
  2. Hasil akurasi tergantung pada panjang interval kelas yang dipakai

7.1.4. Multiple Corelation

Bagaimana bila Anda mendapati fenomena dimana variabel yang berpartisipasi tidak hanya 2 tapi bisa 3? Jelas Anda tidak bisa menggunakan korelasi Pearson ataupun Spearman (Joke: sepeda motor hanya bisa untuk 2 orang, bukan 3). Lalu apakah kita harus menyerah dan berhenti mencari nilai korelasi untuk fenomena tersebut? Jawabannya tidak, kita punya Multiple Corelation. Dalam statistik, Multiple Corelation ini basisnya tetap pada korelasi Spearman, namun diracik lagi agar bisa menangani 3 variabel sekaligus dimana salah satunya adalah Y, dan 2 lagi adalah X1 dan X2. Mengapa susunan polanya seperti itu? Karena yang menjadi pusat perhatian disini adalah Y, sementara X1 dan X2 adalah variabel yang coba dibandingkan dengan Y. Bentuk formula matematis statistik dari fungsi korelasi linear berganda ini adalah seperti berikut:

Rumus: Korelasi berganda pada 3 variabel

Yang bila dikonversi menjadi kode JS, maka jadi seperti ini:

multiLinCor = (y, x1, x2) => withAs(
corelation, cor => pow(1/2)(
(
(pow(2)(cor(y, x1)) + pow(2)(cor(y, x2))) -
(2 * cor(y, x1) * cor(y, x2) * cor(x1, x2))
) / (1 - pow(2)(cor(x1, x2)))
)
)

multiLinCor adalah fungsi yang ketika menerima deret Y, deret X1, dan deret X2, maka akan menghasilkan sebuah angka dalam range -1 s/d +1 untuk menunjukkan korelasi Y terhadap X1 dan X2 sekaligus. Cara kerja fungsi ini adalah dengan memanfaatkan fungsi corelation oleh Pearson dan mengkombinasikan keluarannya untuk mengukur 3 variabel sekaligus.

Pada kebanyakan kasus, korelasi Pearson biasa sudah cukup untuk kita andalkan dalam mencari nilai korelasi antar variabel. Tapi pada kasus tertentu yang “mengharuskan” kita untuk mengukur 3 variabel sekaligus membuat kita membutuhkan alat baru yang dianggap lebih cocok. Mari kita gunakan suatu skenario ekonomi rumah tangga. Seorang ibu rumah tangga yang biasanya dipercayakan untuk mengelola keuangan percaya bahwa mau pengeluaran keluarga itu kecil ataupun besar, selalu faktor yang menentukannya adalah jumlah pendapatan kepala keluarga dan jumlah anggota keluarga yang tinggal di rumah itu. Hanya ibu rumah tangga tersebut tidak bisa yakin dugaannya ini benar atau tidak. Untungnya beliau punya keponakan seperti Anda, “Mana datanya tante?”

Tabel: Contoh data yang diduga korelasi berganda

Kalau dilihat sekilas saja, agak sulit secara intuitif menyebutkan apakah data tersebut saling berkorelasi terhadap Pengeluaran (Y). Makanya kita perlu cara matematis untuk mengambil kesimpulan. Sayangnya terlalu kejam dan akan sangat melelahkan bila kita harus memaksakan diri untuk menghitung semua itu sesuai rumus dengan bermodal tangan dan kalkulator, makanya kita buat software sendiri dengan JS yang bisa dijalankan di browser mana saja. Dengan bermodal fungsi multiLinCor kita lakukan:

multiLinCor(
[3, 5, 6, 7, 4, 6, 9 ],
[5, 8, 9,10, 7, 7 ,11],
[4, 3, 2, 3, 2, 4, 5 ]
) // get 0.9735

Kita memperoleh nilai 0.9735, melihat angka yang nilainya positif ini kita sudah yakin bahwa data ini bergerak searah secara bersama-sama, dan kedekatannya dengan angka 1 menunjukkan kekuatan hubungan tersebut.

Kelebihan metode Multiple Linear Corelation:

  1. Cocok untuk digunakan pada kondisi 3 variabel

Kekurangan metode Multiple Linear Corelation:

  1. Hanya bisa untuk 3 variabel, tidak lebih, tidak kurang

Bedah Kode: Multiple Linear Corelation

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

multiLinCor = (y, x1, x2) => withAs(
// fungsi ini menerima deret y, deret x1, dan deret x2
corelation, cor => pow(1/2)(
// mari kita singkat 'corelation' sebagai 'cor'
(
(pow(2)(cor(y, x1)) + pow(2)(cor(y, x2))) -
(2 * cor(y, x1) * cor(y, x2) * cor(x1, x2))
) / (1 - pow(2)(cor(x1, x2)))
// kita terjemahkan rumus matematisnya sebagai kode JS
)
)

7.1.5. Contingency Corelation

Kesemua fungsi korelasi yang telah kita kaji sejauh ini hanya melibatkan angka, baik ia dalam bentuk data interval, ranking, ataupun dalam kelompok. Seandainya kita menemukan sebuah kondisi dimana yang coba kita cari korelasinya adalah kategori, apakah kita bisa menggunakan rumus korelasi yang ada? Tidak bisa, karena mereka hanya untuk angka, bukan kategori. Misalnya Anda sedang bertanya apakah semakin berpendidikan seseorang maka akan semaking sering ia rekreasi? Siapa yang bisa tahu jawabannya? Bisa jadi orang yang berpendidikan tinggi jarang rekreasi karena ia sibuk baca buku di rumah, bisa jadi dengan pendidikan tingginya, punya pekerjaan bagus dan rutin rekreasi. Bisa jadi pendidikannya rendah tapi sering rekreasi karena pekerjaannya dekat dengan area rekreasi, atau pendidikannya randah dan tidak sempat rekreasi karena belum ada dana. Siapa yang bisa mengambil asumsi ditengah ketidakpastian, kecuali dengan analisis matematis terhadap data real.

Oleh karena itu dikembangkanlah sebuah model matematis statistik yang khusus untuk menangani permasalahan ini, yaitu Contingency Corelation, atau bisa juga dipanggil korelasi bersyarat. Adapun rumus matematisnya adalah seperti berikut:

Rumus: Chi kuadrat
Rumus: Korelasi Kontingensi

Yang bila dikonversi menjadi kode JS, maka jadi seperti ini:

chi2 = arrays => withAs(
arrays.map(i => i.map((k, l) =>
sum(i) * sum(arrays.map(m => m[l]))
/ sum(arrays.flat())
)), pred => sum(pred.flat().map((n, o) =>
pow(2)(arrays.flat()[o] - n) / n
))
)

contingency = arrays => pow(1/2)(
chi2(arrays) / (chi2(arrays) + sum(arrays.flat()))
)

chi2 adalah fungsi yang koefisien yang akan menjadi bahan bagi fungsi contingency berikutnya. Fungsi ini menerima tabel kontingensi, dan akan mengembalikan sebuah angka. Angka yang dikeluarkan ini tidak dapat diterjemahkan secara langsung, karena ia adalah bahan bagi perhitungan berikutnya.

contingency adalah fungsi yang menerima tabel kontingensi dan akan mengembalikan sebuah angka dalam rentang -1 s/d +1 untuk menggambarkan arah dan kekuatan hubungan antar kedua variabel yang sedang diukur.

Mari kita lanjutkan contoh situasi kajian tentang hubungan antara tingkat pendidikan dan rutinitas rekreasi tadi. Hasil pengumpulan data disusun dalam bentuk tabel frekuensi kontingensi berikut:

Tabel: Contoh data yang diduga berkorelasi kontingensi

Dapat Anda lihat bahwa setiap baris mewakili tingkat pendidikan (dari tamat SD sampai level sarjana) dan setiap kolom mewakili tingkat rutinitas rekreasi (dari jarang hingga sering). Sementara setiap selnya adalah frekuensi jawaban orang yang Anda survei menjawab sesuai baris dan kolom tertentu. Sebagai contoh, yang tingkat SD dan jarang rekreasi ada 145 orang, dan yang sarjana dan sering rekreasi ada 19 orang (Info: ini hanya data fiktif untuk latihan). Inilah contoh tabel yang cocok/bisa diolah oleh fungsi chi2 dan contingency untuk menghasilkan angka korelasi yang diharapkan. Anda bisa karang tabel kontingensi lain seperti: korelasi pecinta film horror dan percaya tahayul, korelasi pesepeda dan kepedulian terhadap lingkungan, atau hal lain sesuai minat Anda. Bila kita konversi tabel diatas menjadi kode JS, maka bentuknya sebagai berikut:

contingency([
[145, 58, 8],
[77, 13, 27],
[21, 32, 19]
]) // get 0.3759

Pada contoh kode diatas kita mendapati nilai perolehan 0.3759. Nilainya positif, artinya kedua variabel tersebut bergerak bersamaan, hanya kekuatan hubungannya relatif rendah, karena lebih dekat ke angka 0 daripada ke angka 1. Dengan itu kita bisa menyimpulkan bahwa “Ya, ada korelasinya antara tingkat pendidikan seseorang dengan rutinitas dia berekreasi, tapi lumayan lemah” (begitu kalau orang statistik berargumen).

Kelebihan metode Contingency Corelation:

  1. Cocok untuk mencari korelasi data kategorikal
  2. Bisa gunakan kategori sebanyak apapun, bebas

Kekurangan metode Contingency Corelation:

  1. Penilaian responden cenderung subjektif (dikit/banyak, sering/jarang)
  2. Sangat tergantung pada tingkat kejujuran responden

Bedah Kode: Multiple Linear Corelation

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

chi2 = arrays => withAs(
// fungsi ini menerima tabel kontingensi
arrays.map(i => i.map((k, l) =>
// setiap baris diurai
sum(i) * sum(arrays.map(m => m[l]))
// jumlah setiap baris dikali dengan jumlah setiap kolom
/ sum(arrays.flat())
// dibagi dengan jumlah seluruh responden
)), pred => sum(pred.flat().map((n, o) =>
pow(2)(arrays.flat()[o] - n) / n
)) // konversi rumus matematis chi2 menjadi kode JS
)

contingency = arrays => pow(1/2)(
// fungsi ini menerima tabel kontingensi
chi2(arrays) / (chi2(arrays) + sum(arrays.flat()))
// konversi rumus matematis contingency jadi kode JS
)

7.1.6. Partial Corelation

Sering kali kita secara naif berfikir bahwa ketika memandang sebuah fenomena yang jelas ada 2 variabel dominan yang saling terkait, maka hanya 2 variabel itulah yang layak diberikan perhatian dan mengabaikan variabel/faktor lainnya. Ketika kita mengukur hubungan 2 variabel dan mendapati nilai korelasi yang tinggi, kita harus hati-hati untuk tidak tertipu oleh angka ini. Kenapa? Karena bisa jadi dia bernilai tinggi karena kita mengabaikan yang lain, sementara ketika korelasinya diukur dengan beberapa variabel bersama-sama nilainya justru malah rendah. Penulis ajarkan yang basic dulu ya: misalkan kita mendapati A berkorelasi besar dengan B, dan B berkorelasi besar dengan C, tapi A berkorelasi kecil dengan C. Apa yang janggal? Dalam bahasa statistik, bisa jadi si C ini adalah variabel ‘confounding’ bagi variabel A. Artinya ketika variabel A dan B diukur hanya sepasang/mereka berdua saja, nilainya bisa tinggi, padahal dia tinggi hanya karena C diabaikan. Sementara ketika diukur dengan korelasi parsial dimana C dijadikan confounding, barulah ketahuan bahwa korelasi A dan B tidak setinggi itu.

Mari kita buat skenario yang lebih konkrit lagi, seperti finansial seorang pekerja kantoran. Kita tentu dengan mudah berasumsi bahwa pengeluaran itu berkorelasi positif dan signifikan dengan pendapatan. Si Udin dengan bahagia dan bangganya menunjukkan laporan bahwa “ya, pengeluaran dan pendapatan itu berkorelasi positif dan signifikan”. Tapi naifnya dia lupa bahwa secara alamiah, kebutuhan untuk pengeluaran antara pekerja pria dan wanita itu berbeda. Pria tidak perlu beli lipstik dan make up, pakai pewangi hanya kalau ingat, tidak perlu perawatan rambut mingguan, tidak perlu beli perlengkapan haid, dan seterusnya. Kalaupun ada kebutuhan tertentu pada pria, mungkin juga tidak sebesar checklist pekerja wanita yang sudah disebutkan tadi. Nah, justru ketika variabel ‘gender’ ini dilibatkan dan dihitung dalam korelasi parsial, barulah ketahuan bahwa korelasi pengeluaran dan pendapatan yang diduga diawal tadi, tidak sebesar yang didapat pertama. Tergantung besar kecilnya selisih antara hasil korelasi biasa dan korelasi parsial inilah seorang ahli statistik dapat memutuskan apakah variabel confounding yang diduga/didapat harus dilibatkan dalam penelitian atau tidak.

Korelasi Parsial ini dikembangkan awalnya sebagai sebuah bentuk kritik terhadap korelasi Pearson yang ketika digunakan tanpa mempertimbangkan banyak faktor, bisa mengundang orang untuk misinterpretasi terhadap sebuah fenomena. Formula korelasi parsial ini tetap menggunakan korelasi Pearson sebagai bahannya, tapi dikombinasikan sedikit lebih kompleks agar bisa mengkaji 3 variabel sekaligus atau First Order (Info: silahkan cari tahu tentang Partial Corelation: First Order dan Second Order bagi yang berminat). Adapun bentuk formulanya adalah seperti ini:

Rumus: Korelasi parsial 3 variabel

Yang jika dikonversi menjadi kode JS, maka jadi seperti ini:

partialCorelation = (a, b, c) =>
withAs(corelation, cor =>
(cor(a, b) - cor(a, c) * cor(b, c)) /
pow(1/2)(
(1 - pow(2)(cor(a, c))) *
(1 - pow(2)(cor(b, c)))
)
)

partialCorelation adalah fungsi yang ketika menerima deret data a, b, dan c maka ia akan mengembalikan sebuah angka dalam rentang -1 s/d +1 yang menandakan nilai korelasi antar variabel a dan b dimana c adalah confounding (Info: buku statistik lain sering gunakan istilah control variable/variabel kendali).

Mari kita lanjutkan contoh kasus yang disebut diawal tadi tentang finansial pekerja kantoran. Dibawah ini adalah contoh pemanggilan fungsi corelation dengan a sebagai data pengeluaran dan b sebagai data pendapatan. Komputer mengeluarkan angka korelasi yang sangat tinggi dan kitapun secara naifnya percaya bahwa inilah fakta, tiada yang lain.

corelation(
[3, 5, 6, 7, 4, 6, 9 ], // a
[5, 8, 9,10, 7, 7, 11], // b
) // get 0.9234

partialCorelation(
[3, 5, 6, 7, 4, 6, 9 ], // a
[5, 8, 9,10, 7, 7, 11], // b
[0, 1, 1, 1, 0, 1, 1 ] // c
) // get 0.8341

Tapi ketika kita mempertimbangkan variabel c yang berisi data gender (0=wanita, 1=pria) maka nilai korelasi yang didapat tetap positif tapi sudah ada sedikit pengurangan sebesar 0.0893. Walau selisihnya tidak besar, bukan berarti tidak ada peranan gender dalam menentukan besar kecilnya pengeluaran.

Lalu bagaimana dengan kasus lain yang ketika nilai korelasi Pearsonnya relatif rendah, tapi ketika dilakukan korelasi parsial dengan variabel lain malah nilainya jadi lebih tinggi? Bisa jadi artinya dengan menambah/mempertimbangkan variabel kendali/confounding, kita memperjelas hubungan 2 variabel pertama ketika variabel 3 diketahui/dikendalikan. Mari kita lanjutkan contoh skenario tadi dengan variabel c yang berbeda, yaitu latar belakang finansial keluarga.

partialCorelation(
[3, 5, 6, 7, 4, 6, 9 ], // a
[5, 8, 9,10, 7, 7, 11], // b
[4, 7, 6, 8, 4, 5, 6 ] // c
) // get 0.8931

Ketika variabel c latar belakang kemampuan finansial keluarga ditambahkan, justru nilai korelasinya naik. Kenapa? Bisa jadi peranan kekuatan finansial keluarga membuat dia semakin percaya diri untuk melakukan pengeluaran belanja (Joke: toh keluarganya emang udah tajir juga). Atau justru karena dia berpendapatan besar dari keluarga yang terdidik sederhana membuat mereka jadi berhemat. Terlepas dari apapun itu, adanya perbedaan antara nilai output korelasi Pearson dan nilai output korelasi parsial menandakan bahwa pada derajat tertentu, ada perbedaan yang dibuat oleh suatu variabel confounding tersebut. Sekarang coba Anda tes membuat uji korelasi Pearson dan korelasi parsial pada contoh kasus variabel a harga game, b kualitas grafisnya, dan c (genre, popularitas, durasi game, dsb). Anda akan melihat sendiri bagaimana partialCorelation dapat membantu membuka informasi yang sebelumnya tidak Anda ketahui kalau hanya pakai korelasi biasa.

Kelebihan metode Korelasi Parsial:

  1. Dapat mendeteksi signifikasi variabel confounding
  2. Memperjelas bias pada penelitian multi-variat

Kekurangan metode Korelasi Parsial:

  1. First order hanya bisa menampung 1 variabel confounding
  2. Butuh korelasi parsial second order untuk yang lebih advanced

Bedah Kode: Korelasi Parsial

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

partialCorelation = (a, b, c) =>
// berikan deret a, deret b, deret c
// a= dependen, b=independen, c=confounding
// pastikan panjang mereka bertiga sama
withAs(corelation, cor =>
// persingkat corelation jadi 'cor'
(cor(a, b) - cor(a, c) * cor(b, c)) /
pow(1/2)( // pangkat 1/2 itu sama dengan akar
(1 - pow(2)(cor(a, c))) *
(1 - pow(2)(cor(b, c)))
) // terjemahkan rumus matematisnya jadi kode JS
)

7.2. Regression

Photo by Sam Poullain on Unsplash

Kita sudah pernah belajar garis tren, kita sudah pernah juga belajar tentang korelasi. Korelasi memungkinkan kita untuk melihat hubungan antar 2 atau lebih variabel, garis tren memungkinkan kita untuk melakukan prediksi pada 1 variabel dalam dimensi waktu. Bisa tidak ya kita punya sebuah alat yang memungkinkan kita melakukan keduanya sekaligus tanpa terikat oleh dimensi waktu? Ada, jawabannya garis regresi.

7.2.1. Linear Regression

Tahun 1853 di Inggris ada seorang anak muda bernama Galton, lahir dari keluarga Dalton asal Birmingham. Sempat masuk kelas ilmu kesehatan di Cambridge University tapi sayangnya berhenti dan tidak dapat gelar apapun. Tak lama setelah gagal di bidang medis, ayahnya pun meninggal. Ia memutuskan untuk jadi seorang traveller sampai ke benua Afrika, dan untungnya memenangkan medali French Geographical Society. Setelah itu ia bekerja di lembaga riset di negerinya dengan mengkuantifikasi apapun hasil observasi yang dia temukan. Sama seperti kita yang sedang baca buku ini, dia menemukan pertanyaan yang sama seperti pada kalimat paragraf sebelumnya. Karena orangnya memang pintar matematika, dia coba mencari fenomena keterkaitan antara sebuah garis regresi dengan mean-nya. Berkat jasanya dalam bidang statistik, iapun diberikan gelar “Sir” oleh kerajaan. Lalu mana dia jasa Galton yang tersohor itu? Ini dia:

Rumus: Regresi linear untuk 2 variabel

“Y” adalah nilai Y yang akan diprediksi keluar ketika fungsi “Y = a + bX” diberikan nilai X. Maka untuk mendapatkan formula prediksi tersebut kita perlu mencari nilai a dan b. Bagaimana mencarinya? Seperti yang terlihat pada rumus 'a' dan 'b' dalam gambar di atas. Dari rumus prediksi tadi kita tahu bahwa 'a' itu adalah konstanta yang nilainya tidak akan berubah, terlepas dari berapapun nilai X yang diberikan. Sementara 'b' itu adalah koefisien variabel X yang akan menjadi faktor perkalian setiap kali nilai X berubah. Dengan adanya persamaan berpangkat 1 ini kita sudah tahu bahwa hasilnya akan berupa garis lurus. Maka kalau kita konversi formula diatas menjadi kode JS, maka bentuknya adalah seperti ini:

regression = (x, y) => withAs({
x2: sum(x.map(pow(2))),
xy: sum(x.map((i, j) => i * y[j]))
}, ({x2, xy}) => ({
a: (sum(y) * x2 - sum(x) * xy) /
(x.length * x2 - pow(2)(sum(x))),
b: (x.length * xy - sum(x) * sum(y)) /
(x.length * x2 - pow(2)(sum(x)))
}))

regression(
[2, 3, 2, 5, 6, 1, 4, 1],
[5, 8, 8, 7, 11, 3, 10, 4]
) // get {a: 3.25, b: 1.25}
linearPred = (equ, num) =>
equ.a + equ.b * num

linearPred({a: 3.25, b: 1.25}, 3.5) // get 7.625

linearPred(
regression(
[2, 3, 2, 5, 6, 1, 4, 1],
[5, 8, 8, 7, 11, 3, 10, 4]
), 3.5
) // get 7.625

regression adalah fungsi yang menerima deret data variabel x dan deret data variabel y. Ia akan mengembalikan sepasang nilai, yaitu a dan b. Kedua nilai ini dibungkus dalam format objek untuk diserahkan sebagai input bagi fungsi berikutnya, ataupun untuk dibaca langsung.

linearPred adalah fungsi yang menerima persamaan regresi dan sebuah angka dari variabel X. Dan akan mengembalikan nilai Y hasil prediksi sesuai rumus regresi.

Kalau seandainya kita kurang yakin dengan hasil prediksi formula tersebut, mari coba kita lakukan secara manual.

var x = [2, 3, 2, 5, 6, 1, 4, 1]
var y = [5, 8, 8, 7,11, 3,10, 4]

// setelah diurutkan secara manual
var x = [1, 1, 2, 2, 3, 4, 5, 6]
var y = [3, 4, 5, 8, 8,10, 7,11]

// sekarang kita punya angka x = 3.5
// menurut 'naluri' manusia, seharusnya diletakkan dimana?

var x = [1, 1, 2, 2, 3, 3.5 4, 5, 6]
var y = [3, 4, 5, 8, 8, 9 10, 7,11]
// menurut manusia disini ^

var x = [1, 1, 2, 2, 3, 3.5 4, 5, 6]
var y = [3, 4, 5, 8, 8, 7.6 10, 7,11]
// menurut statistik disini ^

Kalau seandainya kita hanya mengandalkan naluri/intuisi manusia dalam melakukan prediksi, bisa saja tepat, tapi ia belum tentu membentuk sebuah garis lurus. Menggunakan alat statistikpun bukan berarti pekerjaan kita sempurna karena hasilnya garis lurus, tapi setidaknya ia lebih objektif dan dapat diukur akurasinya. Lalu bagaimana kita tahu seberapa baik garis regresi dapat menjelaskan data realnya? Akan kita bahas di sub-bab berikutnya ya.

Penulis ingin para pembaca menyediakan sebuah kertas, buat diagram X dan Y, lalu tebarkan angka acak di dalamnya yang membentuk pola linear mulai dari kiri bawah ke kanan atas. Berikan perkiraan posisi X dan Y pada masing-masing titik dan pindahkan dalam sebuah tabel variabel X dan variabel Y. Dengan demikian Anda sudah punya bahan untuk diregresi. Masukkan semua angka tersebut seperti pada contoh kode regression dan catat hasilnya. Sekarang berikan sebuah angka acak pada X, dan dengan fungsi linearPred izinkan komputer memprediksi seharusnya pada posisi mana ia pada Y. Dengan demikian, Anda akan melihat, bagaimana statistik seolah seperti punya kecerdasan buatan untuk mmemprediksi sebuah nilai. Masalahnya,,, kecerdasan ini belum begitu 'cerdas' sehingga ia tidak mungkin bisa menghasilkan nilai Y yang posisinya diluar garis formula yang komputer tetapkan (namanya juga garis linier).

Garis Tren:

  1. Menghasilkan garis yang menunjukkan hubungan antara sebuah variabel terhadap waktu
  2. Harus dan akan selalu digunakan pada data berbasis waktu
  3. Tidak mempertimbangkan proses probabilistik atau stokastik

Garis Regresi:

  1. Mampu menghitung hubungan antara 2 variabel
  2. Tidak tergantung pada dimensi waktu
  3. Sifat stokastik yang dipertimbangkan dalam formula

Bedah Kode: Linear Regression

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

regression = (x, y) => withAs({
// terima deret X dan deret Y
x2: sum(x.map(pow(2))),
// ^ pangkat 2-kan semua X
// ^ lalu jumlahkan
xy: sum(x.map((i, j) => i * y[j]))
// ^ setiap X dikali Y pasangannya
// ^ lalu jumlahkan
}, ({x2, xy}) => ({
// ^ siapkan bahan-bahannya
a: (sum(y) * x2 - sum(x) * xy) /
(x.length * x2 - pow(2)(sum(x))),
b: (x.length * xy - sum(x) * sum(y)) /
(x.length * x2 - pow(2)(sum(x)))
// sesuaikan dengan formula aslinya
}))

linearPred = (equ, num) =>
// ^ terima persamaan
// ^ berpa nilai X yang mau diprediksi?
equ.a + equ.b * num
// sesederhana formula aslinya

7.2.2. SEE

‘See’ dalam bahasa Inggris artinya melihat, melihat apa? Kita mau melihat, kalau seandainya pada sebuah set data dengan 2 variabel diprediksi dengan menggunakan garis regresi, akan seberapa tepatkah garis regresi tersebut? Terjemahan tersebut hanya kebetulan saja, nama aslinya adalah Standard Error Mean. Rumusnya adalah seperti pada gambar berikut:

Rumus: Standard Error Estimate

Yang kalau diterjemahkan menjadi kode JS, maka bentuknya seperti ini:

SEE = (x, y) => withAs({
y2: sum(y.map(pow(2))),
xy: sum(x.map((i, j) => i * y[j])),
reg: regression(x, y)
}, ({y2, xy, reg}) => pow(1/2)(
(y2 - reg.a * sum(y) - reg.b * xy)
/ (x.length - 2)
))

SEE(
[2, 3, 2, 5, 6, 1, 4, 1],
[5, 8, 8, 7,11, 3,10, 4]
) // get 1.7559

SEE adalah fungsi yang menerima deret X dan deret Y yang lalu akan mengembalikan sebuah angka yang melambangkan seberapa meleset antara data real dari nilai prediksinya. Pada contoh diatas kita menggunakan bahan deret X dan Y yang sama dengan contoh kode sub-bab sebelumnya. Dapat kita lihat bahwa hasilnya adalah 1.75, lalu apa artinya angka ini? Semakin besar angka yang dikeluarkan oleh fungsi ini, maka semakin meleset-lah antara nilai real dan nilai prediksi, secara rata-rata. Tapi apakah dengan angka ini kita tahu bahwa garis prediksi itu bagus atau tidak? Tergantung syarat yang ditentukan oleh seorang peneliti. Kalau peneliti mensyaratkan bahwa yang 'bagus' itu harus dalam range 0 - 1, maka jelas hasil prediksinya dianggap jelek. Tapi kalau range yang disyaratkan boleh dalam range 0 - 2 berarti garis prediksi masih bisa diterima.

SEE(
[2, 3, 2, 5, 6, 1, 4, 1],
[2, 3, 2, 5, 6, 1, 4, 1]
) // get 0

Bagaimana contoh garis prediksi yang sempurna itu? Adalah ketika hasil hitung SEE pas di 0. Coba perhatikan contoh kode diatas dimana kita menggunakan deret yang sama untuk X dan Y, fungsi-nya mengembalikan angka 0. Kalau seandainya kedua deret yang 'sama' tersebut Anda gambarkan pada kurva, Anda akan mendapatkan garis lurus sempurna, tanpa ada 1 titikpun di luar garis. Namun pertanyaannya, apakah data seperti itu realistis di dunia nyata?

Ada 2 batang bunga yang sama, mendapatkan pengairan yang sama, dan cahaya matahari yang sama. Bisa jadi salah satu mati dan salah satu hidup dan berkembang biak. Para karyawan di kantor yang katanya akan memperoleh pendapatan sesuai kinerja. Apakah iya bos kita mengetahui performa asli kita dan memberikan gaji yang sesuai itu? (Joke: bukan curhat ya). Ratusan judul buku bekas diobral di area bazar dengan label ‘Serba 10K’, apakah kualitas buku sudah pasti setara 10K semua? Semakin banyak Anda mengumpulkan contoh data real hubungan antara 2 variabel, semakin Anda akan sadar bahwa nilai SEE yang pas di 0 itu tidak ada. Realita ini penuh distorsi, justru karena itu lah dia natural. (Joke: kok seperti lirik lagu ya).

Bedah Kode: Standard Error Estimate

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

SEE = (x, y) => withAs({
// terima deret X dan deret Y
y2: sum(y.map(pow(2))),
// ^ pangkatkan semua Y
// ^ lalu jumlahkan
xy: sum(x.map((i, j) => i * y[j])),
// ^ kalikan semua X dengan Y pasangannya
// ^ lalu jumlahkan
reg: regression(x, y)
// carikan nilai {a, b}-nya
}, ({y2, xy, reg}) => pow(1/2)(
(y2 - reg.a * sum(y) - reg.b * xy)
/ (x.length - 2)
// sesuaikan dengan rumus aslinya
))

7.2.3. Exponential Regression

Apakah statistik hanya bisa memprediksi garis lurus? Tentu tidak. Pada beberapa kasus, Anda akan menemui data lapangan dimana nilai variabel Y bertumbuh lebih cepat seiring membesarnya nilai X. Sebagai contoh, adalah pertambahan jumlah penduduk. Kalau seandainya di sebuah planet ada sepasang manusia dan mereka memutuskan untuk berkembang biak dengan standar “setiap pasangan harus punya 4 anak, tidak lebih dan tidak kurang”, akan seperti apakah kurva pertambahan jumlah manusianya dari waktu ke waktu? Berarti sepasang pertama akan menghasilkan 4 anak, 4 anak tadi menghasilkan 8 anak, 8 anak tadi menghasilkan 16 anak, dan seterusnya bertumbuh dengan pola ‘generasi terakhir’ kali 2. Atau yang dalam bahasa matematika setara dengan 2 pangkat ‘urutan generasi’ = 2^n. Kalau kita terjemahkan permasalahan diatas menjadi sebuah kode, maka bentuknya seperti berikut:

populate = (seed, grow, gen) =>
makeArray(gen).map(
i => Math.pow(seed, (i+1))
)

sumAlive = (max, gen) => sum(gens.slice(-max))

populate(2, 2, 2) // generasi anak
// hasilnya [2, 4]

populate(2, 2, 3) // generasi cucu
// hasilnya [2, 4, 8]

populate(2, 3, 5) // generasi anak cicit
// hasilnya [2, 4, 8, 16, 32]

sumAlive(populate(2, 3, 5)) // jumlah di generasi ke-5
// 56 orang masih hidup di generasi ke-5

populate adalah fungsi yang ketika diberikan nilai awal, tingkat pertumbuhan, dan panjang generasi, ia akan mengembalikan sebuah deret angka riwayat pertumbuhan data tersebut sepanjang generasi yang diminta. Berasal dari rumus yang sederhana, yaitu Y = n ^ X. Dimana n adalah data awal, X adalah generasi ke-sekian, dan Y adalah ukuran generasi pada saat X. Fungsi ini hanya perkiraan naif bahwa semua generasi yang lahir memiliki sepasang jantan-betina yang seimbang tanpa ada kematian 1 bayi pun (fungsi ini hanya untuk pengandaian).

sumAlive adalah fungsi yang ketika menerima daftar generasi(= gens) dan lama hidup maksimal sebuah generasi(= max) maka ia akan mengembalikan jumlah anggota yang masih hidup pada generasi tersebut. Kalau seandainya harapan hidup manusia di planet itu panjang, bisa jadi nilai max-nya naik, atau bila populasinya rawan mati, maka nilai max-nya turun. Sebagai contoh--di Indonesia--umum ditemukan keluarga yang kakek-nenek-nya masih lengkap bersama cucu, dan ada pula yang tidak, berarti kurang lebih koefisien max-nya adalah 2 s/d 3.

Kalau seandainya diteruskan hingga generasi ke-20, didapati generasi terbaru sejumlah 1,048,576 manusia, dan kalau dijumlahkan semuanya di generasi itu menjadi 2,097,150 manusia. Dan pada generasi ke 50, jumlah orang yang hidup saat itu berjumlah 1,970,324,836,974,592 (nyaris 2 ribu triliun manusia). Padahal selisih 20 ke 50 itu hanya 30, tapi selisih hasilnya sangat jauh hampir tak terkirakan. Terlepas dari hal itu mungkin atau tidak, skenario dan fungsi diatas adalah untuk menceritakan bagaimana bentuk pertumbuhan yang eksponensial itu. Data yang awalnya bertumbuh dengan lambat, makin lama makin cepat, dan semakin lama semakin bertambah cepat lagi. Kalau fungsi 2 pangkat X itu digambarkan dalam kurva bentuknya adalah seperti ini:

Gambar: Contoh kurva 2 pangkat x

Tapi perlu diketahui bahwa, bertambah secepat apapun pertambahan data tersebut, tidak akan pernah menyentuh infinity, mau berapa ratus juta triliunpun nilainya. Exponential adalah kurva yang berupaya mendekati infinity tanpa pernah menyentuhnya. Nah, sekarang bagaimana bila pada data lapangan kita menemui kondisi data yang polanya mirip seperti ini dan kita mau cari fungsi regresinya dengan statistik? Jawabannya adalah regresi eksponensial.

expoRegress = (x, y) => withAs(
regression(x.map(Math.log10), y.map(Math.log10)),
reg => ({a: pow(reg.a)(10), b: reg.b})
)

expoRegPred = (reg, num) =>
reg.a * pow(reg.b)(num)

expoRegress adalah fungsi yang ketika diberikan nilai X dan nilai Y, maka dia akan mengembalikan sebuah fungsi dengan format Y = a + X^b. Dimana a adalah sebuah konstanta, dan b adalah nilai pangkat dari variabel X.

expoRegPred adalah fungsi yang menerima objek dengan koefisien a dan b sebagai bahan persamaan dan menerima nilai X sebagai nilai variabel untuk memprediksi nilai Y.

Pada skenario sebelumnya kita sudah membuat perumpamaan pertumbuhan manusia di planet asing dengan asumsi pertumbuhan atas dasar persamaan 2 pangkat ‘panjang generasi’. Ketika data keluaran dari persamaan itu kita serahkan ke fungsi expoRegress, contohnya seperti ini:

expoRegress(
[1, 2, 3, 4, 5],
[2, 4, 8, 16, 32]
) // get {a: 1.6036, b: 1.6785}
// equal to Y = a + X^b

expoRegPred({a: 1.6036, b: 1.6785}, 5) // get 23.9

Deret data pertama adalah variabel urutan generasi, dan deret kedua adalah jumlah tiap generasi tersebut dengan asumsi 2 pangkat ’n’. Alat statistik kita menghasilkan nilai dengan konstanta 1.6 dan koefisien pangkat bagi X senilai 1.67. Walaupun tidak eksak sama dengan 2 pangkat ’n’, setidaknya persamaan yang dihasilkan alat kita sudah mendekati pola data real di awal. Baik koefisiennya 2 ataupun 1.67, ketika persamaan baru ini digambarkan pada kurva maka polanya akan tetap mirip dengan contoh grafik di atas tadi.

Bedah Kode: Regresi Eksponensial

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

expoRegress = (x, y) => withAs(
// ^ terima deret x dan y
regression(x.map(Math.log10), y.map(Math.log10)),
// ^ hitung log10 semua X
// ^ hitung log10 semua Y
// ^ hitung koefisien regresinya
reg => ({a: pow(reg.a)(10), b: reg.b})
// ^ kembalikan sepasang nilai a dan b
)

expoRegPred = (reg, num) =>
reg.a * pow(reg.b)(num)
// sesuaikan dengan rumus aslinya

populate = (seed, grow, gen) =>
// ^ berapa jumlah bibit awalnya?
// ^ berapa peningkatan per generasi?
// ^ selama berapa generasi?
makeArray(gen).map(
// ^ buat deret baru sepanjang gen
i => Math.pow(seed, (i+1))
// ^ setiap generasi adalah hasil hitung dari
// nilai bibit dipangkatkan dengan urutan generasi
)

sumAlive = (max, gen) => sum(gens.slice(-max))
// ^ lama masa hidup maksimal
// ^ deret generasi yang jadi bahan

7.2.4. Parabolic Regression

Bagaimana kalau pada grafik sebuah data kita prediksi ia tidak berpola garis lurus, tapi tidak pula lekukannya mengikuti pola eksponensial? Bagaimana bila data itu memiliki lekukan terbuka keatas, terbuka kebawah, atau lekukan yang lebih mirip garis kuadrat? Menggunakan regresi linear sudah pasti tidak cocok, tapi menggunakan garis exponensial ataupun logistik juga kurang pas, solusinya adalah regresi parabolik, atau bisa juga disebut regresi kuadrat atau regresi polinomial.

Kenapa disebut parabolik? Karena bentuknya mirip parabola yang cekung. Kenapa disebut polinomial? Karena koefisiennya ada 3, bukan 2 (binomial). Kenapa disebut kuadrat? Karena pada persamaan yang akan kita hasilkan nanti pangkat tertingginya adalah 2. Lalu apa yang membuat regresi ini spesial dibanding yang lain? Adalah karena dia tidak harus terikat pada pola lurus maupun logistik/eksponensial. Rumus matematisnya adalah sebagai berikut:

Rumus: Kurva Regresi Parabolik

Jika pada garis regresi linear kita hanya mendapati 1 konstanta + 1 koefisien X sebagai prediktor Y, pada regresi polinomial ini kita mendapatkan 1 konstanta + 1 koefisien X dan + 1 koefisien X pangkat 2. Yang unik adalah pada 3 rumus dibawahnya. Jika kita mengerjakannya secara manual atau dengan bantuan spreadsheet sekalipun, kita tidak akan bisa menemukan nilai a, b, dan c secara langsung. Yang bisa kita kumpulkan adalah bahan-bahannya seperti sigma X, sigma Y, dan setiap kuadratnya. Lalu bagaimana cara agar kita memperoleh nilai a, b, dan c tersebut? Yaitu dengan pemrograman linear. Bagi para pembaca yang sudah pernah ambil kelas aljabar, pasti pernah berhadapan dengan teknik ini. Dan bagi yang belum, silahkan Googling tentang pemrograman linear, lihat bagaimana teknik ini bermanfaat pada banyak bidang, mulai dari ilmu alam, sosial, hingga ekonomi. Dan penulispun telah membuat artikel khusus tentang ini di halaman https://medium.com/@rikyperdana, silahkan dilihat bagi yang berminat. Singkat kata, inilah fungsi linPro dalam bentuk kode JSnya:

elim = (arr, n = 0) => arr.slice(-2-n)[0]
rest = (arr, n = 0) => arr.filter(
(i, j) => j !== arr.length - 2 - n
)

gcf = (eq1, eq2) => elim(eq1) * elim(eq2)

multi = (eq1, eq2) => [
eq1.map(i => i * gcf(eq1, eq2) / elim(eq1)),
eq2.map(i => i * gcf(eq1, eq2) / elim(eq2))
]

diff = (eq1, eq2) => rest(
makeArray(eq1.length).map(i =>
multi(eq1, eq2)[0][i] -
multi(eq1, eq2)[1][i]
)
)

reduce = mat =>
mat.length === 1 ? [] : [
diff(mat[0], mat[1]),
...reduce(mat.slice(1-mat.length))
]

solve = mat =>
mat[0].length === 2 ?
mat[0][1] / mat[0][0]
: solve(reduce(mat))

swap = (arr, n) => [elim(arr, n), ...rest(arr, n)]

linPro = mat =>
mat.length >= mat[0].length - 1 &&
makeArray(mat[0].length - 1).map(
i => mat.map(j => swap(j, i))
).map(solve).reverse()

linPro([
[1, 1, 50],
[0.1, 0.6, 15]
]) // get [30, 20]

linPro([
[5,-2,-4, 3],
[3, 3, 2,-3],
[-2,5, 3, 3],
]) // get [-1, 2, -3]

linPro([
[5, 7, 9, -1, 67],
[1, 9, 6, -5, 3],
[-5, -6, 1, -2, -33],
[-7, -4, -5, -1, -64],
]) // get [3, 1, 6, 9]

linPro adalah fungsi yang menerima sebuah matriks persamaan dimana angka yang diujung setiap baris adalah hasil penjumlahan seluruh koefisien yang dikali dengan nilai variabel masing-masing. Pastikan jumlah baris yang disediakan sama dengan jumlah variabel yang ingin dicari. Pada kasus ini kita hanya membutuhkan 3 variabel, oleh karena itu setiap baris mengandung koefisien 3 variabel + 1 penjumlahannya. Apa yang terjadi kalau jumlah variabel tidak sama dengan jumlah baris? Maka fungsi ini akan menolaknya, karena secara matematispun soal itu juga tidak akan bisa dikerjakan. Pada contoh kedua terdapat baris pertama dengan data [5,-2,-4, 3], cara bacanya: 5a - 2b - 4c = 3, dan begitu juga polanya untuk semua baris yang lain. Nah, fungsi linPro diatas adalah untuk mencari nilai a, b, dan c tadi. Dalam algoritma dasarnya, fungsi ini tidak melakukan prediksi, tapi murni proses matematis untuk menghasilkan nilai pasti setiap variabel tersebut.

Berikut ini adalah kode JS untuk formula statistik pencari persamaan Parabolic Regression:

powSum = (arr, n) => sum(arr.map(pow(n)))

parabolRegress = (x, y) => withAs(linPro([
[
x.length, sum(x),
powSum(x, 2), sum(y)
], [
sum(x), powSum(x, 2), powSum(x, 3),
sum(x.map((i, j) => i * y[j]))
], [
powSum(x, 2), powSum(x, 3), powSum(x, 4),
sum(x.map((i, j) => i * i * y[j]))
]
]), res => ({a: res[0], b: res[1], c: res[2]}))

parabolRegress(
[1, 2, 3, 5, 6, 7, 9, 10],
[4, 6, 7, 9, 8, 7, 4, 3]
) // get {a: 1.89, b: 2.48, c: -0.24}

parabolRegPred = (equ, x) =>
equ.a + equ.b * x + equ.c * x * x

parabolRegPred({a: 1.89, b: 2.48, c: -0.24}, 5) // get 8.29

powSum adalah fungsi yang ketika menerima sebuah deret angka, ia akan memangkat 2-kan setiap angka lalu menjumlahkannya. Fungsi biasa saja.

parabolRegress adalah fungsi yang ketika menerima deret x dan deret y, maka ia akan mencarikan nilai-nilai bahan seperti sigma X, sigma Y, sigma X*Y, dan sebagainya dan disusun dalam bentuk matriks yang nantinya diserahkan kepada fungsi linPro untuk dicarikan nilai a, b, dan c-nya. Info: jika Anda mendapati nilai c-nya minus, sudah dipastikan bahwa kurvanya akang bengkok ke bawah/turun. Sementara bila ia positif, maka bengkokannya akan mengarah ke atas.

parabolRegPred adalah fungsi yang ketika menerima objek yang mengandung nilai a, b, dan c, lalu menerima nilai X, maka ia akan mengembalikan prediksi nilai Y tergantung nilai X-nya. Dapat dilihat pada contoh data diatas, ketika X-nya bernilai 5, Y-nya bernilai 9, dan fungsi ini memberikan nilai prediksi 8.29. Cukup akurat bukan? Sekarang mari kita gunakan angka bahan yang sama untuk membuat deret prediksinya:

[1, 2, 3, 5, 6, 7, 9, 10].map(
i => parabolRegPred({
a: 1.89, b: 2.48, c: -0.24
}, i)
) // get [4.13, 5.89, 7.17, 8.29, 8.13, 7.49, 4.77, 2.69]
// real Y [ 4, 6, 7, 9, 8, 7, 4, 3]

Bedah Kode: Parabolic Regression

Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:

powSum = (arr, n) => sum(arr.map(pow(n)))
// ^ terima sebuah deret angka
// ^ mereka mau dipangkatkan berapa?

parabolRegress = (x, y) => withAs(linPro([
// serahkan bahan ke fungsi linPro ^
[x.length, sum(x), powSum(x, 2), sum(y)],
// samakan dengan kebutuhan persamaan 1
[
sum(x), powSum(x, 2), powSum(x, 3),
sum(x.map((i, j) => i * y[j]))
// samakan dengan kebutuhan persamaan 2
], [
powSum(x, 2), powSum(x, 3), powSum(x, 4),
sum(x.map((i, j) => i * i * y[j]))
// samakan dengan kebutuhan persamaan 3
]
]), res => ({a: res[0], b: res[1], c: res[2]}))
// ^ dapatkan nilai a, b, dan c

--

--

No responses yet