Statistik JS: Chap. 5
5. Beautiful Curve
Dalam ilmu statistik simbol bel hampir selalu diidentikkan dengan kurva sebaran data yang relatif normal atau ideal. Lalu mengapa sering diwakilkan dengan simbol bel? Jawaban sederhananya adalah karena kebetulan mirip, sementara jawaban kompleksnya adalah seperti yang dijelaskan oleh matematikawan Jerman bernama Carl Gauss. Gauss meyakini bahwa kurva bel adalah bentuk yang paling mewakili distribusi normal, dimana kurva bel memiliki ciri khas:
- nilai dominan cenderung terletak di tengah kurva
- semakin ke pangkal atau ke ujung kurva data semakin jarang
- ada kencederungan bentuk simetris pada sisi kiri dan kanan kurva
Banyak juga statistikawan yang percaya bahwa kurva bel adalah bentuk yang paling alamiah untuk mencul di alam semesta, dan memang sering terjadi (bukan selalu). Contoh yang paling sederhana adalah distribusi nilai berat badan pada sebuah kelas. Kita akan lebih umum menemukan kelas yang mayoritas mahasiswanya memiliki berat badan 50–60kg sementara sisanya berbobot 40–50kg dan 60–70kg dan dapat dihitung dengan cari mahasiswa anoreksia (<40kg) atau yang obesitas (>90kg). Tanpa perlu menggambarkan kurvanya pun kita juga sudah bisa membayangkan bahwa berat badan semua mahasiswa di kelas tersebut akan berdistribusi normal. Tapi di Jepang ada juga kelas yang rata-rata bobot anggotanya di 120–150kg, namanya kelas atlit Sumo. Distribusi data mereka bisa jadi normal, tapi kan sudah beda populasi dengan kelas yang sebelumnya. Dari distribusi data berat badan hingga distribusi materi di alam semesta, semuanya memiliki kemungkinan/kecenderungan untuk menyerupai atau mendekati bentuk bel.
Mudah bagi manusia untuk men-judge apakah suatu kurva sudah mendekati distribusi normal atau belum dilihat dari sudah seberapa mirip ia dengan bentuk bel. Tapi justifikasi manusia adalah hal yang sangat subjektif dan bertentangan dengan prinsip objektifitas statistik. Untungnya ilmu statistik menyediakan beberapa kotak perkakas yang berisi alat-alat ukur untuk membantu ahli statistik mengamati kurva dengan cara yang lebih objektif dan matematis. Ketiga kota perkakas yang akan kita bahas dalam buku ini adalah: 1. Dispersion, 2. Skewness, 3. Kurtosis
5.1. Dispersion
Dispersion adalah suatu ukuran seberapa jauh setiap nilai dalam data terhadap nilai pertengahan data tersebut. Karena dispersi adalah soal membandingkan data maka pembaca wajib untuk lebih dahulu memahami yang lebih basic seperti central tendency, kuartil, dan bahasan lain pada bab-bab sebelumnya. Dispersion yang telah kita analogikan sebagai kotak perkakas terdiri dari alat-alat sebagai berikut:
5.1.1. Range
Pada bab-bab sebelumnya kita telah lebih dulu akrab dengan konsep range untuk kebutuhan berbagai formula namun disini dibahas kembali sebagai pengingat. Berikut ini adalah kode-kode JS untuk menemukan range baik untuk data tunggal maupun yang distribusi frekuensi berkelompok:
range = array => Math.max(...array) - Math.min(...array),
distRange = dist =>
(dist[dist.length - 1].top + 0.5) -
(dist[0].bot - 0.5)
range(data) // hasilnya 17
distRange(distFreq(data)) // hasilnya 18
Perlu diperhatikan disini bahwa nilai jangkauan (range) distribusi frekuensi akan selalu lebih besar dari range data tunggalnya karena yang menjadi acuannya adalah batas bawah dan batas atas data berkelompok. Lalu manfaat apa yang bisa kita peroleh dari mengetahui hasil range? Pertama, adalah kita mengetahui rentang data dari yang terkecil hingga ke yang terbesar, kita tahu bahwa selisih maksimal antar data tidak mungkin lebih besar dari range. Kedua, ada banyak formula lainnya yang memanfaatkan range sebagai bahan perhitungan.
Bedah Kode: Range
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
range = array => Math.max(...array) - Math.min(...array)
// ^ terima sebuah deret angka
// ^ nilai maksimum
// dikurangi dengan nilai minimum ^
distRange = dist =>
// ^ terima sebuah tabel distribusi
(dist[dist.length - 1].top + 0.5) -
// ambil angka top pada baris kelas tertinggi
// dan tambahkan dengan 0.5
(dist[0].bot - 0.5)
// kurangi dengan angka bot pada kelas terendah
// dan kurangi dengan 0.5
5.1.2. Intequartile Range
Sesuai namanya, IQR adalah jarak dari data kuartil pertama dan ketiga (terakhir). Maka rumus matematisnya pun sederhana pula yaitu IQR = Q3 — Q1 yang jika dikonversi menjadi kode JS:
iQR = array => fractile(4, 3, array) - fractile(4, 1, array)
distIQR = dist =>
distFractile(4, 3, distCumulative(dist)) -
distFractile(4, 1, distCumulative(dist))
iQR(data) // hasilnya 4
distIQR(distFreq(data)) // hasilnya 4,68
Apa manfaat yang bisa diperoleh dari mengetahui informasi jarak antar kuartil? Yaitu untuk mengetahui data pencilan atau outlier, nilai yang kemunculannya relatif jauh dari nilai rata-rata hitung. Memang kenapa kalau ada data outlier? Sebenarnya kemunculan data outlier adalah hal yang natural di lapangan, hanya saja kehadiran outlier tersebut dapat merusak bentuk bel yang umumnya memvisualisasikan normalitas distribusi. Di lain sisi, keberadaan data outlier juga mengindikasikan bahwa data outlier tersebut mungkin lebih tepat bila ditempatkan pada populasi lain dimana ia bisa dianggap normal. Distribusi tidak normal pada sebuah kelompok data tidak mengartikan bahwa data yang dikumpulkan tersebut jelek melainkan untuk menunjukkan bahwa tidak semua konstituen dalam data dapat terwakili dengan baik oleh hasil olah data statistiknya. Bila keterangan diatas masih cukup abstrak dan teknikal, mari penulis coba perkuat pemahamannya dengan sebuah contoh kasus.
Pada sebuah kelas di SMA unggulan terdapat 20 siswa-siswi didik dimana salah seorang anak diantara mereka adalah outlier. 19 anak diantaranya memiliki prestasi yang cukup bagus dilihat dari pencapaian nilai berbagai mata pelajaran, kelas seni dan kelas olah raga. 1 orang anak outlier tersebut memiliki nilai yang sangat rendah di bidang kesenian dan olah raga namun memiliki nilai sempurna pada mata pelajaran eksakta. Bila mata pelajaran seni dan olah raga digambarkan dalam kurva, maka Anda bisa membayangkan bahwa anak tersebut akan berada di ujung kiri distribusi dan berada di ujung kanan kurva distribusi nilai mata pelajaran eksakta. Dalam perspektif statistik, meski datanya benar apa adanya tapi tergolong tidak berdistribusi normal. Kehadiran anak outlier tersebut merusak central tendency, fraktil, dan alat ukur lainnya. Jelas bahwa selagi anak outlier tersebut masih berada di kelas tersebut maka statistik tidak bisa memberikan representasi yang akurat mewakili 19 anak dan 1 anak outlier tersebut sekaligus. Mungkin lebih tepat bila 1 anak outlier tersebut ditempatkan pada kelas lain yang anak-anaknya memiliki kecenderungan serupa dengan dia, dimana dalam kelas baru tersebut ia dapat terdistribusi normal.
Analogi diatas dapat pula berlaku pada bidang ilmu lainnya yang memanfaatkan statistik untuk penalaran data seperti fisika, kimia, biologi, hingga ilmu sosial. Semoga dengan ini Anda lebih memahami apa makna, karakteristik, dan kegunaan dari pengetahui distribusi normal.
Bedah Kode: Interquartile Range
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
iQR = array => fractile(4, 3, array) - fractile(4, 1, array)
// ^ terima sebuah deret angka
// ^ ambil fraktil ketiganya
// kurangi dengan fraktil pertamanya ^
distIQR = dist =>
// ^ terima sebuah deret angka
distFractile(4, 3, distCumulative(dist)) -
// carikan fratil ketiganya
distFractile(4, 1, distCumulative(dist))
// kurangi dengan fraktil pertama
5.1.3. Deviasi Rata-rata
Alat berikutnya dalam kotak perkakas dispersi adalah deviasi rata-rata. Deviasi sendiri adalah selisih absolut setiap nilai terhadap rata-rata hitungnya dan deviasi rata-rata adalah rata-rata dari keseluruhan deviasi tersebut. Berikut ini adalah rumus matematis dari deviasi rata-rata:
Jika dikonversikan menjadi kode JS maka bentuknya seperti ini:
devMean = array => withThis(
mean(array), meanVal => add(
array.map(i => i - meanVal)
.map(Math.abs)
) / array.length
)
distDevMean = dist => withThis(
distMean(dist), meanVal => add(
dist.map(i => i.fre * Math.abs(
(i.bot + ((i.top - i.bot) / 2)) - meanVal
))
) / add(dist.map(get('fre')))
)
devMean(data) // hasilnya 2,77875
distDevMean(distFreq(data)) // hasilnya 2,98125
Lalu apa gunanya kita mengetahui nilai rata-rata deviasi? Angka yang dihasilkan oleh formula diatas menggambarkan seberapa jauh jarak rata-rata setiap data terhadap nilai tengahnya. Semakin besar angka tersebut maka diduga akan semakin melebar pula kurvanya baik ke kiri atau ke kanan, semakin kecil angka tersebut maka akan semakin mengerucut ketengah kurva belnya. Dan kurva mana yang dapat dianggap lebih bagus? Tidak masalah apakah nilai dari devMean-nya besar atau kecil selagi bentuknya tetap simetris, minim data outlier, dan tidak terlalu miring ke salah satu sisi.
Bedah Kode: Deviation Mean
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
devMean = array => withThis(
// ^ terima sebuah deret angka
mean(array), meanVal => add(
// meanVal itu rata-rata deret
array.map(i => i - meanVal)
// hitung nilai selisih antara
// nilai asli dengan rata-rata
.map(Math.abs)
// ubah jadi nilai ^ absolut
) / array.length
// bagi dengan panjang deret
)
distDevMean = dist => withThis(
// ^ terima tabel distribusi
distMean(dist), meanVal => add(
// meanVal itu rata-rata distribusi
dist.map(i => i.fre * Math.abs(
// ^ urai setiap baris
// ^ nilai frekuensi dikali
// nilai absolut dari..
(i.bot + ((i.top - i.bot) / 2)) - meanVal
// selisih antara nilai kelas dengan mean-nya
))
) / sum(dist.map(get('fre')))
// ^ ambil hanya frekuensinya saja
// ^ lalu jumlahkan
)
5.1.4. Varians
Bila pada devMean yang dihitung adalah rata-rata absolut nilai selisih maka pada varians yang dihitung adalah rata-rata kuadrat nilai selisih. Formula matematisnya adalah sebagai berikut:
- Catatan: ganti n dengan (n — 1) bila sampel yang dihitung jumlahnya tidak sampai 30
Jika dikonversi menjadi kode JS maka bentuknya adalah sebagai berikut:
variance = array => withThis(
mean(array), meanVal => add(
array.map(i => i - meanVal)
.map(pow(2))
) / (array.length - (
array.length > 30 ? 0 : 1
))
)
distLength = dist => add(dist.map(get('fre'))),
distVariance = dist => withThis(
distMean(dist), meanVal => add(
dist.map(i => i.fre * pow(2)(
(i.bot + ((i.top - i.bot) / 2)) - meanVal
))
) / distLength(dist) - (
distLength(dist) > 30 ? 0 : 1
)
)
variance(data) // hasilnya 13,0693
distVariance(distFreq(data)) // hasilnya 13,3593
Lalu apa manfaatnya dengan mengetahui nilai varians sebuah himpunan data? Kurang lebih penjelasannya sama dengan pada sub-bab rata-rata deviasi sebelumnya.
Bedah Kode: Variance
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
variance = array => withThis(
// ^ terima sebuah deret angka
mean(array), meanVal => sum(
// meanVal itu rata-rata dari deret
array.map(i => i - meanVal)
// ubah array menjadi selisih
// antara nilai dengan meannya
.map(pow(2))
// ^ pangkat 2-kan semuanya
// lalu jumlahkan ^
) / (array.length - (
// ^ panjang deret
array.length > 30 ? 0 : 1
// kalau lebih dari 30, tidak dikurangi
// kalau kurang dari 30, kurangi 1
))
)
distLength = dist => sum(dist.map(get('fre')))
// ^ terima tabel distribusi
// ambil hanya nilai frekuensinya saja ^
// baru jumlahkan ^
distVariance = dist => withThis(
// ^ terima tabel distribusi
distMean(dist), meanVal => add(
// meanVal itu rata-rata pada distribusi
dist.map(i => i.fre * pow(2)(
// ^ urai distribusi
// ^ frekuensi pada setiap baris
// ^ dikali dengan pangkat 2 dari..
(i.bot + ((i.top - i.bot) / 2)) - meanVal
// ^ pertengahan kelas dikurangi dengan meannya
))
) / distLength(dist) - (
// ^ panjang data dalam distribusi
distLength(dist) > 30 ? 0 : 1
// kalau lebih dari 30, tidak dikurangi
// kalau kurang dari 30, kurangi dengan 1
)
)
5.1.5. Standar Deviasi
Sederhananya adalah akar kuadrat dari hasil perhitungan varians, yang rumus matematisnya adalah:
Dan kode JS-nya juga sederhana yaitu:
stanDev = arr => pow(1/2)(variance(arr))
distStanDev = dist => pow(1/2)(distVariance(dist))
stanDev(data) // get 3.6151
distStanDev(distFreq(data)) // get 3.6550
5.1.6. Relative Dispersion
Semua alat hitung dispersi diatas tergolong dispersi absolut, yang artinya membandingkan perbedaan setiap data dengan rata-ratanya sendiri. Untuk dapat membandingkan dispersi pada 2 atau lebih set data yang berbeda maka kita membutuhkan dispersi relatif. Cara mengerjakannya cukup mudah bahkan kita tiak membutuhkan formula yang kompleks. Berikut ini adalah beberapa ukuran dispersi relatif:
- koefisien variasi = standarDeviasi / Xbar * 100%
- variasi jangkauan = range / Xbar * 100%
- variasi kuartil = Qd / Median * 100%
- variasi simpangan rata-rata = SR / Xbar * 100%
Dari sini kita dapat melihat bahwa seluruh formula variasi memiliki bentuk yang sederhana dan pola yang sama, yaitu membagi pembilang dan penyebut lalu mengalikannya dengan 100 agar menjadi persentase. Maka ktia bisa membangun kode JS yang generik untuk semua jenis variasi:
variation = (a, b) => a / b * 100
variation(
stanDev(variance(data)), mean(data)
) // result 4.9471899
variation(
stanDev(distVariance(distFreq(data))),
distMean(distFreq(data))
) // result 4.9983
variation(range(data), mean(data)) // result 23.263
variation(
distRange(distFreq(data)),
distMean(distFreq(data))
) // result 24.61538
variation(iQR(data), median(data)) // result 5.4794
variation(
distIQR(distFreq(data)),
distMedian(distFreq(data))
) // result 6.58965
5.2. Kemiringan
Bahkan tidak semua kurva bel itu berbentuk simetris yang sempurna. Pada beberapa kasus, Anda akan menemukan bahwa ada kurva yang miring ke salah satu sisi. Anda dapat mengidentifikasi kemiringan ini dari melihat kakinya yang lebih panjang sebelah atau puncak gunungnya yang lebih condong ke salah satu sisi. Maka, dalam statistik fenomena ini populer disebut dengan skewness atau yang dalam bahasa Indonesianya disebut kemencengan/kemiringan.
Mata manusia bisa saja dengan mudah mendeteksi kemiringan kurva bel bila kemiringannya memang kentara. Tapi mata kita tidak mungkin cukup sensitif untuk mendeteksi kemiringan yang sangat tipis. Untuk itu kita bisa mengandalkan statistik untuk mengukur kemiringan tersebut. Ukuran sempurnanya kurva adalah ketika Xbar = Median = Moda. Bila salah satu saja dari mereka ada yang nilainya tidak sama maka aman untuk kita berasumsi bahwa kurva tersebut memiliki gejala kemiringan. Tapi seberapa miring dan ke arah mana miringnya?
Arah kemiringan kurva dapat kita tentukan dari puncak sebelah mana yang lebih tinggi. Bila tingginya di sebelah kiri maka disebut menceng ke kiri atau negatif, sementara bila puncaknya condong ke kanan maka disebut menceng positif. Sekarang mari kita tanggalkan subjektifitas kita dan gunakan statistik agar lebih objektif dalam menentukan kemiringan kurva.
5.2.1. Kemencengan Pearson
Pearson berpendapat bahwa koefisien kemiringan dapat diukur dengan cara membandingkan antara mean dan moda lalu membaginya dengan standar deviasi. Bila dijabarkan dalam formula maka bentuknya adalah seperti ini:
Tapi sayangnya tidak semua distribusi memiliki moda, untuk itu Pearson menyediakan formula alternatif yang tidak mengandalkan moda, tapi median. Rumusnya adalah sebagai berikut:
Yang jika dikonversi menjadi kode JS maka bentuknya seperti ini:
skewMod = array =>
(mean(array) - mode(array)) /
stanDev(array)
distSkewMod = dist =>
(distMean(dist) - distMode(dist)) /
distStanDev(dist)
skewMod(data) // get -0.2558
distSkewMod(distFreq(data)) // get -0.1846
skewMed = array =>
(mean(array) - median(array))
* 3 / stanDev(array)
distSkewMed = dist =>
(distMean(dist) - distMedian(dist))
* 3 / distStanDev(dist)
skewMed(data) // get 0.0622
distSkewMed(distFreq(data)) // get -0.1025
Dari hasil olah data diatas didapati bahwa data yang kita gunakan dalam buku ini memiliki kecenderungan untuk menceng ke arah kiri/negatif menurut perhitungan yang berdasarkan moda. Tetapi ketika dihitung dengan formula berbasi median maka kurva dianggap positif. Perbedaan hasil hitung formula yang berbasi moda dan median adalah hal yang normal, karena titik acuang yang berbeda. Justru perbedaan ini mengindikasikan bahwa kurva relatif simetris kiri dan kanan. Sementara bila Anda menemukan bahwa kedua formula menghasilkan nilai negatif maka Anda lebih yakin bahwa kurvanya memang menceng ke arah negatif, begitu pula bila kasusnya keduanya bernilai positif.
Bedah Kode: Pearson Skewness
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
skewMod = array =>
// ^ terima sebuah deret angka
(mean(array) - mode(array)) /
// mean dari array dikurangi modanya
stanDev(array)
// dibagi dengan standar deviasinya
distSkewMod = dist =>
// ^ terima tabel distribusi
(distMean(dist) - distMode(dist)) /
// mean dari distribusi dikurangi modanya
distStanDev(dist)
// dibagi dengan stanDev distribusinya
skewMed = array =>
// ^ terima sebuah deret angka
(mean(array) - median(array))
// mean dari deret dikurangi dengan mediannya
* 3 / stanDev(array)
// kali 3 dan dibagi stanDev-nya
distSkewMed = dist =>
// ^ terima tabel distribusi
(distMean(dist) - distMedian(dist))
// mean distribusi dikurangi dengan mediannya
* 3 / distStanDev(dist)
// kali 3 dan dibagi stanDev distribusinya
5.2.2. Kemiringan Bowley
Bukan hanya Pearson yang memikirkan tentang kemiringan kurva, tapi juga seorang Sir Arthur Lyon Bowley. Bowley mencoba menghitung kemencengan bukan dengan moda ataupun median seperti yang dilakukan Pearson, tapi dengan selisih antar kuartil-kuartil. Rumusnya adalah sebagai berikut:
Yang jika dikonversi menjadi kode JS maka bentuknya seperti ini:
skewBow = (first, second, third) =>
((third - second) - (second - first)) /
((third - second) + (second - first))
skewBow(
fractile(4, 1, data),
fractile(4, 2, data),
fractile(4, 3, data)
) // get 0
skewBow(
distFractile(4, 1, distFreq(data)),
distFractile(4, 2, distFreq(data)),
distFractile(4, 3, distFreq(data)),
) // get -0.0358
Dari hasil uji kode diatas dapat kita lihat bahwa dengan menggunakan himpunan data tunggal nilai skewness adalah 0, sementar dari data distribusi frekuensi didapati nilai minus yang relatif kecil. Perbedaan ini adalah hal yang wajar, karena data distribusi frekuensi adalah data tunggal yang disimplifikasi.
Bedah Kode: Bowley Skewness
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
skewBow = (first, second, third) =>
// terima quartile 1, 2, dan 3
((third - second) - (second - first)) /
((third - second) + (second - first))
// ubah rumus matematisnya jadi kode JS
5.2.3. Kemiringan Persentil
Bila Bowley mengukur kemiringan berdasarkan kuartil, maka kemiringan juga bisa diukur dengan persentil, formulanya adalah:
Kita tidak perlu membuat kode JS baru untuk menangani rumus statistik yang satu ini. Cukup mendaur ulang kode JS yang sudah kita buat untuk kemiringan Bowley dengan mengisi input first
, second
, dan third
nya dengan nilai P90, P50, dan P10.
5.2.4. Kemiringan Moment
Kemiringan juga dapat dihitung dengan menggunakan perbandingan mement ke-3 dan pangkat 3 simpangan baku. Ada hubungan yang unik antara mean, varians, kemiringan, dan keruncingan, semuanya terletak pada level perpangkatan yang digunakan, seperti yang ditunjukkan pada gambar di bawah. Bila ingin menghitung kemiringan Moment pada data tunggal, maka gunakan rumus berikut:
Bila ingin menghitung kemiringan Moment pada data distribusi, maka gunakan rumus berikut:
Yang bila dikonversi menjadi kode JS maka bentuknya adalah:
skewMom = array =>
sum(array.map(i => pow(3)(i - mean(array)))) /
((array.length - 1) * pow(3)(stanDev(array)))
distSkewMom = dist => withAs(
{
meanVal: distMean(dist),
midVal: i => i.bot + ((i.top - i.bot) / 2)
}, ({meanVal, midVal}) => sum(
dist.map(i => i.fre * pow(3)(
midVal(i) - meanVal
))
) / distLength(dist)
/ pow(3)(distStanDev(dist))
)
skewMom(data) // get 0.1364
distSkewMom(distFreq(data)) // get 0.0013
Bedah Kode: Moment Skewness
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
skewMom = array =>
// ^ terima sebuah deret angka
sum(array.map(i => pow(3)(i - mean(array)))) /
// ^ ubah setiap angka menjadi
// ^ pangkat 3 dari
// ^ nilai dikurangi mean
// lalu dibagi dengan ^
((array.length - 1) * pow(3)(stanDev(array)))
// panjang array dikurang 1, dikali dengan
// pangkat 3 dari standar deviasinya ^
distSkewMom = dist => withAs(
// ^ terima tabel distribusi
{
meanVal: distMean(dist),
// meanVal = mean dari distribusi itu
midVal: i => i.bot + ((i.top - i.bot) / 2)
// midVal = fungsi pencari titik tengah kelas
}, ({meanVal, midVal}) => sum(
// siapkan bahannya
dist.map(i => i.fre * pow(3)(
// urai distribusinya
// ^ nilai frekuensi
// dikali pangkat tiga dari ^ ..
midVal(i) - meanVal
// ^ selisih nilai tengah dan meannya
))
) / distLength(dist)
// dibagi dengan panjang data distribusi
/ pow(3)(distStanDev(dist))
// bagi dengan pangkat 3 standar deviasinya
)
5.3. Kurtosis
Ukuran normalitas distribusi ketiga yang akan kita perhatikan adalah kurtosis atau keruncingan puncak kurva. Jika kita ambil lagi analogi gunung maka kita dapat bayangkan bahwa ada gunung yang puncaknya relatif landai, cukup terjal, dan sangat terjal. Ketiga gunung ini bisa dianggap normal karena bebatuan yang membentuknya memadat di tengah dan relatif sedikit di lerengnya. Rasio ketinggian pada bagian tengah terhadap kelandaian pada lereng inilah yang ingin diukur oleh kurtosis. Sama seperti pengamatan visual sebelumnya dimana setiap orang boleh secara subjektif mengkalim sebuah gunung landai, cukup terjal atau sangat terjal tergantung pada siapa yang sedang menilai, seorang wisatawan amatir atau seorang professional hill-climber dapat menilai keterjalan gunung dengan cara yang berbeda.
Untuk menjaga objektifitas penilaian itulah kita butuh statistik. Hampir mirip dengan perhitungan kemiringan momen, rumus statistik kurtosis adalah sebagai berikut:
5.3.1. Kurtosis Moment
Jika dikonversi menjadi kode JS maka bentuknya adalah sebagai berikut:
kurtMom = array => sum(
(array.map(i => Math.abs(pow(4)(i - mean(array)))))
) / array.length / pow(4)(stanDev(array))
distKurtMom = dist => withAs(
{
meanVal: distMean(dist),
midVal: i => i.bot + ((i.top - i.bot) / 2)
}, ({meanVal, midVal}) => sum(
dist.map(i => i.fre * pow(4)(
midVal(i) - meanVal
))
) / distLength(dist)
/ pow(4)(distStanDev(dist))
)
kurtMom(data) // get 3.1558
distKurtMom(distFreq(data)) // get 2.7454
Terlihat disana bahwa terdapat perbedaan antara olah data himpunan dan distribusi frekuensinya. Hal ini adalah normal karena data distribusi frekuensi tidak semulus distribusi pada himpunan data tunggal. Hal ini sekaligus menunjukkan bahwa himpunan data mentahnya masih berada pada area mesokurtik.
Lalu setelah mengetahui nilai kurtosis, gunanya apa? Dengan megnetahui keruncingan kurva tersebut peneliti dapat melihat bahwa seberapa terpusat datanya ke area tengah. Kurva yang kelewat runcing menandakan bahwa populasi atau sampel masih dapat dipersempit. Sementara bila keruncaingannya platikurtik maka ada kemungkinan bahwa populasi/sampel data terlalu sempit dimana data-data minoritas pinggir kurva belum tercakup. Bentuk keruncingan yang paling normal tentunya adalah mesokurtik, namun bukan berarti keruncingan yang paling ideal harus mengikuti bentuk mesokurtik.
Bedah Kode: Kurtosis Moment
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
kurtMom = array => sum(
// ^ terima deret angka
(array.map(i => Math.abs(pow(4)(i - mean(array)))))
// ubah setiap angka yang ada menjadi
// ^ pangkat empat dari
// selisih nilai dengan mean-nya ^
// pangkat 4-kan ^
// ambil nilai absolutnya^
) / array.length / pow(4)(stanDev(array))
// ^ bagi dengan panjang array
// bagi lagi dengan ^ pangkat 4 dari stanDev
distKurtMom = dist => withAs(
// ^ terima tabel distribusi
{
meanVal: distMean(dist),
// meanVal = mean dari distribusi itu
midVal: i => i.bot + ((i.top - i.bot) / 2)
// midVal = nilai tengah dari suatu kelas
}, ({meanVal, midVal}) => sum(
// ^ siapkan bahannya
dist.map(i => i.fre * pow(4)(
// urai setiap baris menjadi
// ^ nilai frekuensi
// pangkat empat dari 4 ^
midVal(i) - meanVal
// selisih antara nilai tengah dan meannya
))
) / distLength(dist)
// panjang data distribus itu
/ pow(4)(distStanDev(dist))
// pangkat 4 dari standar deviasinya
)
5.3.2. Kurtosis Persentil
Selain mengandalkan perhitungan moment, ada cara alternatif untuk menentukan kurtosis yaitu dengan mengolah persentilnya. Rumusnya matematisnya adalah sebagai berikut:
Yang bila dikonversi menjadi kode JS maka bentuknya adalah sebagai berikut:
kurtPer = (q1, q3, p10, p90) =>
((q3 - q1) / 2) / (p90 - p10)
arr1 = [
fractile(4, 1, data),
fractile(4, 3, data),
fractile(100, 10, data),
fractile(100, 90, data)
] // get [71, 75, 68.1, 78.9]
arr2 = [
distFractile(4, 1, distFreq(data)),
distFractile(4, 3, distFreq(data)),
distFractile(100, 10, distFreq(data)),
distFractile(100, 90, distFreq(data))
] // get [70.75, 75.57, 68, 78]
kurtPer(...arr1) // get 0.1852
kurtPer(...arr2) // get 0.2413
Dari contoh diatas dapat kita lihat bahwa terdapat potensi perbedaan hasil perhitungan antara himpunan data tunggal dan distribusi frekuensi berkelompoknya. Walaupun hitungan fraktil tiap komponennya kita lihat cukup kecil. Berbeda dengan perhitungan kurtosis momen, kurtosis persentil menggunakan nilai 0.263 sebagai acuan distribusi normalnya. Yang berarti dalam hal ini menurut kurtosis persentil data dasar yang kita gunakan selama ini cukup normal bila dilihat dari distribusi frekuensi berkelompoknya.
5.4. Z-Score Distribution
Setiap peneliti, ilmuan, pebisnis, hingga pemerintah yang bergaul dengan statistik pasti pernah, sedang, dan akan berhadapan dengan berbagai macam distribusi data. Pelajar dengan distribusi berat badan teman sekelas, pemerintah dengan distribusi masyarakat miskin setiap daerah, ahli biologi dengan distribusi kodok pada hutan hujan, hingga dokter dengan distribusi demografi pasien covid pada suatu daerah.
Masalah muncul ketika kita mencoba membandingkan antara distribusi berat badan siswi-siswi kelas balet dengan distribusi berat badan siswa kelas Sumo. Setiap distribusi tersebut dapat memiliki mean dan standar deviasi yang berbeda bukan? Kita juga tidak bisa membandingkan antara distribusi masyarakat miskin negara maju dengan masyarakat miskin pada negara tertinggal. Atau, bisakah? Mari kita berkenalan dengan Z-Score.
Z-Score adalah cara statistik untuk mengkonversi setiap nilai mentah dalam suatu himpunan menjadi nilai standar yang acuannya adalah jarak antara nilai mentah dengan mean dibandingan dengan standar deviasi himpunan tersebut. Lalu bagaimana mengkonversi nilai mentah ke Z-Score? Formula statistiknya adalah sebagai berikut:
Pada buku statistik umumnya akan diajarkan bagaimana cara mencari z-score melalui Excel. Dibawah ini ditunjukkan fungsi JS-nya:
zConvert = array => withAs(
{m: mean(array), sd: stanDev(array)},
({m, sd}) => array.map(i => (i - m) / sd)
)
zConvert([5, 4, 8, 7, 1])
// get [0, -0.365, 1.095, 0.73, -1.46]
zConvert([5000, 4000, 8000, 7000, 1000])
// get [0, -0.365, 1.095, 0.73, -1.46]
// kenapa bisa sama? penasaran?
Lho, kenapa hasilnya bisa sama? Padahal meannya berbeda, bahkan jarak antar nilai bisa hingga ribuah. Itulah kemampuan zScore. Ia bisa mengkonversi nilai mentahnya menjadi himpunan nilai relatif yang acuannya adalah jarak nilai dengan mean berdasarkan standar deviasi. Dua distribusi nilai yang berbeda kini dapat diperbandingkan.
Pada contoh diatas Anda dapat melihat bahwa ada angka positif, negatif, bahkan yang ada yang 0. Bila angka yang keluar pas 0 maka artinya nilai mentahnya tepat berada pas di mean himpunan. Bila positif, maka artinya nilai mentahnya berada di atas mean atau di sebelah kanan kurva. Sementara bila negatif maka artinya nilai mentahnya berada di bawah mean atau berada di sebelah kiri kurva. Sementara besaran angka tersebut menandakan seberapa jauh nilai mentahnya dari titik mean. Sebagai contoh, 1.095 berarti nilai mentahnya berada lebih dari 1 poin dari mean. Dan -0.365 berarti nilai mentahnya 0.3 poin jaraknya di sebelah kiri mean.
Lalu apa manfaat praktis dari menghitung dan mengetahui nilai zScore? Jika Anda adalah seorang investor yang sedang mempertimbangkan untuk investasi pada 2 industri yang berbeda, Anda akan mengumpulkan data mentah 100 harga saham perusahan terbesar untuk masing-masing industri tersebut dan melihat normalitas distribusi keduanya. Ketika data hipunan masing-masing industri dikonversi menjadi himpunan zScore, Anda dapat membandingkan keduanya secara berimbang, terlepas dari besaran nilai harga perlembar saham yang mereka terbitkan. Berdasarkan perbandingan kedua kurva tersebut Anda dapat mengetahui industri mana yang lebih stabil dibanding yang lain, terlepas dari nominal besarannya. zScore bermanfaat secara generik untuk menganalisa data pekerjaan apapun untuk tujuan perbandingan antar objek.
Info: Tolong bedakan antara zConvert
dengan zTest
. zConvert
khusus untuk urusan mengubah sebuah deret angka menjadi nilai z Score, sementara untuk urusan zTest
akan ada fungsi khusus yang bisa membandingkan hasil uji dengan z-Tabel. Nantikan di buku berikutnya.
Bedah Kode: Konversi ke z Score
Silahkan baca bagian ini bagi yang berminat untuk mempelajari detail kode JSnya:
zConvert = array => withAs(
// ^ terima sebuah deret angka
{m: mean(array), sd: stanDev(array)},
// m = mean himpunan itu
// sd: standar deviasinya
({m, sd}) => array.map(i => (i - m) / sd)
// sesuaikan dengan kebutuhan rumusnya
)