Kategori
Opinion

Avalanche: Penggiringan Opini dan Hitung Cepat

Pada tahun pemilihan umum 2019, sejarah Indonesia terukir, partisipasi masyarakat dalam pemilihan umum melebihi ekspektasi dari penyelenggara pemilihan umum. Di tengah maraknya partisipasi masyarakat, ada hal negatif yang sangat memengaruhi masyarakat, yaitu terjadinya konflik horizontal akibat polarisasi pilihan politik. Polarisasi ini tidak kunjung usai, sejak pemungutan suara sudah dilakukan, bahkan sesudah diumumkan pemenangnya. Gerakan kampanye yang diserukan sejak tahun lalu, bahkan sampai sekarang, ibarat tidak ada hentinya. Banyak masalah politik yang muncul selama kontestasi pemilu 2019 ini. Masih disayangkan bahwa banyak sekali penggiringan opini yang dilakukan oleh elit dari kedua belah pihak dan adu kekuatan maupun kelantangan dari pendukung dua pihak. Penggiringan opini dari elit dan kekuatan pendukung menjadi sebuah akseleran yang sangat baik untuk memperparah terjadinya konflik horizontal.

Konflik horizontal ini berujung pada kekerasan yang menimbulkan korban jiwa sebanyak 6 orang, namun minim pemberitaan terhadap hal ini. Aktifitas warga sekitar maupun gedung perkantoran sekitar Bawaslu menjadi terhenti selama konflik terjadi. Aksi damai pada saat matahari tenggelam berubah menjadi aksi yang disusupi banyak perusuh. Apresiasi perlu diberikan kepada bapak Prabowo Subianto yang mengajak pendukung yang masih mau mendengarkan beliau untuk mengalah dan menghindari kontak fisik. Di saat yang berbeda, dalam acara Mata Najwa, elit politik bergandengan tangan dan menyerukan damai. Kita dapat bersyukur bahwa adanya inisiatif yang baik yang dapat meredamkan suasana perpolitikan Indonesia. Namun, kita tidak boleh memungkiri adanya struggle of power antara elit kedua kubu yang membantu menyulut konflik ini.

Penolakan Hitung Cepat

Hitung Cepat adalah salah satu metodologi estimasi hasil pemungutan suara yang dilakukan berdasarkan pengambilan sampel acak sesuai dengan kaidah statistika. Selama sepuluh tahun dilaksanakannya hitung cepat oleh beberapa lembaga survey, terbukti bahwa Hitung Cepat dapat menghasilkan estimasi yang cukup akurat. Namun tahun ini, pada tahun 2019, elit politik di salah satu kubu rupanya sepakat untuk menolak hasil Hitung Cepat yang dilakukan oleh berbagai lembaga survei yang memenangkan lawan politiknya. Kalimat-kalimat dari elit inipun berujung pada agitasi di kalangan simpatisan mereka, alhasil lontaran hinaan maupun serangan personal dilayangkan kepada bos lembaga-lembaga survei. Hitung Cepat yang dibuat untuk menjaga suara rakyat dengan mendapatkan data primer langsung dari tempat pencoblosan dan mencegah adanya upaya perubahan suara rakyat, menjadi kambing hitam dari penggiringan opini.

“Hitung Cepat adalah penggiringan opini. Juragan survei adalah tukang bohong.” Inilah yang dipercaya oleh pendukung salah satu kubu. Kedua kubu percaya bahwa adanya hasil dari Hitung Cepat dapat menjadi dasar deklarasi kemenangan dari salah satu kubu. Sebuah cuplikan pembicaraan antara TGB dengan Yusuf Martak menunjukkan bahwa adanya desakan deklarasi kemenangan oleh Joko Widodo setelah Hitung Cepat sudah menunjukkan kemenangan beliau. Yusuf Martak menjelaskan bahwa kabar deklarasi Joko Widodo membuat kubu Prabowo segera melaksanakan deklarasi. Yusuf Martak juga menyatakan bahwa jika ada deklarasi kemenangan dari kubu Joko Widodo, maka akan terjadi pembentukan opini bahwa kubu Prabowo sudah kalah. Terlihat bahwa kedua kubu tahu persis apa implikasi dari hasil Hitung Cepat dan bagaimana deklarasi pemenangan terhadap mental para pendukungnya.

https://tirto.id/jubir-bpn-bachtiar-nasir-sebut-quick-count-adalah-sihir-sains-dm3n

Sihir Sains, itulah istilah yang disebutkan oleh salah satu anggota BPN, Bachtiar Nasir. Ini adalah salah satu contoh serangan terhadap lembaga Hitung Cepat. Serangan ini rupanya efektif untuk membuat masyarakat simpatisan kubu Prabowo untuk tidak percaya dengan Hitung Cepat. Padahal, Perhimpunan Survei Opini Publik Indonesia (Persepi) telah membuka data masing-masing lembaga survei dan metodologi hitung cepatnya di depan publik. Data metodologi dan rumusan yang terbuka, di tambah oleh data terbuka dari KPU maupun dari inisatif KawalPemilu, siapapun dapat menghitung dan menarik kesimpulan berdasarkan hitungan yang dilakukan.

Darurat Matematika

Rakyat Indonesia sudah pintar, kata yang digaungkan oleh elit politik. Memang rakyat Indonesia sudah dapat mencari informasi sendiri, dan mampu berargumen berdasarkan informasi yang ditemukan. Namun, hal ini tidak dapat ditemukan saat Hitung Cepat dipertanyakan. Opini yang beredar di masyarakatpun terpecah dua, satu mempercayai Hitung Cepat dan satu menolak dengan keras Hitung Cepat dan menuduh lembaga survei sebagai tukang bohong. Kedua pandangan berseberangan ini adalah produk dari informasi yang tersedia di media sosial, yang disuplai oleh elit-elit politik pada masing-masing kubu tersebut. Namun, hanya sedikit masyarakat yang melihat laporan dari lembaga survei yang membuka dengan terang-benderang masalah metodologi hitung cepat.

\displaystyle \hat{p} = \frac{\displaystyle \sum_{h=1}^{H} \sum_{i=1}^{n_h} \frac{N_h}{n_h}y_{hi}}{\displaystyle \sum_{h=1}^{H} \sum_{i=1}^{n_h} \frac{N_h}{n_h}x_{hi}}

\displaystyle moe = 2 \times \sqrt{\frac{1}{\hat{X}^2} \sum_{h=1}^{H}\frac{N_h(N_h-n_h)}{n_h}\hat{var}_h} \times C

Persamaan di atas adalah persamaan yang dipakai dalam menghitung estimasi perolehan suara berdasarkan hitung cepat dan persentase akurasinya. Lembaga Hitung Cepat membuka juga tabel ringkasan pengambilan data yang dilakukan di 34 provinsi. Namun satu hal yang belum dilaporkan oleh lembaga survey, sumber pendanaannya. Di tengah ketidakpercayaan Hitung Cepat, muncullah seorang tokoh akademisi yang menantang juragan lembaga survey. Sebelumnya, hanya tokoh-tokoh nonakademisi yang melontarkan ketidakpuasan terhadap lembaga survei. Dr. Ronnie Rusli, dosen Universitas Indonesia melayangkan argumen berdasarkan pengambilan jumlah sampel untuk Hitung Cepat.

Dr. Ronnie Rusli membawa argumen kontra-Hitung Cepat melalui rumusan yang ditulisnya di Twitter. Belakangan ini saya baru sadar melihat video paparan Dr. Ronnie di depan Bawaslu, ternyata rumus yang salah ini juga yang menjadi acuan testimoni beliau di depan Bawaslu. Saya telah menulis tentang kesalahan persamaan yang dipaparkan di Twitter (baca: Deciphering the Tweet: Kesalahan Rumus dan Syarat Quick Count). Kesalahan ini rupanya tidak hanya luput dari ribuan masyarakat yang mencuit ulang persamaan ini, tetapi juga tidak disadari oleh mereka yang berperkara di hadapan Bawaslu. Ironis, masyarakat Indonesia yang sudah menerima pelajaran statistika sejak SMP, maupun aljabar sejak SMP, tidak dapat menyadari kesalahan rumus yang sangat mendasar yang berulang kembali dilakukan oleh Dr. Ronnie, bahkan di depan Bawaslu (lihat juga: Statistika 101: Ukuran Sampel untuk Data Proporsi). Kebenaran matematik dapat disepelekan demi kepentingan politik, Indonesia ada dalam darurat matematika.

Margin of Error disampaikan 0.02% sementara seharusnya dapat digunakan rumus ini:

\displaystyle MoE = \bigg(\frac{50\%}{\sqrt{n}}\bigg) 2.58

Substansi Ketidakpercayaan Kepada Hitung Cepat

Skeptisme terhadap Hitung Cepat bukannya tidak berdasar, berdasarkan teori statistika menggunakan Central Limit Theorem, seperti yang disampaikan oleh Dr. Ronnie, untuk mendapatkan sampel acak yang mencapai tingkat kesalahan tertentu, dapat digunakan rumus:

\displaystyle MoE = \frac{S_{\hat{p}}}{\sqrt{n}}Z_{99\%}

Rumus ini jika dimasukkan dengan nilai yang tepat akan menghasilkan 16ribu TPS untuk menghasilkan tingkat kesalahan 1 persen. Terlihat dari laporan lembaga survey, sepertinya pemilihan jumlah sampel tidak berdasarkan rumus di atas namun berdasarkan pengalaman Hitung Cepat sebelumnya. Untuk membuktikan kesahihan jumlah sampel lembaga survey dapat digunakan pendekatan empiris untuk mengambil kesimpulan.

Untuk menguji jumlah pengambilan sampel 2000 sampel, saya membuat program Stratified Random Sampling berdasarkan data dari KawalPemilu, persamaan estimasi proporsi dan variance berdasarkan laporan dari SMRC. Data mentah hasil sampel acak yang saya buat dapat dilihat pada GitHub, program tersedia pada GitHub kawal-pemilu-data. Program ini adalah usaha perbaikkan dari Penulis setelah masukan dari @RajaGuguk14. Sudah terdapat data mentah dari masing-masing TPS yang dapat dicek-ulang dan dibandingkan dengan berbagai sumber, tautan ke KawalPemilu juga diberikan. Berikut adalah tabel dengan jumlah sampel 2000.

01 SAMPLE 02 SAMPLE 01 KPU 02 KPU MOE (99%) PerbedaanSuara
55,36% 44,64% 55,50% 44,50% 1,20% -0,14%
54,88% 45,12% 55,50% 44,50% 1,34% -0,62%
54,86% 45,14% 55,50% 44,50% 1,40% -0,64%
55,01% 44,99% 55,50% 44,50% 1,43% -0,49%
54,86% 45,14% 55,50% 44,50% 1,45% -0,64%
54,87% 45,13% 55,50% 44,50% 1,47% -0,63%
54,98% 45,02% 55,50% 44,50% 1,48% -0,52%
55,12% 44,88% 55,50% 44,50% 1,48% -0,38%
55,23% 44,77% 55,50% 44,50% 1,49% -0,27%
55,23% 44,77% 55,50% 44,50% 1,49% -0,27%

Hasil ini tentu tidak sesuai dengan persamaan margin of error sebelumnya, di mana untuk mencapai tingkat kesalahan sebesar 1% dibutuhkan setidaknya 16000 TPS sampel. Seperti program saya sebelumnya, saya juga memasukkan sampel 1000 TPS dan menghasilkan tabulasi berdasarkan masukkan dari Dr. @saiful_mujani

01 SAMPLE 02 SAMPLE 01 KPU 02 KPU MOE (99%) Perbedaan Suara
54,68% 45,32% 55,50% 44,50% 1,80% -0,82%
54,52% 45,48% 55,50% 44,50% 1,89% -0,98%
54,64% 45,36% 55,50% 44,50% 1,97% -0,86%
54,79% 45,21% 55,50% 44,50% 2,02% -0,71%
54,74% 45,26% 55,50% 44,50% 2,05% -0,76%
54,83% 45,17% 55,50% 44,50% 2,07% -0,67%
54,95% 45,05% 55,50% 44,50% 2,08% -0,55%
55,16% 44,84% 55,50% 44,50% 2,09% -0,34%
55,25% 44,75% 55,50% 44,50% 2,10% -0,25%
55,24% 44,76% 55,50% 44,50% 2,11% -0,26%

Program ini belum sempurna dan masih ada kemungkinan kesalahan, namun bukti empiris berdasarkan hitungan dan dikonfirmasi oleh pengumuman KPU juga bahwa metodologi Hitung Cepat dengan Stratified Random Sampling dapat memprediksi hasil pemungutan suara dengan cukup akurat.

Kesimpulan

Kisruh berdasarkan Hitung Cepat ini seharusnya tidak perlu dibakar atau dijadikan bahan penggiringan opini dari kedua kubu. Deklarasi kemenangan berdasarkan Hitung Cepat maupun ketidakpercayaan penuh terhadap Hitung Cepat sangat rentan menghasilkan konflik horizontal. Di tengah kristalisasi, akademisi Dr. Ronnie Rusli menunjukkan rumus pengambilan sampel yang keliru, bahkan perhitungan margin of error yang keliru itu juga disebutkan di hadapan sidang Bawaslu (menit 10:35 – 11:12). Seharusnya seorang akademisi mampu memberikan informasi yang mencerahkan berdasarkan ilmunya. Berdasarkan uji coba simulasi Hitung Cepat dengan Stratified Random Sampling untuk menguji argumen Dr. Ronnie Rusli, hasil menunjukkan bahwa jumlah sampel sebesar 2000 TPS ataupun 1000 TPS sudah dapat mengestimasi hasil pemungutan suara dengan cukup akurat.

Kategori
Opinion Statistics

Deciphering the Tweet: Kesalahan Rumus dan Syarat Quick Count

Tidak bosan saya menulis artikel tentang tweet ini, karena sepertinya belum ada jawaban dan klarifikasi. Mari kita bedah kembali tweet dari Dr. Ronnie Higuchi Rusli, dosen program pascasarjana Universitas Indonesia. Pembedahan ini dilakukan untuk menguji pernyataan Dr. Ronnie Rusli tentang kesahihan Quick Count.

twit2

Dr. Ronnie Higuchi Rusli juga menuliskan syarat Quick Count sebagai berikut:

SyaratQuickCount

Pembahasan Tujuh Statement Dr. Ronnie

Ada delapan hal yang disampaikan pada link Tweet di atas yaitu terdiri dari:

  1. Dua buah persamaan, satu persamaan untuk Margin of Error dan satu lagi persamaan jumlah sampel TPS
  2. Lima pernyataan tentang masing-masing variabel untuk mencapai syarat Quick Count yang benar
  3. Satu grafik perpotongan 2 kurva distribusi normal

Saya akan mengupas ketujuh hal di atas, kecuali grafik, di mana grafik kurang jelas sumbu X dan Y nya menyebabkan grafik tersebut menjadi sulit dimengerti.

Persamaan Jumlah Sampel TPS

Persamaan jumlah sampel TPS ini sudah saya bahas sebelumnya di Statistika 101: Ukuran Sampel untuk Data Proporsi, di mana saya membahas kesalahan dari persamaan ini. Namun sekali lagi kita anggap persamaan Dr. Ronnie benar sehingga kita dapat menggunakan persamaan:

\displaystyle n_{tps} = \frac{p(1-p)}{MoE/(Z_{99\%})^2} + \frac{p(p-1)}{N}

Persamaan Margin of Error

Persamaan Margin of Error yang disampaikan adalah persamaan dasar untuk menghitung Margin of Error berdasarkan Confidence Level dan Standard Deviation:

\displaystyle MoE = \bigg[\frac{S_D}{\sqrt{n_{tps}}}\bigg]Z_{99\%}

Kelima Pernyataan Syarat Quick Count

Standard Deviasi wajib 1 persen
Margin of Error (MoE) 0,02-0,03%
Nilai Koefisien Z_{99\%} harus terpenuhi
Probabilitas masing-masing sama 50%
Jumlah sampel TPS yang dipakai tepat

Mari kita uji persamaan kedua (Margin of Error) dengan kalimat pertama dan kedua di pernyataan syarat Quick Count yang dijabarkan oleh Dr. Ronnie:

\displaystyle MoE = \bigg[\frac{S_D}{\sqrt{n_{sd}}}\bigg]Z_{99\%}

Masukkan margin of error 0.02%, standard deviasi 1% dan Z_{99\%} = 2.58 harus terpenuhi.

\displaystyle 0.02\% = \bigg[\frac{1\%}{\sqrt{n_{sd}}}\bigg]2.58

\displaystyle n_{tps} = \bigg(\frac{1\%}{0.02\%}*2.58\bigg)^2 = 16641

Mari kita uji persamaan pertama dengan variabel yang sama, seharusnya kedua persamaan menghasilkan nilai yang sama

\displaystyle n_{tps} = \frac{p(1-p)}{MoE/(Z_{99\%})^2} + \frac{p(p-1)}{N}

\displaystyle n_{tps} = \frac{0.25}{0.0002/(2.58)^2} + \frac{(-0.25)}{809497} = 8320.5

Terlihat jelas hasil jumlah TPS di persamaan pertama dan persamaan kedua berbeda. Hal ini patut dipertanyakan, seharusnya persamaan pertama dan kedua menghasilkan nilai yang sama. Untuk pembanding dapat dilihat penggunaan persamaan yang saya turunkan di Statistika 101: Ukuran Sampel untuk Data Proporsi:

\displaystyle n_{tps} = \frac{z^2\hat{p}(1-\hat{p})}{e^2}

Persamaan ini dapat disebut juga persamaan Cochran.

\displaystyle n_{tps} = \frac{2.58^2(0.5)(0.5)}{0.01^2} = 16641

Mengetahui bahwa standard deviasi dari sebuah data proporsi sebagai berikut:

\displaystyle \sigma = \sqrt{pq} = \sqrt{0.5(0.5)} = 0.5

Maka dapat kembali dimasukkan kepada persamaan MOE:

\displaystyle 0.01\% = \bigg(\frac{50\%}{n_{tps}}\bigg)Z_{99\%}

\displaystyle n_{tps} = \bigg(\frac{50\%}{1\%}*2.58\bigg)^2 = 16641

Jelas terlihat bahwa persamaan dari Dr. Ronnie salah, karena kedua persamaan tersebut tidak menghasilkan nilai yang sama.

Kesalahan Perlu Diklarifikasi

Kesalahan pertama yang sudah saya bahas adalah kesalahan rumus, di mana harusnya hasil penurunan rumus jumlah sampel TPS adalah

\displaystyle n_{tps} = \frac{z^2\hat{p}(1-\hat{p})}{e^2}

Kesalahan kedua yang nampak pada pernyataan Dr. Ronnie adalah standard deviasi wajib 1% dan probabilitas masing-masing adalah 50%. Keduanya tidak kompatibel di mana jika kita memasukkan nilai probabilitas 50%, nilai standard deviasi adalah:

\sigma = \sqrt{\hat{p}\hat{q}} = \sqrt{(50\%)(1-50\%)} = 50\%

Dengan artikel ini, sekali lagi saya mohon kepada Dr. Ronnie Rusli untuk mengklarifikasi persamaan dan syarat yang dituliskan di depan khalayak umum agar tidak ada misinformasi.

Bagi Anda yang membaca artikel ini, mohon sampaikan dan mention Dr. Ronnie mengenai masalah ini, semoga beliau berkenan untuk memperbaiki dan memberikan penjelasan kepada masyarakat tentang syarat Quick Count yang benar.

Kategori
Opinion

Lagi, Salah Rumus

Kelanjutan dari beberapa artikel belakang yang sudah saya buat mengenai statistika, terutama tentang pengambilan jumlah sampel dan uji coba Stratified Random Sampling dengan menggunakan bahasa pemrograman Python. Saya berharap ada salah satu yang dapat sampai ke Dr. Ronnie Rusli agar beliau dapat memperbaiki kesalahan di rumus nya. Kembali beliau memposting rumus ini:

twit2
Gambar 1. Tweet Dr. Ronnie Rusli mengenai pengambilan jumlah sampel Quick Count

Penggunaan Rumus Dr. Ronnie

Melihat sekilas rumus Dr. Ronnie, terlihat janggal, saya akan menjabarkan, jika saya memasukkan masing-masing variabel sesuai dengan kondisi kenyataan jumlah TPS di Indonesia dan Margin of Error yang diclaim telah dicapai oleh salah satu lembaga survey, yakni 1%.

n_{tps} adalah jumlah sampel yang dibutuhkan
p adalah estimasi persentase pasangan presiden wakil presiden
MoE adalah margin of error yang diinginkan
N adalah jumlah populasi TPS

Penjelasan ini juga dielaborasi sebelumnya oleh tweet Dr. Ronnie Rusli pada Gambar 2.

Capture
Gambar 2. Tweet Dr. Ronnie tentang jumlah sampel Quick Count dan penjelasan variabelnya

Memasukkan rumus di atas dengan nilai-nilai yang kita ketahui maka kita dapat menghitung sendiri jumlah TPS yang diperlukan berdasarkan Margin of Error (1%) dan jumlah TPS populasi (809.497). Asumsi sebelum dilakukan pemilihan adalah peluang masing-masing pasangan adalah sama, yakni 50%.

Rumus yang digunakan oleh Dr. Ronnie Rusli adalah n = [p(1-p)]/[(MoE)/(z99)^2)] + [p(p-1)/N]

Atau jika saya tuliskan dengan LaTeX agar lebih mudah terlihat dalam bentuk pecahan:

\displaystyle n_{tps} = \frac{p(1-p)}{\displaystyle \frac{MoE}{(z_{99\%})^2}} + \frac{p(p-1)}{N}

Masukkan variabel-variabel di atas, maka hasilnya akan menjadi

\displaystyle n_{tps} = \frac{0.5(1-0.5)}{\displaystyle \frac{0.01}{2.58^2}} + \frac{0.5(0.5-1)}{809497} = 166.41 + (-3.08*10^{-7}) \approx 166

Jika Anda tidak percaya dengan hitungan saya, sila coba dengan kalkulator Google, langsung masukkan nilai p, MoE, z, dan N pada rumus langsung dari Dr. Ronnie:

[0.5(1-0.5)]/[(0.01)/(2.58)^2)] + [0.5(0.5-1)/809497]
calculator
Gambar 3. Hasil perhitungan dengan kalkulator sesuai dengan rumus Dr. Ronnie

Rumus Jumlah Sampel Berdasarkan Penurunan Rumus

Semenjak SMP, SMA, maupun memasuki bangku kuliah, saya sangat senang dalam menurunkan rumus. Penurunan rumus memerlukan ketelitian, dan dalam matematika, ketelitian sangat penting. Hobby penurunan rumus ini membuat saya menjadi tertarik untuk menurunkan rumus berdasarkan nilai standard error proporsi dan nilai MoE berdasarkan tabel Z. Penurunan rumus saya dapat dilihat pada artikel sebelumnya Statistika 101: Ukuran Sampel untuk Data Proporsi.

\displaystyle n_{tps} = \frac{N}{\displaystyle 1 + \frac{MOE^2(N-1)}{z^2(\hat{p}(1-\hat{p})}}

Persamaan di atas adalah hasil akhir yang saya temukan, jika memasukkan nilai pada persamaan di atas:

\displaystyle n_{tps} = \frac{809497}{\displaystyle 1 + \frac{(0.01)^2(809497-1)}{(2.58)^2(0.5(1-0.5)}} \approx 16306

Addendum dan Opini

Melihat kesalahan sederhana pada rumus Dr. Ronnie Rusli, dapat terlihat bahwa ribuan warganet tidak kritis dan masih mempercayai semua hal yang dikatakan ahli. Hampir tidak ada yang berhenti untuk berpikir, apakah ini benar? Padahal aljabar sudah dipelajari sejak SD ataupun SMP, dan Indonesia menerapkan wajib belajar sampai SMA. Ribuan cuitan ulang (re-tweet) maupun like namun mereka tidak melihat persamaan dan mengujinya langsung.

Namun perlu diperhatikan bahwa walaupun rumus yang di sampaikan oleh Dr. Ronnie salah, namun menurut persamaan yang saya turunkan berdasarkan random sampling dan nilai proporsi, saya dapatkan jumlah TPS sampel sebesar 16rb, jauh di atas nilai 3000 maupun 5000 yang dipakai oleh lembaga survey.

Kategori
Statistics Uncategorized

Statistika 101: Ukuran Sampel untuk Data Proporsi

Background

Saya menulis artikel singkat ini tentang ukuran sampel dan data proporsi karena melihat rumus yang beredar oleh Dr. Ronnie Rusli tentang rumus Quick Count, menurut saya rumus ini memiliki permasalahan, seperti yang saya jabarkan di artikel sebelumnya: https://josefmtd.com/2019/05/04/statistika-101-memberikan-pengertian-hasil-quick-count-pilpres-2019/

Rumus yang disampaikan Dr. Ronnie di-retweet oleh 2778 akun dan diberi like oleh 4808 akun. Menurut saya keanehan ini perlu dijawab dengan sebuah artikel dan klarifikasi, maka saya menulis kembali artikel ini.

Artikel ini juga bertujuan untuk merapihkan catatan statistik dari mata kuliah Probabilitas dan Stokastik yang saya terima pada tanggal 25 Maret 2015, diampu oleh Bapak M. Firdaus S. Lubis, S.T., M.T., sekaligus memberikan contoh kasus pada sebuah data proporsi yakni dalam aplikasi Quick Count.

Central Limit Theorem dan Distribusi Normal

Dasar dari Random Sampling adalah Central Limit Theorem. Central Limit Theorem adalah sebuah teori statistik di mana jika diambil banyak sampel dari sebuah populasi dengan variansi data yang berhingga (finite), mean dari sampel yang diambil pada populasi yang sama akan sesuai dengan mean dari populasi. Central Limit Theorem menunjukkan bahwa semakin bertambahnya jumlah sampel yang diambil secara acak, maka distribusi kemungkinan letak nilai mean dari sampel tersebut akan mengikuti distribusi normal.

normaldistribution
Gambar 1. Persebaran mean dengan distribusi normal

Asumsi distribusi normal dapat kita pakai ketika jumlah sampel yang kita ambil sudah mencapai batas nilai tertentu. Jika distribusi normal dapat dicapai dengan sampel yang kita ambil, maka persamaan-persamaan ini menjadi valid:

\displaystyle S_x = \frac{\sigma_x}{\sqrt{n}}

S_x adalah standard error dari mean
\sigma_x adalah standard deviasi
n adalah jumlah sampel (tps)

\displaystyle moe = z(S_x)

moe adalah margin of error
z adalah nilai dari tabel distribusi normal sesuai dengan Confidence Level
S_x adalah standard error dari mean

Data Proporsi

Data proporsi menunjukkan perbandingan atau persentase dari sebuah populasi dengan karakteristik tertentu. Data proporsi ini memiliki kemungkinan binomial, antara ya atau tidak. Hal ini dapat diaplikasikan juga pada polling maupun quick count karena data yang diambil merepresentasikan persentase dipilihnya suatu kandidat atau partai politik. Nilai p (proportion of interest dari populasi) ini yang ingin dihitung dengan cepat dengan sampel untuk mendapatkan estimasi nilai p: \hat{p}. Untuk mendapatkan simpangan baku (standard deviasi) dari data hasil proporsi ini, kita perlu mengetahui proporsi populasi sesungguhnya, hal ini tidak memungkinkan pada aplikasi Quick Count, umumnya rumus standard error dari proporsi yang dipakai:

\displaystyle S_{\hat{p}} = \sqrt{\frac{\hat{p}(1-\hat{p})}{n}}

S_{\hat{p}} adalah standard error dari estimasi proporsi hasil sampel
\hat{p} adalah estimasi proporsi hasil sampel

Proporsi adalah data dengan distribusi binomial, namun seiring dengan bertambahnya sampel acak yang diambil pada populasi yang sama, maka distribusi kemungkinan nilai \hat{p} akan menuju distribusi normal, sehingga rumus sebelumnya kembali dapat dipakai.

\displaystyle moe_{\hat{p}} = z(S_{\hat{p}})

moe_{\hat{p}} adalah margin of error dari estimasi proporsi hasil sampel

Untuk memastikan bahwa sampel yang kita ambil sudah cukup untuk mendekati distribusi normal terdapat beberapa rule of thumb sebagai berikut:

\displaystyle np > 5
\displaystyle nq > 5

Mengambil Jumlah Sampel

Mengetahui syarat-syarat untuk mencapai jumlah sampel yang tepat, yaitu data proporsi (data binomial) harus merupakan sampel acak dengan jumlah yang dapat memenuhi syarat np > 5 dan nq > 5. Setelah itu dapat digunakan persamaan yang merupakan substitusi nilai S_{\hat{p}} pada persamaan moe_{\hat{p}} dan mengubah fungsi untuk mendapatkan nilai n maka didapatkan rumus:

\displaystyle n = \frac{\displaystyle z^2 [\hat{p}(1-\hat{p})]}{\displaystyle moe_{\hat{p}}^2}

Menggunakan persamaan ini dapat dihasilkan jumlah sampel yang sesuai dengan dasar Central Limit Theorem bahwa sampel memiliki distribusi normal untuk random sampling, dan kaidah binomial dan pendekatannya menuju distribusi normal jika sampel memadai.

Efek Populasi Berhingga terhadap Jumlah Sampel

Rumus di atas adalah rumus yang didefinisikan untuk sebuah populasi yang tak berhingga (infinite), namun pada kondisi riil, atau dalam konteks Pemilu, jumlah populasi TPS adalah berhingga, sehingga terdapat faktor pengali koreksi terhadap populasi yang berhingga pada standard deviasi. Hal ini disebabkan oleh pilihan sampel TPS tidak boleh overlap dari keseluruhan TPS populasi, (sampling without replacement). Hal ini menyebabkan nilai proporsi yang diambil menjadi dependen terhadap jumlah sampel dan populasi, sehingga standard error dari sampling perlu dikalikan dengan faktor koreksi populasi:

\displaystyle S_{\hat{p} finite N} = S_{\hat{p}} \sqrt{\frac{N_{tps}-n_{tps}}{N_{tps}-1}}

S_{\hat{p} finite N} adalah standard error sampling pada populasi berhingga
N_{tps} adalah jumlah populasi
n_{tps} adalah jumlah sampel

Perlu digarisbawahi bahwa rumus ini hanya berlaku jika sampel yang diambil sudah melebihi 5% dari populasi, jika tidak, nilai faktor koreksi ini akan mendekati 1, sehingga pengaruhnya tidak lagi besar.

Menurunkan rumus untuk mencari jumlah TPS (n_{tps} dengan pengaruh jumlah populasi ini didapatkan:

\displaystyle MOE = z \sqrt{\frac{\hat{p}(1-\hat{p})}{n}}\sqrt{\frac{N-n}{N-1}}

Kuadratkan kedua sisi menjadi:

\displaystyle MOE^2 = z^2 \frac{\hat{p}(1-\hat{p})}{n} \frac{N-n}{N-1}

Lalu tukar posisi masing-masing variabel sehingga berbentuk:

\displaystyle \frac{N-n}{n} = \frac{(N-1)(MOE)^2}{\hat{p}(1-\hat{p})z^2}

Lalu ubah persamaan di atas sehingga dapat menghasilkan fungsi n_{tps}

\displaystyle n_{tps} = \frac{N}{\displaystyle 1 + \frac{MOE^2(N-1)}{z^2 \big( \hat{p}(1-\hat{p} \big)}}

Persamaan di atas adalah persamaan yang mungkin harusnya di unggah dan di cuit oleh Dr. Ronnie Higuchi Rusli.

EDIT: Penambahan penurunan rumus pencarian jumlah sampel TPS

Appendix: Postingan Dr. Ronnie Rusli

capture.png

Kategori
Opinion

Statistika 101: Memberikan Pengertian Hasil Quick Count Pilpres 2019

Disclaimer: Saya bukan orang praktisi statistik maupun orang yang memiliki background di bidang statistik. Saya adalah lulusan S1 Teknik Elektro yang pada kurikulumnya hanya mendapatkan mata kuliah “Probabilitas dan Stokastik” di mana topik statistik hanya dibahas oleh dosen pengampu saya dalam 3 kali pertemuan sebagai pengantar sebelum masuk materi kuliah tentang Probability Density Function

Terlalu Panjang; Tidak Membaca (TL;DR): Dugaan pak Ronnie Rusli terhadap kebutuhan sampel yang lebih banyak dari 2000 untuk mencapai margin of error serendah 1% memiliki dasar yang valid berdasarkan teori pengambilan sampel Random Sampling. Metode Stratified Random Sampling dengan 2000 sampel menghasilkan Margin of Error di bawah 1% menurut percobaan dari Penulis. Dengan Margin of Error 1% maupun 2% tetap terdapat jarak lebih besar dari 2 kali Margin of Error untuk kedua metode, sehingga tidak bisa dipungkiri bahwa Quick Count dapat memprediksikan bahwa pasangan ’01’ menang.

Background

Mengapa saya menulis blog post ini? Hal ini saya lakukan karena sebagai alumni Universitas Indonesia, terketuk hati dengan pernyataan pak Ronnie Rusli yang mempertanyakan sampling dari juragan survey Indonesia. Saya dan teman juga skeptis tentang kehebatan juragan survey yang mampu menghasilkan data cukup akurat dengan hanya 2000 data dengan margin of error yang sebesar 1%.

Ramai di jagat media sosial bahwa mereka harus dipertemukan dengan suasana debat akademis. Namun, menurut saya kurang tepat jika hal ini diselesaikan dengan debat akademis, permasalahan ini adalah permasalahan matematika dan dengan mudah dapat diselesaikan dengan perhitungan. Banyak alat yang dapat digunakan pada zaman ini seperti pemrograman Python untuk melakukan simulasi hitungan tanpa perlu menggunakan berlembar-lembar kertas dan pulpen.

Seperti kata banyak orang, “Show, don’t tell“, maka saya akan menunjukkan simulasi perhitungan Quick Count dengan metode Stratified Random Sampling dengan Python. Anda pun dapat mengikuti apa yang saya kerjakan karena saya akan membuka datanya di GitHub saya: https://github.com/josefmtd/kpu-data/

Margin of Error dari Random Sampling

Untuk penjelasan lebih lanjut tentang Margin of Error dan Standard Error, Anda dapat melihat di blog oleh dosen Teknik Industri UI: Bapak Komarudin https://staff.blog.ui.ac.id/komarudin74/mengotak-atik-statistik-quick-count-pilpres-2014/

Seperti dari coretan bapak Ronnie Rusli, margin of error didefinisikan dengan:

\displaystyle SE = \frac{SD}{\sqrt{n}}

\displaystyle MOE = z(SE)

MOE adalah Margin of Error, SD adalah Standard Deviation, n adalah jumlah sample, dan z adalah nilai critical yang diambil dari tabel F(z) sesuai dengan nilai confidence level yang kita inginkan. Untuk confidence level 99%, kita menggunakan nilai z = 2.58.

Untuk mencari sample size dari sebuah data pilihan biner seperti Pemilu yakni antara 01 dan 02, maka dapat digunakan rumus Standard Error khusus untuk proporsi yakni:

\displaystyle SE_p = \sqrt{\frac{p(1-p)}{n}}

dengan menggabungkan rumus di atas dengan rumus MOE dan mengubahnya untuk mencari jumlah sampel (n) maka didapatkan persamaan:

\displaystyle n = \frac{z^2(p(1-p))}{(MOE)^2}

p adalah persentase suara 01 dan (1-p) merepresentasikan suara 02, karena sebelum sampling kita tidak bisa menebak persentase suara, kita dapat masukkan nilai 50% untuk p dan 50% untuk (1-p).

\displaystyle n = \frac{ (2.58)^2 (50\%) (50\%) }{(1\%)^2} = 16641 samples

\displaystyle n = \frac{ (2.58)^2 (50\%) (50\%) }{(0.5\%)^2} = 66564 samples

Dengan persamaan ini kita dapat membuktikan secara teori bahwa untuk menghasilkan data dengan Margin of Error sebesar 1% perlu 16641 sampel dan 0.5% perlu 66564 sampel. Sementara Quick Count Indikator dengan sampel 2975 disebut-sebut dapat menghasilkan Margin of Error sebesar 0.63%, dan Quick Count SMRC dengan sampel 5907 TPS dapat menghasilkan Margin of Error sebesar 0.5%. Hal ini tentu berkontradiksi dengan persamaan yang saya tunjukkan di atas. Saya dan teman saya, setuju dengan pak Ronnie Rusli yang skeptis dengan nilai sampel yang sangat sedikit dapat menghasilkan Margin of Error yang sangat rendah.

Namun, perlu digarisbawahi juga sikap skeptis ini berdasarkan teori statistik Random Sampling. Sikap skeptis ini bukan karena pendirian partisan, namun karena dasar ilmiah. Teman sayapun berbicara: “Always question your results“, maka saya mencoba melakukan Random Sampling dengan Python untuk membuktikan apakah benar lembaga survey dapat menghasilkan margin of error serendah itu dengan sampel 2000 TPS?

UPDATE 05 May: Bapak Doktor Ronnie Rusli mengeluarkan rumus yang digunakan untuk mendapatkan sampel:

\displaystyle n_{tps} = \frac{[p(1-p)]}{\displaystyle \frac{MOE}{z_{99\%}^2} + \frac{p(1-p)}{N}}

\displaystyle n_{tps} = \frac{25\%}{\displaystyle \frac{1\%}{2.58^2} + \frac{25\%}{809000}} = 166

Capture.PNG

Hasilnya malah melebihi jumlah TPS, sepertinya ada yang salah dengan rumus pak Doktor Ronnie Rusli, saya tetap akan mengambil dari rumus yang saya cantumkan, berasal dari catatan statistik saya dan juga sama dengan yang ditulis oleh bapak dosen Komarudin.  Terdapat typo dalam input kalkulator sehingga  hasil menjadi salah, persamaan Dr. Ronnie menghasilkan nilai 166 TPS

Menggunakan nilai sampel TPS dengan persamaan oleh Dr. Ronnie, hasilnya adalah 166 TPS, hasil ini malah lebih rendah dari 2000 TPS. Pasti ada kesalahan di persamaan

Intermezzo: Distribusi Suara Nasional

Keskeptisan saya tidak hanya berada pada jumlah sampel, tapi juga terhadap distribusi suara tiap-tiap TPS per provinsi, apakah datanya terdistribusi normal? Seperti yang sudah dibahas di blog bapak dosen FTUI di atas, penggunaan rumus-rumus dalam Quick Count dengan Random Sampling, menggunakan asumsi bahwa data terdistribusi normal, dengan Pilpres yang terlalu terpolarisasi seperti ini, apakah benar Pilpres menghasilkan data distribusi Normal? Saya ragu, sehingga saya mengambil data untuk mencari tahu.

Keraguan saya, saya luapkan dengan code sederhana dalam Python seperti ini (dapat diakses di github.com/josefmtd/kpu-data/distributionPlot.py):

Tekan Spoiler ini untuk menunjukkan code distributionPlot.py
# -*- coding: utf-8 -*-
"""
DistributionPlot.py
Created on Fri May 3 20:35:56 2019

@author: JosefStevanus
"""

import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

directory = 'C:/Users/JosefStevanus/Documents/GitHub/kpu-data/'
data = {}
cleanNolSatuNasional = []
cleanNolDuaNasional = []
cleanTotalSuaraNasional = []

for filename in os.listdir(directory):
if filename.endswith(".csv"):
dataName = filename[:-4]
data[dataName] = pd.read_csv(filename)

nolSatu = data[dataName]["01 KPU"] 
nolDua = data[dataName]["02 KPU"]
cleanNolSatu = []
cleanNolDua = []

for x in range(len(nolSatu)):
if nolSatu[x] == 0 and nolDua[x] == 0:
continue
else:
cleanNolSatu.append(nolSatu[x])
cleanNolDua.append(nolDua[x])

cleanTotalSuara = np.add(cleanNolSatu, cleanNolDua)

cleanNolSatuNasional += cleanNolSatu
cleanNolDuaNasional += cleanNolDua
cleanTotalSuaraNasional += cleanTotalSuara.tolist() 

percentageNolSatu = np.divide(cleanNolSatu, cleanTotalSuara)*100
percentageNolSatuSeries = pd.Series(percentageNolSatu,
name = "Distribusi Persentase Suara 01 di "+dataName )

plotDistribusi, seaborn = plt.subplots()
sns.distplot(percentageNolSatuSeries, kde=False, bins=100, ax=seaborn)
plotDistribusi.savefig('C:/Users/JosefStevanus/Documents/GitHub/kpu-data/'+dataName+".png")
continue
else:
continue

percentageNolSatuNasional = np.divide(cleanNolSatuNasional, cleanTotalSuaraNasional)*100
percentageNolSatuNasionalSeries = pd.Series(percentageNolSatuNasional,
name = "Distribusi Persentase Suara 01 Nasional")

plotDistribusiNasional, seabornNasional = plt.subplots()
sns.distplot(percentageNolSatuNasionalSeries, kde=False, bins=100, ax = seabornNasional)
plotDistribusiNasional.savefig("C:/Users/JosefStevanus/Documents/GitHub/kpu-data/Nasional.png")

 

Hasilnya saya mendapatkan distribusi suara 01 diseluruh TPS di Indonesia seperti pada Gambar 1. Grafik histogram pada Gambar 1 menunjukkan distribusi yang sama sekali tidak terlihat seperti distribusi normal. Hal ini dapat dimaklumkan karena banyaknya provinsi yang tidak memiliki distribusi normal, contohnya pada Gambar 2 yang menunjukkan distribusi persentase suara di provinsi yang sangat mengunggulkan salah satu pihak (01 atau 02), atau pada Gambar 3 dimana distribusi suara menunjukkan persebaran suara yang terpolarisasi, di mana ada dua nilai peak pada 01 maupun 02.

Nasional
Gambar 1. Distribusi Persentase Suara 01 di Seluruh TPS di Indonesia
heavilySkewed
Gambar 2. Distribusi Persentase Suara 01 di Seluruh TPS di Provinsi (atas kiri) Aceh, (atas kanan) Bali, (bawah kiri) NTT, (bawah kanan) Papua Barat
polarized.png
Gambar 3. Distribusi Persentase Suara 01 di Seluruh TPS di Provinsi (atas kiri) Sumatera Utara, (atas kanan) Maluku Utara, dan (bawah kiri) Kalimantan Barat

Data yang sangat tidak lazim ini menyebabkan saya semakin skeptis dengan metode Quick Count yang dilaksanakan, karena semakin skeptis, maka saya mulai menulis program singkat dengan Random Sampling dan Stratified Random Sampling.

Random Sampling

Rumus yang saya gunakan di awal adalah rumus untuk mencari jumlah sampel Random Sampling. maka program pertama yang saya buat adalah program Random Sampling menggunakan data sementara dari Situng KPU menggunakan program Python, data saya saya ambil oleh hasil crawling data oleh bapak Yohanda Mandala (https://twitter.com/jokidz90).  Data ini terakhir di update oleh beliau pada tanggal 3 Mei jam 08.06 pagi.

Tekan Spoiler ini untuk melihat code RandomSampling.py
# -*- coding: utf-8 -*-
"""
RandomSampling.py
Created on Sat May 4 09:45:12 2019

@author: DarwinHarianto
"""

import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import random

directory = 'C:/Users/JosefStevanus/Documents/GitHub/kpu-data/'
data = {}
cleanNolSatuNasional = []
cleanNolDuaNasional = []
cleanTotalSuaraNasional = []

for filename in os.listdir(directory):
if filename.endswith(".csv"):
dataName = filename[:-4]
data[dataName] = pd.read_csv(filename)

nolSatu = data[dataName]["01 KPU"] 
nolDua = data[dataName]["02 KPU"]
cleanNolSatu = []
cleanNolDua = []

for x in range(len(nolSatu)):
if nolSatu[x] == 0 and nolDua[x] == 0:
continue
else:
cleanNolSatu.append(nolSatu[x])
cleanNolDua.append(nolDua[x])

cleanTotalSuara = np.add(cleanNolSatu, cleanNolDua)

cleanNolSatuNasional += cleanNolSatu
cleanNolDuaNasional += cleanNolDua
cleanTotalSuaraNasional += cleanTotalSuara.tolist() 
continue
else:
continue

percentageNolSatuNasional = np.divide(cleanNolSatuNasional, cleanTotalSuaraNasional)*100
percentageNolSatuNasionalSeries = pd.Series(percentageNolSatuNasional,
name = "Distribusi Persentase Suara 01 Nasional")

plotDistribusiNasional, seabornNasional = plt.subplots()
sns.distplot(percentageNolSatuNasionalSeries, kde=False, bins=100, ax = seabornNasional)
plotDistribusiNasional.savefig("C:/Users/JosefStevanus/Documents/GitHub/kpu-data/Nasional.png")

randomSample = random.sample(range(len(cleanTotalSuaraNasional)), 2000)

nolSatuRandomSample = []
nolDuaRandomSample = []
totalSuaraRandomSample = []

for x in randomSample:
    nolSatuRandomSample.append(cleanNolSatuNasional[x])
    nolDuaRandomSample.append(cleanNolDuaNasional[x])
    totalSuaraRandomSample.append(cleanTotalSuaraNasional[x])

percentageNolSatuRandomSample = np.divide(nolSatuRandomSample, totalSuaraRandomSample)*100
percentageNolSatuRandomSampleSeries = pd.Series(percentageNolSatuRandomSample, 
                                                name = "Distribusi Persentase Suara 01 Random Sample")

meanNolSatu = np.sum(nolSatuRandomSample)/np.sum(totalSuaraRandomSample)*100
meanNolDua = 100 - meanNolSatu
standardError = np.std(percentageNolSatuRandomSample)/np.sqrt(len(randomSample))

meanNolSatuNasional = np.sum(cleanNolSatuNasional)/np.sum(cleanTotalSuaraNasional)*100
meanNolDuaNasional = 100 - meanNolSatuNasional
standardErrorNasional = np.std(percentageNolSatuNasional)/np.sqrt(len(cleanTotalSuaraNasional))

plotDistribusiNasionalRandomSample, ax = plt.subplots(2,1)
sns.distplot(percentageNolSatuRandomSampleSeries, kde=False, bins=100, ax = ax[0])
sns.distplot(percentageNolSatuNasionalSeries, kde=False, bins=100, ax = ax[1])
plotDistribusiNasionalRandomSample.suptitle('{:.2f}% vs {:.2f}% Real Count Sementara \n {:.2f}% vs {:.2f}% Random Sampling dengan MOE = +/-{:.2f}%'.format(meanNolSatuNasional, meanNolDuaNasional, meanNolSatu, meanNolDua, standardError*2.58))
plotDistribusiNasionalRandomSample.savefig('RandomSampling.png')

 

Dalam mengambil sampel random dari Data Seluruh TPS Nasional yang saya dapatkan, saya menggunakan fungsi random yang ada di Python. Saya cukup percaya bahwa komputer tidak memihak 01 maupun 02. Untuk meyakinkan Anda, saya juga menunjukkan distribusi sampel yang diambil oleh program dan dibandingkan dengan distribusi populasi (yakni dari Situng KPU). Selain itu program saya juga menghitung mean persentase 01 dan 02, dan mencari nilai standard error dan margin of error nya. Semua hasil ditunjukkan dalam 1 grafik yang menunjukkan distribusi dan nilai Random Sampling terhadap Real Count.

RandomSampling4
Gambar 4. Hasil Random Sampling 2000 TPS dari seluruh TPS di Indonesia sementara (456.135 TPS)

Karena menggunakan Python, saya dapat dengan bebas mengambil beberapa kali Random Sampling sesuka saya, dengan mengambil data yang berbeda-beda. Hasilnya dapat dilihat pada Gambar 5.

randomSamplingData.png
Gambar 5. Beberapa Hasil Random Sampling 2000 TPS

Gambar 5 memperkuat pernyataan bapak Ronnie Rusli bahwa 2000 TPS jelas-jelas tidak cukup untuk menghasilkan Margin of Error dibawah 1.5%, bisa saja saya minta program itu berjalan 1000 kali lagi, saya yakin hasilnya pasti tidak jauh berbeda dari 1.5%.

“Insanity is doing the same thing and expecting a different result”, kata Albert Einstein

Perlu digarisbawahi bahwa Quick Count dari berbagai lembaga survey ini menggunakan Stratified Clustered Random Sampling, di mana suara individu direpresentasikan dalam TPS, dan jumlah TPS yang diambil per provinsi disesuaikan dengan jumlah proporsi penduduknya, sehingga kembali saya mempertanyakan hasil Random Sampling ini dan membuat program Stratified Random Sampling

Stratified Random Sampling

Lembaga survey sudah membagikan laporan quick count mereka, di situ saya dapat melihat berapa jumlah TPS yang mereka pakai, dengan mengikuti proporsi yang mereka gunakan, saya mengambil sampel TPS berdasarkan proporsi jumlah TPS provinsi tersebut dibandingkan TPS seluruh Indonesia.

Mereka menuliskan rumus quick count untuk mendapatkan persentase nilai 01 atau 02 dan juga nilai margin of errornya. Berikut yang ditampilkan oleh lembaga survey tersebut:

\displaystyle \hat{p} = \frac{\displaystyle \sum_{h=1}^{H} \sum_{i=1}^{n_h} \frac{N_h}{n_h}y_{hi}}{\displaystyle \sum_{h=1}^{H} \sum_{i=1}^{n_h} \frac{N_h}{n_h}x_{hi}}

\displaystyle moe = 2(SE) = 2 \sqrt{\frac{1}{\hat{X}^2}\sum_{h=1}^{H} \frac{N_h(N_h - n_h)}{n_h} \hat{var_h}}

Kedua persamaan itu saya realisasikan dalam program Python sebagai berikut:

Tekan Spoiler ini untuk melihat code StratifiedRandomSampling.py
# -*- coding: utf-8 -*-
"""
StratifiedRandomSampling.py
Created on Sat May 4 09:45:12 2019

@author: JosefStevanus
"""

# -*- coding: utf-8 -*-
"""
Created on Fri May 3 20:35:56 2019

@author: JosefStevanus
"""

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import random

class dataPemilu:
def __init__(self, filename, dataSource, totalTPS, sampleSize):
self.totalTPS = totalTPS
self.sampleSize = sampleSize
self.nolSatu = []
self.nolDua = []
self.totalSuara = []
self.sampleNolSatu = []
self.sampleNolDua = []
self.sampleTotalSuara = []
self.nolSatuQuickCount = 0
self.nolDuaQuickCount = 0
self.totalSuaraQuickCount = 0
self.varianceQuickCount = 0
self.filename = filename
self.getRawData(dataSource)
self.cleanData()
self.getQuickCountData()

def getRawData(self, dataSource):
data = pd.read_csv(self.filename)
if dataSource == "KPU":
self.nolSatu = data["01 KPU"]
self.nolDua = data["02 KPU"]
elif dataSource == "KawalPemilu":
self.nolSatu = data ["01 KawalPemilu"]
self.nolDua = data ["02 KawalPemilu"]
else:
print("Source data does not exist")
self.totalSuara = np.add(self.nolSatu, self.nolDua)

def cleanData(self):
cleanNolSatu = []
cleanNolDua = []
for x in range (len(self.totalSuara)):
if self.nolSatu[x] == 0 and self.nolDua[x] == 0:
continue
else:
cleanNolSatu.append(self.nolSatu[x])
cleanNolDua.append(self.nolDua[x])

self.nolSatu = cleanNolSatu
self.nolDua = cleanNolDua
self.totalSuara = np.add(cleanNolSatu, cleanNolDua).tolist()

def randomSample(self):
listSample = random.sample(range(len(self.totalSuara)), self.sampleSize)
for x in listSample:
self.sampleNolSatu.append(self.nolSatu[x])
self.sampleNolDua.append(self.nolDua[x])
self.sampleTotalSuara.append(self.totalSuara[x])

def getQuickCountData(self):
self.randomSample()
self.nolSatuQuickCount = np.sum(self.sampleNolSatu)*self.totalTPS/self.sampleSize
self.nolDuaQuickCount = np.sum(self.sampleNolDua)*self.totalTPS/self.sampleSize
self.totalSuaraQuickCount = np.sum(self.sampleTotalSuara, dtype=np.float64)*self.totalTPS/self.sampleSize # needs 64 bit to prevent overflow

def getVariance(self, proporsi):
vhi = np.subtract(self.sampleNolSatu, np.multiply(proporsi, self.sampleTotalSuara))
vh = np.sum(vhi)/self.sampleSize
variance = np.sum(np.square(vhi-vh))/(self.sampleSize-1)
varianceQuickCount = variance*self.totalTPS*(self.totalTPS-self.sampleSize)/self.sampleSize
return varianceQuickCount

sampleSize = 2000

totalTPSAceh = 17389
totalTPSBali = 12386
totalTPSBanten = 33471
totalTPSBengkulu = 6165
totalTPSDaerahIstimewaYogyakarta = 11781
totalTPSDaerahKhususIbukotaJakarta = 29063
totalTPSGorontalo = 5866
totalTPSJambi = 11342
totalTPSJawaBarat = 70169
totalTPSJawaTengah = 86121
totalTPSJawaTimur = 67454
totalTPSKalimantanBarat = 10791
totalTPSKalimantanSelatan = 6722
totalTPSKalimantanTengah = 4780
totalTPSKalimantanTimur = 6780
totalTPSKalimantanUtara = 1512
totalTPSKepulauanBangka = 3597
totalTPSKepulauanRiau = 4659
totalTPSLampung = 20407
totalTPSMaluku = 2705
totalTPSMalukuUtara = 3805
totalTPSNusaTenggaraBarat = 10082
totalTPSNusaTenggaraTimur = 7656
totalTPSPapua = 1006
totalTPSPapuaBarat = 749
totalTPSRiau = 13174
totalTPSSulawesiBarat = 1857
totalTPSSulawesiSelatan = 14608
totalTPSSulawesiTengah = 3719
totalTPSSulawesiTenggara = 3710
totalTPSSulawesiUtara = 3986
totalTPSSumateraBarat = 13804
totalTPSSumateraSelatan = 19427
totalTPSSumateraUtara = 30883
totalTPSNasional = 809497

aceh = dataPemilu("Aceh.csv", "KPU", totalTPSAceh, int(1.95/100*sampleSize))
bali = dataPemilu("Bali.csv", "KPU", totalTPSBali, int(1.53/100*sampleSize))
banten = dataPemilu("Banten.csv", "KPU", totalTPSBanten, int(4.13/100*sampleSize))
bengkulu = dataPemilu("Bengkulu.csv", "KPU", totalTPSBengkulu, int(0.76/100*sampleSize))
daerahIstimewaYogyakarta = dataPemilu("DaerahIstimewaYogyakarta.csv", "KPU", totalTPSDaerahIstimewaYogyakarta, int(1.46/100*sampleSize))
daerahKhususIbukotaJakarta = dataPemilu("DaerahKhususIbukotaJakarta.csv", "KPU", totalTPSDaerahKhususIbukotaJakarta, int(3.58/100*sampleSize))
gorontalo = dataPemilu("Gorontalo.csv", "KPU", totalTPSGorontalo, int(0.42/100*sampleSize))
jambi = dataPemilu("Jambi.csv", "KPU", totalTPSJambi, int(1.40/100*sampleSize))
jawaBarat = dataPemilu("JawaBarat.csv", "KPU", totalTPSJawaBarat, int(17.05/100*sampleSize))
jawaTengah = dataPemilu("JawaTengah.csv", "KPU", totalTPSJawaTengah, int(14.25/100*sampleSize))
jawaTimur = dataPemilu("JawaTimur.csv", "KPU", totalTPSJawaTimur, int(16.06/100*sampleSize))
kalimantanBarat = dataPemilu("KalimantanBarat.csv", "KPU", totalTPSKalimantanBarat, int(2.04/100*sampleSize))
kalimantanSelatan = dataPemilu("KalimantanSelatan.csv", "KPU", totalTPSKalimantanSelatan, int(1.34/100*sampleSize))
kalimantanTengah = dataPemilu("KalimantanTengah.csv", "KPU", totalTPSKalimantanTengah, int(1.00/100*sampleSize))
kalimantanTimur = dataPemilu("KalimantanTimur.csv", "KPU", totalTPSKalimantanTimur, int(1.34/100*sampleSize))
kalimantanUtara = dataPemilu("KalimantanUtara.csv", "KPU", totalTPSKalimantanUtara, int(0.27/100*sampleSize))
kepulauanBangka = dataPemilu("KepulauanBangka.csv", "KPU", totalTPSKepulauanBangka, int(0.47/100*sampleSize))
kepulauanRiau = dataPemilu("KepulauanRiau.csv", "KPU", totalTPSKepulauanRiau, int(0.67/100*sampleSize))
lampung = dataPemilu("Lampung.csv", "KPU", totalTPSLampung, int(3.24/100*sampleSize))
maluku = dataPemilu("Maluku.csv", "KPU", totalTPSMaluku, int(0.68/100*sampleSize))
malukuUtara = dataPemilu("MalukuUtara.csv", "KPU", totalTPSMalukuUtara, int(0.47/100*sampleSize))
nusaTenggaraBarat = dataPemilu("NusaTenggaraBarat.csv", "KPU", totalTPSNusaTenggaraBarat, int(1.98/100*sampleSize))
nusaTenggaraTimur = dataPemilu("NusaTenggaraTimur.csv", "KPU", totalTPSNusaTenggaraTimur, int(1.85/100*sampleSize))
papua = dataPemilu("Papua.csv", "KPU", totalTPSPapua, int(1.88/100*sampleSize))
papuaBarat = dataPemilu("PapuaBarat.csv", "KPU", totalTPSPapuaBarat, int(0.48/100*sampleSize))
riau = dataPemilu("Riau.csv", "KPU", totalTPSRiau, int(2.18/100*sampleSize))
sulawesiBarat = dataPemilu("SulawesiBarat.csv", "KPU", totalTPSSulawesiBarat, int(0.48/100*sampleSize))
sulawesiSelatan = dataPemilu("SulawesiSelatan.csv", "KPU", totalTPSSulawesiSelatan, int(3.25/100*sampleSize))
sulawesiTengah = dataPemilu("SulawesiTengah.csv", "KPU", totalTPSSulawesiTengah, int(1.13/100*sampleSize))
sulawesiTenggara = dataPemilu("SulawesiTenggara.csv", "KPU", totalTPSSulawesiTenggara, int(0.97/100*sampleSize))
sulawesiUtara = dataPemilu("SulawesiUtara.csv", "KPU", totalTPSSulawesiUtara, int(0.97/100*sampleSize))
sumateraBarat = dataPemilu("SumateraBarat.csv", "KPU", totalTPSSumateraBarat, int(2.06/100*sampleSize))
sumateraSelatan = dataPemilu("SumateraSelatan.csv", "KPU", totalTPSSumateraSelatan, int(3.13/100*sampleSize))
sumateraUtara = dataPemilu("SumateraUtara.csv", "KPU", totalTPSSumateraUtara, int(5.27/100*sampleSize))

## Real Count KPU

nolSatuNasional = aceh.nolSatu + bali.nolSatu + banten.nolSatu + bengkulu.nolSatu + daerahIstimewaYogyakarta.nolSatu + daerahKhususIbukotaJakarta.nolSatu + gorontalo.nolSatu + jambi.nolSatu + jawaBarat.nolSatu + jawaTengah.nolSatu + jawaTimur.nolSatu + kalimantanBarat.nolSatu + kalimantanSelatan.nolSatu + kalimantanTengah.nolSatu + kalimantanTimur.nolSatu + kalimantanUtara.nolSatu + kepulauanBangka.nolSatu + kepulauanRiau.nolSatu + lampung.nolSatu + maluku.nolSatu + malukuUtara.nolSatu + nusaTenggaraBarat.nolSatu + nusaTenggaraTimur.nolSatu + papua.nolSatu + papuaBarat.nolSatu + riau.nolSatu + sulawesiBarat.nolSatu + sulawesiSelatan.nolSatu + sulawesiTengah.nolSatu + sulawesiTenggara.nolSatu + sulawesiUtara.nolSatu + sumateraBarat.nolSatu + sumateraSelatan.nolSatu + sumateraUtara.nolSatu
nolDuaNasional = aceh.nolDua + bali.nolDua + banten.nolDua + bengkulu.nolDua + daerahIstimewaYogyakarta.nolDua + daerahKhususIbukotaJakarta.nolDua + gorontalo.nolDua + jambi.nolDua + jawaBarat.nolDua + jawaTengah.nolDua + jawaTimur.nolDua + kalimantanBarat.nolDua + kalimantanSelatan.nolDua + kalimantanTengah.nolDua + kalimantanTimur.nolDua + kalimantanUtara.nolDua + kepulauanBangka.nolDua + kepulauanRiau.nolDua + lampung.nolDua + maluku.nolDua + malukuUtara.nolDua + nusaTenggaraBarat.nolDua + nusaTenggaraTimur.nolDua + papua.nolDua + papuaBarat.nolDua + riau.nolDua + sulawesiBarat.nolDua + sulawesiSelatan.nolDua + sulawesiTengah.nolDua + sulawesiTenggara.nolDua + sulawesiUtara.nolDua + sumateraBarat.nolDua + sumateraSelatan.nolDua + sumateraUtara.nolDua
totalSuaraNasional = aceh.totalSuara + bali.totalSuara + banten.totalSuara + bengkulu.totalSuara + daerahIstimewaYogyakarta.totalSuara + daerahKhususIbukotaJakarta.totalSuara + gorontalo.totalSuara + jambi.totalSuara + jawaBarat.totalSuara + jawaTengah.totalSuara + jawaTimur.totalSuara + kalimantanBarat.totalSuara + kalimantanSelatan.totalSuara + kalimantanTengah.totalSuara + kalimantanTimur.totalSuara + kalimantanUtara.totalSuara + kepulauanBangka.totalSuara + kepulauanRiau.totalSuara + lampung.totalSuara + maluku.totalSuara + malukuUtara.totalSuara + nusaTenggaraBarat.totalSuara + nusaTenggaraTimur.totalSuara + papua.totalSuara + papuaBarat.totalSuara + riau.totalSuara + sulawesiBarat.totalSuara + sulawesiSelatan.totalSuara + sulawesiTengah.totalSuara + sulawesiTenggara.totalSuara + sulawesiUtara.totalSuara + sumateraBarat.totalSuara + sumateraSelatan.totalSuara + sumateraUtara.totalSuara

persentaseNolSatuNasional = np.divide(nolSatuNasional, totalSuaraNasional)*100

meanNolSatuNasional = np.sum(nolSatuNasional)/np.sum(totalSuaraNasional)*100
meanNolDuaNasional = 100 - meanNolSatuNasional

## Stratified Random Sampling

nolSatuQuickCountNasional = aceh.nolSatuQuickCount + bali.nolSatuQuickCount + banten.nolSatuQuickCount + bengkulu.nolSatuQuickCount + daerahIstimewaYogyakarta.nolSatuQuickCount + daerahKhususIbukotaJakarta.nolSatuQuickCount + gorontalo.nolSatuQuickCount + jambi.nolSatuQuickCount + jawaBarat.nolSatuQuickCount + jawaTengah.nolSatuQuickCount + jawaTimur.nolSatuQuickCount + kalimantanBarat.nolSatuQuickCount + kalimantanSelatan.nolSatuQuickCount + kalimantanTengah.nolSatuQuickCount + kalimantanTimur.nolSatuQuickCount + kalimantanUtara.nolSatuQuickCount + kepulauanBangka.nolSatuQuickCount + kepulauanRiau.nolSatuQuickCount + lampung.nolSatuQuickCount + maluku.nolSatuQuickCount + malukuUtara.nolSatuQuickCount + nusaTenggaraBarat.nolSatuQuickCount + nusaTenggaraTimur.nolSatuQuickCount + papua.nolSatuQuickCount + papuaBarat.nolSatuQuickCount + riau.nolSatuQuickCount + sulawesiBarat.nolSatuQuickCount + sulawesiSelatan.nolSatuQuickCount + sulawesiTengah.nolSatuQuickCount + sulawesiTenggara.nolSatuQuickCount + sulawesiUtara.nolSatuQuickCount + sumateraBarat.nolSatuQuickCount + sumateraSelatan.nolSatuQuickCount + sumateraUtara.nolSatuQuickCount
nolDuaQuickCountNasional = aceh.nolDuaQuickCount + bali.nolDuaQuickCount + banten.nolDuaQuickCount + bengkulu.nolDuaQuickCount + daerahIstimewaYogyakarta.nolDuaQuickCount + daerahKhususIbukotaJakarta.nolDuaQuickCount + gorontalo.nolDuaQuickCount + jambi.nolDuaQuickCount + jawaBarat.nolDuaQuickCount + jawaTengah.nolDuaQuickCount + jawaTimur.nolDuaQuickCount + kalimantanBarat.nolDuaQuickCount + kalimantanSelatan.nolDuaQuickCount + kalimantanTengah.nolDuaQuickCount + kalimantanTimur.nolDuaQuickCount + kalimantanUtara.nolDuaQuickCount + kepulauanBangka.nolDuaQuickCount + kepulauanRiau.nolDuaQuickCount + lampung.nolDuaQuickCount + maluku.nolDuaQuickCount + malukuUtara.nolDuaQuickCount + nusaTenggaraBarat.nolDuaQuickCount + nusaTenggaraTimur.nolDuaQuickCount + papua.nolDuaQuickCount + papuaBarat.nolDuaQuickCount + riau.nolDuaQuickCount + sulawesiBarat.nolDuaQuickCount + sulawesiSelatan.nolDuaQuickCount + sulawesiTengah.nolDuaQuickCount + sulawesiTenggara.nolDuaQuickCount + sulawesiUtara.nolDuaQuickCount + sumateraBarat.nolDuaQuickCount + sumateraSelatan.nolDuaQuickCount + sumateraUtara.nolDuaQuickCount
totalSuaraQuickCountNasional = aceh.totalSuaraQuickCount + bali.totalSuaraQuickCount + banten.totalSuaraQuickCount + bengkulu.totalSuaraQuickCount + daerahIstimewaYogyakarta.totalSuaraQuickCount + daerahKhususIbukotaJakarta.totalSuaraQuickCount + gorontalo.totalSuaraQuickCount + jambi.totalSuaraQuickCount + jawaBarat.totalSuaraQuickCount + jawaTengah.totalSuaraQuickCount + jawaTimur.totalSuaraQuickCount + kalimantanBarat.totalSuaraQuickCount + kalimantanSelatan.totalSuaraQuickCount + kalimantanTengah.totalSuaraQuickCount + kalimantanTimur.totalSuaraQuickCount + kalimantanUtara.totalSuaraQuickCount + kepulauanBangka.totalSuaraQuickCount + kepulauanRiau.totalSuaraQuickCount + lampung.totalSuaraQuickCount + maluku.totalSuaraQuickCount + malukuUtara.totalSuaraQuickCount + nusaTenggaraBarat.totalSuaraQuickCount + nusaTenggaraTimur.totalSuaraQuickCount + papua.totalSuaraQuickCount + papuaBarat.totalSuaraQuickCount + riau.totalSuaraQuickCount + sulawesiBarat.totalSuaraQuickCount + sulawesiSelatan.totalSuaraQuickCount + sulawesiTengah.totalSuaraQuickCount + sulawesiTenggara.totalSuaraQuickCount + sulawesiUtara.totalSuaraQuickCount + sumateraBarat.totalSuaraQuickCount + sumateraSelatan.totalSuaraQuickCount + sumateraUtara.totalSuaraQuickCount

proporsiNolSatu = nolSatuQuickCountNasional/totalSuaraQuickCountNasional
proporsiNolDua = nolDuaQuickCountNasional/totalSuaraQuickCountNasional
persentaseNolSatu = proporsiNolSatu*100
persentaseNolDua = proporsiNolDua*100

print(proporsiNolSatu)
print(proporsiNolDua)

varianceNasional = aceh.getVariance(proporsiNolSatu) + bali.getVariance(proporsiNolSatu) + banten.getVariance(proporsiNolSatu) + bengkulu.getVariance(proporsiNolSatu) + daerahIstimewaYogyakarta.getVariance(proporsiNolSatu) + daerahKhususIbukotaJakarta.getVariance(proporsiNolSatu) + gorontalo.getVariance(proporsiNolSatu) + jambi.getVariance(proporsiNolSatu) + jawaBarat.getVariance(proporsiNolSatu) + jawaTengah.getVariance(proporsiNolSatu) + jawaTimur.getVariance(proporsiNolSatu) + kalimantanBarat.getVariance(proporsiNolSatu) + kalimantanSelatan.getVariance(proporsiNolSatu) + kalimantanTengah.getVariance(proporsiNolSatu) + kalimantanTimur.getVariance(proporsiNolSatu) + kalimantanUtara.getVariance(proporsiNolSatu) + kepulauanBangka.getVariance(proporsiNolSatu) + kepulauanRiau.getVariance(proporsiNolSatu) + lampung.getVariance(proporsiNolSatu) + maluku.getVariance(proporsiNolSatu) + malukuUtara.getVariance(proporsiNolSatu) + nusaTenggaraBarat.getVariance(proporsiNolSatu) + nusaTenggaraTimur.getVariance(proporsiNolSatu) + papua.getVariance(proporsiNolSatu) + papuaBarat.getVariance(proporsiNolSatu) + riau.getVariance(proporsiNolSatu) + sulawesiBarat.getVariance(proporsiNolSatu) + sulawesiSelatan.getVariance(proporsiNolSatu) + sulawesiTengah.getVariance(proporsiNolSatu) + sulawesiTenggara.getVariance(proporsiNolSatu) + sulawesiUtara.getVariance(proporsiNolSatu) + sumateraBarat.getVariance(proporsiNolSatu) + sumateraSelatan.getVariance(proporsiNolSatu) + sumateraUtara.getVariance(proporsiNolSatu)

standardErrorProporsi = np.sqrt(1/np.square(totalSuaraQuickCountNasional)*varianceNasional)
marginOfErrorProporsi = 2*standardErrorProporsi
marginOfErrorPercentage = marginOfErrorProporsi*100

sampleNolSatuNasional = aceh.sampleNolSatu + bali.sampleNolSatu + banten.sampleNolSatu + bengkulu.sampleNolSatu + daerahIstimewaYogyakarta.sampleNolSatu + daerahKhususIbukotaJakarta.sampleNolSatu + gorontalo.sampleNolSatu + jambi.sampleNolSatu + jawaBarat.sampleNolSatu + jawaTengah.sampleNolSatu + jawaTimur.sampleNolSatu + kalimantanBarat.sampleNolSatu + kalimantanSelatan.sampleNolSatu + kalimantanTengah.sampleNolSatu + kalimantanTimur.sampleNolSatu + kalimantanUtara.sampleNolSatu + kepulauanBangka.sampleNolSatu + kepulauanRiau.sampleNolSatu + lampung.sampleNolSatu + maluku.sampleNolSatu + malukuUtara.sampleNolSatu + nusaTenggaraBarat.sampleNolSatu + nusaTenggaraTimur.sampleNolSatu + papua.sampleNolSatu + papuaBarat.sampleNolSatu + riau.sampleNolSatu + sulawesiBarat.sampleNolSatu + sulawesiSelatan.sampleNolSatu + sulawesiTengah.sampleNolSatu + sulawesiTenggara.sampleNolSatu + sulawesiUtara.sampleNolSatu + sumateraBarat.sampleNolSatu + sumateraSelatan.sampleNolSatu + sumateraUtara.sampleNolSatu
sampleNolDuaNasional = aceh.sampleNolDua + bali.sampleNolDua + banten.sampleNolDua + bengkulu.sampleNolDua + daerahIstimewaYogyakarta.sampleNolDua + daerahKhususIbukotaJakarta.sampleNolDua + gorontalo.sampleNolDua + jambi.sampleNolDua + jawaBarat.sampleNolDua + jawaTengah.sampleNolDua + jawaTimur.sampleNolDua + kalimantanBarat.sampleNolDua + kalimantanSelatan.sampleNolDua + kalimantanTengah.sampleNolDua + kalimantanTimur.sampleNolDua + kalimantanUtara.sampleNolDua + kepulauanBangka.sampleNolDua + kepulauanRiau.sampleNolDua + lampung.sampleNolDua + maluku.sampleNolDua + malukuUtara.sampleNolDua + nusaTenggaraBarat.sampleNolDua + nusaTenggaraTimur.sampleNolDua + papua.sampleNolDua + papuaBarat.sampleNolDua + riau.sampleNolDua + sulawesiBarat.sampleNolDua + sulawesiSelatan.sampleNolDua + sulawesiTengah.sampleNolDua + sulawesiTenggara.sampleNolDua + sulawesiUtara.sampleNolDua + sumateraBarat.sampleNolDua + sumateraSelatan.sampleNolDua + sumateraUtara.sampleNolDua
sampleTotalSuaraNasional = aceh.sampleTotalSuara + bali.sampleTotalSuara + banten.sampleTotalSuara + bengkulu.sampleTotalSuara + daerahIstimewaYogyakarta.sampleTotalSuara + daerahKhususIbukotaJakarta.sampleTotalSuara + gorontalo.sampleTotalSuara + jambi.sampleTotalSuara + jawaBarat.sampleTotalSuara + jawaTengah.sampleTotalSuara + jawaTimur.sampleTotalSuara + kalimantanBarat.sampleTotalSuara + kalimantanSelatan.sampleTotalSuara + kalimantanTengah.sampleTotalSuara + kalimantanTimur.sampleTotalSuara + kalimantanUtara.sampleTotalSuara + kepulauanBangka.sampleTotalSuara + kepulauanRiau.sampleTotalSuara + lampung.sampleTotalSuara + maluku.sampleTotalSuara + malukuUtara.sampleTotalSuara + nusaTenggaraBarat.sampleTotalSuara + nusaTenggaraTimur.sampleTotalSuara + papua.sampleTotalSuara + papuaBarat.sampleTotalSuara + riau.sampleTotalSuara + sulawesiBarat.sampleTotalSuara + sulawesiSelatan.sampleTotalSuara + sulawesiTengah.sampleTotalSuara + sulawesiTenggara.sampleTotalSuara + sulawesiUtara.sampleTotalSuara + sumateraBarat.sampleTotalSuara + sumateraSelatan.sampleTotalSuara + sumateraUtara.sampleTotalSuara

persentaseSampleNolSatuNasional = np.divide(sampleNolSatuNasional, sampleTotalSuaraNasional)*100
persentaseSampleNolSatuNasionalSeries = pd.Series(persentaseSampleNolSatuNasional,
name = "Distribusi Persentase Suara 01 Stratified Random Sampling")

plotDistribusiNasionalStratifiedRandomSample, ax = plt.subplots(2,1)
sns.distplot(persentaseNolSatuNasional, kde=False, bins=100, ax = ax[0])
sns.distplot(persentaseSampleNolSatuNasionalSeries, kde=False, bins=100, ax = ax[1])
plotDistribusiNasionalStratifiedRandomSample.suptitle('{:.2f}% vs {:.2f}% Real Count Sementara \n {:.2f}% vs {:.2f}% Stratified Random Sampling dengan MOE = +/-{:.2f}%'.format(meanNolSatuNasional, meanNolDuaNasional, persentaseNolSatu, persentaseNolDua, marginOfErrorPercentage))

plotDistribusiNasionalStratifiedRandomSample.savefig("StratifiedRandomSample4.png")

 

Program Python ini juga menghasilkan plot distribusi yang membandingkan plot distribusi suara nasional seluruh TPS sementara dengan sampling yang dipakai. Selain itu pada grafik juga dibubuhkan hasil persentase quick count 01 maupun 02 dengan margin of error yang didapatkan dari rumus di atas Gambar 6 menunjukkan hasil stratified random sampling dengan margin of error dibawah 1% dengan jumlah sampel sebesar 2000.

StratifiedRandomSample4
Gambar 6. Stratified Random Sampling dari 2000 TPS dari seluruh TPS di Indonesia data sementara (456.135 TPS)

Seperti Random Sampling, saya juga menjalankan program ini 5 kali sehingga terdapat 5 hasil yang berbeda seperti dapat dilihat pada Gambar 7. Gambar 7 menunjukkan dari kelima data yang ditampilkan pada Gambar 6 maupun Gambar 7 memiliki Margin of Error pada sekitaran 0.95%, yakni di bawah 1%. Melihat hasil ini saya dapat memahami bahwa hasil Quick Count dengan 2000 TPS menggunakan metode Stratified Random Sampling itu bukan hal yang mustahil.

stratifiedRandomSamplingData
Gambar 7. Beberapa Hasil Stratified Random Sampling dengan Sampel 2000 TPS

Kesimpulan

Menggunakan metode Random Sampling, memang dibuktikan bahwa 2000 TPS tidak akan mencapai Margin of Error sebesar 1%, namun standard Quick Count menggunakan Stratified Random Sampling dan dengan metode ini, percobaan Penulis dalam melaksanakan simulasi Stratified Random Sampling dengan Python membuktikan bahwa Quick Count dari 2000 TPS dapat menghasilkan Margin of Error di bawah 1%

Margin of Error dari Random Sampling memerlukan data yang terdistribusi normal, sedangkan persamaan Margin of Error dari Stratified Random Sampling sudah dengan asumsi bahwa tidak secara persis terdistribusi normal (lihat Metodologi SMRC slide 9). Penggunaan persamaan Margin of Error dengan asumsi distribusi normal terhadap data persebaran suara yang tidak terdistribusi normal, menyebabkan adanya perbedaan pendapat jumlah sampel yang dibutuhkan.

Menggunakan metode Stratified Random Sampling maupun Random Sampling biasa seperti yang ditampilkan di artikel ini, tetap menghasilkan perbedaan suara 01 dan 02 yang cukup signifikan (> 2(moe)) sehingga kesimpulan dari Quick Count tetap sama, yakni pasangan 01 diprediksikan akan memenangi Pemilihan Presiden 2019.

 

EDITED 05 May: Menambahkan spoiler untuk menunjukkan code, sehingga bagi pembaca yang tidak ingin melihat code dapat melewati bagian code Python yang digunakan.