<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://ikanx101.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ikanx101.com/" rel="alternate" type="text/html" /><updated>2026-05-14T14:19:13+00:00</updated><id>https://ikanx101.com/feed.xml</id><title type="html">Mathematics, Market Research &amp;amp; Data Science</title><subtitle>Bunch of Ideas, a little bit of Maths.</subtitle><author><name>Bunch of Ideas, a little bit of Maths.</name></author><entry><title type="html">Ketika Survey Bilang Loyalist Turun 27%, Tapi Sales Cuma -15%: Siapa yang Salah?</title><link href="https://ikanx101.com/blog/loyalist-vs-sales/" rel="alternate" type="text/html" title="Ketika Survey Bilang Loyalist Turun 27%, Tapi Sales Cuma -15%: Siapa yang Salah?" /><published>2026-05-14T20:24:00+00:00</published><updated>2026-05-14T20:24:00+00:00</updated><id>https://ikanx101.com/blog/loyalist-vs-sales</id><content type="html" xml:base="https://ikanx101.com/blog/loyalist-vs-sales/"><![CDATA[<p>Beberapa hari yang lalu, tim <em>marketing research</em> menyampaikan hasil survey kuartal ini kepada tim <em>marketing</em>. Datanya cukup mengkhawatirkan: <strong>basis loyalist produk kami turun 27%</strong> dibanding tahun lalu.</p>

<p>Spontan, rapat jadi agak panas. Tim <em>marketing</em> langsung bereaksi:</p>

<blockquote>
  <p><em>“Kok bisa? Sales value kita cuma turun 15%, loh. Masa loyalisnya turun 27%? Pasti metode survey-nya yang kurang tepat.”</em></p>
</blockquote>

<p>Saya hanya bisa tersenyum kecil di dalam hati. Fenomena ini sebenarnya <strong>sangat wajar</strong>. Bahkan fenomena ini bisa dijelaskan dengan matematika sederhana yang kita ketahui bersama. Sayangnya, di lapangan, banyak yang masih menganggap hubungan antara jumlah loyalist dan sales value itu <strong>linear</strong>.</p>

<p><strong>Padahal tidak demikian.</strong></p>

<p>Mari saya coba jelaskan dengan cara yang (semoga) mudah dipahami.</p>

<hr />

<h2 id="kenapa-loyalist-dan-sales-value-tidak-bisa-dibandingkan-satu-lawan-satu">Kenapa <em>Loyalist</em> dan <em>Sales Value</em> Tidak Bisa Dibandingkan Satu Lawan Satu?</h2>

<p>Pertama-tama, kita harus paham dulu struktur dari <em>sales value</em> itu sendiri. Secara matematis:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sales Value = Jumlah Orang × Frekuensi Beli × Kuantitas per Beli × Harga per Unit
</code></pre></div></div>

<p>Atau kalau ditulis dalam notasi yang lebih rapi:</p>

<p><strong>S = L x F x Q x H</strong></p>

<p>Di mana:</p>
<ul>
  <li><strong>L</strong> = jumlah <em>loyalist</em> (atau pembeli secara umum)</li>
  <li><strong>F</strong> = rata-rata frekuensi beli per periode</li>
  <li><strong>Q</strong> = rata-rata kuantitas per transaksi</li>
  <li><strong>H</strong> = rata-rata harga per unit</li>
</ul>

<p>Nah, survey <em>loyalist</em> yang di lakukan oleh tim <em>market research</em> hanya mengukur <strong>satu</strong> variabel saja: yaitu <strong>L</strong>. Sedangkan <em>sales value</em> adalah <strong>hasil kali dari empat variabel sekaligus</strong>.</p>

<p>Selama tiga variabel lainnya (<em>F, Q, H</em>) <strong>tidak diam/diikat</strong>, maka perubahan pada <em>L</em> tidak akan pernah berbanding lurus dengan perubahan pada <em>S</em>. Ini matematika dasar, bukan masalah metode survey.</p>

<hr />

<h2 id="simulasi-sederhana">Simulasi Sederhana</h2>

<p>Biar lebih jelas, saya buatkan skenario dengan angka-angka.</p>

<h3 id="skenario-a-semua-variabel-lain-tetap-ilusi-linear">Skenario A: Semua Variabel Lain Tetap (Ilusi Linear)</h3>

<p>Misalkan tahun lalu:</p>

<table>
  <thead>
    <tr>
      <th>Variabel</th>
      <th>Nilai</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>L (<em>loyalist</em>)</td>
      <td>100 orang</td>
    </tr>
    <tr>
      <td>F (frekuensi/kuartal)</td>
      <td>4 kali</td>
    </tr>
    <tr>
      <td>Q (qty/transaksi)</td>
      <td>2 <em>pcs</em></td>
    </tr>
    <tr>
      <td>H (harga/pcs)</td>
      <td>Rp25.000</td>
    </tr>
  </tbody>
</table>

<p><strong>Sales tahun lalu</strong> = 100 × 4 × 2 × 25.000 = <strong>Rp20.000.000</strong></p>

<p>Sekarang, loyalis turun 27%. <em>L</em> baru = 73 orang. Jika <em>F, Q, H</em> tetap:</p>

<p><strong>Sales tahun ini</strong> = 73 × 4 × 2 × 25.000 = <strong>Rp14.600.000</strong></p>

<p>Penurunan sales = (20jt - 14,6jt) / 20jt = <strong>27%</strong>. Nah, ini baru linear.</p>

<p>Tapi ini skenario <strong>dunia ideal</strong> yang hampir tidak pernah terjadi di pasar nyata.</p>

<hr />

<h3 id="skenario-b-yang-realistis-ada-kompensasi-dari-variabel-lain">Skenario B: Yang Realistis (Ada Kompensasi dari Variabel Lain)</h3>

<p>Di dunia nyata, ketika <em>loyalist</em> berkurang, yang tersisa biasanya adalah <strong><em>hardcore loyalist</em></strong> — mereka yang paling setia. Dan mereka cenderung <strong>berkompensasi</strong> dengan membeli lebih sering atau lebih banyak.</p>

<p>Coba lihat skenario ini:</p>

<table>
  <thead>
    <tr>
      <th>Variabel</th>
      <th>Tahun Lalu</th>
      <th>Tahun Ini</th>
      <th>Perubahan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>L</td>
      <td>100</td>
      <td>73</td>
      <td><strong>-27%</strong></td>
    </tr>
    <tr>
      <td>F</td>
      <td>4</td>
      <td>5</td>
      <td><strong>+25%</strong></td>
    </tr>
    <tr>
      <td>Q</td>
      <td>2</td>
      <td>2</td>
      <td>tetap</td>
    </tr>
    <tr>
      <td>H</td>
      <td>Rp25.000</td>
      <td>Rp25.000</td>
      <td>tetap</td>
    </tr>
  </tbody>
</table>

<p><strong>Sales tahun ini</strong> = 73 × 5 × 2 × 25.000 = <strong>Rp18.250.000</strong></p>

<p>Penurunan <em>sales</em> = (20jt - 18,25jt) / 20jt = <strong>8,75%</strong>.</p>

<p>Lihat? <strong>Loyalist turun 27%, tapi sales cuma turun 8,75%.</strong> Dan ini belum memasukkan efek harga atau kuantitas.</p>

<hr />

<h3 id="skenario-c-efek-harga-naik-mix-shift-ke-premium">Skenario C: Efek Harga Naik (<em>Mix Shift</em> ke Premium)</h3>

<p>Kadang, <em>loyalist</em> yang pergi adalah mereka yang membeli SKU murah. Sementara yang tersisa beralih ke varian premium.</p>

<table>
  <thead>
    <tr>
      <th>Variabel</th>
      <th>Tahun Lalu</th>
      <th>Tahun Ini</th>
      <th>Perubahan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>L</td>
      <td>100</td>
      <td>73</td>
      <td><strong>-27%</strong></td>
    </tr>
    <tr>
      <td>F</td>
      <td>4</td>
      <td>4</td>
      <td>tetap</td>
    </tr>
    <tr>
      <td>Q</td>
      <td>2</td>
      <td>2</td>
      <td>tetap</td>
    </tr>
    <tr>
      <td>H</td>
      <td>Rp25.000</td>
      <td><strong>Rp30.000</strong></td>
      <td><strong>+20%</strong></td>
    </tr>
  </tbody>
</table>

<p><strong>Sales tahun ini</strong> = 73 × 4 × 2 × 30.000 = <strong>Rp17.520.000</strong></p>

<p>Penurunan <em>sales</em> = (20jt - 17,52jt) / 20jt = <strong>12,4%</strong>.</p>

<p>Lagi-lagi, <em>gap</em> antara -27% dan -12,4%. Tanpa mengubah metode survey sama sekali.</p>

<hr />

<h3 id="skenario-d-kombinasi-paling-mendekati-realita">Skenario D: Kombinasi (Paling Mendekati Realita)</h3>

<p>Sekarang kita gabungkan semuanya; karena di pasar nyata, semuanya bergerak simultan:</p>

<table>
  <thead>
    <tr>
      <th>Variabel</th>
      <th>Perubahan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>L</td>
      <td><strong>-27%</strong></td>
    </tr>
    <tr>
      <td>F</td>
      <td><strong>+15%</strong> (loyalist tersisa beli lebih sering)</td>
    </tr>
    <tr>
      <td>Q</td>
      <td><strong>+10%</strong> (beli lebih banyak setiap kali)</td>
    </tr>
    <tr>
      <td>H</td>
      <td><strong>+5%</strong> (mix shift ke SKU premium)</td>
    </tr>
  </tbody>
</table>

<p><strong>Sales tahun ini</strong> = 73 × (4×1,15) × (2×1,10) × (25.000×1,05)
= 73 × 4,6 × 2,2 × 26.250
= <strong>Rp19.399.725</strong></p>

<p><strong>Penurunan sales = (20jt - 19,4jt) / 20jt ≈ 3%.</strong></p>

<p><strong><em>Boom!</em></strong></p>

<p><strong>Loyalist ambles 27%, tapi <em>sales value</em> hampir tidak bergerak.</strong> Ini bukan rekayasa data tapi realita multivariat yang setiap hari terjadi di pasar FMCG.</p>

<hr />

<h2 id="lalu-siapa-yang-salah-tim-marketing-tim-sales-atau-tim-market-riset">Lalu, Siapa yang Salah? Tim <em>Marketing</em>, Tim <em>Sales</em> atau Tim Market Riset?</h2>

<p>Jawabannya: <strong>tidak ada yang salah.</strong></p>

<p>Hal yang perlu diluruskan adalah <strong>ekspektasi</strong> tentang hubungan antara dua metrik yang secara dimensional berbeda.</p>

<p>Survey <em>loyalist</em> mengukur <strong>L</strong> (jumlah <em>loyalist</em>). Itu adalah <em>attitudinal metric</em>, mengukur perilaku dan komitmen konsumen terhadap <em>brand</em>. Validitasnya tergantung pada metodologi <em>sampling</em>, instrumen kuesioner, sistem <em>quality control</em>, dan analisis yang digunakan. Dalam kasus kami, semua sudah melalui <em>quality control</em> yang ketat.</p>

<p>Sementara itu, <em>sales value</em> mengukur <strong>L × F × Q × H</strong> — itu adalah <em>behavioral metric</em>, hasil akhir dari interaksi kompleks antara jumlah orang, kebiasaan beli, dan harga.</p>

<p><strong>Keduanya penting, tapi menjawab pertanyaan yang berbeda.</strong></p>

<ul>
  <li>Survey <em>loyalist</em> menjawab: <em>“Apakah hubungan emosional dan perilaku konsumen terhadap brand kita mulai rapuh?”</em></li>
  <li><em>Sales value</em> menjawab: <em>“Berapa banyak uang yang masuk ke kas perusahaan?”</em></li>
</ul>

<p>Dan yang lebih penting: <strong>loyalist adalah leading indicator</strong>, sedangkan <em>sales</em> adalah <strong>lagging indicator</strong>. Penurunan <em>loyalist</em> sebesar 27% adalah alarm yang berbunyi <em>sekarang</em>. Dampaknya ke <em>sales</em> mungkin baru akan terasa penuh satu atau dua kuartal ke depan, yakni ketika <em>loyalist</em> yang sudah pergi benar-benar tidak lagi membeli, dan tidak ada <em>loyalist</em> baru yang menggantikan.</p>

<p>Kalau saya jadi tim <em>marketing</em>, saya justru akan berterima kasih pada tim riset karena sudah memberikan peringatan dini. Karena menunggu sampai <em>sales</em> benar-benar turun 27% untuk bereaksi, <strong>itu sudah terlambat</strong>.</p>

<blockquote>
  <p>Selain itu, perlu <strong>dipahami bahwa omset di-<em>generate</em> tidak hanya dari <em>loyalist</em>!</strong> Masih ada <em>occasional user</em> dan <em>new trialist</em> yang sedikit banyak pembelian mereka pasti berdampak pada <em>sales value</em>.</p>
</blockquote>

<hr />

<h2 id="data-market-riset-vs-data-sales-dua-dunia-yang-berbeda">Data Market Riset vs Data <em>Sales</em>: Dua Dunia yang Berbeda</h2>

<p>Diskusi kami dengan tim <em>marketing</em> itu membuka mata saya akan satu hal: <strong>masih banyak yang belum paham bahwa data market riset dan data <em>sales</em> itu lahir dari filosofi yang berbeda.</strong> Mereka memang sama-sama angka, tapi cara membaca, memaknai, dan menghubungkannya tidak bisa disamakan.</p>

<p>Mari saya bedah perbedaan mendasarnya.</p>

<h3 id="sifat-data-attitudinal-vs-behavioral">Sifat Data: <em>Attitudinal vs Behavioral</em></h3>

<table>
  <thead>
    <tr>
      <th>Dimensi</th>
      <th>Data Market Riset</th>
      <th>Data Sales</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Apa yang diukur?</strong></td>
      <td>Sikap, persepsi, niat, kesadaran (<em>attitudinal</em>)</td>
      <td>Perilaku aktual, transaksi riil (<em>behavioral</em>)</td>
    </tr>
    <tr>
      <td><strong>Sumber data</strong></td>
      <td>Sampel terpilih (survei, FGD, depth interview)</td>
      <td>Populasi (seluruh transaksi yang tercatat)</td>
    </tr>
    <tr>
      <td><strong>Arah waktu</strong></td>
      <td><em>Forward-looking</em> — bisa mendeteksi niat beli, loyalitas, preferensi ke depan</td>
      <td><em>Backward-looking</em> — mencatat apa yang <em>sudah</em> terjadi</td>
    </tr>
    <tr>
      <td><strong>Struktur</strong></td>
      <td>Diskrit, kategorik, skala Likert, proporsi</td>
      <td>Kontinu, agregat, numerik (Rp, unit, qty)</td>
    </tr>
    <tr>
      <td><strong>Galat/error</strong></td>
      <td>Sampling error, non-sampling error, bias responden</td>
      <td>Galat input data, missing SKU, double counting — relatif minimal</td>
    </tr>
    <tr>
      <td><strong>Pertanyaan khas</strong></td>
      <td><em>“Apakah Anda akan membeli lagi?”</em></td>
      <td><em>“Berapa banyak yang terjual?”</em></td>
    </tr>
  </tbody>
</table>

<p>Dari tabel di atas, jelas bahwa <strong>keduanya menjawab pertanyaan yang berbeda</strong>. Satu bicara soal <em>mindset</em>, satu lagi bicara soal <em>outcome</em>. Dan dalam ilmu apapun baik psikologi, ekonomi, maupun statistik, <em>mindset</em> dan <em>outcome</em> tidak pernah bergerak bersisian secara linear.</p>

<p>Oke, kalau masih bingung saya coba jelaskan dengan analogi sederhana sebagai berikut:</p>

<h3 id="analogi-sederhana-cek-kesehatan-vs-catatan-medis">Analogi Sederhana: Cek Kesehatan vs Catatan Medis</h3>

<p>Bayangkan kita periksa kesehatan ke dokter. Dokter melakukan serangkaian tes: cek gula darah, kolesterol, tekanan darah, dan EKG. Salah satu hasilnya menunjukkan bahwa <strong>kadar gula Anda naik 27%</strong> dibanding tahun lalu. Ini menjadi alarm pre-diabetes.</p>

<p>Dokter bilang:</p>

<blockquote>
  <p><em>“Hati-hati, ini tanda awal. Kalau tidak diubah pola makannya, risiko diabetes Anda tinggi.”</em></p>
</blockquote>

<p>Tapi Anda menjawab:</p>

<blockquote>
  <p><em>“Ah, masa sih? Saya kan masih sehat, berat badan cuma naik 3 kg kok. Tes darah Anda pasti salah.”</em></p>
</blockquote>

<p>Kedengarannya konyol, <em>kan?</em></p>

<p><em>Nah</em>, <strong>data market riset itu ibarat tes kesehatan</strong>. Data itu memberikan <em>early warning</em> tentang kondisi brand di benak konsumen. Sedangkan <strong>data sales itu ibarat catatan medis</strong>, ia mencatat apa yang sudah terjadi secara aktual. Dua-duanya penting, tapi tidak bisa saling menggantikan.</p>

<h3 id="lalu-bagaimana-cara-menghubungkannya-dengan-benar">Lalu Bagaimana Cara Menghubungkannya dengan Benar?</h3>

<p>Ini yang jarang diajarkan di bangku kuliah, atau paling tidak, jarang dipraktikkan di dunia kerja. Berikut pendekatan yang bisa kita gunakan:</p>

<h4 id="1-bangun-model-bridging-bukan-korelasi-langsung">1. Bangun <em>Model Bridging</em>, Bukan Korelasi Langsung</h4>

<p>Jangan plot jumlah <em>loyalist vs sales value</em> lalu hitung R²-nya sambil berharap tinggi. Itu <em>naif</em>. Yang benar: <strong>bangun model yang menjembatani.</strong></p>

<p>Secara konseptual:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Attitudinal Metrics (survei)
        ↓
Brand Health Index / Loyalty Score
        ↓
Dimediasi oleh: distribusi, harga, promosi, musiman
        ↓
Behavioral Outcomes (sales)
</code></pre></div></div>

<p>Jadi <em>loyalist</em> itu bukanlah <em>predictor langsung</em> dari <em>sales</em> dalam seminggu atau sebulan. Tapi <em>loyalist</em> adalah <strong>fondasi</strong> yang menentukan <em>resilience</em> <em>sales</em> terhadap <em>shock</em>, misal saat ada kompetitor masuk, krisis, kenaikan harga, dsb.</p>

<h4 id="2-gunakan-time-lag-analysis">2. Gunakan <em>Time Lag Analysis</em></h4>

<p><em>Loyalist</em> adalah <em>leading indicator</em>. Efek perubahan <em>loyalist</em> ke <em>sales</em> biasanya punya <strong>time lag</strong>, bisa 1-2 kuartal, tergantung kategori produk dan siklus pembelian.</p>

<p>Cara ilmiahnya: jangan regresikan <em>sales</em> Q1 dengan <em>loyalist</em> Q1. Tapi regresikan <strong>sales Q2 dan Q3</strong> dengan <em>loyalist</em> Q1. Cari <em>lag structure</em> yang paling signifikan secara statistik. Ini bisa dilakukan dengan <em>cross-correlation function</em> (CCF) atau <em>distributed lag models</em>.</p>

<h4 id="3-kontrol-variabel-lain-ceteris-paribus">3. Kontrol Variabel Lain (<em>Ceteris Paribus</em>)</h4>

<p>Kalau mau benar-benar mengisolasi efek loyalis ke <em>sales</em>, kita perlu <strong>mengontrol</strong> variabel-variabel lain:</p>

<ul>
  <li>Aktivitas promosi &amp; diskon</li>
  <li>Perubahan harga rata-rata (<em>price mix</em>)</li>
  <li>Distribusi &amp; ketersediaan produk (<em>out of stock rate</em>)</li>
  <li>Aktivitas kompetitor</li>
  <li>Faktor musiman</li>
</ul>

<p>Kalau semua itu tidak dikontrol, maka membandingkan persentase perubahan <em>loyalist</em> dengan persentase perubahan <em>sales</em> secara langsung adalah <strong>kesalahan ilmiah yang fundamental</strong>.</p>

<p>Teknik statistik seperti <strong>regresi berganda</strong>, <strong>GLM</strong>, atau <strong>mixed models</strong> bisa digunakan untuk ini.</p>

<h4 id="4-triangulasi-bukan-konfrontasi">4. Triangulasi, Bukan Konfrontasi</h4>

<p>Pada akhirnya, data market riset dan data <em>sales</em> bukanlah dua hal yang harus dipertentangkan. Mereka adalah dua sisi mata uang yang sama.</p>

<p><strong>Triangulasi</strong> adalah pendekatan ilmiah di mana kita menggunakan kedua sumber data secara komplementer:</p>

<table>
  <thead>
    <tr>
      <th>Temuan Market Riset</th>
      <th>Cek dengan Data Sales</th>
      <th>Kesimpulan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Loyalist turun</td>
      <td>Sales turun lebih kecil</td>
      <td>Ada kompensasi dari F, Q, H — cek mana yang naik</td>
    </tr>
    <tr>
      <td>Loyalist turun</td>
      <td>Sales ikut turun besar</td>
      <td>Masalahnya sistemik — dari brand ke lini terdepan</td>
    </tr>
    <tr>
      <td>Loyalist stabil</td>
      <td>Sales turun</td>
      <td>Bukan masalah brand image — cek distribusi, harga, atau stok</td>
    </tr>
    <tr>
      <td>Loyalist naik</td>
      <td>Sales belum naik</td>
      <td><em>Leading indicator</em> positif — pantau 1-2 kuartal ke depan</td>
    </tr>
  </tbody>
</table>

<p>Dengan pendekatan ini, tidak ada lagi budaya saling lempar tanggung jawab. Yang ada adalah budaya <em>sense-making</em>: memahami apa yang terjadi dari berbagai sudut pandang data, lalu mengambil keputusan berdasarkan gambaran utuh.</p>

<hr />

<h2 id="epilog"><em>Epilog</em></h2>

<p>Fenomena <em>loyalist</em> turun 27% tapi sales cuma -15% bukanlah anomali. Bukan juga akibat metode survey yang keliru. Ini adalah konsekuensi alami dari <strong>sistem multivariat</strong> dimana output (<em>sales</em>) adalah hasil perkalian dari beberapa <em>inputs</em> yang bergerak independen.</p>

<p>Selama variabel frekuensi (F), kuantitas (Q), dan harga (H) tidak dikontrol, <strong>tidak akan pernah ada hubungan linear antara jumlah <em>loyalist</em> dan <em>sales value</em></strong>. Sesederhana itu.</p>

<p>Data market riset dan data <em>sales</em> adalah dua jenis data yang <strong>secara fundamental berbeda</strong>. Satu <em>attitudinal</em> dan satu lainnya <em>behavioral</em>. Satu <em>forward-looking</em> dan satu lainnya <em>backward-looking</em>. Menghubungkan keduanya secara langsung tanpa kerangka ilmiah yang tepat adalah kesalahan yang masih sering terjadi di industri kita.</p>

<p>Yang perlu dilakukan sekarang bukan saling menyalahkan, tapi duduk bersama memahami <em>story</em> di balik angka-angka ini:</p>

<ol>
  <li><strong>Kenapa <em>loyalist</em> berkurang?</strong> Apakah ada masalah produk? Harga? Distribusi? Kompetitor?</li>
  <li><strong>Apa yang membuat yang tersisa tetap bertahan dan bahkan membeli lebih banyak?</strong></li>
  <li><strong>Berapa lama efek kompensasi dari F, Q, dan H ini bisa bertahan?</strong></li>
  <li><strong>Model bridging apa yang perlu dibangun agar tim riset dan <em>marketing</em> bicara dalam bahasa yang sama?</strong></li>
</ol>

<p>Karena kalau hanya mengandalkan <em>sales value</em> yang “masih OK”, tanpa menyadari bahwa fondasi loyalist-nya sudah jebol, kita sedang membangun istana di atas pasir.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Market research" /><category term="Data analysis" /><category term="Sales" /><category term="Sales research" /><category term="FMCG" /><category term="Loyalist" /><summary type="html"><![CDATA[Beberapa hari yang lalu, tim marketing research menyampaikan hasil survey kuartal ini kepada tim marketing. Datanya cukup mengkhawatirkan: basis loyalist produk kami turun 27% dibanding tahun lalu.]]></summary></entry><entry><title type="html">Paradoks Protein di Indonesia: Konsumsi Daging Terendah di ASEAN, Tapi Asupan Protein Terpenuhi</title><link href="https://ikanx101.com/blog/paradox-protein/" rel="alternate" type="text/html" title="Paradoks Protein di Indonesia: Konsumsi Daging Terendah di ASEAN, Tapi Asupan Protein Terpenuhi" /><published>2026-05-13T15:04:00+00:00</published><updated>2026-05-13T15:04:00+00:00</updated><id>https://ikanx101.com/blog/paradox-protein</id><content type="html" xml:base="https://ikanx101.com/blog/paradox-protein/"><![CDATA[<p>Artikel ini lahir dari sesi diskusi santai dengan <em>AI agent</em> asisten pribadi saya. Dimulai dari sebuah pertanyaan sederhana:</p>

<blockquote>
  <p><em>“Benarkah rakyat Indonesia kurang konsumsi daging?”</em></p>
</blockquote>

<p>Kemudian saya menelusuri beberapa data dan menguji dugaan saya hingga akhirnya mencoba merumuskan strategi untuk suatu produk nutrisi.</p>

<hr />

<h2 id="awal-mula-benarkah-indonesia-kurang-makan-daging">Awal Mula: Benarkah Indonesia Kurang Makan Daging?</h2>

<p>Saya membaca sekilas laporan <strong>OECD</strong> yang menyebut konsumsi daging Indonesia rendah. Di benak saya langsung terbersit: <strong>seberapa rendah?</strong> Apakah ini masalah yang perlu dikhawatirkan, atau cuma statistik yang dibesar-besarkan?</p>

<p>Maka saya mulai mencari data tersebut.</p>

<h3 id="data-1-konsumsi-daging-per-kapita-di-asean-2023">Data 1: Konsumsi Daging per Kapita di ASEAN (2023)</h3>

<table>
  <thead>
    <tr>
      <th>Negara</th>
      <th>Unggas</th>
      <th>Sapi</th>
      <th>Babi</th>
      <th>Domba/Kambing</th>
      <th><strong>Total Daging</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Malaysia</strong></td>
      <td>51,90</td>
      <td>8,75</td>
      <td>7,24</td>
      <td>1,17</td>
      <td><strong>69,07 kg</strong></td>
    </tr>
    <tr>
      <td><strong>Vietnam</strong></td>
      <td>19,65</td>
      <td>5,92</td>
      <td>34,37</td>
      <td>0,24</td>
      <td><strong>60,48 kg</strong></td>
    </tr>
    <tr>
      <td><strong>Filipina</strong></td>
      <td>15,75</td>
      <td>3,36</td>
      <td>14,11</td>
      <td>0,26</td>
      <td><strong>33,48 kg</strong></td>
    </tr>
    <tr>
      <td><strong>Thailand</strong></td>
      <td>10,23</td>
      <td>1,45</td>
      <td>12,67</td>
      <td>0,04</td>
      <td><strong>24,48 kg</strong></td>
    </tr>
    <tr>
      <td><strong>Indonesia</strong></td>
      <td>15,95</td>
      <td>3,01</td>
      <td>0,56</td>
      <td>0,41</td>
      <td><strong>19,95 kg</strong></td>
    </tr>
    <tr>
      <td><strong>Myanmar</strong></td>
      <td>12,09</td>
      <td>2,65</td>
      <td>5,91</td>
      <td>0,22</td>
      <td><strong>20,87 kg</strong></td>
    </tr>
  </tbody>
</table>

<p><em>Sumber: FAO via Our World in Data (2023)</em></p>

<p><strong>Indonesia berada di posisi terendah bersama Myanmar.</strong> Konsumsi dagingnya hanya sekitar ~20 kg per orang per tahun. Bandingkan dengan Malaysia yang mencapai ~69 kg, lebih dari 3 kali lipat. Tapi apakah ini berarti kita kekurangan protein?</p>

<p>Jawabannya ternyata <strong>tidak sesederhana itu</strong>.</p>

<h2 id="paradoks-protein-konsumsi-daging-rendah-tapi-protein-total-terpenuhi">Paradoks Protein: Konsumsi Daging Rendah, Tapi Protein Total Terpenuhi</h2>

<p>Inilah titik di mana data mulai bicara hal yang menarik.</p>

<h3 id="data-2-pasokan-protein-per-kapita-per-hari-2023">Data 2: Pasokan Protein per Kapita per Hari (2023)</h3>

<table>
  <thead>
    <tr>
      <th>Negara</th>
      <th>Protein Total</th>
      <th>Protein Hewani</th>
      <th>Protein Nabati</th>
      <th>% Hewani</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Vietnam</td>
      <td>102,2 g</td>
      <td>43,2 g</td>
      <td>59,0 g</td>
      <td>42,3%</td>
    </tr>
    <tr>
      <td>Malaysia</td>
      <td>93,3 g</td>
      <td>54,7 g</td>
      <td>38,7 g</td>
      <td>58,6%</td>
    </tr>
    <tr>
      <td>Myanmar</td>
      <td>78,4 g</td>
      <td>23,1 g</td>
      <td>55,3 g</td>
      <td>29,4%</td>
    </tr>
    <tr>
      <td><strong>Indonesia</strong></td>
      <td><strong>77,8 g</strong></td>
      <td><strong>30,0 g</strong></td>
      <td><strong>47,8 g</strong></td>
      <td><strong>38,5%</strong></td>
    </tr>
    <tr>
      <td>Filipina</td>
      <td>77,5 g</td>
      <td>28,6 g</td>
      <td>48,9 g</td>
      <td>36,9%</td>
    </tr>
    <tr>
      <td>Thailand</td>
      <td>68,6 g</td>
      <td>27,2 g</td>
      <td>41,4 g</td>
      <td>39,6%</td>
    </tr>
  </tbody>
</table>

<p><em>Sumber: FAO via Our World in Data (2023)</em></p>

<p>Perhatikan data Thailand:</p>

<blockquote>
  <p><strong>Thailand konsumsi dagingnya 24,48 kg — lebih tinggi dari Indonesia 19,95 kg. Tapi protein total Thailand justru LEBIH RENDAH (68,6 g vs 77,8 g).</strong></p>
</blockquote>

<p>Kok bisa?</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post2_sarkopenia/fig1_paradoks_protein.png" alt="Paradoks Protein ASEAN" /></p>

<p>Jawabannya ada di <strong>ikan</strong> dan <strong>nabati</strong>.</p>

<h3 id="ikan-senjata-rahasia-protein-indonesia">Ikan: <em>“Senjata Rahasia”</em> Protein Indonesia</h3>

<p>Indonesia punya konsumsi ikan yang sangat tinggi. Pada 2021:</p>

<table>
  <thead>
    <tr>
      <th>Negara</th>
      <th>Konsumsi Ikan (kg/kapita/tahun)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Malaysia</td>
      <td>52,3 kg</td>
    </tr>
    <tr>
      <td><strong>Indonesia</strong></td>
      <td><strong>41,1 kg</strong></td>
    </tr>
    <tr>
      <td>Myanmar</td>
      <td>40,9 kg</td>
    </tr>
    <tr>
      <td>Vietnam</td>
      <td>40,6 kg</td>
    </tr>
    <tr>
      <td>Thailand</td>
      <td>28,6 kg</td>
    </tr>
    <tr>
      <td>Filipina</td>
      <td>26,8 kg</td>
    </tr>
  </tbody>
</table>

<p><em>Sumber: FAO via Our World in Data (2021)</em></p>

<p><strong>Indonesia adalah konsumen ikan tertinggi kedua di ASEAN.</strong> Dengan 41,1 kg per kapita per tahun, ikan menjadi sumber protein hewani utama yang menggantikan peran daging.</p>

<h3 id="tahu-tempe-pahlawan-protein-nabati">Tahu Tempe: Pahlawan Protein Nabati</h3>

<p>Ini yang membedakan Indonesia dari negara Asia Tenggara lainnya. Tahu dan tempe, terutama tempe hasil fermentasi, adalah makanan sehari-hari yang dikonsumsi lintas kelas sosial. Tempe memiliki <strong>19-20 gram protein per 100 gram</strong>. Angka ini setara dengan daging! Selain itu tahu, meskipun kandungan airnya lebih tinggi, tetap menjadi sumber protein yang murah dan mudah diakses.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post2_sarkopenia/fig3_sumber_protein_indonesia.png" alt="Komposisi Sumber Protein Indonesia" /></p>

<p>Dari total 77,8 gram protein per hari:</p>

<ul>
  <li><strong>61% dari nabati</strong> (tahu, tempe, beras, kacang-kacangan)</li>
  <li><strong>39% dari hewani</strong> (ikan, unggas, telur, susu, daging)</li>
</ul>

<p>Ini adalah <strong>paradoks protein Indonesia</strong>: meskipun konsumsi daging terendah di ASEAN, protein total kita sehat karena kombinasi <strong>ikan + nabati</strong> yang sudah mendarah daging dalam pola makan tradisional.</p>

<hr />

<h2 id="bom-waktu-sarcopenia">Bom Waktu <a href="https://ikanx101.com/blog/sarcopenia-hilo/"><em>Sarcopenia</em></a></h2>

<blockquote>
  <p><strong>“Kenyang protein belum tentu cukup untuk otot.”</strong></p>
</blockquote>

<p>Kalau data rata-rata nasional menunjukkan kecukupan, kenapa saya merasa ada sesuatu yang tidak beres?</p>

<p>Jawabannya terletak pada <strong>kualitas dan distribusi</strong>.</p>

<p>Protein hewani (dari ikan, daging, telur, susu) memiliki <strong>profil asam amino esensial yang lebih lengkap</strong> dan <strong>lebih mudah diserap</strong> oleh tubuh manusia, terutama untuk <strong>sintesis otot</strong>. Protein nabati, meskipun baik, memerlukan kombinasi yang cermat agar asam aminonya seimbang.</p>

<p>Dan inilah masalahnya: <strong>30 gram protein hewani per hari itu tidak cukup untuk menjaga massa otot, terutama pada lansia.</strong></p>

<p>Selain itu, saya kok merasa konsumsi protein pada data tersebut tidak mewakili keseluruhan populasi Indonesia. Tapi tentunya ini <strong>menurut keyakinan</strong> saya <em>yah</em>, semoga saja saya salah.</p>

<h3 id="sarcopenia-the-silent-epidemic"><em>Sarcopenia: The Silent Epidemic</em></h3>

<p><strong>Sarcopenia</strong> adalah kondisi dimana seseorang mengalami penurunan massa, kekuatan, dan fungsi otot akibat penuaan. <em>Sarcopenia</em> adalah ancaman yang tidak banyak dibicarakan di Indonesia. Tahun lalu saya pernah <a href="https://ikanx101.com/blog/sarcopenia-hilo/">menuliskan tentang hal ini di <em>blog</em></a>.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post2_sarkopenia/fig5_prevalensi_sarcopenia.png" alt="Prevalensi Sarcopenia Indonesia vs Global" /></p>

<table>
  <thead>
    <tr>
      <th>Studi</th>
      <th>Sampel</th>
      <th>Prevalensi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>ILAS 2023</strong> (Halilintar et al.)</td>
      <td>1.598 lansia ≥60 tahun nasional</td>
      <td><strong>51,1%</strong> <em>possible sarcopenia</em></td>
    </tr>
    <tr>
      <td><strong>West Jakarta</strong> (PMC12051965, 2024)</td>
      <td>334 lansia ≥60 tahun</td>
      <td>~<strong>45,5%</strong></td>
    </tr>
    <tr>
      <td><strong>Systematic Review</strong> (Setiati et al.)</td>
      <td>Multi-studi Indonesia</td>
      <td><strong>9,1% - 53%</strong></td>
    </tr>
    <tr>
      <td><strong>Global rata-rata</strong> (Meta-analysis)</td>
      <td>—</td>
      <td>~<strong>24,5%</strong></td>
    </tr>
  </tbody>
</table>

<p>Dari hasil penelitian yang terbatas: <strong>Satu dari dua lansia Indonesia berisiko sarcopenia.</strong> Angka ini 2 kali lipat lebih tinggi dari rata-rata global.</p>

<p>Inilah yang saya sebut <strong>bom waktu demografis</strong>. Indonesia sedang menikmati bonus demografi (masa-masa di saat usia produktif mendominasi). Tapi 20-30 tahun lagi, tanpa intervensi pola makan dan gaya hidup, kita bisa menghadapi generasi lansia yang rapuh, rentan jatuh, kehilangan kemandirian. Akibatnya bisa membebani sistem kesehatan yang belum siap.</p>

<p><strong>Ironisnya</strong>: hampir tidak ada yang peduli. Coba tanya orang di sekitar kita. Berapa banyak yang tahu istilah sarcopenia?</p>

<h2 id="harga-protein-kenapa-solusi-beli-daging-saja-itu-tidak-realistis">Harga Protein: Kenapa Solusi “Beli Daging Saja” Itu Tidak Realistis</h2>

<p>Ketika saya membahas temuan ini dengan AI asisten saya, ia menantang premis saya tentang harga. Dan ini membuka mata saya.</p>

<p>Mari kita lihat biaya per gram protein dari berbagai sumber makanan:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post2_sarkopenia/fig4_biaya_protein.png" alt="Biaya per Gram Protein" /></p>

<table>
  <thead>
    <tr>
      <th>Sumber Protein</th>
      <th>Perkiraan Harga (Rp/kg)</th>
      <th>Protein/100g</th>
      <th><strong>Rp/gram protein</strong></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ikan Kembung</td>
      <td>35.000</td>
      <td>18 g</td>
      <td><strong>~195</strong></td>
    </tr>
    <tr>
      <td>Tahu Putih</td>
      <td>5.000</td>
      <td>8 g</td>
      <td><strong>~250</strong></td>
    </tr>
    <tr>
      <td>Tempe</td>
      <td>13.000</td>
      <td>20 g</td>
      <td><strong>~260</strong></td>
    </tr>
    <tr>
      <td>Ayam Broiler</td>
      <td>38.000</td>
      <td>18 g</td>
      <td><strong>~211</strong></td>
    </tr>
    <tr>
      <td>Susu HiLo (HP)</td>
      <td>~20.000/L</td>
      <td>5 g/100ml</td>
      <td><strong>~400</strong></td>
    </tr>
    <tr>
      <td>Telur Ayam</td>
      <td>2.500/butir</td>
      <td>6 g/butir</td>
      <td><strong>~415</strong></td>
    </tr>
    <tr>
      <td>Daging Sapi</td>
      <td>140.000</td>
      <td>20 g</td>
      <td><strong>~700</strong></td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p><strong>Fakta mengejutkan</strong>: Tahu dan tempe justru lebih murah per gram protein daripada telur. Kemudia ikan kembung adalah sumber protein hewani termurah.</p>
</blockquote>

<p><strong>Ini wawasan penting untuk strategi intervensi</strong>: solusi yang paling realistis dan berkelanjutan bukanlah mengubah pola makan rakyat ke daging sapi atau susu mahal, melainkan <strong>mengoptimalkan apa yang sudah ada</strong>:</p>

<ol>
  <li><strong>Optimalkan konsumsi ikan lokal</strong> (lele, kembung, tongkol, nila).</li>
  <li><strong>Maksimalkan tahu dan tempe</strong> — sumber protein nabati terbaik dan termurah.</li>
  <li><strong>Edukasi kombinasi protein</strong> — tidak perlu mahal untuk cukup.</li>
  <li><strong>Suplemen protein hewani untuk segmen spesifik</strong> — lansia perkotaan yang kesulitan mengunyah.</li>
</ol>

<blockquote>
  <p>Semoga saja program intervensi seperti <strong>MBG</strong> bisa menggerakkan optimalisasi konsumsi asupan protein ini.</p>
</blockquote>

<hr />

<h2 id="refleksi-tentang-qurban">Refleksi Tentang <strong>Qurban</strong></h2>

<p>Sebagai <em>muslim</em>, dalam hitungan minggu kita akan melaksanakan ibadah qurban. Tentu saja Qurban ini berlangsung setiap tahunnya. Di komplek saya (dan hampir di semua daerah di Indonesia), daging sapi qurban dibagikan ke semua warga sekitar tanpa memandang agama. Tradisi ini mulia baik secara spiritual maupun sosial.</p>

<p>Dalam konteks <em>sarcopenia</em>, apakah qurban bisa menjadi solusi?</p>

<blockquote>
  <p><strong>Jawabannya: tidak secara struktural.</strong></p>
</blockquote>

<p>Dengan ~1,8 juta ekor hewan qurban per tahun (~45.000 ton daging), dan penerima manfaat sekitar 20-25 juta jiwa, setiap penerima rata-rata mendapat ~2 kg daging. Jika dikonsumsi 50-100 gram per hari, itu hanya bertahan 20-40 hari. <strong>Setahun penuh ada 325 hari tanpa daging qurban.</strong></p>

<p>Tapi ini <strong>bukan berarti qurban tidak penting</strong>. Justru sebaliknya — saya melihat <strong>potensi besar yang belum sepenuhnya tergarap</strong>:</p>

<blockquote>
  <p><strong>Bagaimana jika kesadaran berqurban bisa meningkat? Bukan hanya sebagai ritual tahunan, tetapi sebagai gerakan sosial pangan yang lebih masif?</strong></p>
</blockquote>

<p>Di negara dengan 240 juta penduduk muslim terbesar di dunia, peningkatan jumlah qurban bahkan 10-20% per tahun bisa menambah pasokan protein hewani gratis ke puluhan juta penerima. Ini adalah instrumen redistribusi protein yang unik dan tidak dimiliki negara lain.</p>

<p>Qurban tetaplah solusi parsial tapi potensinya bisa ditingkatkan jauh lebih besar jika kesadaran umat akan dimensi gizi dan kesehatannya ikut tumbuh.</p>

<blockquote>
  <p>Jika tertarik membaca analisis lebih mendalam, saya pernah menulis tentang HiLo sebagai strategi mitigasi <em>sarcopenia</em> di tautan berikut: <a href="https://ikanx101.com/blog/sarcopenia-hilo/">ikanx101.com/blog/sarcopenia-hilo</a></p>
</blockquote>

<hr />

<h2 id="dari-data-ke-arah-implikasi-untuk-produk-nutrisi">Dari Data ke Arah: Implikasi untuk Produk Nutrisi</h2>

<p>Saya bekerja di bidang <em>market research</em>, sudah jadi naluri saya setelah melihat data kemudian bertanya: <strong>“Lalu apa yang bisa dilakukan?”</strong></p>

<h3 id="masalah-yang-teridentifikasi">Masalah yang Teridentifikasi</h3>

<ol>
  <li><strong>Protein total cukup</strong> (77,8 g/hari) tapi <strong>kualitas kurang optimal</strong> karena 61% dari nabati. Selain itu distribusinya juga masih tanda tanya.</li>
  <li><strong>Protein hewani hanya 30 g/hari</strong>. Hal ini belum ideal untuk sintesis otot optimal.</li>
  <li><strong>Prevalensi sarcopenia 51% pada lansia</strong>. Hal ini mengindikasikan defisit kronis protein hewani yang baru terlihat di usia tua.</li>
  <li><strong>Akses terbatas</strong>, daging dan susu mahal, belum terjangkau semua lapisan.</li>
  <li><strong>Kesadaran rendah</strong>, <em>sarcopenia</em> bukan kosakata umum.</li>
</ol>

<h3 id="peluang-untuk-produk-seperti-susu-hilo">Peluang untuk Produk Seperti <strong>Susu HiLo</strong></h3>

<p>Dari paparan data di atas, <strong>menurut <em>point of view</em> saya</strong> ada beberapa hal yang bisa dipertimbangkan dalam konteks strategi <em>marketing</em>. Tentu saya bukan menggurui justru sebaliknya, saya hanya ingin berbagi perspektif saja.</p>

<p><strong>Beberapa hal yang mungkin bisa dipertimbangkan:</strong></p>

<p><strong>Pertama</strong>, pertimbangkan untuk <strong>tidak menjual “sarcopenia”</strong>. Ini bahasa medis yang menakutkan dan tidak relevan untuk sebagian besar konsumen. Sebagai gantinya, <strong>jual “hidup aktif dan otot sehat untuk masa depan”</strong> — lebih aspiratif, lebih positif, lebih relevan untuk target usia 30-50 tahun yang punya daya beli.</p>

<p><strong>Kedua</strong>, manfaatkan <strong>heritage brand yang sudah kuat</strong>. HiLo sudah dikenal sebagai “susu untuk gerak aktif” sejak awal 2000-an. <em>Pivot</em> ke <em>high protein</em> adalah langkah cerdas, tetapi jangan tinggalkan akar yang sudah dikenal itu. <strong>“Gerak aktif + protein cukup”</strong> adalah narasi yang lebih utuh daripada <em>“cegah sarcopenia”</em>.</p>

<p><strong>Ketiga</strong>, bungkus dengan <strong>budaya makan Indonesia</strong>. Jangan memposisikan HiLo sebagai pengganti nasi, lauk, atau makanan tradisional. Justru sebisa mungkin ia hadir sebagai <strong>pelengkap yang praktis</strong>. Secara sederhana, bahasanya bisa dibuat seperti ini:</p>

<blockquote>
  <p>“Sudah makan tahu tempe? Bagus. Tapi otot juga butuh protein hewani yang cukup. HiLo bisa bantu.”</p>
</blockquote>

<p><strong>Keempat</strong>, sadari bahwa <strong>solusi sejati ada pada yang sudah tersedia</strong>: ikan murah, tahu, tempe, telur. HiLo bukan jawaban untuk seluruh Indonesia tapi ia adalah jawaban untuk <strong>segmen spesifik</strong> (urban, daya beli cukup, sudah sadar kesehatan) yang butuh <strong>suplemen protein hewani praktis</strong>.</p>

<h2 id="epilog"><em>Epilog</em></h2>

<p>Ada tiga hal yang saya bawa pulang dari diskusi ini:</p>

<p><strong>Pertama</strong>, <strong>data seringkali tidak sesederhana kelihatannya</strong>. “Konsumsi daging rendah” terdengar seperti masalah — sampai Anda lihat bahwa konsumsi ikan Indonesia adalah yang tertinggi kedua di ASEAN. Konteks mengubah segalanya.</p>

<p><strong>Kedua</strong>, <strong>paradoks bukan kontradiksi</strong>. Bahwa konsumsi daging rendah tapi protein total mencukupi bukanlah kesalahan data — ini adalah ciri khas pola makan Indonesia yang unik dan layak dipahami lebih dalam.</p>

<p><strong>Ketiga</strong>, <strong>dari problem framing, validasi data, sampai solusi — semuanya perlu dikerjakan dengan hati-hati</strong>. Sebagai <em>data scientist</em>, godaan terbesar adalah cepat menyimpulkan. Tapi semakin dalam saya menggali, semakin saya sadar bahwa <strong>pertanyaan yang tepat lebih penting daripada jawaban yang cepat</strong>.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Daging" /><category term="Qurban" /><category term="Protein" /><category term="Sarkopenia" /><category term="Indonesia" /><category term="ASEAN" /><category term="Malaysia" /><category term="Thailand" /><category term="Ayam" /><category term="Ikan" /><category term="Tahu" /><category term="Tempe" /><summary type="html"><![CDATA[Artikel ini lahir dari sesi diskusi santai dengan AI agent asisten pribadi saya. Dimulai dari sebuah pertanyaan sederhana:]]></summary></entry><entry><title type="html">Perang Kopi di Indonesia: Perjalanan Kapal Api, Pergeseran Torabika, dan Perjuangan Top Coffee</title><link href="https://ikanx101.com/blog/market-kopi/" rel="alternate" type="text/html" title="Perang Kopi di Indonesia: Perjalanan Kapal Api, Pergeseran Torabika, dan Perjuangan Top Coffee" /><published>2026-05-08T15:04:00+00:00</published><updated>2026-05-08T15:04:00+00:00</updated><id>https://ikanx101.com/blog/market-kopi</id><content type="html" xml:base="https://ikanx101.com/blog/market-kopi/"><![CDATA[<p>Saya masih ingat dengan jelas pada tahun 2010. Saat itu saya sedang mengerjakan sebuah survei <em>market</em> untuk salah satu <strong>pemain</strong> di industri kopi. Salah satu kategorinya adalah <strong>kopi bubuk</strong>, sebuah kategori yang sebenarnya sudah sangat dewasa, dengan pemain-pemain yang sudah mapan puluhan tahun.</p>

<p>Di hasil survei itu, peta persaingannya cukup jelas: ada <strong>Kapal Api</strong> di puncak, dan <strong>Torabika</strong> sebagai penantang terdekat di segmen kopi bubuk hitam (<em>ground coffee</em>). Dua brand ini seperti raja dan pangeran yang saling berhadapan. Saya kemudian menyimpan temuan itu di <em>memory</em> saya.</p>

<p>Belasan tahun kemudian, tepatnya kemarin, saya iseng membuka kembali memori lama itu. Lalu saya bertanya ke asisten AI saya:</p>

<blockquote>
  <p><em>“Coba carikan data market share untuk pasar kopi bubuk di Indonesia selama beberapa tahun terakhir.”</em></p>
</blockquote>

<p>Dan dari situlah perjalanan <em>rabbit hole</em> ini dimulai. Saya menemukan bahwa <strong>peta persaingan yang saya ingat sudah berubah total</strong>. Kapal Api tetap kokoh di puncak, tapi Torabika yang dulu saya lihat sebagai penantang kuat sudah <em>berganti meja</em>. Dan yang lebih menarik: ada <em>brand</em> <strong>Top Coffee</strong> yang melakukan gebrakan paling dahsyat dalam sejarah periklanan Indonesia namun hasilnya tetap tidak mampu menggoyahkan singgasana.</p>

<p>Artikel ini adalah dokumentasi dari penelusuran itu.</p>

<blockquote>
  <p>Perlu saya tekankan bahwa tulisan ini adalah hasil penelurusan saya dibantu dengan AI. Semua analisa dan argumen yang saya lakukan tentu bersifat subjektif dan memiliki <em>point fo view</em> tersendiri. Satu lagi, saya tidak mengikutsertakan warung-warung kopi dan <em>brand</em> kopi siap minum yang sekarang ini menjamur dalam artikel ini.</p>
</blockquote>

<p><em>So, enjoy the article</em>.</p>

<hr />

<h2 id="pertarungan-tiga-era">Pertarungan Tiga Era</h2>

<p>Pasar kopi bubuk Indonesia bisa dibagi ke dalam tiga era besar dalam 20 tahun terakhir.</p>

<h3 id="era-1-2006-2011-kapal-api-dan-para-penantang-klasik">Era 1 (2006-2011): Kapal Api dan Para Penantang Klasik</h3>

<p>Data dari <strong>MARS Indonesia</strong> (via paper marketing Kapal Api) menunjukkan peta persaingan tahun 2006-2007:</p>

<table>
  <thead>
    <tr>
      <th>Merek</th>
      <th style="text-align: center">2006</th>
      <th style="text-align: center">2007</th>
      <th style="text-align: left">Induk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Kapal Api</strong></td>
      <td style="text-align: center"><strong>44.0%</strong></td>
      <td style="text-align: center"><strong>44.3%</strong></td>
      <td style="text-align: left">Santos Jaya Abadi</td>
    </tr>
    <tr>
      <td>ABC</td>
      <td style="text-align: center">17.5%</td>
      <td style="text-align: center">17.9%</td>
      <td style="text-align: left">Santos Jaya Abadi</td>
    </tr>
    <tr>
      <td>Nescafe</td>
      <td style="text-align: center">9.9%</td>
      <td style="text-align: center">—</td>
      <td style="text-align: left">Nestle</td>
    </tr>
    <tr>
      <td>Torabika</td>
      <td style="text-align: center">7.5%</td>
      <td style="text-align: center">—</td>
      <td style="text-align: left">Mayora Group</td>
    </tr>
    <tr>
      <td>Indocafe</td>
      <td style="text-align: center">6.4%</td>
      <td style="text-align: center">—</td>
      <td style="text-align: left">Sari Incofood</td>
    </tr>
    <tr>
      <td>Lainnya</td>
      <td style="text-align: center">14.7%</td>
      <td style="text-align: center">—</td>
      <td style="text-align: left">—</td>
    </tr>
  </tbody>
</table>

<p>Pada saat itu, Santos Jaya Abadi (induk Kapal Api) sudah menguasai lebih dari 60% pangsa pasar lewat dua merek andalannya.</p>

<p><strong>Majalah SWA</strong> merilis data <em>market share</em> kopi bubuk (agregat) tahun 2009-2011:</p>

<table>
  <thead>
    <tr>
      <th>Perusahaan</th>
      <th>Merek</th>
      <th style="text-align: center">2009</th>
      <th style="text-align: center">2010</th>
      <th style="text-align: center">2011</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Santos Jaya Abadi</td>
      <td><strong>Kapal Api</strong></td>
      <td style="text-align: center"><strong>43.6%</strong></td>
      <td style="text-align: center"><strong>39.4%</strong></td>
      <td style="text-align: center"><strong>35.7%</strong></td>
    </tr>
    <tr>
      <td>Santos Jaya Abadi</td>
      <td>ABC</td>
      <td style="text-align: center">18.9%</td>
      <td style="text-align: center">22.1%</td>
      <td style="text-align: center">24.4%</td>
    </tr>
    <tr>
      <td>Nestle</td>
      <td>Nescafe</td>
      <td style="text-align: center">9.9%</td>
      <td style="text-align: center">8.3%</td>
      <td style="text-align: center">5.2%</td>
    </tr>
    <tr>
      <td><strong>Mayora</strong></td>
      <td><strong>Torabika</strong></td>
      <td style="text-align: center"><strong>7.5%</strong></td>
      <td style="text-align: center"><strong>6.2%</strong></td>
      <td style="text-align: center"><strong>8.5%</strong></td>
    </tr>
    <tr>
      <td>Sari Incofood</td>
      <td>Indocafe</td>
      <td style="text-align: center">6.4%</td>
      <td style="text-align: center">9.1%</td>
      <td style="text-align: center">8.4%</td>
    </tr>
  </tbody>
</table>

<p>Data ini menarik karena menunjukkan bahwa <strong>Torabika sebenarnya bukan <em>co-leader</em> di level agregat</strong>. Justru posisinya hanya 6-8%, jauh di bawah Kapal Api (35-44%) dan ABC (19-24%). Tapi di segmen spesifik <strong>ground coffee (kopi bubuk berampas)</strong>, Torabika <em>Roast &amp; Ground</em> memiliki posisi yang cukup kuat sebagai pemain nomor 2 atau 3.</p>

<h3 id="era-2-2012-2016-invasi-pendatang-baru">Era 2 (2012-2016): Invasi Pendatang Baru</h3>

<p>Tahun 2012 menjadi tahun yang sangat penting. Dua hal besar terjadi:</p>

<ol>
  <li><strong>Top Coffee dari Wings Food masuk ke dalam <em>market</em> kopi</strong> dengan belanja iklan Rp 421,7 miliar di tahun pertama.</li>
  <li><strong>Luwak White Coffee mulai mengangkat kategori <em>“White Coffee”</em></strong> yang kemudian menjadi tren. Hal ini sangat menarik karena nyatanya menurut saya kategori <em>white coffee</em> tak hanya sekedar <em>hype</em> tapi berhasil menjadi tren yang lama.</li>
</ol>

<p>Dari perspektif data, sayangnya tahun 2012-2021 adalah <strong>lubang hitam data</strong>. Data TBI (<em>Top Brand Index</em>) untuk kategori kopi bubuk tidak tersedia secara gratis di publik. Data tahunan dari <strong>Frontier Research, Nielsen, dan Euromonitor</strong> umumnya berbayar.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post1_kopi/fig1_timeline_ground_coffee.png" alt="" /></p>

<p>Beberapa hal yang bisa kita rekonstruksi adalah:</p>

<ul>
  <li><strong>Torabika perlahan kehilangan <em>share</em> di kategori <em>ground coffee</em></strong>. Jika kita lihat, produk <em>ground coffee</em>-nya (<em>Torabika Roast &amp; Ground</em>) mulai tidak agresif dipasarkan, fokus bergeser ke instan/<em>sachet</em>.</li>
  <li><strong>Luwak White Coffee tumbuh pesat</strong> dan menciptakan segmen baru yang tidak ada sebelumnya.</li>
  <li><strong>Good Day (brand miliki Kapal Api - Santos Jaya Abadi) menguasai kopi instan</strong> dengan TBI konsisten di atas 40%.</li>
</ul>

<h3 id="era-3-2022-sekarang-multi-brand-vs-single-brand">Era 3 (2022-Sekarang): <em>Multi-Brand</em> vs <em>Single-Brand</em></h3>

<p>Data <strong>Top Brand Award</strong> kembali tersedia secara publik di tahun 2022 ke atas. Dan inilah yang mengejutkan:</p>

<p><strong>Ground Coffee (Kopi Bubuk Berampas):</strong></p>

<table>
  <thead>
    <tr>
      <th>Merek</th>
      <th style="text-align: center">2022</th>
      <th style="text-align: center">2023</th>
      <th style="text-align: center">2024</th>
      <th style="text-align: center">2025</th>
      <th style="text-align: center">2026</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Kapal Api</strong> 🏆</td>
      <td style="text-align: center"><strong>62.4%</strong></td>
      <td style="text-align: center"><strong>62.8%</strong></td>
      <td style="text-align: center"><strong>52.1%</strong></td>
      <td style="text-align: center"><strong>49.7%</strong></td>
      <td style="text-align: center"><strong>56.5%</strong></td>
    </tr>
    <tr>
      <td>ABC</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">11.1%</td>
      <td style="text-align: center">17.9%</td>
      <td style="text-align: center">—</td>
    </tr>
    <tr>
      <td>Luwak White Coffee</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">20.1%</td>
      <td style="text-align: center">14.4%</td>
      <td style="text-align: center">—</td>
    </tr>
    <tr>
      <td>Excelso</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">5.4%</td>
      <td style="text-align: center">5.5%</td>
      <td style="text-align: center">—</td>
    </tr>
    <tr>
      <td>Top Coffee</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">3.7%</td>
      <td style="text-align: center">3.1%</td>
      <td style="text-align: center">—</td>
    </tr>
    <tr>
      <td><strong>Torabika</strong></td>
      <td style="text-align: center"><strong>❌</strong></td>
      <td style="text-align: center"><strong>❌</strong></td>
      <td style="text-align: center"><strong>❌</strong></td>
      <td style="text-align: center"><strong>❌</strong></td>
      <td style="text-align: center"><strong>❌</strong></td>
    </tr>
  </tbody>
</table>

<p><strong>Kopi Bubuk Instan/Sachet:</strong></p>

<table>
  <thead>
    <tr>
      <th>Merek</th>
      <th style="text-align: center">TBI 2024</th>
      <th style="text-align: center">TBI 2025</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Good Day</strong> 🏆</td>
      <td style="text-align: center"><strong>48.4%</strong></td>
      <td style="text-align: center"><strong>42.8%</strong></td>
    </tr>
    <tr>
      <td>Indocafe</td>
      <td style="text-align: center">19.3%</td>
      <td style="text-align: center">19.7%</td>
    </tr>
    <tr>
      <td>ABC</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">17.6%</td>
    </tr>
    <tr>
      <td>Nescafe</td>
      <td style="text-align: center">8.3%</td>
      <td style="text-align: center">9.1%</td>
    </tr>
    <tr>
      <td><strong>🏷️ Torabika</strong></td>
      <td style="text-align: center"><strong>4.1%</strong></td>
      <td style="text-align: center"><strong>6.4%</strong></td>
    </tr>
    <tr>
      <td>Kopiko</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">1.1%</td>
    </tr>
  </tbody>
</table>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post1_kopi/fig2_instan_sachet.png" alt="" /></p>

<p>Ada hal menarik yakni <strong>Torabika tidak lagi muncul di <em>market</em> <em>ground coffee</em></strong>. Dia sudah sepenuhnya menjadi pemain di market kopi instan dengan pangsa yang masih jauh di bawah <strong>Good Day</strong>.</p>

<hr />

<h2 id="brand-yang-bertahan-kapal-api"><em>Brand</em> yang Bertahan: Kapal Api</h2>

<h3 id="strategi-multi-brand-yang-tak-terkalahkan">Strategi <em>Multi-Brand</em> yang Tak Terkalahkan</h3>

<p>Kalau kita melihat perjalanan Kapal Api dari 2006 sampai 2026, ada satu kata kunci: <strong>konsistensi</strong>.</p>

<p>Data dari <em>paper marketing</em> Kapal Api yang saya temukan (di <em>Scribd/pdfcoffee</em>) mengungkap rahasia strategi mereka dari 2006-2007:</p>

<table>
  <thead>
    <tr>
      <th>Merek</th>
      <th>Posisi</th>
      <th>Target</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Kapal Api</strong></td>
      <td><em>Market Leader</em></td>
      <td>Kopi bubuk tradisional, semua kalangan</td>
    </tr>
    <tr>
      <td><strong>ABC</strong></td>
      <td>#2 di <em>Ground</em></td>
      <td>Kopi bubuk, segmen yang lebih terjangkau</td>
    </tr>
    <tr>
      <td><strong>Good Day</strong></td>
      <td>#1 di Instan</td>
      <td>Kopi instan, anak muda, varian rasa</td>
    </tr>
    <tr>
      <td><strong>Merek Ya</strong></td>
      <td>Ekonomi</td>
      <td>Kopi murah, kelas bawah</td>
    </tr>
    <tr>
      <td><strong>Excelso</strong></td>
      <td>Premium</td>
      <td>Kedai kopi, kopi <em>specialty</em></td>
    </tr>
  </tbody>
</table>

<p>Ini yang disebut dengan <strong>strategi mengepung</strong> (<em>encirclement strategy</em>). Konsumen punya preferensi apapun, mulai dari tradisional, modern, murah, mahal, instan, seduh tapi kita bisa melihat bahwa uang konsumen tetap masuk ke <strong>kantong yang sama</strong>.</p>

<p>Strategi ini luar biasa efektifnya. Dari data paper tersebut:</p>

<p><strong>Pangsa pasar 2006-2007 (MARS Indonesia):</strong></p>

<table>
  <thead>
    <tr>
      <th>Merek</th>
      <th style="text-align: center">2006</th>
      <th style="text-align: center">2007</th>
      <th style="text-align: left">Induk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kapal Api</td>
      <td style="text-align: center">44.0%</td>
      <td style="text-align: center">44.3%</td>
      <td style="text-align: left">Santos</td>
    </tr>
    <tr>
      <td>ABC</td>
      <td style="text-align: center">17.5%</td>
      <td style="text-align: center">17.9%</td>
      <td style="text-align: left">Santos</td>
    </tr>
    <tr>
      <td>Good Day</td>
      <td style="text-align: center">0.6%</td>
      <td style="text-align: center">0.9%</td>
      <td style="text-align: left">Santos</td>
    </tr>
    <tr>
      <td>Merek Ya</td>
      <td style="text-align: center">2.3%</td>
      <td style="text-align: center">2.2%</td>
      <td style="text-align: left">Santos</td>
    </tr>
    <tr>
      <td><strong>Total Santos Group</strong></td>
      <td style="text-align: center"><strong>64.4%</strong></td>
      <td style="text-align: center"><strong>65.3%</strong></td>
      <td style="text-align: left">-</td>
    </tr>
  </tbody>
</table>

<p><strong>Hampir 20 tahun kemudian</strong> (2025) angka total Santos Jaya Abadi masih konsisten di sekitar 60% (Kapal Api 49.7% + ABC 17.9% + Excelso 5.5% + brand lainnya).</p>

<blockquote>
  <p>Inilah kekuatan sebenarnya: bukan Kapal Api yang sulit dikalahkan, tapi Santos Jaya Abadi yang kuat dan pintar sebagai grup.</p>
</blockquote>

<h3 id="mengapa-kapal-api-bisa-bertahan">Mengapa Kapal Api Bisa Bertahan?</h3>

<ol>
  <li><strong>Brand Heritage</strong>; Kapal Api sudah ada sejak 1978. Tiga generasi konsumen Indonesia tumbuh dengan Kapal Api.</li>
  <li><strong>Distribusi Super Luas</strong>; PT Fastrata Buana (anak usaha Santos) menangani distribusi. Dari warung pinggir jalan sampai supermarket modern, Kapal Api selalu ada.</li>
  <li><strong>Rejuvenasi Tanpa Kehilangan Identitas</strong>; Kapal Api tidak berpuas diri. Mereka menggandeng Maudy Ayunda kemudian membuat <em>podcast</em> anak muda dengan citra “kopi bubuk asli Indonesia” tetap dijaga.</li>
  <li><strong>Multi-Brand Buffer</strong>; Kalau Kapal Api turun, ABC naik. Lihat data 2024-2025: Kapal Api turun dari 52.1% ke 49.7%, tapi ABC naik dari 11.1% ke 17.9%. <strong>Uangnya tetap dikuasai Santos</strong>.</li>
</ol>

<hr />

<h2 id="brand-yang-bergeser-torabika"><em>Brand</em> yang Bergeser: Torabika</h2>

<h3 id="dari-ground-coffee-ke-kopi-instan">Dari <em>Ground Coffee</em> ke Kopi Instan</h3>

<p>Sekarang kita sampai ke kasus yang paling menarik buat saya pribadi karena ini yang paling kontras dengan <em>memory</em> saya dari tahun 2010.</p>

<p><strong>Torabika tidak jatuh. Dia bergeser.</strong></p>

<p>Dari penelusuran yang saya lakukan, PT Torabika Eka Semesta (anak usaha Mayora Group) sejak awal punya <strong>dua divisi</strong>: Instan dan <em>Ground</em>, dengan <em>Ground</em> terbagi menjadi dua bagian lagi (<em>Ground 1</em> dan <em>Ground 2</em>). Fakta ini dikonfirmasi oleh sebuah <em>paper</em> akademik berjudul <em>“Analisis Kemasan Produk Kopi Bubuk Merek Torabika Roast and Ground di PT Torabika Eka Semesta Divisi Ground 2”</em> dari Politeknik ATI Padang.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post1_kopi/fig4_pergeseran_torabika.png" alt="" /></p>

<p>Artinya, Torabika benar-benar bermain di dua <em>market</em> sekaligus.</p>

<p>Tapi kenapa kemudian Torabika <strong>menghilang dari ground coffee</strong>?</p>

<h3 id="analisa-tiga-faktor-utama">Analisa: Tiga Faktor Utama</h3>

<h4 id="1-mayora-bukan-perusahaan-kopi-tapi-perusahaan-makanan-ringan">1. Mayora Bukan Perusahaan Kopi tapi Perusahaan Makanan Ringan</h4>

<p>Ini yang sering terlewat. Mayora Group punya puluhan produk: biskuit Roma, permen Kopiko, wafer Tango, Beng Beng, teh Pucuk, dan kopi Torabika hanyalah <strong>salah satu lini</strong> dari portofolio raksasa.</p>

<p>Bandingkan dengan Santos Jaya Abadi yang <strong>hanya fokus di kopi</strong>. Atau Wings Food yang menjadikan kopi sebagai lini strategis baru yang digeber habis-habisan.</p>

<p>Di Mayora, Torabika harus bersaing dengan lini produk lain untuk mendapat alokasi sumber daya. Ketika <em>ground coffee</em> tidak menunjukkan pertumbuhan yang menjanjikan, <strong>sumber daya dialihkan ke instan</strong> yang volumenya lebih besar.</p>

<h4 id="2-good-day-milik-santos-bukan-torabika">2. Good Day Milik Santos Bukan Torabika</h4>

<p>Ini ironis. Di segmen kopi instan/<em>sachet</em>, Torabika harus berhadapan dengan <strong>Good Day</strong> yang ternyata juga milik Santos Jaya Abadi. Dengan TBI 42-48% di kategori kopi instan, Good Day adalah raja yang hampir tidak tergoyahkan.</p>

<p>Torabika di instan cuma punya TBI 4-6%. Bertahan, tapi tidak pernah benar-benar menjadi ancaman.</p>

<h4 id="3-ground-coffee-stagnan-tidak-ada-inovasi">3. <em>Ground Coffee</em> Stagnan (Tidak Ada Inovasi)</h4>

<p>Produk <em>Torabika Roast &amp; Ground</em> relatif tidak berubah dari dulu sampai sekarang. Bahkan hari ini — tahun 2026 — produk “Torabika Kopi Bubuk 6.5g Roast Ground” masih dijual di Tokopedia dan Shopee. Tapi tanpa inovasi, tanpa <em>campaign</em> besar, tanpa rejuvenasi.</p>

<p>Sementara Kapal Api terus mengeluarkan varian baru: Kapal Api Special Mix, Kapal Api Creamy Latte, Kapal Api Less Sugar kemudian semuanya dengan iklan gencar di TV dan media sosial.</p>

<hr />

<h2 id="brand-yang-mencoba-top-coffee"><em>Brand</em> yang Mencoba: Top Coffee</h2>

<h3 id="rp-421-miliar-yang-tidak-cukup">Rp 421 Miliar yang Tidak Cukup</h3>

<p>Nah, ini kasus yang paling dramatis. <strong>Top Coffee</strong> dari Wings Food masuk ke pasar pada <strong>Juli 2012</strong> (dua tahun setelah survei 2010 yang saya lakukan). Dan cara masuknya… <em>wow</em>.</p>

<p>Data dari <strong>Mix.co.id</strong> (mengutip <em>Nielsen Ad Index</em>) menunjukkan:</p>

<table>
  <thead>
    <tr>
      <th>Periode</th>
      <th style="text-align: center">Belanja Iklan Top Coffee</th>
      <th style="text-align: center">Peringkat Nasional</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>2012 (Full Year)</strong></td>
      <td style="text-align: center"><strong>Rp 421,7 miliar</strong></td>
      <td style="text-align: center"><strong>#4</strong> dari semua merek di Indonesia</td>
    </tr>
    <tr>
      <td>H1 2012</td>
      <td style="text-align: center">~Rp 70 miliar</td>
      <td style="text-align: center">—</td>
    </tr>
    <tr>
      <td>H1 2013</td>
      <td style="text-align: center">Rp 205,84 miliar</td>
      <td style="text-align: center">#1 kategori Kopi &amp; Teh</td>
    </tr>
    <tr>
      <td>Pertumbuhan H1 2012 → H1 2013</td>
      <td style="text-align: center"><strong>+190%</strong></td>
      <td style="text-align: center">—</td>
    </tr>
  </tbody>
</table>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post1_kopi/fig3_belanja_iklan_top_coffee.png" alt="" /></p>

<p>Coba kita pikir bersama, Top Coffee, sebuah merek yang <strong>baru lahir</strong> langsung menjadi <strong>pembelanja iklan terbesar ke-4 di seluruh Indonesia</strong>, mengalahkan <em>brands</em> mapan seperti Indomie (Rp 339 miliar) dan hanya kalah dari Ponds White Beauty (Rp 510 miliar), Mie Sedaap (Rp 504 miliar), dan Partai Nasdem (Rp 425 miliar).</p>

<blockquote>
  <p>Menurut saya, Top Coffee sendiri tidak hanya besar secara nominal. Secara persentase, kenaikan H1 2012 ke H1 2013 adalah 190%.</p>
</blockquote>

<h3 id="gebrakan-marketing-campaign-yang-belum-pernah-ada-sebelumnya">Gebrakan <em>Marketing Campaign</em> yang Belum Pernah Ada Sebelumnya</h3>

<ol>
  <li><strong>Brand Ambassador: Iwan Fals</strong>; Bukan sekadar artis. Iwan Fals adalah ikon lintas generasi. Satu iklan, dua segmen: orang tua (nostalgia) dan anak muda (penasaran). Iwan bahkan memberikan testimoni: <em>“Saya tidak merasakan nyeri lambung ketika minum ini.”</em></li>
  <li><strong>Model Iklan: Samuel Zylgwyn &amp; Nikita Willy</strong>; Menarget anak muda dengan varian Kopi Susu &amp; Mocca.</li>
  <li><strong>Tagline: “Kopinya Orang Indonesia”</strong>; Nasionalisme sebagai senjata pemasaran.</li>
  <li><strong>Klaim Diferensiasi</strong>; Pertama di Indonesia yang <em>blend Robusta + Arabica</em> untuk kopi instan.</li>
  <li><strong>Harga: Rp 7.500/dus (isi 10)</strong>; Sangat terjangkau, langsung sasar pasar massal.</li>
  <li><strong>BTL Activity</strong>; Konser Iwan Fals di berbagai daerah sebagai ajang <em>sampling</em>.</li>
</ol>

<h3 id="tapi-hasilnya-hanya-3-4-pangsa">Tapi Hasilnya? Hanya 3-4% Pangsa.</h3>

<p>Data <em>Top Brand Index</em> untuk Top Coffee di kategori <em>Ground Coffee</em>:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">Tahun</th>
      <th style="text-align: center">TBI</th>
      <th style="text-align: center">Posisi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">2024</td>
      <td style="text-align: center">3.7%</td>
      <td style="text-align: center">#5</td>
    </tr>
    <tr>
      <td style="text-align: center">2025</td>
      <td style="text-align: center">3.1%</td>
      <td style="text-align: center">#5</td>
    </tr>
  </tbody>
</table>

<p>Rp 421,7 miliar untuk 3,7% pangsa. <strong>Kurang lebih Rp 114 miliar per 1% pangsa pasar.</strong> Kenapa hanya <em>“segitu”</em>?</p>

<h3 id="analisa-empat-alasan-top-coffee-gagal-mengguncang">Analisa: Empat Alasan Top Coffee Gagal Mengguncang</h3>

<h4 id="1-ambigu-positioning-tidak-jelas-main-di-market-mana">1. Ambigu <em>Positioning</em> (Tidak Jelas Main di <em>Market</em> Mana)</h4>

<p>Ini masalah fundamental. Produk Top Coffee adalah <strong>kopi instan</strong> (<em>sachet</em>) tapi <em>positioning</em>-nya seperti <strong><em>ground coffee</em> tradisional</strong>. Menggunakan Iwan Fals (citra kopi hitam kental), <em>tagline</em> nasionalis, warna kemasan merah-hitam seperti kopi tubruk.</p>

<p>Akibatnya:</p>

<ul>
  <li><strong>Di kategori Ground Coffee:</strong> Dianggap kurang <em>legit</em> karena bentuknya instan. Kalah sama Kapal Api, ABC, dan Luwak.</li>
  <li><strong>Di kategori Instan/Sachet:</strong> Tidak se-_modern_ Good Day, tidak serumit varian Torabika.</li>
</ul>

<p>Kita bisa duga Top Coffee terjebak di antara dua kategori.</p>

<h4 id="2-gebrakan-iklan-tidak-diikuti-retensi">2. Gebrakan Iklan Tidak Diikuti Retensi</h4>

<p>Data belanja iklan menunjukkan <strong>ledakan di tahun pertama</strong> tapi setelah itu? Tidak ada data publik yang menunjukkan bahwa agresivitas itu berlanjut. Sangat mungkin setelah tahun pertama, <em>budget</em> iklan diturunkan signifikan karena target awal tidak tercapai.</p>

<p>Ini berbeda dengan Kapal Api yang konsisten beriklan <strong>setiap tahun selama 40+ tahun</strong>. Atau Luwak White Coffee yang bertahap membangun <em>brand</em>.</p>

<h4 id="3-multi-brand-santos-tetap-tak-terkalahkan">3. <em>Multi-Brand</em> Santos Tetap Tak Terkalahkan</h4>

<p>Bahkan dengan Rp 421 M, Top Coffee hanya mampu merebut sebagian kecil pangsa. Pasalnya:</p>

<table>
  <thead>
    <tr>
      <th>Kondisi</th>
      <th style="text-align: center">2012</th>
      <th style="text-align: center">Sekarang</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Total Santos Group</strong></td>
      <td style="text-align: center">~60%+</td>
      <td style="text-align: center">~60%+</td>
    </tr>
    <tr>
      <td><strong>Top Coffee</strong></td>
      <td style="text-align: center">0% (baru masuk)</td>
      <td style="text-align: center">3.1%</td>
    </tr>
    <tr>
      <td><strong>Torabika (Ground)</strong></td>
      <td style="text-align: center">8.5%</td>
      <td style="text-align: center">❌</td>
    </tr>
    <tr>
      <td><strong>Luwak White Coffee</strong></td>
      <td style="text-align: center">~5% (mulai naik)</td>
      <td style="text-align: center">14.4%</td>
    </tr>
  </tbody>
</table>

<p>Santos tetap di ~60%. Yang berubah hanyalah siapa yang mengisi 40% sisanya — dari yang dikuasai Torabika + Nescafe + Indocafe, bergeser ke Luwak + Top Coffee + Excelso.</p>

<h4 id="4-luwak-white-coffee-mencuri-perhatian">4. Luwak White Coffee Mencuri Perhatian</h4>

<p>Antara 2012-2014, ada <em>brand</em> yang benar-benar mengubah peta persaingan bukan Top Coffee tapi <strong>Luwak White Coffee</strong> yang sukses menciptakan kategori baru: <em>“White Coffee”</em>. Ini cerita selanjutnya.</p>

<hr />

<h2 id="kemunculan-white-coffee-luwak-white-coffee">Kemunculan White Coffee: Luwak White Coffee</h2>

<p>Di tengah hiruk-pikuk perang iklan Top Coffee vs Kapal Api, ada pemain yang bergerak diam-diam tapi efektif: <strong>Luwak White Coffee</strong>.</p>

<h3 id="apa-itu-white-coffee">Apa Itu <em>White Coffee</em>?</h3>

<p><em>“White Coffee”</em> bukanlah kopi dengan susu putih. Ini adalah metode pengolahan kopi di mana biji kopi <strong>disangrai dengan suhu lebih rendah dan waktu lebih singkat</strong> dari kopi biasa sehingga menghasilkan warna yang lebih terang, rasa yang lebih ringan, dan tingkat keasaman yang lebih rendah.</p>

<p>Di Indonesia, istilah <em>“White Coffee”</em> dipopulerkan oleh <strong>Luwak White Coffee</strong> dan mereka berhasil menciptakan <strong>kategori baru</strong> yang sebelumnya tidak ada di peta persaingan.</p>

<h3 id="dampak-luwak-white-coffee-pada-pasar">Dampak Luwak White Coffee pada Pasar</h3>

<table>
  <thead>
    <tr>
      <th>Indikator</th>
      <th style="text-align: center">Sebelum Luwak</th>
      <th style="text-align: center">Setelah Luwak</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kategori <em>White Coffee</em></td>
      <td style="text-align: center">Tidak ada</td>
      <td style="text-align: center">Muncul sebagai sub-segmen</td>
    </tr>
    <tr>
      <td>Pesaing di kategori</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center">Luwak White Coffee memimpin</td>
    </tr>
    <tr>
      <td>TBI Luwak (2024)</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center"><strong>20.1%</strong> (#2 di Ground Coffee)</td>
    </tr>
    <tr>
      <td>TBI Luwak (2025)</td>
      <td style="text-align: center">—</td>
      <td style="text-align: center"><strong>14.4%</strong> (#3 di Ground Coffee)</td>
    </tr>
  </tbody>
</table>

<p>Luwak White Coffee mengambil pangsa dari mana? Dua sumber:</p>

<ol>
  <li><strong>Dari ground coffee tradisional</strong>; konsumen yang bosan dengan rasa kopi hitam pahit beralih ke <em>“white coffee”</em> yang lebih ringan.</li>
  <li><strong>Dari kopi instan</strong>; konsumen yang ingin naik kelas dari <em>sachet</em> ke kopi bubuk <em>“semi-premium”</em>.</li>
</ol>

<p>Inilah yang tidak dilakukan Top Coffee: <strong>menciptakan kategori baru.</strong> Top Coffee mencoba merebut pangsa dari pemain <em>existing</em> dengan uang; Luwak menciptakan <em>pie</em> baru dan memimpinnya.</p>

<hr />

<h2 id="santos-jaya-abadi-satu-induk-banyak-merek">Santos Jaya Abadi: Satu Induk, Banyak Merek</h2>

<p>Saya rasa penting untuk mengakhiri bagian analisis dengan melihat gambaran besarnya: <strong>siapa sebenarnya yang menguasai kopi Indonesia?</strong></p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post1_kopi/fig6_santos_multibrand.png" alt="" /></p>

<p>Dari gambar di atas bisa dilihat bahwa Santos Jaya Abadi memiliki setidaknya enam merek yang mencakup semua segmen:</p>

<table>
  <thead>
    <tr>
      <th>Merek</th>
      <th>Segmen</th>
      <th style="text-align: center">TBI Tertinggi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Kapal Api</strong></td>
      <td><em>Ground Coffee</em> — Massal</td>
      <td style="text-align: center"><strong>62.8%</strong></td>
    </tr>
    <tr>
      <td><strong>ABC</strong></td>
      <td><em>Ground Coffee</em> — Ekonomis</td>
      <td style="text-align: center"><strong>24.4%</strong></td>
    </tr>
    <tr>
      <td><strong>Good Day</strong></td>
      <td>Kopi Instan/Sachet</td>
      <td style="text-align: center"><strong>48.4%</strong></td>
    </tr>
    <tr>
      <td><strong>Excelso</strong></td>
      <td>Premium / Kedai Kopi</td>
      <td style="text-align: center"><strong>5.5%</strong></td>
    </tr>
    <tr>
      <td><strong>Merek Ya</strong></td>
      <td>Ekonomis</td>
      <td style="text-align: center"><strong>2.2%</strong></td>
    </tr>
    <tr>
      <td><strong>Fresco</strong></td>
      <td>Lainnya</td>
      <td style="text-align: center"><strong>1.0%</strong></td>
    </tr>
  </tbody>
</table>

<p>Total TBI tertinggi yang bisa dikumpulkan Santos: <strong>62.8 + 24.4 + 48.4 + 5.5 + 2.2 + 1.0 = ~144% dari total indeks.</strong> Tapi ini tidak bisa dijumlahkan langsung karena kategori berbeda. Yang jelas: di setiap kategori kopi di Indonesia, <strong>Santos selalu ada di puncak.</strong></p>

<hr />

<h2 id="analisis-komparatif-tiga-jalan-bertahan">Analisis Komparatif: Tiga Jalan Bertahan</h2>

<p>Dari tiga brand yang saya analisis (<strong>Kapal Api, Torabika, dan Top Coffee</strong>) masing-masing mengambil jalan yang berbeda. Dan hasilnya berbeda pula.</p>

<h3 id="matriks-perbandingan">Matriks Perbandingan</h3>

<table>
  <thead>
    <tr>
      <th>Dimensi</th>
      <th style="text-align: center">Kapal Api (Santos)</th>
      <th style="text-align: center">Torabika (Mayora)</th>
      <th style="text-align: center">Top Coffee (Wings)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Tahun Masuk</strong></td>
      <td style="text-align: center">1978</td>
      <td style="text-align: center">1990</td>
      <td style="text-align: center">2012</td>
    </tr>
    <tr>
      <td><strong>Modal Awal</strong></td>
      <td style="text-align: center">Organik, puluhan tahun</td>
      <td style="text-align: center">Organik, distribusi Mayora</td>
      <td style="text-align: center">Rp 421 M iklan tahun pertama</td>
    </tr>
    <tr>
      <td><strong>Strategi</strong></td>
      <td style="text-align: center">Multi-brand, konsisten</td>
      <td style="text-align: center">Bergeser fokus ke instan</td>
      <td style="text-align: center">Gebrak &amp; harapkan dampak instan</td>
    </tr>
    <tr>
      <td><strong>Inovasi</strong></td>
      <td style="text-align: center">Rutin, setiap tahun</td>
      <td style="text-align: center">Stagnan di ground, inovatif di instan</td>
      <td style="text-align: center">Produk unik (blend Robusta-Arabica)</td>
    </tr>
    <tr>
      <td><strong>Distribusi</strong></td>
      <td style="text-align: center">Super luas (Fastrata Buana)</td>
      <td style="text-align: center">Numpang distribusi Mayora</td>
      <td style="text-align: center">Kuat (Wings Group)</td>
    </tr>
    <tr>
      <td><strong>Hasil TBI 2025</strong></td>
      <td style="text-align: center"><strong>~50%</strong> (Kapal Api)</td>
      <td style="text-align: center"><strong>❌</strong> Ground / <strong>6.4%</strong> Instan</td>
      <td style="text-align: center"><strong>3.1%</strong></td>
    </tr>
    <tr>
      <td><strong>Kondisi 2026</strong></td>
      <td style="text-align: center">Kokoh</td>
      <td style="text-align: center">Bertahan di instan</td>
      <td style="text-align: center">Terjebak 3-4%</td>
    </tr>
  </tbody>
</table>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/market_analisis/post1_kopi/fig5_pangsa_2006_vs_2025.png" alt="" /></p>

<h3 id="pelajaran-untuk-kita-semua">Pelajaran untuk Kita Semua</h3>

<blockquote>
  <p><strong>Uang bisa membeli <em>awareness</em>. Tapi loyalitas harus dibangun bertahun-tahun.</strong></p>
</blockquote>

<p>Top Coffee membuktikan bahwa Rp 421 miliar cuma cukup untuk <em>menggebrak pintu</em> tapi tidak untuk sampai <em>duduk di kursi</em>. Setelah gebrakan selesai, yang diperlukan adalah konsistensi, inovasi, dan distribusi yang merata.</p>

<p>Sementara Torabika walaupun yang punya modal lebih kecil tapi memilih bertahan dengan <strong>bergeser</strong>. Daripada mati di <em>ground coffee</em>, mereka pindah ke instan. Hasilnya: masih hidup, meski tidak pernah jadi pemimpin.</p>

<p>Kapal Api (Santos), di sisi lain mereka tidak melakukan satu hal besar, tapi ribuan hal kecil dengan benar setiap hari selama 40+ tahun. <strong>Multi-brand, distribusi, inovasi, dan konsistensi.</strong></p>

<hr />

<h2 id="kesimpulan">Kesimpulan</h2>

<p>Perjalanan pasar kopi bubuk Indonesia dari 2006 sampai 2026 memberikan beberapa pelajaran yang, <strong>menurut keyakinan saya</strong> relevan untuk siapapun yang berkecimpung di industri FMCG:</p>

<ol>
  <li><strong>Multi-brand strategy adalah benteng pertahanan terkuat.</strong> Satu brand bisa turun, tapi grup tetap kokoh. Santos membuktikan ini dengan enam mereknya.</li>
  <li><strong>Pergeseran bukan kejatuhan.</strong> Torabika tidak hilang tapi dia pindah ke meja yang lebih cocok. Ini keputusan bisnis yang rasional, meski secara <em>brand positioning</em> terkesan <em>“menurun”</em>.</li>
  <li><strong>Kategori baru lebih efektif daripada merebut pangsa existing.</strong> Luwak White Coffee menciptakan kategori <em>“White Coffee”</em> dan langsung memimpinnya. Top Coffee mencoba merebut pangsa Kapal Api dengan uang namun kurang berhasil.</li>
  <li><strong>Konsistensi &gt; gebrakan.</strong> Rp 421 miliar di tahun pertama lebih rendah nilainya dari Rp 10 miliar per tahun selama 42 tahun.</li>
</ol>

<h3 id="epilog"><em>Epilog</em></h3>

<p>Saya menulis artikel ini sambil minum kopi, <em>tentu saja hehe</em>.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Marketing" /><category term="Sales" /><category term="Business" /><category term="Top Brand Index" /><category term="Market Share" /><category term="Market Size" /><category term="Kopi" /><category term="Kapal Api" /><category term="Torabika" /><category term="Top Coffee" /><summary type="html"><![CDATA[Saya masih ingat dengan jelas pada tahun 2010. Saat itu saya sedang mengerjakan sebuah survei market untuk salah satu pemain di industri kopi. Salah satu kategorinya adalah kopi bubuk, sebuah kategori yang sebenarnya sudah sangat dewasa, dengan pemain-pemain yang sudah mapan puluhan tahun.]]></summary></entry><entry><title type="html">Mengukur Seberapa Sensitif Konsumen terhadap Perubahan Harga dari Data Transaksi</title><link href="https://ikanx101.com/blog/pe-2/" rel="alternate" type="text/html" title="Mengukur Seberapa Sensitif Konsumen terhadap Perubahan Harga dari Data Transaksi" /><published>2026-04-27T13:46:30+00:00</published><updated>2026-04-27T13:46:30+00:00</updated><id>https://ikanx101.com/blog/pe-2</id><content type="html" xml:base="https://ikanx101.com/blog/pe-2/"><![CDATA[<p>Di suatu waktu saat sedang <em>meeting</em> untuk menentukan strategi <em>pricing</em>
produk, ada informasi yang menunjukkan bahwa harga bahan baku akan naik
15% sehingga <em>margin</em> mulai tergerus. Lalu seseorang dari tim <em>sales</em>
mengusulkan: <em>“Kita naikkan harga jual saja”</em>. Seketika ruangan menjadi
sunyi sejenak, kemudian <em>finance director</em> bertanya:</p>

<blockquote>
  <p><em>“Kalau harga kita naikkan 10%, kira-kira penjualan kita akan turun
berapa persen?”</em></p>
</blockquote>

<p>Sering kali, jawaban yang muncul pada saat <em>meeting</em> tersebut hanyalah
tebakan berbasis intuisi: <em>“Mungkin turun sedikit”</em> atau <em>“Kompetitor
juga naik kok, harusnya aman”</em>.</p>

<p>Padahal, data untuk menjawab pertanyaan ini dengan presisi sebenarnya
sudah ada di sistem. Kita memiliki data transaksi harian yang tersimpan
rapi tapi jarang diolah untuk keperluan ini. Itulah yang akan kita bahas
hari ini: <a href="https://ikanx101.com/blog/blog-posting-regresi/"><em>Price Elasticity of
Demand</em></a>, cara
menghitungnya dari data transaksi, dan bagaimana hasilnya bisa langsung
dipakai untuk keputusan <em>pricing</em>.</p>

<hr />

<h1 id="apa-itu-price-elasticity-of-demand">Apa Itu <em>Price Elasticity of Demand</em>?</h1>

<p>Sebagaimana apa yang pernah saya ulas di tulisan saya
<a href="https://ikanx101.com/blog/price-elasticity/">sebelumnya</a>, <em>Price
Elasticity of Demand</em> (PED) adalah ukuran seberapa besar persentase
perubahan <em>sales quantity</em> yang diminta ketika harga berubah sebesar
satu persen.</p>

<p>Rumus dasarnya sederhana:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PED = (% Perubahan Kuantitas) / (% Perubahan Harga)  Atau dalam bentuk yang lebih operasional: PED = (dQ/Q) / (dP/P) = (dQ/dP) x (P/Q)
</code></pre></div></div>

<p>Karena kenaikan harga hampir selalu diikuti penurunan permintaan, nilai
PED biasanya negatif. Tapi dalam praktiknya, kita sering bekerja dengan
nilai absolutnya. Berikut cara membaca nilai PED:</p>

<table>
  <thead>
    <tr>
      <th>Nilai PED</th>
      <th>Kategori</th>
      <th>Artinya</th>
      <th>Contoh kategori produk</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">&gt; 1</code></td>
      <td>Elastis</td>
      <td>Konsumen sangat sensitif terhadap harga</td>
      <td>Minuman ringan, <em>snack premium</em>, pakaian</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">= 1</code></td>
      <td>Unit elastis</td>
      <td>% perubahan <em>sales quantity</em> sama dengan % perubahan harga</td>
      <td>Kondisi khusus, jarang terjadi di dunia nyata</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">0 &lt; abs(PED) &lt; 1</code></td>
      <td>Inelastis</td>
      <td>Konsumen kurang sensitif terhadap harga</td>
      <td>Beras, garam, BBM, obat-obatan</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">= 0</code></td>
      <td>Perfectly inelastis</td>
      <td>Harga naik berapapun, <em>sales quantity</em> tidak berubah</td>
      <td>Sangat jarang terjadi. Biasanya obat-obatan khusus.</td>
    </tr>
  </tbody>
</table>

<h1 id="implikasi-langsung-untuk-revenue">Implikasi Langsung untuk <em>Revenue</em></h1>

<p>Inilah bagian yang paling <em>actionable</em>. Jika kita tahu nilai PED, maka
kita bisa tahu apa yang akan terjadi pada <em>revenue</em> kalau harga kita
ubah.</p>

<table>
  <thead>
    <tr>
      <th>Kondisi</th>
      <th>Jika harga naik</th>
      <th>Jika harga turun</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Elastis</td>
      <td>Revenue TURUN karena <em>sales qty</em> turun lebih besar dari kenaikan harga</td>
      <td>Revenue NAIK karena <em>sales qty</em> naik lebih besar dari penurunan harga</td>
    </tr>
    <tr>
      <td>Inelastis</td>
      <td>Revenue NAIK karena <em>sales qty</em> turun tapi tidak cukup mengimbangi kenaikan harga</td>
      <td>Revenue TURUN karena penurunan harga lebih besar dari kenaikan <em>sales qty</em></td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p><em>Kalau produk kamu inelastis (konsumen tidak terlalu sensitif harga),
kenaikan harga justru meningkatkan <strong>revenue</strong>. Kalau elastis,
kenaikan harga akan memangkas <strong>revenue</strong> karena konsumen langsung
kabur ke kompetitor atau berhenti beli.</em></p>
</blockquote>

<h1 id="metode-perhitungan">Metode Perhitungan</h1>

<p>Salah satu metode perhitungan yang bisa digunakan adalah <em>log-log
regression</em>. Metode ini paling populer dan paling mudah
diinterpretasikan. Model ini dikenal sebagai <em>constant elasticity
model</em>. Ide dasarnya adalah alih-alih meregresikan <em>sales qty</em> langsung
terhadap <em>price</em>, kita meregresikan <em>log(sales qty)</em> terhadap
<em>log(price)</em>. Model <em>log-log</em>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>log(Qty) = α + β × log(Harga) + ε  
</code></pre></div></div>

<p>Di mana <strong>β</strong> adalah koefisien yang langsung bisa dibaca sebagai <em>price
elasticity</em>. Jika <code class="language-plaintext highlighter-rouge">β = -1.5</code> berarti setiap kenaikan harga <strong>1%</strong> maka
akan ada penurunan volume <strong>1.5%</strong>.</p>

<p>Mengapa <em>log-log</em> lebih disukai dari regresi linier biasa? Ada tiga
alasan utama:</p>

<ol>
  <li>Koefisien bisa langsung direpresentasikan sebagai indeks
elastisitas. Tidak perlu melakukan konversi apapun.</li>
  <li>Hubungan <em>price</em> dan <em>sales qty</em> di dunia nyata lebih sering
bersifat multiplikatif (persentase) daripada aditif (unit absolut).
<em>Log-log</em> menangkap ini lebih natural.</li>
  <li>Transformasi logaritmik <code class="language-plaintext highlighter-rouge">log( )</code> sering menstabilkan variansi
(membuat data lebih <em>compact</em>) dan membuat distribusi residual lebih
mendekati normal.</li>
</ol>

<h1 id="case-study-menggunakan-data-simulasi"><em>Case Study</em> Menggunakan Data Simulasi</h1>

<p>Untuk membantu menjelaskan tentang model ini, saya akan menggunakan data
simulasi berdasarkan suatu skenario yang saya buat. Berikut adalah
skenarionya:</p>

<blockquote>
  <p>Kita adalah <em>data analyst</em> di sebuah perusahaan FMCG minuman teh
kemasan. Produk kita dijual di jaringan minimarket seluruh
Jabodetabek. Selama 2 tahun terakhir, ada beberapa kali perubahan
harga. Bisa naik maupun turun karena berbagai alasan seperti: kenaikan
biaya produksi, promo periodik, dan penyesuaian kompetitif.</p>
</blockquote>

<p>Data yang saat ini tersedia adalah <em>sales qty</em> harian per gerai beserta
harga jual yang berlaku hari itu. Kita punya sekitar 730 hari data untuk
50 gerai. Berdasarkan banyaknya baris data yang kita miliki, seharunya
data ini sudah cukup untuk estimasi yang <em>robust</em>.</p>

<p>Kita buat data transaksi yang realistis (lengkap dengan efek musiman,
promosi, noise, dan beberapa kali kenaikan harga yang jelas).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Dimensi data: 36550 baris x 13 kolom

Periode: 19723 - 20453 

Rows: 36,550
Columns: 13
$ tanggal    &lt;date&gt; 2024-01-01, 2024-01-02, 2024-01-03, 2024-01-04, 2024-01-05…
$ gerai_id   &lt;int&gt; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ skala_base &lt;dbl&gt; 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,…
$ tipe       &lt;chr&gt; "Residensial", "Residensial", "Residensial", "Residensial",…
$ harga      &lt;dbl&gt; 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500,…
$ hari_ke    &lt;dbl&gt; 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6,…
$ efek_hari  &lt;dbl&gt; 1.0, 1.0, 1.0, 1.0, 1.1, 1.3, 1.2, 1.0, 1.0, 1.0, 1.0, 1.1,…
$ bln        &lt;dbl&gt; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ efek_bulan &lt;dbl&gt; 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15,…
$ harga_ref  &lt;dbl&gt; 5875, 5875, 5875, 5875, 5875, 5875, 5875, 5875, 5875, 5875,…
$ elas       &lt;dbl&gt; -1.35, -1.35, -1.35, -1.35, -1.35, -1.35, -1.35, -1.35, -1.…
$ qty_true   &lt;dbl&gt; 91.76809, 91.76809, 91.76809, 91.76809, 100.94490, 119.2985…
$ qty        &lt;dbl&gt; 81, 95, 79, 93, 100, 149, 126, 86, 86, 75, 97, 101, 140, 12…
</code></pre></div></div>

<p>Berikut adalah sampel datanya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>     tanggal gerai_id        tipe harga hari_ke bln qty
1 2024-01-01        1 Residensial  5500       1   1  81
2 2024-01-02        1 Residensial  5500       2   1  95
3 2024-01-03        1 Residensial  5500       3   1  79
4 2024-01-04        1 Residensial  5500       4   1  93
5 2024-01-05        1 Residensial  5500       5   1 100
6 2024-01-06        1 Residensial  5500       6   1 149
</code></pre></div></div>

<p>Jika digambarkan ke dalam <em>line chart</em>, berikut adalah total <em>sales qty</em>
dari seluruh gerai di berbagai tipe harga:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/price%20elasticity/post2/draft_files/figure-commonmark/unnamed-chunk-4-1.png" alt="" /></p>

<p>Sebelum membangun model regresi, kita perlu mengeksplorasi data secara
visual. Ini penting untuk memastikan apakah ada <em>signal</em> yang bisa
ditangkap dan tidak ada anomali yang merusak analisis. Pertama-tama saya
akan membuat analisa sederhana dan visualisasi distribusi <em>sales qty</em>
per <em>price level</em>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== RINGKASAN VOLUME PER HARGA ===

# A tibble: 3 × 5
  harga n_observasi rata_qty median_qty sd_qty
  &lt;dbl&gt;       &lt;int&gt;    &lt;dbl&gt;      &lt;dbl&gt;  &lt;dbl&gt;
1  5500       18150    104.         104   31.3
2  6000        9200     86.0         86   25.4
3  6500        9200     77.6         77   23.2
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/price%20elasticity/post2/draft_files/figure-commonmark/unnamed-chunk-5-1.png" alt="" /></p>

<p>Berikut adalah visualisasi <em>scatterplot</em> antara <em>log(price)</em> dan
<em>log(sales qty)</em>:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/price%20elasticity/post2/draft_files/figure-commonmark/unnamed-chunk-6-1.png" alt="" /></p>

<p>Sekarang kita akan membuat beberapa model <em>price elasticity</em> dengan
<em>log-log regression</em>. Pada tulisan ini, saya tidak akan membahas tentang
<a href="https://ikanx101.com/blog/belajar-regresi/"><em>goodness of fit</em> dan uji
asumsi</a> dari model regresi
yang dihasilkan.</p>

<h2 id="model-1-regresi-agregat-baseline">Model 1: Regresi Agregat (<em>Baseline</em>)</h2>

<p>Kita mulai dari model paling sederhana dulu: regresikan <em>log(sales qty)</em>
terhadap <em>log(price)</em> menggunakan seluruh data tanpa memisahkan per tipe
gerai.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Model 1: Log-log regresi sederhana ──────────────────────────</span><span class="w">
</span><span class="n">model1</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="n">log_qty</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">log_harga</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">df_weekly</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== MODEL 1: AGREGAT (tanpa kontrol) ===


Call:
lm(formula = log_qty ~ log_harga, data = df_weekly)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.97502 -0.14055  0.06608  0.20481  0.58363 

Coefficients:
            Estimate Std. Error t value Pr(&gt;|t|)    
(Intercept) 20.08356    0.49624   40.47   &lt;2e-16 ***
log_harga   -1.79761    0.05719  -31.43   &lt;2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2866 on 5248 degrees of freedom
Multiple R-squared:  0.1584,    Adjusted R-squared:  0.1583 
F-statistic:   988 on 1 and 5248 DF,  p-value: &lt; 2.2e-16


Estimasi Elastisitas (Model 1): -1.798 

Interpretasi: kenaikan harga 1% -&gt; -1.798 % perubahan volume
</code></pre></div></div>

<h2 id="model-2-regresi-dengan-kontrol-musiman-dan-tipe-gerai">Model 2: Regresi dengan Kontrol Musiman dan Tipe Gerai</h2>

<p>Model pertama mengabaikan faktor-faktor yang juga mempengaruhi <em>sales
qty</em> seperti <em>seasonal</em>, hari dalam minggu, dan tipe gerai. Ini bisa
membuat estimasi elastisitas bias (<em>confounding</em>). Kita tambahkan
variabel kontrol seperti:</p>

<ol>
  <li>Apakah sedang bulan Ramadhan.</li>
  <li>Apakah musim lbiuran?</li>
  <li>Faktor tipe gerai dijadikan faktor.</li>
</ol>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Persiapan variabel kontrol ───────────────────────────────────</span><span class="w">
</span><span class="n">df_weekly</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">df_weekly</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
  </span><span class="n">mutate</span><span class="p">(</span><span class="w">
    </span><span class="n">bulan</span><span class="w">       </span><span class="o">=</span><span class="w"> </span><span class="n">month</span><span class="p">(</span><span class="n">minggu</span><span class="p">),</span><span class="w">
    </span><span class="c1"># Dummy musiman</span><span class="w">
    </span><span class="n">is_ramadan</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="nf">as.integer</span><span class="p">(</span><span class="n">bulan</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="m">4</span><span class="p">)),</span><span class="w">
    </span><span class="n">is_liburan</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="nf">as.integer</span><span class="p">(</span><span class="n">bulan</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">6</span><span class="p">,</span><span class="w"> </span><span class="m">7</span><span class="p">,</span><span class="w"> </span><span class="m">12</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">)),</span><span class="w">
    </span><span class="c1"># Log gerai size: kontrol skala tiap gerai</span><span class="w">
    </span><span class="c1"># Proxy: rata-rata volume saat harga paling rendah</span><span class="w">
    </span><span class="n">tipe</span><span class="w">        </span><span class="o">=</span><span class="w"> </span><span class="n">factor</span><span class="p">(</span><span class="n">tipe</span><span class="p">,</span><span class="w"> </span><span class="n">levels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'Residensial'</span><span class="p">,</span><span class="w">
                                           </span><span class="s1">'Perkantoran'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Sekolah'</span><span class="p">))</span><span class="w">
  </span><span class="p">)</span><span class="w">

</span><span class="c1"># ── Model 2: Dengan kontrol lengkap ──────────────────────────────</span><span class="w">
</span><span class="n">model2</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="w">
  </span><span class="n">log_qty</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">log_harga</span><span class="w"> </span><span class="o">+</span><span class="w">
            </span><span class="n">tipe</span><span class="w"> </span><span class="o">+</span><span class="w">                </span><span class="c1"># Kontrol tipe gerai</span><span class="w">
            </span><span class="n">is_ramadan</span><span class="w"> </span><span class="o">+</span><span class="w">          </span><span class="c1"># Kontrol efek Ramadan</span><span class="w">
            </span><span class="n">is_liburan</span><span class="w"> </span><span class="o">+</span><span class="w">          </span><span class="c1"># Kontrol efek liburan</span><span class="w">
            </span><span class="n">factor</span><span class="p">(</span><span class="n">month</span><span class="p">(</span><span class="n">minggu</span><span class="p">))</span><span class="w"> </span><span class="c1"># Kontrol musiman bulanan</span><span class="w">
  </span><span class="p">,</span><span class="w">
  </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">df_weekly</span><span class="w">
</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== MODEL 2: DENGAN KONTROL LENGKAP ===


Call:
lm(formula = log_qty ~ log_harga + tipe + is_ramadan + is_liburan + 
    factor(month(minggu)), data = df_weekly)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.85994 -0.13123  0.07352  0.19132  0.51359 

Coefficients: (2 not defined because of singularities)
                         Estimate Std. Error t value Pr(&gt;|t|)    
(Intercept)             15.390587   0.973631  15.807  &lt; 2e-16 ***
log_harga               -1.262097   0.111339 -11.336  &lt; 2e-16 ***
tipePerkantoran          0.043300   0.009124   4.746 2.13e-06 ***
tipeSekolah             -0.145998   0.009407 -15.520  &lt; 2e-16 ***
is_ramadan               0.191213   0.023606   8.100 6.77e-16 ***
is_liburan               0.120815   0.023606   5.118 3.20e-07 ***
factor(month(minggu))2   0.005204   0.023606   0.220   0.8255    
factor(month(minggu))3   0.025775   0.018078   1.426   0.1540    
factor(month(minggu))4         NA         NA      NA       NA    
factor(month(minggu))5  -0.001068   0.023606  -0.045   0.9639    
factor(month(minggu))6  -0.033489   0.018211  -1.839   0.0660 .  
factor(month(minggu))7  -0.045685   0.023731  -1.925   0.0543 .  
factor(month(minggu))8  -0.010459   0.017966  -0.582   0.5605    
factor(month(minggu))9  -0.010680   0.017993  -0.594   0.5528    
factor(month(minggu))10 -0.010054   0.018526  -0.543   0.5873    
factor(month(minggu))11        NA         NA      NA       NA    
factor(month(minggu))12  0.004310   0.021556   0.200   0.8415    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2695 on 5235 degrees of freedom
Multiple R-squared:  0.2579,    Adjusted R-squared:  0.256 
F-statistic:   130 on 14 and 5235 DF,  p-value: &lt; 2.2e-16


Estimasi Elastisitas (Model 2): -1.262 

Interpretasi: kenaikan harga 1% -&gt; -1.262 % perubahan volume
</code></pre></div></div>

<h2 id="model-3-elastisitas-per-tipe-gerai-interaction-model">Model 3: Elastisitas per Tipe Gerai (<em>Interaction Model</em>)</h2>

<p>Pertanyaan yang lebih dalam: apakah konsumen di gerai tipe yang berbeda
punya sensitivitas harga yang berbeda juga? Gerai di dekat sekolah
mungkin lebih sensitif karena konsumennya anak-anak dengan uang jajan
terbatas sedangkan gerai di kawasan perkantoran mungkin lebih inelastis.</p>

<p>Oleh karena itu, kita tambahkan <em>interaction term</em> antara <em>log(price)</em>
dan tipe gerai. Caranya adalah dengan mengalikan kedua variabel
tersebut.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Model 3: Interaksi harga x tipe gerai ────────────────────────</span><span class="w">
</span><span class="n">model3</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="w">
  </span><span class="n">log_qty</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">log_harga</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">tipe</span><span class="w"> </span><span class="o">+</span><span class="w">    </span><span class="c1"># Interaksi: elastisitas berbeda per tipe</span><span class="w">
            </span><span class="n">is_ramadan</span><span class="w"> </span><span class="o">+</span><span class="w">
            </span><span class="n">is_liburan</span><span class="w"> </span><span class="o">+</span><span class="w">
            </span><span class="n">factor</span><span class="p">(</span><span class="n">month</span><span class="p">(</span><span class="n">minggu</span><span class="p">))</span><span class="w">
  </span><span class="p">,</span><span class="w">
  </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">df_weekly</span><span class="w">
</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== MODEL 3: INTERAKSI HARGA x TIPE GERAI ===


Call:
lm(formula = log_qty ~ log_harga * tipe + is_ramadan + is_liburan + 
    factor(month(minggu)), data = df_weekly)

Residuals:
    Min      1Q  Median      3Q     Max 
-0.8317 -0.1315  0.0757  0.1910  0.5059 

Coefficients: (2 not defined because of singularities)
                           Estimate Std. Error t value Pr(&gt;|t|)    
(Intercept)               15.731942   1.062017  14.813  &lt; 2e-16 ***
log_harga                 -1.301438   0.121602 -10.702  &lt; 2e-16 ***
tipePerkantoran           -4.103998   1.141809  -3.594 0.000328 ***
tipeSekolah                2.826712   1.177192   2.401 0.016375 *  
is_ramadan                 0.191213   0.023549   8.120 5.77e-16 ***
is_liburan                 0.120815   0.023549   5.130 3.00e-07 ***
factor(month(minggu))2     0.005204   0.023549   0.221 0.825113    
factor(month(minggu))3     0.025775   0.018034   1.429 0.153002    
factor(month(minggu))4           NA         NA      NA       NA    
factor(month(minggu))5    -0.001068   0.023549  -0.045 0.963816    
factor(month(minggu))6    -0.033489   0.018167  -1.843 0.065324 .  
factor(month(minggu))7    -0.045685   0.023674  -1.930 0.053685 .  
factor(month(minggu))8    -0.010459   0.017922  -0.584 0.559542    
factor(month(minggu))9    -0.010680   0.017950  -0.595 0.551858    
factor(month(minggu))10   -0.010054   0.018481  -0.544 0.586432    
factor(month(minggu))11          NA         NA      NA       NA    
factor(month(minggu))12    0.004310   0.021503   0.200 0.841157    
log_harga:tipePerkantoran  0.477974   0.131589   3.632 0.000284 ***
log_harga:tipeSekolah     -0.342603   0.135666  -2.525 0.011588 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2688 on 5233 degrees of freedom
Multiple R-squared:  0.2618,    Adjusted R-squared:  0.2596 
F-statistic:   116 on 16 and 5233 DF,  p-value: &lt; 2.2e-16


=== ELASTISITAS PER TIPE GERAI ===

   tipe_gerai elastisitas abs_elas  kategori
1 Residensial      -1.301    1.301   Elastis
2 Perkantoran      -0.823    0.823 Inelastis
3     Sekolah      -1.644    1.644   Elastis
</code></pre></div></div>

<p>Bagi gerai residensial, harga naik 10% mengakibatkan <em>sales qty</em> turun
sekitar 13% sehingga <em>revenue</em> ikut turun. Kita harus hati-hati naikkan
harga di gerai ini.</p>

<p>Bagi gerai perkantoran, harga naik 10% mengakibatkan <em>sales qty</em> turun
sekitar 8% saja sehingga <em>revenue</em> bisa tetap naik. Gerai bertipe ini
lebih aman untuk dinaikkan harganya sampai level harga tertentu.</p>

<p>Bagi gerai sekolah, paling sensitif. Harga naik 10% mengakibatkan <em>sales
qty</em> turun sekitar 16%. Kita harus mempertimbangkan harga yang lebih
kompetitif di sini.</p>

<h1 id="visualisasi-hasil-elastisitas">Visualisasi Hasil Elastisitas</h1>

<p>Berikutnya kita bisa melakukan simulasi jika harga naik X%, apa yang
akan terjadi dengan <em>sales qty</em>? Inilah bagian yang paling langsung
berguna pada saat <em>meeting</em> membahas <em>pricing strategy</em>. Kita buat
kalkulator sederhana: berikan beberapa skenario kenaikan/penurunan
harga, dan lihat dampaknya terhadap <em>sales qty</em> dan <em>revenue</em>. Perlu
saya ingatkan kembali bahwa harga produk saat ini adalah <strong>Rp6.500</strong>.</p>

<p>Hasilnya, pertama-tama adalah visualisasi <em>demand curve</em>: <strong>Berapa Sales
Qty pada Tiap Level Harga?</strong></p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/price%20elasticity/post2/draft_files/figure-commonmark/unnamed-chunk-13-1.png" alt="" /></p>

<p>Kemudian dari grafik di atas, kita bisa menghitung harga optimal
sehingga <em>revenue</em> yang dihasilkan tinggi. <em>Revenue curve</em>: <strong>Harga
Berapa yang Memaksimalkan Pendapatan?</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== HARGA OPTIMAL PER TIPE GERAI ===

# A tibble: 3 × 4
# Groups:   tipe [3]
  tipe        harga qty_pred revenue_per_gerai
  &lt;fct&gt;       &lt;dbl&gt;    &lt;dbl&gt;             &lt;dbl&gt;
1 Residensial  4500      116            520638
2 Perkantoran  8000       66            530207
3 Sekolah      4500      109            492672
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/price%20elasticity/post2/draft_files/figure-commonmark/unnamed-chunk-14-1.png" alt="" /></p>

<p>Bentuk lain dari grafik di atas, saya bisa membuat <em>revenue index</em> vs
persentase perubahan harga.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/price%20elasticity/post2/draft_files/figure-commonmark/unnamed-chunk-15-1.png" alt="" /></p>

<h1 id="keterbatasan-yang-harus-diakui">Keterbatasan yang Harus Diakui</h1>

<ol>
  <li><em>Ceteris paribus</em>. Model elastisitas mengasumsikan faktor lain
konstan. Di dunia nyata, kompetitor ikut bereaksi, kondisi ekonomi
berubah, dan konsumen bisa menemukan substitusi. Estimasi
elastisitas adalah <em>baseline</em>, bukan prediksi deterministik.</li>
  <li><em>Endogeneity</em>. Kalau harga ditentukan berdasarkan kondisi permintaan
(misalnya dinaikkan saat <em>demand</em> sedang tinggi), ada masalah
<em>endogeneity</em> yang membuat estimasi OLS bias. Solusinya adalah
<em>Instrumental Variables</em> (IV) <em>regression</em>. Tentunya hal ini
merupakan topik yang lebih <em>advanced</em>.</li>
  <li>Elastisitas tidak konstan sepanjang waktu. Sensitifitas harga
konsumen bisa berubah seiring meningkatnya pendapatan, munculnya
kompetitor baru, atau perubahan preferensi. Model <em>log-log</em>
mengasumsikan elastisitas konstan (<em>constant elasticity</em>). Untuk
mengecek stabilitas, bisa dilakukan <em>rolling regression</em>.</li>
  <li>Tidak memperhitungkan <em>cross-price elasticity</em>. Perubahan harga
produk kita mempengaruhi penjualan kompetitor, dan sebaliknya. Model
ini hanya mengukur <em>own-price elasticity</em>, bukan reaksi kompetitif.</li>
  <li>Granularitas data. Analisis ini bekerja pada level gerai per minggu.
Untuk keputusan <em>pricing</em> yang lebih presisi, idealnya ada data
SKU-level dan kompetitor <em>price</em> yang dikumpulkan secara sistematis.</li>
</ol>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="R" /><category term="Machine Learning" /><category term="Artificial Intelligence" /><category term="Price Elasticity" /><category term="Regresi Linear" /><category term="Optimization" /><category term="Korelasi" /><category term="Correlation" /><summary type="html"><![CDATA[Di suatu waktu saat sedang meeting untuk menentukan strategi pricing produk, ada informasi yang menunjukkan bahwa harga bahan baku akan naik 15% sehingga margin mulai tergerus. Lalu seseorang dari tim sales mengusulkan: “Kita naikkan harga jual saja”. Seketika ruangan menjadi sunyi sejenak, kemudian finance director bertanya:]]></summary></entry><entry><title type="html">Membuat Algoritma Rekomendasi dari Nol</title><link href="https://ikanx101.com/blog/sistem-reko/" rel="alternate" type="text/html" title="Membuat Algoritma Rekomendasi dari Nol" /><published>2026-04-16T19:27:00+00:00</published><updated>2026-04-16T19:27:00+00:00</updated><id>https://ikanx101.com/blog/sistem-reko</id><content type="html" xml:base="https://ikanx101.com/blog/sistem-reko/"><![CDATA[<p>Semalam, saya dan istri bercerita bahwa di salah satu <em>boarding school</em>
yang kami incar untuk si Sulung memberikan Macbook kepada para siswanya
sebagai <em>daily driver</em> di sekolah. Karena penasaran dengan harganya,
saya coba <em>Googling</em> terkait Macbook.</p>

<blockquote>
  <p>Tiba-tiba pagi ini, iklan-iklan yang muncul di <em>gadget</em> saya dipenuhi
bukan hanya iklan Macbook, tapi juga aksesoris iPad (kebetulan saya
juga pengguna iPad).</p>
</blockquote>

<p>Saya rasa rekan-rekan semua pasti pernah mengalami saat membeli
<em>charger</em> HP, lalu tiba-tiba kalian malah membeli juga <em>casing</em>, kabel
data, dan <em>powerbank</em>? Atau saat kalian membuka Netflix untuk nonton
satu <em>film</em>, tapi berakhir <em>marathon</em> tiga <em>film</em> atau <em>series</em> karena
rekomendasi berikutnya selalu tepat sasaran?</p>

<p>Di dunia digital dimana data bisa ditambang dari <em>user</em> secara tak
disadari, rekomendasi-rekomendasi itu bukan kebetulan belaka. Di balik
setiap rekomendasi itu ada algoritma yang bekerja dan algoritma itu jauh
lebih sederhana dari yang kita bayangkan.</p>

<p>Tidak ada sihir, tidak ada AI yang “membaca pikiran”. Fondasinya
hanyalah satu premis sederhana, yakni:</p>

<blockquote>
  <p><em>Orang yang berperilaku serupa di masa lalu cenderung menyukai hal
yang serupa di masa depan. Lalu produk yang sering dibeli bersama-sama
kemungkinan besar saling melengkapi.</em></p>
</blockquote>

<p>Di tulisan ini, saya akan membangun sistem rekomendasi dari nol
menggunakan <strong>R</strong> tanpa <em>library</em> khusus yang menyembunyikan
mekanismenya. Kita akan mencoba memahami cara kerja sistem rekomendasi
melalui dua pendekatan utama:</p>

<ul>
  <li><em>User-Based Collaborative Filtering</em> dan</li>
  <li><em>Item-Based Collaborative Filtering</em>.</li>
</ul>

<p>Kemudian saya akan coba bandingkan keduanya.</p>

<p>Studi kasusnya: data transaksi toko <em>online</em> FMCG <strong>fiktif</strong> untuk
produk-produk seperti minuman, <em>snack</em>, dan produk perawatan diri.
Tentunya pendekatan ini bisa langsung diaplikasikan ke konteks
<em>e-commerce</em> atau <em>modern trade</em>. Oke, saya mulai ya.</p>

<hr />

<h1 id="beberapa-pendekatan-sistem-rekomendasi">Beberapa Pendekatan Sistem Rekomendasi</h1>

<p>Sebelum masuk ke algoritma, saya akan coba paparkan terlebih dahulu 2 +
1 pendekatan yang bisa digunakan untuk membangun sistem rekomendasi:</p>

<table>
  <thead>
    <tr>
      <th>Pendekatan</th>
      <th>Ide Dasar</th>
      <th>Contoh Penggunaan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Content-Based Filtering</td>
      <td>Rekomendasikan produk yang mirip dengan yang sudah dibeli/disukai user, berdasarkan <strong>atribut</strong> produk</td>
      <td><strong>Spotify</strong> merekomendasikan lagu dengan <em>genre</em> dan tempo serupa</td>
    </tr>
    <tr>
      <td>Collaborative Filtering</td>
      <td>Rekomendasikan berdasarkan kesamaan <strong>perilaku</strong> antar user atau antar item</td>
      <td><strong>Netflix</strong>: <em>“User seperti kamu juga menonton film ini”</em></td>
    </tr>
    <tr>
      <td>Hybrid</td>
      <td>Gabungan antara <strong>konten</strong> dan <strong>perilaku</strong></td>
      <td>Amazon</td>
    </tr>
  </tbody>
</table>

<p>Di tulisan ini saya hanya fokus ke <em>Collaborative Filtering</em> karena
lebih bergantung pada data transaksi yang biasanya sudah tersedia dan
tidak butuh deskripsi atribut produk yang lengkap. <em>Collaborative
Filtering</em> sendiri punya dua variasi:</p>

<ul>
  <li><em>User-Based CF</em>: Cari <em>user</em> yang mirip dengan target <em>user</em>, lalu
rekomendasikan apa yang mereka beli tapi <em>target user</em> belum beli.</li>
  <li><em>Item-Based CF</em>: Cari <em>item</em> yang sering dibeli bersama dengan <em>item</em>
yang sudah dibeli <em>target user</em>, lalu rekomendasikan <em>item</em> tersebut.</li>
</ul>

<h2 id="mana-yang-lebih-baik">Mana yang Lebih Baik?</h2>

<p><em>Item-Based CF</em> umumnya lebih stabil dan lebih mudah di-<em>upscale</em> di
dunia nyata karena hubungan antar produk lebih konsisten dibanding
preferensi antar <em>user</em>. <strong>Netflix</strong> sendiri beralih dari <em>User-Based</em>
ke <em>Item-Based</em> di awal 2000-an karena alasan ini. Tapi keduanya tetap
relevan dan kita akan buat algoritma keduanya.</p>

<h2 id="matematika-di-balik-sistem-rekomendasi">Matematika di Balik Sistem Rekomendasi</h2>

<p>Di beberapa kesempatan, saat saya kembali ke kampus untuk <em>sharing</em>
kepada mahasiswa, saya sering bilang bahwa:</p>

<blockquote>
  <p><strong>Dunia ini dijalankan melalui aljabar</strong>.</p>
</blockquote>

<p>Salah satu aplikasi aljabar yang nyata adalah sistem rekomendasi yang
menggunakan prinsip matriks dalam aljabar.</p>

<p>Semua <em>Collaborative Filtering</em> bekerja di atas satu struktur data yang
disebut <em>User-Item Matrix</em>. Baris menandakan <em>user</em>, Kolom menandakan
<em>item</em> atau produk, dan Nilai menandakan <em>rating</em> dari produk tersebut
atau jumlah pembelian.</p>

<p>Coba lihat contoh ilustrasi matriks berikut ini:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>           Teh Botol   Indomie   Oreo   Pocari   Pringles 
  Andi          3          1        0       2         0 
  Budi          0          2        3       0         2 
  Citra         2          0        1       3         0 
  Dewi          0          3        2       0         3
</code></pre></div></div>

<p>Angka 0 berarti belum pernah beli (atau <em>rating</em> tidak diketahui). Ini
disebut <em>sparse matrix</em> karena mayoritas nilainya 0. Pada kondisi <em>real</em>
di <em>e-commerce</em>, seorang <em>user</em> mungkin hanya pernah beli 0.1% dari
<strong>semua produk yang tersedia</strong>.</p>

<p>Beberapa tahun yang lalu, saya sempat menuliskan tentang <a href="https://ikanx101.com/blog/jarak-simmilarity/">kemiripan
sepasang data</a>. Salah satu
metode untuk mengukur kemiripan adalah menggunakan <a href="https://ikanx101.com/blog/phone-book/"><em>cosine
simmilarity</em></a>. Kunci dari
<em>Collaborative Filtering</em> adalah mengukur <strong>seberapa mirip dua <em>user</em>
atau dua <em>item</em></strong> menggunakan <em>cosine simmilarity</em>.</p>

<p>Secara teknis, saya memperlakukan histori pembelian setiap <em>user</em>
sebagai sebuah <em>vektor</em> di ruang N-dimensi (N = jumlah produk). Dua
<em>users</em> disebut <strong>mirip</strong> kalau vektor mereka menunjuk ke arah yang sama
(maksudnya adalah mereka beli produk yang sama dalam proporsi yang
serupa).</p>

<h2 id="lift-dan-support-cara-alternatif-untuk-item-based-cf"><em>Lift</em> dan <em>Support</em>: Cara Alternatif untuk <em>Item-Based CF</em></h2>

<p>Untuk <em>Item-Based CF</em>, ada metode yang lebih populer yang bisa
digunakan, yakni: <strong><em>association rules</em></strong> (<em>Market Basket Analysis</em>).
Dua <em>metrics</em> penting yang bisa didapatkan dari analisa ini adalah:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Support(A → B)</code>, artinya P(A dan B dibeli bersama). Jumlah transaksi
yang berisi A dan B per total transaksi. <strong>Seberapa sering keduanya (A
dan B) muncul bersamaan</strong>.</li>
  <li><code class="language-plaintext highlighter-rouge">Lift(A → B) = P(A dan B) / (P(A) × P(B))</code>. Nilai <code class="language-plaintext highlighter-rouge">lift &gt; 1</code> berarti
produk A dan B lebih sering ditemui bersama dari yang diharapkan
secara acak (ada asosiasi positif yang nyata). Begitu pula sebaliknya,
<code class="language-plaintext highlighter-rouge">lift &lt; 1</code> berarti produk A dan B jarang ditemui bersama.</li>
</ul>

<hr />

<h1 id="memulai-simulasi">Memulai Simulasi</h1>

<h2 id="membuat-katalog-produk">Membuat Katalog Produk</h2>

<p>Pertama-tama, saya akan membuat katalog produk berisi:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Jumlah produk dalam katalog: 30 

        kategori  n
1        Minuman 10
2 Perawatan Diri 10
3          Snack 10
</code></pre></div></div>

<p>Ini sampel katalog produknya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   item_id             nama_item       kategori harga
9        9          Good Day RTD        Minuman  7000
14      14 Chitato Sapi Panggang          Snack 15000
23      23       Sunsilk Shampoo Perawatan Diri 18000
25      25       Vaseline Lotion Perawatan Diri 20000
</code></pre></div></div>

<h2 id="membuat-simulasi-transaksi">Membuat Simulasi Transaksi</h2>

<p>Selanjutnya saya akan membuat 500 orang <em>users</em> dengan masing-masing
5-20 transaksi. Agar realistis, saya akan tanamkan polas asosiasi secara
eksplisit pada algoritma simulasinya. Misalkan: <em>“Indomie sering dibeli
bersamaan degan Teh Botol atau sabun sering dibeli bersamaan dengan
shampoo”</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Total baris transaksi: 19432 

Jumlah transaksi unik: 6218 

Jumlah user: 500 

Rata-rata item per transaksi: 3.13 
</code></pre></div></div>

<p>Berikut adalah beberapa sampel transaksinya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] user_id      transaksi_id item_id      nama_item    kategori    
[6] harga       
&lt;0 rows&gt; (or 0-length row.names)

  user_id transaksi_id item_id      nama_item kategori harga
1      81     T0081_04       4   Sprite 390ml  Minuman  5000
2      81     T0081_04       5 Kopi Kapal Api  Minuman  2500
3      81     T0081_04       8    Yakult 5pcs  Minuman 12000

  user_id transaksi_id item_id       nama_item kategori harga
1      78     T0078_01      17     Choki-Choki    Snack  1000
2      78     T0078_01      10        Milo RTD  Minuman  7000
3      78     T0078_01       1 Teh Botol 500ml  Minuman  5500
4      78     T0078_01       2      Aqua 600ml  Minuman  3000
5      78     T0078_01      10        Milo RTD  Minuman  7000
6      78     T0078_01      11  Indomie Goreng    Snack  3500
</code></pre></div></div>

<p>Berikut ini adalah visualisasi dari top 15 produk yang paling sering
dibeli:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/recommendizer/draft_files/figure-commonmark/unnamed-chunk-8-1.png" alt="" /></p>

<h2 id="membangun-user-item-matrix">Membangun <em>User-Item Matrix</em></h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Dimensi User-Item Matrix: 500 30 

( 500 user x 30 item)

Sparsity matrix: 30.9 %
</code></pre></div></div>

<p>Ini adalah sampelnya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># A tibble: 4 × 31
  user_id   `3`   `4`   `5`   `7`   `9`  `10`  `15`  `21`  `23`  `24`  `25`
    &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt;
1       9     2     2     0     2     2     1     0     1     0     0     3
2      14     0     1     2     1     1     0     1     0     1     0     3
3      23     2     2     3     5     0     2     0     2     2     0     0
4      25     1     3     3     2     0     1     1     3     1     0     1
# ℹ 19 more variables: `29` &lt;int&gt;, `1` &lt;int&gt;, `2` &lt;int&gt;, `6` &lt;int&gt;, `8` &lt;int&gt;,
#   `11` &lt;int&gt;, `12` &lt;int&gt;, `13` &lt;int&gt;, `16` &lt;int&gt;, `17` &lt;int&gt;, `18` &lt;int&gt;,
#   `20` &lt;int&gt;, `22` &lt;int&gt;, `26` &lt;int&gt;, `27` &lt;int&gt;, `28` &lt;int&gt;, `14` &lt;int&gt;,
#   `30` &lt;int&gt;, `19` &lt;int&gt;
</code></pre></div></div>

<p>Jika saya buat <em>heatmap</em> dari matrix tersebut, begini bentuknya:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/recommendizer/draft_files/figure-commonmark/unnamed-chunk-11-1.png" alt="" /></p>

<h2 id="user-based-collaborative-filtering"><em>User-Based Collaborative Filtering</em></h2>

<h3 id="hitung-cosine-similarity-antar-user">Hitung <em>Cosine Similarity</em> Antar <em>User</em></h3>

<p>Pertama-tama, saya akan menghitung kesamaan antar <em>user</em> dan membuat
<em>simmilarity matrix</em>.</p>

<p>Dari <em>matrix</em> itu, saya bisa mengecek <em>user</em> mana yang paling mirip
dengan <strong><em>user 1</em></strong>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Menghitung user similarity matrix...

Dimensi user similarity matrix: 500 500 


Top 5 user paling mirip dengan User 1:

      290         3       203       248        44 
0.7365895 0.7212280 0.7202966 0.7172191 0.7045639 
</code></pre></div></div>

<h3 id="fungsi-rekomendasi-user-based">Fungsi Rekomendasi <em>User-Based</em></h3>

<p>Dari data-data di atas, saya akan membuat <em>function</em> untuk memberikan
rekomendasi produk apa saja yang bisa ditawarkan kepada <strong><em>user 1</em></strong></p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Fungsi rekomendasi User-Based CF ─────────────────────────────</span><span class="w">
</span><span class="n">rekomendasi_user_based</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">target_user</span><span class="p">,</span><span class="w">
                                    </span><span class="n">n_neighbor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">20</span><span class="p">,</span><span class="w">
                                    </span><span class="n">n_rekomendasi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="c1"># 1. Temukan N user paling mirip (neighbor)</span><span class="w">
  </span><span class="n">sim_scores</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">user_sim_matrix</span><span class="p">[</span><span class="nf">as.character</span><span class="p">(</span><span class="n">target_user</span><span class="p">),</span><span class="w"> </span><span class="p">]</span><span class="w">
  </span><span class="n">top_neighbor</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">names</span><span class="p">(</span><span class="n">sort</span><span class="p">(</span><span class="n">sim_scores</span><span class="p">,</span><span class="w"> </span><span class="n">decreasing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">))[</span><span class="m">1</span><span class="o">:</span><span class="n">n_neighbor</span><span class="p">]</span><span class="w">

  </span><span class="c1"># 2. Item yang sudah dibeli target user</span><span class="w">
  </span><span class="n">sudah_dibeli</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="n">mat_ui</span><span class="p">[</span><span class="nf">as.character</span><span class="p">(</span><span class="n">target_user</span><span class="p">),</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w">

  </span><span class="c1"># 3. Hitung skor rekomendasi: weighted sum of neighbor ratings</span><span class="w">
  </span><span class="c1">#    Bobot = similarity score neighbor tersebut</span><span class="w">
  </span><span class="n">skor_item</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">ncol</span><span class="p">(</span><span class="n">mat_ui</span><span class="p">))</span><span class="w">
  </span><span class="nf">names</span><span class="p">(</span><span class="n">skor_item</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">colnames</span><span class="p">(</span><span class="n">mat_ui</span><span class="p">)</span><span class="w">

  </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">neighbor</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">top_neighbor</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">sim_w</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sim_scores</span><span class="p">[</span><span class="n">neighbor</span><span class="p">]</span><span class="w">
    </span><span class="c1"># Tambahkan weighted rating dari neighbor</span><span class="w">
    </span><span class="n">skor_item</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">skor_item</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">sim_w</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">mat_ui</span><span class="p">[</span><span class="n">neighbor</span><span class="p">,</span><span class="w"> </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">

  </span><span class="c1"># 4. Nolkan item yang sudah pernah dibeli target user</span><span class="w">
  </span><span class="n">skor_item</span><span class="p">[</span><span class="n">sudah_dibeli</span><span class="p">]</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">0</span><span class="w">

  </span><span class="c1"># 5. Ambil top N rekomendasi</span><span class="w">
  </span><span class="n">top_items</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sort</span><span class="p">(</span><span class="n">skor_item</span><span class="p">,</span><span class="w"> </span><span class="n">decreasing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)[</span><span class="m">1</span><span class="o">:</span><span class="n">n_rekomendasi</span><span class="p">]</span><span class="w">

  </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">item_id</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="nf">as.integer</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">top_items</span><span class="p">)),</span><span class="w">
    </span><span class="n">skor_ub</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">top_items</span><span class="p">)</span><span class="w">
  </span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">left_join</span><span class="p">(</span><span class="n">katalog</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'item_id'</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">select</span><span class="p">(</span><span class="n">item_id</span><span class="p">,</span><span class="w"> </span><span class="n">nama_item</span><span class="p">,</span><span class="w"> </span><span class="n">kategori</span><span class="p">,</span><span class="w"> </span><span class="n">harga</span><span class="p">,</span><span class="w"> </span><span class="n">skor_ub</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Berikut adalah histori pembelian untuk <strong><em>user 1</em></strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== HISTORI PEMBELIAN USER 1 ===

           nama_item       kategori n
1       Pocari Sweat        Minuman 2
2    Deterjen Attack Perawatan Diri 1
3       Good Day RTD        Minuman 1
4     Kopi Kapal Api        Minuman 1
5     Lifebuoy Sabun Perawatan Diri 1
6           Milo RTD        Minuman 1
7   Rexona Deodorant Perawatan Diri 1
8         Roma Marie          Snack 1
9       Sprite 390ml        Minuman 1
10   Sunsilk Shampoo Perawatan Diri 1
11 Ultra Milk Coklat        Minuman 1
12   Vaseline Lotion Perawatan Diri 1
</code></pre></div></div>

<p>Dan berikut ini adalah produk yang bisa direkomendasikan kepada <strong><em>user
1</em></strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== REKOMENDASI USER-BASED CF UNTUK USER 1 ===

  item_id             nama_item kategori harga  skor_ub
1      12         Oreo Original    Snack  8500 20.40432
2       8           Yakult 5pcs  Minuman 12000 19.24507
3      14 Chitato Sapi Panggang    Snack 15000 18.50356
4       6        Energen Coklat  Minuman  6500 18.46504
5       2            Aqua 600ml  Minuman  3000 17.62897
</code></pre></div></div>

<h2 id="item-based-collaborative-filtering"><em>Item-Based Collaborative Filtering</em></h2>

<h3 id="hitung-cosine-similarity-antar-item">Hitung <em>Cosine Similarity</em> Antar <em>Item</em></h3>

<p>Berbeda dengan bagian sebelumnya, sekarang saya akan menghitung
kebalikan POV. Yakni dengan menghitung antar <em>item</em>. Selanjutnya akan
disimpan sebagai <em>simmilarity matrix per item</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Dimensi item similarity matrix: 30 30 
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/recommendizer/draft_files/figure-commonmark/unnamed-chunk-16-1.png" alt="" /></p>

<h3 id="fungsi-rekomendasi-item-based">Fungsi Rekomendasi <em>Item-Based</em></h3>

<p>Berdasarkan <em>matrix</em> tersebut, saya bisa membuat <em>function</em> untuk
mengeluarkan <em>item</em> rekomendasi dengan sudut pandang <em>item-based</em>.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Fungsi rekomendasi Item-Based CF ─────────────────────────────</span><span class="w">
</span><span class="n">rekomendasi_item_based</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">target_user</span><span class="p">,</span><span class="w">
                                    </span><span class="n">n_rekomendasi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="c1"># 1. Item yang sudah dibeli target user</span><span class="w">
  </span><span class="n">profil_user</span><span class="w">   </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">mat_ui</span><span class="p">[</span><span class="nf">as.character</span><span class="p">(</span><span class="n">target_user</span><span class="p">),</span><span class="w"> </span><span class="p">]</span><span class="w">
  </span><span class="n">sudah_dibeli</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="n">profil_user</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w">
  </span><span class="n">belum_dibeli</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="n">profil_user</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w">

  </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">sudah_dibeli</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">cat</span><span class="p">(</span><span class="s1">'User belum punya histori pembelian.\n'</span><span class="p">)</span><span class="w">
    </span><span class="nf">return</span><span class="p">(</span><span class="kc">NULL</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">

  </span><span class="c1"># 2. Untuk setiap item yang belum dibeli, hitung skor:</span><span class="w">
  </span><span class="c1">#    skor(item_baru) = sum(sim(item_baru, item_lama) * frekuensi_beli)</span><span class="w">
  </span><span class="n">skor_item</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">belum_dibeli</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">target_item</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">sim_ke_sudah_dibeli</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">item_sim_matrix</span><span class="p">[</span><span class="w">
      </span><span class="nf">as.character</span><span class="p">(</span><span class="n">target_item</span><span class="p">),</span><span class="w">
      </span><span class="nf">as.character</span><span class="p">(</span><span class="n">sudah_dibeli</span><span class="p">)</span><span class="w">
    </span><span class="p">]</span><span class="w">
    </span><span class="nf">sum</span><span class="p">(</span><span class="n">sim_ke_sudah_dibeli</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">profil_user</span><span class="p">[</span><span class="n">sudah_dibeli</span><span class="p">])</span><span class="w">
  </span><span class="p">})</span><span class="w">
  </span><span class="nf">names</span><span class="p">(</span><span class="n">skor_item</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">belum_dibeli</span><span class="w">

  </span><span class="c1"># 3. Ambil top N</span><span class="w">
  </span><span class="n">top_items</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sort</span><span class="p">(</span><span class="n">skor_item</span><span class="p">,</span><span class="w"> </span><span class="n">decreasing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)[</span><span class="m">1</span><span class="o">:</span><span class="n">n_rekomendasi</span><span class="p">]</span><span class="w">

  </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">item_id</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="nf">as.integer</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">top_items</span><span class="p">)),</span><span class="w">
    </span><span class="n">skor_ib</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">top_items</span><span class="p">)</span><span class="w">
  </span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">left_join</span><span class="p">(</span><span class="n">katalog</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'item_id'</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">select</span><span class="p">(</span><span class="n">item_id</span><span class="p">,</span><span class="w"> </span><span class="n">nama_item</span><span class="p">,</span><span class="w"> </span><span class="n">kategori</span><span class="p">,</span><span class="w"> </span><span class="n">harga</span><span class="p">,</span><span class="w"> </span><span class="n">skor_ib</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Berikut adalah rekomendasi untuk <strong><em>user 1</em></strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== REKOMENDASI ITEM-BASED CF UNTUK USER 1 ===

  item_id             nama_item kategori harga  skor_ib
1      14 Chitato Sapi Panggang    Snack 15000 8.364571
2      13     Pringles Original    Snack 25000 8.250580
3      16   Khong Guan Assorted    Snack 35000 8.222321
4      19               Richoco    Snack  2000 8.126354
5      15            Roma Marie    Snack  8000 8.054033
</code></pre></div></div>

<h2 id="market-basket-analysis-juga-sering-dibeli-bersama"><em>Market Basket Analysis:</em> “Juga Sering Dibeli Bersama”</h2>

<p>Di luar <em>Collaborative Filtering</em> berbasis <em>user</em>, ada pendekatan lain
yang sangat intuitif dan langsung <em>actionable</em>, yakni <em>Market Basket
Analysis</em>. Saya pernah mengulas metode ini di <em>blog</em> saya yang lama. Ini
yang menghasilkan fitur <em>“Frequently Bought Together”</em> di Amazon atau
<em>“Orang juga membeli”</em> di beberapa <em>e-commerce</em> lokal.</p>

<h3 id="menghitung-support-dan-lift">Menghitung <em>Support</em> dan <em>Lift</em></h3>

<p>Metodenya adalah dengan menghitung nilai <em>support</em> dan <em>lift</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Total transaksi unik: 6218 

Menghitung support dan lift untuk semua pasangan item...


=== TOP 15 PASANGAN PRODUK DENGAN LIFT TERTINGGI ===

              nama_A                nama_B n_bersama support  lift
1    Sunsilk Shampoo        Lifebuoy Sabun       159  0.0256 3.879
2     Indomie Goreng       Teh Botol 500ml       450  0.0724 3.358
3     Lifebuoy Sabun       Pepsodent 190gr       124  0.0199 3.269
4     Indomie Goreng         Oreo Original       266  0.0428 2.402
5    Teh Botol 500ml            Aqua 600ml       334  0.0537 2.010
6    Sunsilk Shampoo       Pepsodent 190gr        99  0.0159 1.911
7       Sprite 390ml Chitato Sapi Panggang       149  0.0240 1.784
8  Ultra Milk Coklat        Energen Coklat       179  0.0288 1.720
9       Softex 10pcs     Tisu Paseo 200lbr        53  0.0085 1.690
10      Good Day RTD           Yakult 5pcs       167  0.0269 1.680
11     Oreo Original     Pringles Original       139  0.0224 1.590
12 Ultra Milk Coklat          Pocari Sweat       135  0.0217 1.420
13 Ultra Milk Coklat          Sprite 390ml       137  0.0220 1.378
14       Choki-Choki     Tisu Paseo 200lbr        57  0.0092 1.274
15   Teh Botol 500ml         Oreo Original       163  0.0262 1.264
</code></pre></div></div>

<p>Berikut adalah visualisasi untuk pasangan produk yang memiliki nilai
<code class="language-plaintext highlighter-rouge">lift &gt; 1</code>.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/recommendizer/draft_files/figure-commonmark/unnamed-chunk-20-1.png" alt="" /></p>

<h3 id="rekomendasi-juga-sering-dibeli-bersama-per-produk">Rekomendasi “Juga Sering Dibeli Bersama” per Produk</h3>

<p>Dari perhitungan <em>lift</em> tersebut, saya bisa membuat <em>function</em>
rekomendasi produk apa yang bisa ditawarkan saat <em>user</em> membeli produk
tertentu.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Fungsi: rekomendasi 'frequently bought together' ─────────────</span><span class="w">
</span><span class="n">rekomendasi_fbt</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">nama_produk</span><span class="p">,</span><span class="w"> </span><span class="n">n_rek</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">lift_min</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1.0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="c1"># Temukan item_id dari nama produk</span><span class="w">
  </span><span class="n">id_target</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">katalog</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">filter</span><span class="p">(</span><span class="n">grepl</span><span class="p">(</span><span class="n">nama_produk</span><span class="p">,</span><span class="w"> </span><span class="n">nama_item</span><span class="p">,</span><span class="w"> </span><span class="n">ignore.case</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">))</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">pull</span><span class="p">(</span><span class="n">item_id</span><span class="p">)</span><span class="w">

  </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">id_target</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">cat</span><span class="p">(</span><span class="s1">'Produk tidak ditemukan.\n'</span><span class="p">);</span><span class="w"> </span><span class="nf">return</span><span class="p">(</span><span class="kc">NULL</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">

  </span><span class="c1"># Cari semua pasangan yang melibatkan produk ini</span><span class="w">
  </span><span class="n">df_rek</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">df_asosiasi</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">filter</span><span class="p">((</span><span class="n">item_A</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">id_target</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">item_B</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">id_target</span><span class="p">),</span><span class="w">
           </span><span class="n">lift</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">lift_min</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">mutate</span><span class="p">(</span><span class="w">
      </span><span class="n">item_partner</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="n">item_A</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">id_target</span><span class="p">,</span><span class="w"> </span><span class="n">item_B</span><span class="p">,</span><span class="w"> </span><span class="n">item_A</span><span class="p">),</span><span class="w">
      </span><span class="n">nama_partner</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="n">item_A</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">id_target</span><span class="p">,</span><span class="w"> </span><span class="n">nama_B</span><span class="p">,</span><span class="w"> </span><span class="n">nama_A</span><span class="p">)</span><span class="w">
    </span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">filter</span><span class="p">(</span><span class="o">!</span><span class="n">item_partner</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">id_target</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">arrange</span><span class="p">(</span><span class="n">desc</span><span class="p">(</span><span class="n">lift</span><span class="p">))</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">select</span><span class="p">(</span><span class="n">nama_partner</span><span class="p">,</span><span class="w"> </span><span class="n">n_bersama</span><span class="p">,</span><span class="w"> </span><span class="n">support</span><span class="p">,</span><span class="w"> </span><span class="n">lift</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
    </span><span class="n">head</span><span class="p">(</span><span class="n">n_rek</span><span class="p">)</span><span class="w">

  </span><span class="n">cat</span><span class="p">(</span><span class="s1">'=== Sering Dibeli Bersama:'</span><span class="p">,</span><span class="w"> </span><span class="n">toupper</span><span class="p">(</span><span class="n">nama_produk</span><span class="p">),</span><span class="w"> </span><span class="s1">'===\n'</span><span class="p">)</span><span class="w">
  </span><span class="n">print</span><span class="p">(</span><span class="n">df_rek</span><span class="p">)</span><span class="w">
  </span><span class="nf">invisible</span><span class="p">(</span><span class="n">df_rek</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Berikut ini adalah contoh produk yang rekomendasikan jika <em>user</em> membeli
produk:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rekomendasi_fbt</span><span class="p">(</span><span class="s1">'Indomie'</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Sering Dibeli Bersama: INDOMIE ===
     nama_partner n_bersama support  lift
1 Teh Botol 500ml       450  0.0724 3.358
2   Oreo Original       266  0.0428 2.402
3      Aqua 600ml       161  0.0259 1.128
</code></pre></div></div>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rekomendasi_fbt</span><span class="p">(</span><span class="s1">'Lifebuoy'</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Sering Dibeli Bersama: LIFEBUOY ===
     nama_partner n_bersama support  lift
1 Sunsilk Shampoo       159  0.0256 3.879
2 Pepsodent 190gr       124  0.0199 3.269
3         Richoco        42  0.0068 1.134
</code></pre></div></div>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rekomendasi_fbt</span><span class="p">(</span><span class="s1">'Teh Botol'</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== Sering Dibeli Bersama: TEH BOTOL ===
    nama_partner n_bersama support  lift
1 Indomie Goreng       450  0.0724 3.358
2     Aqua 600ml       334  0.0537 2.010
3  Oreo Original       163  0.0262 1.264
</code></pre></div></div>

<hr />

<h1 id="evaluasi-model-seberapa-bagus-rekomendasi-kita">Evaluasi Model: Seberapa Bagus Rekomendasi Kita?</h1>

<p><em>Business question</em> yang kemudian muncul dan perlu dijawab adalah:
<em>“Seberapa bagus sistem rekomendasi yang kita buat?”</em></p>

<p>Sistem rekomendasi yang sudah jadi tetap perlu dievaluasi secara
kuantitatif. Metode standar yang bisa digunakan adalah dengan membagi
data menjadi <em>train</em> dan <em>test</em>, sembunyikan sebagian histori pembelian
<em>user</em> di <em>test set</em>, lalu ukur apakah rekomendasi berhasil memprediksi
<em>item</em> yang disembunyikan itu</p>

<p><em>Metrics</em> yang bisa digunakan adalah <em>precision@K</em> dan <em>recall@K</em>.</p>

<p><em>Precision@K</em> berarti: <em>“Dari K item yang direkomendasikan, berapa
banyak yang relevan?”</em></p>

<p>Contoh: Sistem merekomendasikan 10 film (<code class="language-plaintext highlighter-rouge">K=10</code>) kepada <em>user</em>:</p>

<ul>
  <li><em>User</em> sebenarnya menyukai 4 film dari 10 itu.</li>
  <li><em>Precision@10</em> = 4/10 = 0.4 (40%).</li>
  <li><strong>40% dari rekomendasi top-10 adalah relevan.</strong></li>
</ul>

<p><em>Recall@K</em>. berarti: <em>“Dari semua item yang relevan untuk user, berapa
banyak yang muncul di K rekomendasi teratas?”</em></p>

<p>Contoh: <em>User</em> memiliki 20 film favorit di <em>database</em>:</p>

<ul>
  <li>Sistem merekomendasikan 10 film (<code class="language-plaintext highlighter-rouge">K=10</code>).</li>
  <li>Sebanyak 4 Dari 10 film itu adalah film favorit <em>user</em>.</li>
  <li><em>Recall@10</em> = 4/20 = 0.2 (20%).</li>
  <li><strong>Sistem berhasil menemukan 20% dari film favorit <em>user</em> dalam 10
rekomendasi teratas.</strong></li>
</ul>

<blockquote>
  <p><em>Precision@K adalah tentang membuat user happy dengan apa yang mereka
lihat, Recall@K adalah tentang menemukan semua yang bisa membuat user
happy.”</em></p>
</blockquote>

<p>Saya akan hitung <em>precision@5</em> dan <em>recall@5</em> dari rekomendasi
<em>item-based CF</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Mengevaluasi model...


=== HASIL EVALUASI (Item-Based CF, K=5) ===

Precision@5: 0.3112 

Recall@5   : 0.3565 


Interpretasi Precision@5 = 0.XX: 
Rata-rata ada X dari 5 rekomendasi yang benar-benar dibeli user
</code></pre></div></div>

<p>Artinya: Dari 5 rekomendasi teratas yang diberikan sistem:</p>

<ul>
  <li>Hanya 1.56 item (rata-rata) yang relevan untuk <em>user</em>.</li>
  <li>3.44 <em>item</em> lainnya tidak relevan.</li>
</ul>

<p>Dalam bahasa sederhana: “Hanya 31% dari 5 rekomendasi utama yang
benar-benar disukai <em>user</em>.”</p>

<ol>
  <li>Recall@5 = 35.65%</li>
</ol>

<p>Artinya: Dari semua item yang sebenarnya relevan untuk user:</p>

<ul>
  <li>Sistem hanya berhasil menemukan 35.65% dalam 5 rekomendasi teratas.</li>
  <li>64.35% item relevan lainnya terlewatkan.</li>
</ul>

<p>Dalam bahasa sederhana: “Sistem hanya menemukan 36% dari semua item yang
<em>user</em> sukai.”</p>

<p>Oke, jadi sekarang kita sudah memiliki <em>metrics</em> yang cukup untuk
memutuskan apakah sistem rekomendasi yang kita buat sudah baik atau
belum.</p>

<h2 id="membandingkan-rekomendasi-user-based-vs-item-based">Membandingkan Rekomendasi <em>User-Based</em> vs <em>Item-Based</em></h2>

<p>Sekarang saya akan bandingkan hasil rekomendasi antara <em>user-based</em>
dengan <em>item-based</em>:</p>

<p>Kita bandingkan hasil untuk <strong><em>user 1</em></strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ======================================================= 
USER: 1 
======================================================= 
HISTORI PEMBELIAN:
        nama_item n
1    Pocari Sweat 2
2 Deterjen Attack 1
3    Good Day RTD 1
4  Kopi Kapal Api 1
5  Lifebuoy Sabun 1

REKOMENDASI USER-BASED CF:
              nama_item kategori  skor_ub
1         Oreo Original    Snack 20.40432
2           Yakult 5pcs  Minuman 19.24507
3 Chitato Sapi Panggang    Snack 18.50356
4        Energen Coklat  Minuman 18.46504
5            Aqua 600ml  Minuman 17.62897

REKOMENDASI ITEM-BASED CF:
              nama_item kategori  skor_ib
1 Chitato Sapi Panggang    Snack 8.364571
2     Pringles Original    Snack 8.250580
3   Khong Guan Assorted    Snack 8.222321
4               Richoco    Snack 8.126354
5            Roma Marie    Snack 8.054033

Overlap (rekomendasi dari keduanya): 1 item
Chitato Sapi Panggang 
</code></pre></div></div>

<p>Kita bandingkan hasil untuk <strong><em>user 42</em></strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ======================================================= 
USER: 42 
======================================================= 
HISTORI PEMBELIAN:
       nama_item n
1     Aqua 600ml 3
2 Lifebuoy Sabun 3
3 Energen Coklat 2
4   Good Day RTD 2
5  Oreo Original 2

REKOMENDASI USER-BASED CF:
          nama_item kategori  skor_ub
1   Teh Botol 500ml  Minuman 23.87841
2 Pringles Original    Snack 21.78656
3    Kopi Kapal Api  Minuman 19.52340
4       Yakult 5pcs  Minuman 17.98266
5    Indomie Goreng    Snack 17.33572

REKOMENDASI ITEM-BASED CF:
            nama_item kategori  skor_ib
1       Oreo Original    Snack 19.73584
2        Pocari Sweat  Minuman 19.14616
3             Richoco    Snack 18.71345
4   Pringles Original    Snack 18.61522
5 Khong Guan Assorted    Snack 18.52100

Overlap (rekomendasi dari keduanya): 1 item
Pringles Original 
</code></pre></div></div>

<p>Kita bandingkan hasil untuk <strong><em>user 137</em></strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ======================================================= 
USER: 137 
======================================================= 
HISTORI PEMBELIAN:
            nama_item n
1       Oreo Original 5
2        Good Day RTD 4
3 Khong Guan Assorted 4
4        Sprite 390ml 4
5     Vaseline Lotion 4

REKOMENDASI USER-BASED CF:
          nama_item       kategori  skor_ub
1   Teh Botol 500ml        Minuman 24.95373
2 Pringles Original          Snack 18.63394
3   Deterjen Attack Perawatan Diri 15.57189
4 Tisu Paseo 200lbr Perawatan Diri 14.12167
5  Rexona Deodorant Perawatan Diri 12.49974

REKOMENDASI ITEM-BASED CF:
          nama_item       kategori  skor_ib
1     Oreo Original          Snack 29.58868
2          Milo RTD        Minuman 29.03123
3 Pringles Original          Snack 28.29720
4           Richoco          Snack 28.26768
5   Pepsodent 190gr Perawatan Diri 27.89602

Overlap (rekomendasi dari keduanya): 1 item
Pringles Original 
</code></pre></div></div>

<p>Seberapa besar perbedaannya? Secara rata-rata:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== RATA-RATA OVERLAP UB vs IB REKOMENDASI ===

Rata-rata: 26.3 %

(dari top-10 rekomendasi, rata-rata 2.6 item sama antara UB dan IB)
</code></pre></div></div>

<hr />

<h1 id="bagaimana-jika-cold-start">Bagaimana Jika <em>Cold Start</em>?</h1>

<p><strong>Salah satu kelemahan terbesar</strong> <em>Collaborative Filtering</em> adalah <em>cold
start problem</em>: apa yang terjadi kalau <em>user</em> baru yang belum punya
histori pembelian sama sekali datang? Atau produk baru yang belum pernah
dibeli siapapun?</p>

<p>Beberapa alternatif strategi yang bisa langsung diimplementasikan:</p>

<ol>
  <li>Strategi 1: popularitas global, kita rekomendasikan saja semua
produk yang paling populer.</li>
  <li>Strategi 2: popularitas per segmen. Misalkan <em>user</em> baru dari Bekasi
dan umur 25-35 maka rekomendasikan produk terpopuler di segmen itu.
Artinya kita membutuhkan data demografis.</li>
  <li>Strategi 3: sabar menunggu hingga <em>user</em> baru membeli satu produk.
Rekomendasi berbasis satu produk pertama yang dibeli kemudian bisa
dilanjutkan menggunakan <em>Market Basket Analysis</em>.</li>
</ol>

<hr />

<h1 id="business-action-dari-algoritma"><em>Business Action</em> dari Algoritma</h1>

<p>Ada tiga cara mengimplementasikan algoritma sistem rekomendasi, yakni:</p>

<ol>
  <li><em>Cross-selling</em> di halaman produk. Pasang <em>widget</em> ‘Sering Dibeli
Bersama’ di halaman detail produk. Gunakan hasil <em>Market Basket
Analysis</em> (<em>lift</em> tertinggi) sebagai datanya. Ini bisa langsung
diimplementasikan tanpa sistem <em>real-time</em>.</li>
  <li><em>Email/push notification personal</em>. Setiap minggu, jalankan
<em>Item-Based CF</em> untuk semua <em>user</em> aktif. Kirim notifikasi <em>‘Produk
yang mungkin kamu suka’</em> berdasarkan histori pembelian mereka.
Sederhana tapi efektif.</li>
  <li><em>Planogram</em> dan <em>bundling</em>. Pasang produk dengan <em>lift</em> tinggi
berdekatan di rak toko fisik atau halaman kategori. Buat <em>bundle
package</em> dari pasangan dengan <em>support</em> dan <em>lift</em> tertinggi.</li>
</ol>

<h2 id="keterbatasan-yang-perlu-diperhatikan">Keterbatasan yang Perlu Diperhatikan</h2>

<ol>
  <li><em>Scalability</em>. Algoritma di atas menggunakan <em>full matrix
multiplication</em>. Kondisi ini bagus untuk ratusan <em>user</em> dan puluhan
item. Untuk jutaan <em>user</em>, dibutuhkan <em>approximate nearest neighbor</em>
(ANN) atau <em>matrix factorization</em> (SVD, ALS) yang jauh lebih efisien
secara komputasi.</li>
  <li><em>Popularity bias</em>. Algoritma berbasis frekuensi cenderung
merekomendasikan <em>item populer</em> terus-menerus. Produk <em>niche</em> yang
sebenarnya sangat relevan untuk segmen tertentu bisa terus
tersembunyi. Solusi: normalisasi skor atau tambahkan <em>exploration
factor</em>.</li>
  <li><em>Data sparsity</em>. Semakin jarang <em>user</em> berinteraksi dengan produk,
semakin sulit menemukan <em>user</em> yang benar-benar ‘mirip’. Di tahap
awal, <em>Market Basket Analysis</em> (tidak membutuhkan histori panjang)
lebih <em>robust</em>.</li>
  <li><em>Temporal dynamics</em>. Preferensi berubah seiring waktu. Pembelian 2
tahun lalu tidak selalu relevan hari ini. Solusi: beri bobot lebih
tinggi ke transaksi yang lebih baru (<em>time-decay weighting</em>).</li>
  <li>Tidak menangkap konteks. Membeli minuman dingin di musim panas
berbeda konteksnya dengan di musim hujan. <em>Collaborative Filtering</em>
murni tidak menangkap konteks ini. Oleh karena itu, dibutuhkan
<em>Contextual Bandits</em> atau <em>session-based recommendation</em>.</li>
</ol>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Artificial Intelligence" /><category term="Machine Learning" /><category term="Belanja" /><category term="E-commerce" /><category term="Algoritma" /><category term="Filtering" /><category term="Item Based" /><category term="User Based" /><category term="Rekomendasi" /><category term="Prediksi" /><category term="Sistem Rekomendasi" /><category term="Association Rules" /><summary type="html"><![CDATA[Semalam, saya dan istri bercerita bahwa di salah satu boarding school yang kami incar untuk si Sulung memberikan Macbook kepada para siswanya sebagai daily driver di sekolah. Karena penasaran dengan harganya, saya coba Googling terkait Macbook.]]></summary></entry><entry><title type="html">Market Insights vs Market Foresight: Memahami Perbedaan dan Nilai Strategisnya</title><link href="https://ikanx101.com/blog/foresight-insight/" rel="alternate" type="text/html" title="Market Insights vs Market Foresight: Memahami Perbedaan dan Nilai Strategisnya" /><published>2026-04-15T12:08:00+00:00</published><updated>2026-04-15T12:08:00+00:00</updated><id>https://ikanx101.com/blog/foresight-insight</id><content type="html" xml:base="https://ikanx101.com/blog/foresight-insight/"><![CDATA[<p>Saya masih ingat dengan jelas hari itu di tahun 2018, ketika tim <em>research and development</em> di kantor sedang mempersiapkan peluncuran produk baru. Data dari tim <em>market research</em> menunjukkan bahwa <strong>mayoritas konsumen Indonesia</strong> mulai peduli dengan kandungan gula, garam, dan lemak dalam produk makanan minuman mereka. <em>Insight</em> ini jelas: ada peluang untuk produk rendah gula, garam, dan lemak.</p>

<p>Tapi ada pertanyaan yang lebih besar: <em>Apakah tren ini akan bertahan 5 tahun ke depan?</em> Ataukah ini hanya efek sementara dari kampanye kesehatan pemerintah? Di sinilah saya mulai memahami perbedaan mendasar antara <strong><em>market insights</em></strong> (pemahaman tentang apa yang terjadi sekarang) dan <strong><em>market foresight</em></strong> (kemampuan untuk melihat apa yang akan terjadi di masa depan).</p>

<p>Sebagai seorang matematikawan yang terjun ke dunia <em>market research</em> dan <em>data science</em>, saya sering melihat bagaimana perusahaan-perusahaan besar (termasuk tempat saya bekerja) dalam membuat keputusan strategis berdasarkan data historis semata. Padahal, di era <em>VUCA</em> (<em>Volatility</em>, <em>Uncertainty</em>, <em>Complexity</em>, dan <em>Ambiguity</em>) seperti sekarang, kemampuan untuk <strong>melihat ke depan</strong> sama pentingnya dengan kemampuan untuk <strong>memahami sekarang</strong>. Untuk lebih jelasnya, akan saya coba bedah berikut ini:</p>

<h1 id="memahami-dasar-dasar">MEMAHAMI DASAR-DASAR</h1>

<h2 id="market-insights-memahami-what-is"><strong><em>Market Insights</em>: Memahami <em>“What Is”</em></strong></h2>

<p><em>Market insights</em> adalah pemahaman mendalam tentang situasi pasar saat ini berdasarkan analisis data historis dan <em>real-time</em>. Ini adalah tentang menjawab pertanyaan: <strong>“Apa yang sedang terjadi di pasar kita saat ini?”</strong></p>

<p><strong>Definisi formal:</strong> <em>Market insights</em> adalah interpretasi data pasar yang memberikan pemahaman tentang perilaku konsumen, dinamika kompetitif, tren penjualan, dan faktor-faktor lain yang mempengaruhi kinerja bisnis saat ini.</p>

<p>Metodologi utama yang biasanya dipakai antara lain:</p>

<ol>
  <li>Analisis data historis (<em>sales data</em>, <em>market share</em>, dan <em>customer feedback</em>).</li>
  <li>Survei dan penelitian kuantitatif.</li>
  <li>Analisis kompetitif.</li>
  <li><em>Social listening</em> dan <em>sentiment analysis</em>.</li>
  <li><em>A/B testing</em> dan eksperimen pasar.</li>
</ol>

<h2 id="market-foresight-memahami-what-could-be"><strong><em>Market Foresight</em>: Memahami “<em>What Could Be</em>“</strong></h2>

<p><em>Market foresight</em> adalah disiplin yang berfokus pada identifikasi, analisis, dan interpretasi sinyal-sinyal lemah tentang masa depan pasar. Ini adalah tentang menjawab pertanyaan: <strong>“Apa yang mungkin terjadi di pasar kita 3, 5, atau 10 tahun ke depan?”</strong></p>

<p><strong>Definisi formal:</strong> <em>Market foresight</em> adalah proses sistematis untuk mengembangkan pemahaman tentang kemungkinan masa depan pasar, mengidentifikasi peluang dan ancaman yang muncul, dan menginformasikan pengambilan keputusan strategis jangka panjang.</p>

<p>Metodologi utama yang biasa dipakai antara lain:</p>

<ol>
  <li><em>Horizon scanning</em> (pemindaian cakrawala).</li>
  <li><em>Scenario planning</em> (perencanaan skenario).</li>
  <li><em>Trend analysis</em> dan <em>extrapolation</em>.</li>
  <li><em>Delphi method</em> (konsensus ahli).</li>
  <li><em>Weak signal detection</em>.</li>
</ol>

<h2 id="analogi-untuk-membantu-memahami-perbedaan">Analogi untuk Membantu Memahami Perbedaan</h2>

<p>Jika rekan-rekan masih bingung tentang perbedaan keduanya, perhatikan analogi berikut ini:</p>

<p>Bayangkan Anda adalah seorang kapten kapal:</p>

<ul>
  <li><strong><em>Market insights</em></strong> adalah seperti <strong>radar dan sonar</strong> Anda. Alat-alat ini menunjukkan apa yang ada di sekitar Anda sekarang: kapal lain, karang, cuaca saat ini.</li>
  <li><strong><em>Market foresight</em></strong> adalah seperti <strong>teleskop dan peta cuaca jangka panjang</strong>. Alat-alat ini membantu Anda melihat apa yang ada di cakrawala, memprediksi badai yang akan datang, dan merencanakan rute optimal untuk minggu depan.</li>
</ul>

<p>Atau dalam bahasa formula matematika yang lebih teknis:</p>

<ul>
  <li><strong>Market insights</strong> = <code class="language-plaintext highlighter-rouge">f(t)</code> di mana <code class="language-plaintext highlighter-rouge">t</code> adalah waktu sekarang.</li>
  <li><strong>Market foresight</strong> = <code class="language-plaintext highlighter-rouge">∫ f'(t) dt</code> dari <code class="language-plaintext highlighter-rouge">t</code> sekarang ke t masa depan, dengan f’ adalah turunan (perubahan) dari kondisi pasar.</li>
</ul>

<h1 id="perbedaan-mendasar">PERBEDAAN MENDASAR</h1>

<h2 id="tabel-perbandingan-insights-vs-foresight">Tabel Perbandingan: <em>Insights vs Foresight</em></h2>

<table>
  <thead>
    <tr>
      <th>Aspek</th>
      <th><em>Market Insights</em></th>
      <th><em>Market Foresight</em></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Perspektif Waktu</strong></td>
      <td><em>Looking backward &amp; present</em></td>
      <td><em>Looking forward</em></td>
    </tr>
    <tr>
      <td><strong>Fokus Data</strong></td>
      <td><em>Historical &amp; current data</em></td>
      <td><em>Future signals &amp; trends</em></td>
    </tr>
    <tr>
      <td><strong>Tujuan Utama</strong></td>
      <td><em>Optimize current operations</em></td>
      <td><em>Prepare for future changes</em></td>
    </tr>
    <tr>
      <td><strong>Metodologi</strong></td>
      <td><em>Descriptive &amp; diagnostic analytics</em></td>
      <td><em>Predictive &amp; prescriptive analytics</em></td>
    </tr>
    <tr>
      <td><strong>Output</strong></td>
      <td><em>Reports, dashboards, recommendations</em></td>
      <td><em>Scenarios, strategic options, early warnings</em></td>
    </tr>
    <tr>
      <td><strong>Decision Impact</strong></td>
      <td><em>Tactical &amp; operational</em></td>
      <td><em>Strategic &amp; transformational</em></td>
    </tr>
    <tr>
      <td><strong>Certainty Level</strong></td>
      <td><em>High (based on known facts)</em></td>
      <td><em>Low to medium (based on probabilities)</em></td>
    </tr>
    <tr>
      <td><strong>Time Horizon</strong></td>
      <td><em>Days to months</em></td>
      <td><em>Months to years</em></td>
    </tr>
  </tbody>
</table>

<h2 id="perspektif-timeline-looking-back-vs-looking-forward">Perspektif <em>Timeline</em>: <em>Looking Back vs Looking Forward</em></h2>

<p><em>Market insights</em> bekerja pada domain waktu yang sudah terjadi. Ketika kita menganalisis data penjualan kuartal terakhir, kita melihat ke belakang. Ketika kita melakukan survei kepuasan pelanggan, kita mengukur sentimen saat ini. Perspektifnya adalah <strong>reaktif dan adaptif</strong>.</p>

<p><em>Market foresight</em> bekerja pada domain waktu yang belum terjadi. Ketika kita memindai teknologi <em>emerging</em>, kita melihat ke depan. Ketika kita membangun skenario untuk 2030, kita membayangkan masa depan. Perspektifnya adalah <strong>proaktif dan kreatif</strong>.</p>

<h2 id="kebutuhan-data-historical-vs-future-oriented">Kebutuhan Data: <strong><em>Historical vs Future-Oriented</em></strong></h2>

<p>Dalam proyek <em>data science</em> yang saya kerjakan selama ini di Nutrifood, saya menemukan pola menarik:</p>

<ol>
  <li>Data untuk <em>insights</em> biasa saya dapatkan dengan karakteristik:
    <ul>
      <li><em>Structured data</em> (<em>databases</em>, CRM, ERP, hasil survey, dll).</li>
      <li><em>High volume</em> dan <em>high velocity</em>.</li>
      <li><em>Clear metrics and KPIs</em>.</li>
      <li>Contoh: data sales harian dengan 1 juta baris transaksi.</li>
    </ul>
  </li>
  <li>Data untuk <em>foresight</em> biasa saya dapatkan dengan karakteristik:
    <ul>
      <li><em>Unstructured data</em> (<em>news articles, patents, social media</em>, dll).</li>
      <li><em>Low volume</em> dan <em>high variety</em>.</li>
      <li><em>Ambiguous signals and weak correlations</em>.</li>
      <li>Contoh: data nama-nama produk makanan dan minuman <em>emerging</em> yang ada di <em>e-commerce</em>.</li>
    </ul>
  </li>
</ol>

<h2 id="dampak-pengambilan-keputusan-reactive-vs-proactive">Dampak Pengambilan Keputusan: <em>Reactive vs Proactive</em></h2>

<p>Baik <em>market insights</em> dan <em>market foresight</em> memiliki perbedaan dalam hal dampak saat pengambilan keputusan bisnis. Sebagai contoh <em>decisions based on insights</em> biasanya seperti ini:</p>

<ul>
  <li><em>“Kita harus meningkatkan stok produk X karena penjualan naik 30% bulan lalu”</em>.</li>
  <li><em>“Kita perlu memperbaiki layanan pelanggan karena rating turun dari 4.5 ke 4.2”</em>.</li>
  <li><em>“Kita harus menyesuaikan harga karena kompetitor menurunkan harga 10%”</em>.</li>
</ul>

<p>Sedangkan <em>decisions based on foresight</em> contohnya seperti ini:</p>

<ul>
  <li><em>“Kita harus berinvestasi dalam teknologi plant-based karena regulasi akan ketat tahun 2027”</em>.</li>
  <li><em>“Kita perlu membangun partnership dengan startup AI karena akan mengubah customer service dalam 3 tahun”</em>.</li>
  <li><em>“Kita harus diversifikasi supply chain karena risiko geopolitik di region A meningkat”</em>.</li>
</ul>

<h1 id="nilai-positif-masing-masing">NILAI POSITIF MASING-MASING</h1>

<h2 id="nilai-market-insights-the-power-of-now">Nilai <em>Market Insights: The Power of Now</em></h2>

<h3 id="validasi-keputusan">Validasi Keputusan</h3>

<p><em>Market insights</em> memberikan dasar empiris untuk keputusan bisnis. Di perusahaan saya saat ini, sebelum meluncurkan varian baru dari suatu <em>brand</em>, kami selalu melakukan:</p>

<ul>
  <li><strong>Concept testing</strong> dengan 300+ responden.</li>
  <li><strong>Price sensitivity analysis</strong> menggunakan <a href="https://ikanx101.com/blog/price-elasticity/">metode tertentu</a>.</li>
  <li>dan riset lainnya.</li>
</ul>

<p>Hasilnya? Tingkat keberhasilan <em>product launch</em> bisa terjaga persentasenya.</p>

<h3 id="optimasi-operasional">Optimasi Operasional</h3>

<p>Dengan <em>analytics</em> yang tepat, <em>insights</em> bisa menghemat biaya yang dikeluarkan perusahaan. Contoh konkret:</p>

<ul>
  <li><a href="https://ikanx101.com/blog/barang-jadi/"><em>Route optimization</em></a> untuk distribusi bisa mengurangi biaya logistik.</li>
  <li>Optimisasi <a href="https://ikanx101.com/blog/tsp-cat/"><em>production schedulling</em></a> yang bisa mengefesienkan waktu dan biaya produksi.</li>
  <li><a href="https://ikanx101.com/blog/practical-mmm/"><em>Marketing mix modeling</em></a> untuk meningkatkan ROI iklan dan <em>budget marketing</em>.</li>
</ul>

<h3 id="competitive-intelligence"><em>Competitive Intelligence</em></h3>

<p>Memahami kompetitor bukan hanya tentang harga, tapi tentang:</p>

<ul>
  <li><em>Product portfolio gaps</em>: Di mana kompetitor lemah?</li>
  <li><em>Pricing strategy patterns</em>: Kapan mereka biasanya menaikkan/menurunkan harga?</li>
  <li><em>Marketing channel effectiveness</em>: Channel mana yang paling efektif untuk mereka?</li>
</ul>

<h3 id="customer-understanding"><em>Customer Understanding</em></h3>

<p>Ini adalah jantung dari <em>market insights</em>. Dengan teknik seperti:</p>

<ul>
  <li><em>Customer segmentation</em> (<em>RFM analysis, clustering, segmentation,</em> dll),</li>
  <li><em>Journey mapping</em> (<em>touchpoint analysis</em>).</li>
  <li><em>Sentiment analysis</em> (NLP pada <em>reviews</em> dan <em>social media posts</em>).</li>
</ul>

<p>Kita bisa memahami bukan hanya <em>apa</em> yang dibeli pelanggan, tapi <em>mengapa</em> mereka membeli.</p>

<h2 id="nilai-market-foresight-the-power-of-tomorrow">Nilai <em>Market Foresight: The Power of Tomorrow</em></h2>

<h3 id="strategic-advantage"><em>Strategic Advantage</em></h3>

<p>Perusahaan dengan <em>foresight</em> yang baik bisa melakukan “skate to where the puck is going to be” (Wayne Gretzky). Contoh:</p>

<ul>
  <li><strong>Netflix</strong> melihat tren <em>streaming</em> sebelum Blockbuster.</li>
  <li><strong>Tesla</strong> berinvestasi di EV ketika OEM tradisional masih ragu.</li>
  <li><strong>Amazon</strong> membangun AWS ketika <em>cloud</em> masih konsep akademis.</li>
</ul>

<h3 id="risk-mitigation"><em>Risk Mitigation</em></h3>

<p><em>Foresight</em> membantu mengidentifikasi risiko sebelum menjadi krisis. <em>Framework</em> yang bisa digunakan:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Risk Probability = f(signal strength, time horizon, impact magnitude)
Risk Mitigation Cost = g(early detection advantage, mitigation complexity)
</code></pre></div></div>

<h3 id="innovation-direction"><em>Innovation Direction</em></h3>

<p><em>Foresight</em> menjawab pertanyaan: <em>“Apa yang harus kita bangun/buat/develop?”</em>. Di Nutrifood, <em>foresight</em> membantu:</p>

<ul>
  <li>Mengidentifikasi <strong>health &amp; wellness</strong> sebagai <em>megatrend</em>.</li>
  <li>Memprediksi <strong>plant-based protein</strong> sebagai <em>next big thing</em>.</li>
  <li>Mengantisipasi <strong>personalized nutrition</strong> via AI.</li>
</ul>

<h3 id="future-proofing-business"><em>Future-proofing Business</em></h3>

<p>Ini adalah nilai tertinggi dari <em>foresight</em>, yakni memastikan bisnis tetap relevan di masa depan. Komponen kunci:</p>

<ul>
  <li><em>Business model innovation</em>: Dari <em>product-centric</em> ke <em>solution-centric</em>.</li>
  <li><em>Capability building</em>: <em>Skill</em> dan teknologi apa yang dibutuhkan?</li>
  <li><em>Ecosystem positioning</em>: Di mana kita dalam <em>value chain</em> masa depan?</li>
</ul>

<h1 id="case-studies-konkret"><em>CASE STUDIES KONKRET</em></h1>

<h2 id="case-study-1-personal-care-industry-transformation"><em>Case Study 1: Personal Care Industry Transformation</em></h2>

<p>Disadari atau tidak, kita sedang mengalami perubahan drastis di industri <em>personal care</em> pasca-pandemi. Ada beberapa <em>insights</em> sepanjang 2020 hingga 2021 sebagai berikut:</p>

<ul>
  <li><em>Sales data</em>: Penjualan <em>skincare</em> naik 35% sedangkan <em>make-up</em> turun 40%.</li>
  <li><em>Social listening</em>: <code class="language-plaintext highlighter-rouge">#skinfirst</code> menjadi trending <em>topic</em>.</li>
  <li>Survey: 72% konsumen lebih peduli <em>ingredients</em> daripada <em>brand</em>.</li>
</ul>

<p>Hal tersebut berasal dari <em>foresight</em> yang sudah dikembangkan sejak 2018 dan 2019, yakni:</p>

<ul>
  <li><em>Megatrend identification: Healthification of beauty</em>.</li>
  <li><em>Weak signal: Microbiome research dalam dermatology</em>.</li>
  <li><em>Demographic shift: Aging population dengan disposable income tinggi</em>.</li>
</ul>

<p>Beberapa perusahaan yang berhasil:</p>

<ul>
  <li><strong>The Ordinary</strong>: Transparansi <em>ingredients</em> dan edukasi <em>science-based</em>.</li>
  <li><strong>Cerave</strong>: <em>Dermatologist-recommended</em> dengan harga <em>affordable</em>.</li>
  <li><strong>K-beauty brands</strong>: <em>Innovation</em> dalam <em>formulation</em> dan <em>delivery system</em>.</li>
</ul>

<p>Beberapa <em>learning points</em> yang bisa diambil:</p>

<ul>
  <li>Perusahaan yang hanya mengandalkan <em>insights</em> (<em>reacting to sales data</em>) cenderung akan ketinggalan.</li>
  <li>Perusahaan dengan <em>foresight</em> (<em>anticipating health-beauty convergence</em>) memimpin.</li>
</ul>

<h2 id="case-study-2-tech-industry-disruption-patterns"><em>Case Study 2: Tech Industry Disruption Patterns</em></h2>

<p>Jika kita perhatikan dalam <em>tech industry</em>, ada pola <em>disruption</em> yang berulang dalam 20 tahun terakhir. Sebagai contoh:</p>

<ol>
  <li><em>Mainframe → PC</em> (IBM vs Microsoft/Apple).</li>
  <li><em>Desktop → Web</em> (Microsoft vs Google).</li>
  <li><em>Web → Mobile</em> (Google vs Apple/Android).</li>
  <li><em>Mobile → AI/Cloud</em> (Current transition).</li>
</ol>

<p>Ada satu <em>framework</em> yang bisa digunakan untuk melakukan <em>foresight</em> di <em>tech industry</em>, yaitu:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Disruption Probability = (Technology Maturity × Market Readiness) / (Incumbent Inertia × Switching Cost)
</code></pre></div></div>

<p>Contoh aplikasi:</p>

<ul>
  <li><em>AI disruption</em> dalam <em>creative industries</em>: Midjourney, ChatGPT.</li>
  <li><em>Blockchain</em> dalam <em>finance</em>: DeFi, <em>smart contracts</em>.</li>
  <li><em>Quantum computing</em> dalam <em>pharma</em>: <em>Drug / vaccines discovery acceleration</em>.</li>
</ul>

<h3 id="case-study-3-fmcg-market-shifts-post-pandemic"><em>Case Study 3: FMCG Market Shifts Post-Pandemic</em></h3>

<p>Ada beberapa temuan menarik yang saya kumpulkan dari berbagai data hasil survey yang dijalankan lembaga publik pada tahun 2025:</p>

<table>
  <thead>
    <tr>
      <th>Trend</th>
      <th>Pre-Pandemic (2019)</th>
      <th>Post-Pandemic (2024)</th>
      <th>Growth</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>E-commerce penetration</strong></td>
      <td>8%</td>
      <td>23%</td>
      <td>187%</td>
    </tr>
    <tr>
      <td><strong>Health &amp; wellness spending</strong></td>
      <td>$12B</td>
      <td>$28B</td>
      <td>133%</td>
    </tr>
    <tr>
      <td><strong>Local brand preference</strong></td>
      <td>42%</td>
      <td>65%</td>
      <td>55%</td>
    </tr>
    <tr>
      <td><strong>Sustainability concern</strong></td>
      <td>38%</td>
      <td>62%</td>
      <td>63%</td>
    </tr>
  </tbody>
</table>

<p>Dari temuan di atas, kita bisa meramu <em>foresight</em> sebagai berikut:</p>

<ol>
  <li><em>Digital shelf</em> menjadi sama pentingnya dengan <em>physical shelf</em>.</li>
  <li><em>Health claims</em> perlu <em>scientific backing</em> yang kuat.</li>
  <li><em>“Local for local”</em> bukan lagi opsional, tapi <em>mandatory</em>.</li>
  <li><em>Circular economy</em> akan menjadi <em>competitive advantage</em>.</li>
</ol>

<h1 id="mengapa-market-foresight-penting-dewasa-ini">MENGAPA <em>MARKET FORESIGHT</em> PENTING DEWASA INI</h1>

<h2 id="velocity-of-change-vuca-world"><em>Velocity of Change (VUCA World)</em></h2>

<p>Dunia bisnis sekarang beroperasi dalam kondisi <em>VUCA</em>:</p>

<ul>
  <li><em>Volatility</em>: Perubahan yang cepat dan tidak terduga.</li>
  <li><em>Uncertainty</em>: Ketidakpastian tentang masa depan.</li>
  <li><em>Complexity</em>: Banyak variabel yang saling terkait.</li>
  <li><em>Ambiguity</em>: Kurangnya kejelasan tentang realitas.</li>
</ul>

<p>Sebagai contoh nyata, pandemi COVID-19 mengajarkan kita bahwa <em>black swan events</em> bukan lagi sekadar teori tapi bisa menjadi realitas. Perusahaan dengan <em>foresight capabilities</em> yang baik (memindai <em>weak signals</em> dari Wuhan pada Desember 2019) bisa bertindak lebih cepat.</p>

<h2 id="digital-transformation-acceleration"><em>Digital Transformation Acceleration</em></h2>

<p>Berdasarkan <em>IMD World Digital Competitiveness Ranking 2025</em>, kecepatan adopsi teknologi digital meningkat 3 kali lipat dibanding dekade sebelumnya. Implikasi untuk <em>foresight</em>:</p>

<ul>
  <li><em>Technology convergence</em>: AI + IoT + Blockchain = new business models.</li>
  <li><em>Data explosion</em>: Dari 33 zettabytes (2018) ke 175 zettabytes (2025).</li>
  <li><em>Algorithmic competition</em>: Bukan lagi <em>company vs company</em>, tapi <em>algorithm vs algorithm</em>.</li>
</ul>

<h2 id="consumer-behavior-shifts"><em>Consumer Behavior Shifts</em></h2>

<p>Dari pengalaman saya beberapa tahun terakhir, ada perubahan (<em>shifting</em>) yang terjadi pada konsumen pasca pandemi:</p>

<ol>
  <li><em>Digital-first mindset</em>: 73% transaksi via <em>mobile</em> (naik dari 45% dari sebelum pandemi).</li>
  <li><em>Health consciousness</em>: 70% konsumen prioritaskan <em>wellness</em> (naik dari 52%).</li>
  <li><em>Value-conscious spending</em>: 30% <em>increase in “pay later” searches</em>.</li>
  <li><em>Sustainability demand</em>: 62% <em>willing to pay more for eco-friendly products</em>.</li>
  <li><em>Local preference</em>: <em>Supply chain disruptions</em> memperkuat <em>national pride</em>.</li>
</ol>

<p><em>Challenge</em> selanjutnya adalah jika <em>trends</em> ini berlanjut, seperti apa pasar FMCG pada 2030? Menarik untuk dinantikan.</p>

<h2 id="competitive-landscape-evolution"><em>Competitive Landscape Evolution</em></h2>

<p>Sejak dahulu, kita belajar bahwa kompetitor kita datang dari industri yang sama. Namun hal ini runtuh dalam satu dekade terakhir. Banyak <em>new competitors</em> datang dari <em>unexpected places</em>, seperti:</p>

<ul>
  <li><em>Tech companies</em> masuk industri:
    <ul>
      <li>FMCG (Amazon Fresh, Google shopping, dll).</li>
      <li>Transportasi (Gojek, Grab, Uber, dll).</li>
    </ul>
  </li>
  <li><strong>D2C brands</strong> <em>disrupt traditional distribution</em> (Warung Pintar, Sayurbox, Astro, dll).</li>
  <li><strong>Platform ecosystems</strong> <em>create walled gardens</em> (Shopee, Tokopedia, dll).</li>
</ul>

<p><em>Strategic foresight</em> membantu perusahaan untuk:</p>

<ul>
  <li><em>Identify white space opportunities</em> sebelum kompetitor.</li>
  <li><em>Anticipate disruption vectors</em> (<em>technology, business model, regulation</em>).</li>
  <li><em>Build strategic options</em> (<em>real options theory applied to business</em>).</li>
</ul>

<h2 id="regulatory-and-sustainability-pressures"><em>Regulatory and Sustainability Pressures</em></h2>

<p><em>Regulatory trends</em> yang perlu diantisipasi:</p>

<ol>
  <li><em>Carbon taxation</em>: EU CBAM sudah dimulai, ASEAN akan menyusul.</li>
  <li><em>Plastic regulations</em>: <em>Extended Producer Responsibility (EPR) schemes</em>.</li>
  <li><em>Health claims standardization</em>: BPOM, FDA, EMA alignment.</li>
  <li><em>Data privacy</em>: <em>PDP Law Indonesia dan global equivalents</em>.</li>
  <li><em>Sugar taxation</em>: rencana pemberlakuan pajak makanan dan minuman gula di Indonesia dalam beberapa tahun ke depan.</li>
</ol>

<p>Ada satu <em>framework</em> <em>foresight</em> untuk <em>regulatory analysis:</em></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Regulatory Impact = Σ(Probability of Regulation × Business Impact × Time to Implementation)
</code></pre></div></div>

<hr />

<h1 id="framework-market-foresight"><em>FRAMEWORK MARKET FORESIGHT</em></h1>

<p>Ada beberapa <em>framework market foresight</em> yang bisa digunakan oleh perusahaan. Saya akan coba tulis lima di antaranya:</p>

<h2 id="framework-1-three-horizons-model-mckinsey"><em>Framework 1: Three Horizons Model (McKinsey)</em></h2>

<p><strong>Konsep:</strong> Mengelola inovasi di tiga horizon waktu yang berbeda:</p>

<table>
  <thead>
    <tr>
      <th>Horizon</th>
      <th>Focus</th>
      <th>Timeframe</th>
      <th>Examples</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>H1</strong></td>
      <td>Optimize core business</td>
      <td>0-3 years</td>
      <td>Product improvements, Cost reduction</td>
    </tr>
    <tr>
      <td><strong>H2</strong></td>
      <td>Build emerging businesses</td>
      <td>3-5 years</td>
      <td>New business models, Market expansion</td>
    </tr>
    <tr>
      <td><strong>H3</strong></td>
      <td>Create viable options</td>
      <td>5-10 years</td>
      <td>Moonshot projects, Disruptive innovation</td>
    </tr>
  </tbody>
</table>

<p>Sebagai contoh aplikasi praktis di perusahaan makanan dan minuman:</p>

<ul>
  <li><strong>H1</strong>: reformulasi produk menjadi rendah gula.</li>
  <li><strong>H2</strong>: <em>Launch</em> produk-produk <em>plant-based protein line</em> (kategori baru).</li>
  <li><strong>H3</strong>: <em>Develop personalized nutrition platform (AI + IoT)</em>.</li>
</ul>

<h2 id="framework-2-steeppestle-analysis"><em>Framework 2: STEEP/PESTLE Analysis</em></h2>

<p><em>STEEP categories</em> untuk <em>systematic scanning:</em></p>

<table>
  <thead>
    <tr>
      <th>Category</th>
      <th>What to Scan</th>
      <th>Example Signals</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Social</strong></td>
      <td>Demographics, values, lifestyles</td>
      <td>Aging population, Wellness trend</td>
    </tr>
    <tr>
      <td><strong>Technological</strong></td>
      <td>R&amp;D, innovations, disruptions</td>
      <td>AI in food tech, Blockchain traceability</td>
    </tr>
    <tr>
      <td><strong>Economic</strong></td>
      <td>Growth, inflation, trade</td>
      <td>Middle class expansion, Currency volatility</td>
    </tr>
    <tr>
      <td><strong>Environmental</strong></td>
      <td>Climate, resources, regulations</td>
      <td>Carbon pricing, Water scarcity</td>
    </tr>
    <tr>
      <td><strong>Political</strong></td>
      <td>Government, policies, stability</td>
      <td>Trade agreements, Tax reforms</td>
    </tr>
  </tbody>
</table>

<h2 id="framework-3-scenario-planning"><em>Framework 3: Scenario Planning</em></h2>

<p><em>Framework</em> ini saya rasa sudah sering dilakukan oleh berbagai perusahaan yang melakukan market riset tapi bisa jadi mereka hanya tidak menyadari bahwa hal yang mereka lakukan sejatinya adalah <em>market foresight</em>. Ada empat tahapan yang biasa dilaukan:</p>

<ol>
  <li><em>Identify driving forces (predetermined elements vs critical uncertainties)</em>.</li>
  <li><em>Develop scenario frameworks (2 x 2 matrix based on key uncertainties)</em>.</li>
  <li><em>Flesh out scenarios (narrative, quantitative models)</em>.</li>
  <li><em>Identify implications and options (strategic responses)</em>.</li>
</ol>

<p>Contoh untuk FMCG di tahun 2030, kita bisa mendefinisikan <em>driving forces</em>-nya adalah:</p>

<ul>
  <li>Axis 1: <em>Health consciousness (Low vs High)</em>.</li>
  <li>Axis 2: <em>Technology adoption (Slow vs Fast).</em></li>
</ul>

<p>Kemudian kita akan membuat beberapa skenario seprti <em>“Traditional Wellness”</em>, <em>“Tech-Enabled Health”</em>, dan seterusnya. Selanjutnya kita bisa membuat beberapa simulasi bisnis berdasarkan skenario tersebut.</p>

<h2 id="framework-4-delphi-method"><em>Framework 4: Delphi Method</em></h2>

<p><em>Framework</em> keempat ini juga biasanya pernah dilakukan oleh beberaa perusahaan. Caranya adalah melakukan <em>structured approach</em> untuk <em>expert consensus:</em></p>

<ol>
  <li><em>Select experts (diverse backgrounds, 10-15 people)</em>.</li>
  <li><em>Develop questionnaire (open-ended questions about future)</em>.</li>
  <li><em>Multiple rounds</em> dengan <em>anonymized feedback</em>.</li>
  <li><em>Build consensus</em> atau <em>identify fundamental disagreements</em>.</li>
</ol>

<p>Contohnya hal ini bisa dilakukan untuk melihat beberapa hal seperti:</p>

<ol>
  <li><em>Forecasting regulatory changes</em>.</li>
  <li><em>Technology adoption curves</em>.</li>
  <li><em>Consumer trend evolution</em>.</li>
</ol>

<h2 id="framework-5-trend-extrapolation--wild-cards"><em>Framework 5: Trend Extrapolation &amp; Wild Cards</em></h2>

<p><em>Framework</em> terakhir ini diturunkan dari pendekatan matematika. Bisa saya bilang, “formula”-nya mirip dengan <em>time series</em>, yakni dengan melakukan “ekstrapolasi” terhadap tren dan mengidentifikasi <em>wild cards</em> sedini mungkin.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Trend(t) = Baseline(t) + Σ(TrendComponent_i(t)) + ε(t)
</code></pre></div></div>

<p>Dimana:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Baseline(t)</code> = business as usual projection.</li>
  <li><code class="language-plaintext highlighter-rouge">TrendComponent_i(t)</code> = individual trend effects (S-curve, exponential, dll).</li>
  <li><code class="language-plaintext highlighter-rouge">ε(t)</code> = wild card/black swan events.</li>
</ul>

<p><em>Wild card identification matrix:</em></p>

<table>
  <thead>
    <tr>
      <th>Probability</th>
      <th>High Impact</th>
      <th>Low Impact</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>High</strong></td>
      <td>Strategic priorities</td>
      <td>Contingency plans</td>
    </tr>
    <tr>
      <td><strong>Low</strong></td>
      <td>Monitor closely</td>
      <td>Acknowledge only</td>
    </tr>
  </tbody>
</table>

<h1 id="implementasi-praktis">IMPLEMENTASI PRAKTIS</h1>

<h2 id="how-to-start-dengan-resources-terbatas"><em>How to Start</em> dengan <em>Resources</em> Terbatas</h2>

<p><em>Minimum Viable Foresight (MVF) framework:</em></p>

<ol>
  <li><em>Dedicate 4 hours/month</em> untuk <em>foresight activities</em>.</li>
  <li><em>Assign 1 person</em> sebagai <em>“foresight champion”</em> (bisa <em>part-time</em>).</li>
  <li><em>Use free tools</em>: Google Trends, Twitter analytics, <em>patent databases</em>.</li>
  <li><em>Start with 1 trend</em>: Pilih <em>trend</em> paling relevan untuk bisnis Anda.</li>
  <li><em>Create simple output</em>: <em>1-page future brief</em> setiap bulan.</li>
</ol>

<h2 id="tools--technologies-yang-accessible"><em>Tools &amp; Technologies</em> yang <em>Accessible</em></h2>

<p><em>Free/Open Source Tools:</em></p>

<ul>
  <li><em>Horizon scanning</em>: Feedly, Google Alerts, Talkwalker Alerts.</li>
  <li><em>Trend analysis</em>: Google Trends, AnswerThePublic, Exploding Topics.</li>
  <li><em>Scenario planning</em>: Miro (free tier), Lucidchart.</li>
</ul>

<p><em>Low-cost Professional Tools:</em></p>

<ul>
  <li><em>Social listening</em>: Brandwatch (starter plan), Mention.</li>
  <li><em>Market intelligence</em>: Statista, Euromonitor Passport.</li>
  <li><em>Patent analysis</em>: Google Patents, Lens.org.</li>
  <li><em>Academic research</em>: Google Scholar, ResearchGate.</li>
</ul>

<h2 id="building-foresight-capability-di-perusahaan"><em>Building Foresight Capability</em> di Perusahaan</h2>

<p>Kita bisa menggunakan pendekatan tiga fase:</p>

<p><em>Phase 1: Awareness (Months 1-3)</em></p>

<ul>
  <li><em>Workshop “Introduction to Foresight”</em>.</li>
  <li><em>Create trend radar for your industry</em>.</li>
  <li><em>Identify 2-3 early adopters in organization</em>.</li>
</ul>

<p><em>Phase 2: Capability (Months 4-12)</em></p>

<ul>
  <li><em>Train foresight champions (2-3 days training)</em>.</li>
  <li><em>Establish monthly foresight meetings</em>.</li>
  <li><em>Develop first set of scenarios</em>.</li>
</ul>

<p><em>Phase 3: Integration (Year 2+)</em></p>

<ul>
  <li><em>Incorporate foresight into strategic planning</em>.</li>
  <li><em>Establish foresight KPI (e.g., “strategic surprise index”)</em>.</li>
  <li><em>Create foresight governance (who owns it, how funded)</em>.</li>
</ul>

<h2 id="integrating-dengan-existing-insights-processes"><em>Integrating</em> dengan <em>Existing Insights Processes</em></h2>

<p>Jika perusahaan sudah memiliki tim untuk mencari <em>market insight</em>, kita bisa membuat jembatan antara <em>insights</em> dan <em>foresight</em> dengan <em>flow</em> seperti ini:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Current State (Insights) → Gap Analysis → Future State (Foresight) → Strategic Options
</code></pre></div></div>

<p><em>Practical integration points:</em></p>

<ol>
  <li><em>Monthly business review: Add “future signals” section (10 minutes).</em></li>
  <li><em>Annual planning: Include scenario planning workshop (1 day).</em></li>
  <li><em>Innovation pipeline: Reserve 20% budget for H3 projects.</em></li>
  <li><em>Risk management: Include foresight-derived risks in risk register.</em></li>
</ol>

<p><em>Tool integration</em> sebagai contoh:</p>

<ul>
  <li><em>Sales BI dashboard: Add “future trends” tab.</em></li>
  <li><em>CRM system: Tag customers interested in emerging categories.</em></li>
  <li><em>Product roadmap: Color-code features by horizon (H1/H2/H3).</em></li>
</ul>

<h1 id="epilog"><em>EPILOG</em></h1>

<h2 id="summary-key-takeaways"><em>Summary Key Takeaways</em></h2>

<ol>
  <li><strong>Market insights dan market foresight adalah complementary</strong>, bukan mutually exclusive. Insights memberi Anda peta untuk navigasi hari ini; foresight memberi Anda kompas untuk arah masa depan.</li>
  <li><strong>Dalam dunia VUCA</strong>, mengandalkan insights saja seperti menyetir sambil melihat ke spion. Anda perlu melihat ke depan (foresight) untuk menghindari tabrakan dan menemukan jalan terbaik.</li>
  <li><strong>Framework yang tepat</strong> (Three Horizons, STEEP, Scenario Planning) membuat foresight bukanlah seni mistis, tapi disiplin yang bisa dipelajari dan diterapkan secara sistematis.</li>
  <li><strong>Start small but think big</strong>. Anda tidak perlu tim foresight dedicated dengan budget besar. Mulai dengan 4 jam/bulan, 1 trend, dan 1 orang champion.</li>
  <li><strong>Integration adalah kunci</strong>. Foresight yang terisolasi tidak berguna. Integrasikan ke dalam proses bisnis yang ada: planning, innovation, risk management.</li>
</ol>

<blockquote>
  <p><em>Market insights</em> membantu Anda beroperasi dengan optimal hari ini, sementara <em>market foresight</em> mempersiapkan Anda untuk bertahan dan berkembang di masa depan. Dan dalam dunia bisnis yang berubah dengan kecepatan eksponensial, mengabaikan salah satunya adalah resep untuk kegagalan.</p>
</blockquote>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Market Riset" /><category term="Market Insights" /><category term="Data" /><category term="Indonesia" /><category term="Analisa data" /><category term="FMCG" /><category term="Digital" /><category term="Marketing" /><category term="Market Foresight" /><category term="Market entry" /><category term="Insights" /><summary type="html"><![CDATA[Saya masih ingat dengan jelas hari itu di tahun 2018, ketika tim research and development di kantor sedang mempersiapkan peluncuran produk baru. Data dari tim market research menunjukkan bahwa mayoritas konsumen Indonesia mulai peduli dengan kandungan gula, garam, dan lemak dalam produk makanan minuman mereka. Insight ini jelas: ada peluang untuk produk rendah gula, garam, dan lemak.]]></summary></entry><entry><title type="html">Jabodetabek vs Indonesia: Mikrokosmos yang Tidak Selalu Mewakili Seluruh Negeri</title><link href="https://ikanx101.com/blog/jabo-nasional/" rel="alternate" type="text/html" title="Jabodetabek vs Indonesia: Mikrokosmos yang Tidak Selalu Mewakili Seluruh Negeri" /><published>2026-04-10T14:12:00+00:00</published><updated>2026-04-10T14:12:00+00:00</updated><id>https://ikanx101.com/blog/jabo-nasional</id><content type="html" xml:base="https://ikanx101.com/blog/jabo-nasional/"><![CDATA[<p>Selama saya bekerja di industri <em>market research</em> dan FMCG, terutama
makanan dan minuman, saya seringkali mendengar kalimat ini:</p>

<blockquote>
  <p><strong>“Coba test dulu di Jabodetabek, kalau laku di sini baru kita
<em>launch</em> nasional.”</strong></p>
</blockquote>

<p>Bahkan di awal-awal saya bergabung di perusahaan tempat saya bekerja
sekarang, semua proyek survey <em>market research</em> hanya dilakukan di
Jabodetabek saja tanpa melibatkan kota-kota lain. Tapi seberapa akurat
Jabodetabek mewakili Indonesia?</p>

<p>Setelah mencari data sekunder di BPS, laporan industri, dan berbagai
sumber terbaru, saya menemukan beberapa fakta menarik yang mungkin bikin
saya berpikir dua kali sebelum <strong>mengandalkan</strong> Jabodetabek sebagai
<em>proxy</em> bagi keseluruhan Indonesia. Begini analisanya:</p>

<h2 id="jabodetabek-punya-11-populasi-tapi">Jabodetabek: Punya 11% Populasi, Tapi…</h2>

<p>Dari segi jumlah orang, Jabodetabek memiliki 32.3 juta jiwa (2025)
dibanding total seluruh Indonesia 282.2 juta jiwa (2025). Secara
proporsi Jabodetabek hanya memiliki <strong>11.4%</strong> populasi nasional.</p>

<p>Tapi tunggu dulu, ada hal yang menarik:</p>

<ul>
  <li><strong>Populasi urban</strong> Jabodetabek: 41.9 juta.</li>
  <li><strong>Populasi urban</strong> Indonesia: 158.0 juta.</li>
  <li><strong>Proporsi urban:</strong> <strong>26.5%</strong> populasi urban Indonesia ada di
Jabodetabek!</li>
</ul>

<p>Artinya <strong>Jabodetabek itu konsentrasi orang kota</strong>. Kalau kita punya
produk dengan <em>target market</em> adalah masyarakat urban, maka pemilihan
Jabodetabek mungkin akan relevan. Tapi jika target marketnya adalah
market yang lebih luas dan <em>mass</em>, maka pemilihan Jabodetabek perlu
dilakukan secara hati-hati.</p>

<h2 id="faktor-skala-ekonomi-kontribusi-yang-sangat-besar">Faktor Skala Ekonomi: Kontribusi yang Sangat Besar!</h2>

<p>Sekarang saya akan tunjukan data PDB (Produk Domestik Bruto).
Jabodetabek memiliki PDB sebesar Rp 5,164.6 triliun sedangkan Indonesia
sebesar Rp 23,821.1 triliun. Secara proporsi, Jabodetabek memiliki
kontribusi <strong>21.7%</strong> PDB nasional.</p>

<p>Selain itu, secara data PDB Per kapita, Jabodetabek memiliki nilai Rp
149.2 juta/tahun sedangkan Indonesia Rp 83.7 juta/tahun. Perbandingannya
Jabodetabek <strong>78%</strong> lebih tinggi dari rata-rata nasional.</p>

<p><strong>Secara sederhana bisa disimpulkan</strong> bahwa masyarakat Jabodetabek punya
daya beli <strong>hampir dua kali rata-rata Indonesia</strong>. Makanya jangan kaget
kalau produk-produk premium bisa laku di sini tapi mentok di daerah
lainnya.</p>

<h2 id="pasar-fmcg-jabodetabek-20-share-nasional">Pasar FMCG: Jabodetabek 20% <em>Share</em> Nasional</h2>

<p>Dari data yang saya dapatkan dari berbagai sumber, estimasi pasar FMCG
Indonesia 2025-2026 adalah sebesar <strong>$100 miliar</strong> (sekitar Rp 1.500
triliun) dengan pertumbuhan: <strong>7.6%</strong> per tahun.</p>

<p><strong>Berapa Porsi Jabodetabek?</strong></p>

<p>Berdasarkan tiga metode perhitungan:</p>

<ol>
  <li><strong>Berdasarkan populasi (11.4%):</strong> $11.4 miliar.</li>
  <li><strong>Berdasarkan PDB (21.7%):</strong> $21.7 miliar.</li>
  <li><strong>Berdasarkan pengeluaran:</strong> $18-22 miliar.</li>
</ol>

<p>Konsekuensinya, Jabodetabek punya proporsi sebesar <strong>18-22%</strong> dari
keseluruhan pasar FMCG nasional.</p>

<h2 id="data-pengeluaran-makanan">Data Pengeluaran Makanan</h2>

<h3 id="pengeluaran-bulanan-per-kapita">Pengeluaran Bulanan Per Kapita</h3>

<ul>
  <li><strong>DKI Jakarta:</strong> Rp 2.79 juta</li>
  <li><strong>Jawa Barat:</strong> Rp 1.42 juta</li>
  <li><strong>Banten:</strong> Rp 1.38 juta</li>
  <li><strong>Rata-rata Nasional:</strong> Rp 0.96 juta</li>
  <li><strong>NTT (terendah):</strong> Rp 0.96 juta</li>
</ul>

<p><strong>DKI Jakarta menghabiskan 2.9x lebih banyak</strong> untuk makanan dibanding
rata-rata nasional! Makanya jangan heran kalau harga produk di Jakarta
lebih mahal dan orang masih beli.</p>

<h2 id="karakteristik-konsumen-yang-beda">Karakteristik Konsumen yang Beda</h2>

<p>Jika kita bandingkan karakteristik konsumen di Jabodetabek dengan
Indonesia, kita pasti yakin bahwa ada perbedaan di antara keduanya. Saya
menduga perbedaan ini disebabkan oleh beberapa faktor seperti berikut:</p>

<ol>
  <li><strong>Toko Modern:</strong> 65% retail modern Indonesia ada di Jabodetabek.</li>
  <li><strong>E-commerce:</strong> 78% penetrasi vs 52% nasional.</li>
  <li><strong>Produk Premium:</strong> 45% penjualan vs 15% nasional.</li>
  <li><strong>Adopsi Produk Baru:</strong> 3x lebih cepat.</li>
</ol>

<p>Sedikit banyak, faktor-faktor di atas mempengaruhi dan <em>shaping</em>
karakteristik konsumen di Jabodetabek. Konsekuensinya masyarakat di
Jabodetabek sangat mewakili <strong>konsumen urban, <em>digital savvy</em>, dan
<em>premium segment</em></strong> tapi kurang mewakili <strong><em>rural consumption</em>, <em>mass
market</em>, dan <em>price sensitive</em></strong>.</p>

<p>Dari paparan di atas, saya bisa membuat beberapa poin penting berikut
ini:</p>

<h3 id="kelebihan-memakai-jabodetabek-sebagai-proxy">Kelebihan Memakai Jabodetabek sebagai <em>Proxy</em></h3>

<ol>
  <li><strong>Efisiensi testing</strong> - populasi padat, akses mudah.</li>
  <li><strong>Feedback cepat</strong> - konsumen lebih <em>responsive</em>.</li>
  <li><strong>Trendsetter</strong> - apa yang laku di sini biasanya menyebar.</li>
  <li><strong>Infrastruktur lengkap</strong> - distribusi, retail, digital semua ada.</li>
</ol>

<h3 id="kekurangan-memakai-jabodetabek-sebagai-proxy">Kekurangan Memakai Jabodetabek sebagai <em>Proxy</em></h3>

<ol>
  <li><strong><em>Over-represent</em> daya beli</strong> - 2.9x rata-rata nasional.</li>
  <li><strong><em>Zero rural representation</em></strong> - 100% urban vs 56% nasional.</li>
  <li><strong><em>Different consumption pattern</em></strong> - lebih modern, lebih digital.</li>
  <li><strong><em>Competition intensity</em></strong> - persaingan lebih ketat.</li>
</ol>

<p>Jadi kapan kita bisa menggunakan data Jabodetabek sebagai <em>proxy</em>? Yakni
saat:</p>

<ul>
  <li><em>Testing</em> produk inovasi.</li>
  <li>Analisis <em>segment premium</em>.</li>
  <li>Perilaku konsumen urban.</li>
  <li>Strategi <em>e-commerce</em>.</li>
  <li><em>Benchmarking</em> kompetitor.</li>
  <li><em>Forecasting trend</em>.</li>
</ul>

<p>Tapi kurang cocok digunakan untuk melakukan hal-hal berikut ini:</p>

<ul>
  <li><em>Pricing mass market</em>.</li>
  <li>Strategi penetrasi rural.</li>
  <li>Produk <em>bottom pyramid</em>.</li>
  <li>Klaim <em>market share</em> nasional.</li>
  <li>Analisis <em>price sensitivity</em>.</li>
  <li>Strategi <em>traditional trade</em>.</li>
</ul>

<h2 id="rekomendasi-strategis-untuk-market-research">Rekomendasi Strategis untuk Market Research</h2>

<p>Kita boleh saja menggunakan Jabodetabek untuk melakukan survey untuk
produk premium dan inovatif tapi <strong>jangan hanya mengandalkan
Jabodetabek</strong> untuk <em>mass market</em>. Idealnya kita bisa memadukan
Jabodetabek dengan dua sampai tiga kota lain yang memiliki <em>tier</em> di
bawahnya. Jika diperlukan, kita juga bisa menambahkan <em>sampling</em> khusus
di area <em>rural</em>.</p>

<p><em>Best practices</em> yang bisa dilakukan kira-kira seperti ini:</p>

<ol>
  <li>Untuk <em>product launch</em>:
    <ul>
      <li><strong>Phase 1:</strong> Jabodetabek (validasi pasar dan <em>brand building</em>).</li>
      <li><strong>Phase 2:</strong> Kota besar Jawa (Surabaya, Bandung, Semarang).</li>
      <li><strong>Phase 3:</strong> Nasional dengan penyesuaian harga/varian.</li>
    </ul>
  </li>
  <li>Untuk <em>business planning</em> kita bisa membuat formula konversi dari
nilai-nilai berikut ini di Jabodetabek ke angka nasional:
    <ul>
      <li><strong>Revenue Projection</strong>.</li>
      <li><strong>Market Share</strong>.</li>
      <li><strong>Growth Rate</strong>.</li>
    </ul>
  </li>
</ol>

<p>Beberap formula yang bisa digunakan:</p>

<p><strong>Volume Penjualan:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Penjualan Nasional = Penjualan Jabodetabek × 4.5
</code></pre></div></div>

<p><em>(Margin error: ±15%)</em></p>

<p><strong>Market Share:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Market Share Nasional = Market Share Jabodetabek ÷ 1.8  
</code></pre></div></div>

<p><em>(Margin error: ±20%)</em></p>

<p><strong>Growth Rate:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Growth Nasional = Growth Jabodetabek × 0.75
</code></pre></div></div>

<p><em>(Margin error: ±25%)</em></p>

<p><strong>Product Adoption:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Adoption Nasional = Adoption Jabodetabek × 0.35
</code></pre></div></div>

<p><em>(Margin error: ±30%)</em></p>

<p>Formula ini diturunkan dengan cara menghitung beberapa aproksimasi
berdasarkan data serta asumsi yang saya dapatkan.</p>

<h1 id="epilog"><em>Epilog</em></h1>

<blockquote>
  <p><em>“Jabodetabek adalah <strong>microcosm</strong> canggih dari pasar Indonesia, tapi
bukan miniatur yang akurat. Ia lebih mewakili <strong>masa depan</strong> (trend,
digital, premium) daripada mewakili <strong>realitas saat ini</strong> (mass
market, rural, traditional).</em></p>
</blockquote>

<p>Jabodetabek <strong><em>over-represents</em></strong> dalam hal daya beli, konsumsi modern,
dan adopsi digital tapi <strong><em>under-represents</em></strong> dalam hal <em>rural
consumption</em> dan <em>price sensitivity</em>.</p>

<hr />

<p>Data sumber: BPS 2024-2025, laporan industri FMCG 2026, berbagai
publikasi terkini.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Market Riset" /><category term="Jabodetabek" /><category term="Data" /><category term="Indonesia" /><category term="Analisa data" /><category term="FMCG" /><category term="Digital" /><summary type="html"><![CDATA[Selama saya bekerja di industri market research dan FMCG, terutama makanan dan minuman, saya seringkali mendengar kalimat ini:]]></summary></entry><entry><title type="html">Melihat Penyebaran Wabah Campak Melalui Kacamata Data Science dan Agent-Based Modelling</title><link href="https://ikanx101.com/blog/wabah-campak/" rel="alternate" type="text/html" title="Melihat Penyebaran Wabah Campak Melalui Kacamata Data Science dan Agent-Based Modelling" /><published>2026-04-09T15:11:00+00:00</published><updated>2026-04-09T15:11:00+00:00</updated><id>https://ikanx101.com/blog/wabah-campak</id><content type="html" xml:base="https://ikanx101.com/blog/wabah-campak/"><![CDATA[<h2 id="campak-kembali-dan-ini-bukan-hal-sepele">Campak Kembali dan Ini Bukan Hal Sepele</h2>

<p>Awal 2026, berita tentang wabah campak kembali muncul di berbagai media
Indonesia. Beberapa provinsi melaporkan lonjakan kasus. Banyak di
antaranya menyerang anak-anak yang belum mendapat vaksinasi lengkap.
Padahal, campak adalah penyakit yang sebenarnya sudah sangat bisa
dicegah dengan vaksin yang sudah ada sejak 1960-an.</p>

<p>Sebagai seseorang yang berkecimpung di dunia data, saya jadi
bertanya-tanya:</p>

<blockquote>
  <p><em>Bagaimana sebenarnya penyakit ini menyebar? Mengapa ia bisa menjadi
wabah dengan begitu cepat? Dan apa yang angka-angka di balik campak
ini ceritakan kepada kita?</em></p>
</blockquote>

<p>Untuk itu, saya akan coba melakukan simulasi untuk memahami dinamika
penyebaran campak secara matematis. Akan ada dua pendekatan yang mau
saya coba, yakni:</p>

<ol>
  <li>Memodelkan dengan <a href="https://ikanx101.com/blog/sir-covid/"><em>SIR</em></a>,</li>
  <li>Menggunakan <a href="https://ikanx101.com/blog/simple-economy/"><em>Agent Based
Modelling</em></a>.</li>
</ol>

<p>Dari kedua pendekatan tersebut, saya akan melihat seberapa berbahaya
penyebaran campak ini dibandingkan dengan penyakit virus lainnya.</p>

<p>Oh iya, perlu saya tekankan bahwa saya bukan dokter dan tulisan ini
bersifat edukatif. Saya menggunakan data serta parameter yang bersumber
dari literatur epidemiologi. Simulasi yang disajikan adalah
penyederhanaan untuk tujuan pemahaman, bukan model prediksi resmi. Untuk
informasi kesehatan, selalu rujuk ke Kementerian Kesehatan RI dan tenaga
medis profesional.</p>

<hr />

<h2 id="apa-itu-campak">Apa itu campak?</h2>

<p>Campak (<em>Measles</em>) disebabkan oleh <strong>Measles Morbillivirus</strong>. Virus
tersebut menyebar lewat udara, yakni melalui tetesan pernapasan dan
partikel aerosol yang bisa bertahan di udara sampai dua jam setelah
penderita meninggalkan ruangan. Inilah yang membuatnya sangat berbeda
dari banyak penyakit menular lain. Gejala khasnya:</p>

<ul>
  <li>Demam tinggi,</li>
  <li>Batuk,</li>
  <li>Pilek,</li>
  <li>Mata merah, dan</li>
  <li>Ruam merah yang menyebar dari wajah ke seluruh tubuh.</li>
</ul>

<p>Komplikasi yang menyertai campak bisa serius: <em>pneumonia</em>, <em>ensefalitis</em>
(radang otak), bahkan kematian — terutama pada anak-anak di bawah 5
tahun dengan gizi buruk.</p>

<p>Dalam epidemiologi, kita mengenal angka <strong>R0</strong>. Saya sudah pernah
menjelaskannya pada tulisan <a href="https://ikanx101.com/blog/covid/">model Covid saya yang pertama
kali</a>. <strong>R0</strong> adalah satu angka yang
paling menentukan seberapa ‘berbahaya’ sebuah penyakit. <strong>R0</strong> (dibaca
<em>R-naught</em>) bisa kita sebut dengan <em>basic reproduction number</em>.</p>

<blockquote>
  <p><strong>R0</strong> adalah rata-rata jumlah orang yang akan tertular dari SATU
penderita, dalam populasi yang sepenuhnya rentan (belum kebal). R0 &gt;
1 berarti wabah bisa terjadi. Semakin besar R0, semakin agresif
penyebarannya.</p>
</blockquote>

<p>Tabel berikut inilah yang membuat campak luar biasa:</p>

<table>
  <thead>
    <tr>
      <th>Penyakit</th>
      <th>R0 (estimasi)</th>
      <th>Masa infeksius</th>
      <th>Berapa persen cakupan vaksin agar tercapai <em>Herd Immunity</em></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Campak</td>
      <td>12-18</td>
      <td>~ 8 hari</td>
      <td>~ 95%</td>
    </tr>
    <tr>
      <td>Cacar air</td>
      <td>8-10</td>
      <td>~ 7 hari</td>
      <td>~ 90%</td>
    </tr>
    <tr>
      <td>Gondongan</td>
      <td>4-7</td>
      <td>~ 7 hari</td>
      <td>~ 85%</td>
    </tr>
    <tr>
      <td>Influenza musiman</td>
      <td>2-3</td>
      <td>~ 5 hari</td>
      <td>~ 50%</td>
    </tr>
    <tr>
      <td>Covid-19</td>
      <td>2-3</td>
      <td>~ 10 hari</td>
      <td>~ 60-70%</td>
    </tr>
    <tr>
      <td>Ebola</td>
      <td>1.5-2.5</td>
      <td>~ 10 hari</td>
      <td>~ 50-60%</td>
    </tr>
    <tr>
      <td>SARS</td>
      <td>2-5</td>
      <td>~ 10 hari</td>
      <td>~ 50-80%</td>
    </tr>
  </tbody>
</table>

<p>Dengan <strong>R0</strong> antara <strong>12 hingga 18</strong>, campak adalah salah satu penyakit
menular paling infeksius yang dikenal manusia. Artinya: satu orang yang
terinfeksi, dalam populasi tanpa imunitas, rata-rata bisa menginfeksi 12
sampai 18 orang lain. Bandingkan dengan influenza yang hanya 2-3.
Implikasi langsungnya sangat mengejutkan: untuk mencapai <em>herd immunity</em>
dari campak, setidaknya 95% populasi harus kebal. Kalau cakupan
vaksinasi turun di bawah angka itu karena hoaks, keengganan, atau
kesulitan akses terhadap vaksin maka wabah bisa meledak dengan cepat.</p>

<h2 id="mengapa-wabah-bisa-terjadi-meski-vaksin-ada">Mengapa Wabah Bisa Terjadi Meski Vaksin Ada?</h2>

<p>Fenomena ini dikenal sebagai <em>immunity gap</em>. Selama beberapa tahun
terakhir, cakupan vaksinasi MMR (<em>Measles</em>, <em>Mumps</em>, dan <em>Rubella</em>) di
Indonesia mengalami penurunan, salah satu penyebabnya adalah disrupsi
layanan kesehatan saat pandemi COVID-19 dan meningkatnya gerakan
anti-vaksin di berbagai daerah. Ketika cakupan vaksinasi turun dari 95%
ke, katakanlah menjadi 85% maka ada <em>gap</em> 10% populasi yang tiba-tiba
menjadi rentan. Dalam populasi besar seperti Indonesia dengan 280 juta
jiwa, 10% itu berarti 28 juta orang yang tidak terlindungi. Dengan
<strong>R0</strong> campak yang setinggi 12-18, celah sekecil itu sudah cukup untuk
memicu wabah.</p>

<h1 id="model-sir-fondasi-matematika-dalam-epidemi">Model SIR: Fondasi Matematika dalam Epidemi</h1>

<h2 id="memahami-model-sir">Memahami Model SIR</h2>

<p>Sebelum masuk ke simulasi <em>Agent Based Modelling</em>, kita perlu memahami
model SIR. Yakni suatu model yang merupakan fondasi matematis dalam
epidemiologi. Ini adalah model kompartemen klasik yang dikembangkan oleh
Kermack dan McKendrick pada 1927 dan masih menjadi tulang punggung
epidemiologi modern. Dalam Model SIR, setiap individu berada di salah
satu dari tiga kompartemen:</p>

<ul>
  <li><strong>S</strong> (<em>Susceptible</em>): Rentan yakni kumpulan orang-orang yang belum
terinfeksi dan belum kebal.</li>
  <li><strong>I</strong> (<em>Infectious</em>): Infeksius yakni kumpulan orang-orang yang sedang
terinfeksi dan bisa menularkan.</li>
  <li><strong>R</strong> (<em>Recovered</em>): Pulih yakni kumpulan orang-orang yang sudah
sembuh dan kini kebal, atau meninggal.</li>
</ul>

<p>Pergerakan antar kompartemen diatur oleh dua parameter utama:</p>

<ul>
  <li><em>Beta</em> (β): Laju transmisi, yakni seberapa cepat penyakit menyebar
dari <strong>I</strong> ke <strong>S</strong>.</li>
  <li><em>Gamma</em> (γ): Laju <em>recovery</em>, yakni seberapa cepat individu pindah
dari <strong>I</strong> ke <strong>R</strong>.</li>
</ul>

<p>Dari kedua parameter ini, kita bisa menghitung <strong>R0 = β / γ</strong>.</p>

<h2 id="simulasi-model-sir-dengan-r">Simulasi Model SIR dengan <strong>R</strong></h2>

<p>Untuk bisa melihat penyebaran penyakit, saya akan membuat <em>function</em>
dari model SIR sebagai berikut:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Fungsi Model SIR deterministik ───────────────────────────────</span><span class="w">
</span><span class="c1"># Menggunakan persamaan diferensial biasa (ODE) diskret</span><span class="w">

</span><span class="n">simulasi_SIR</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">N</span><span class="p">,</span><span class="w">          </span><span class="c1"># Ukuran populasi</span><span class="w">
                          </span><span class="n">I0</span><span class="p">,</span><span class="w">         </span><span class="c1"># Kasus awal</span><span class="w">
                          </span><span class="n">beta</span><span class="p">,</span><span class="w">       </span><span class="c1"># Laju transmisi</span><span class="w">
                          </span><span class="n">gamma</span><span class="p">,</span><span class="w">      </span><span class="c1"># Laju recovery</span><span class="w">
                          </span><span class="n">vaksinasi</span><span class="p">,</span><span class="w">  </span><span class="c1"># Proporsi yang sudah divaksin (0-1)</span><span class="w">
                          </span><span class="n">n_hari</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">365</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="c1"># Populasi awal: yang sudah divaksin langsung masuk R</span><span class="w">
  </span><span class="n">S</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="m">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">vaksinasi</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">I0</span><span class="w">
  </span><span class="n">I</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">I0</span><span class="w">
  </span><span class="n">R</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">vaksinasi</span><span class="w">

  </span><span class="n">hasil</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">hari</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">I</span><span class="p">,</span><span class="w"> </span><span class="n">R</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">R</span><span class="p">,</span><span class="w">
    </span><span class="n">kasus_baru</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">I0</span><span class="w">
  </span><span class="p">)</span><span class="w">

  </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">t</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">n_hari</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="c1"># Persamaan SIR diskret</span><span class="w">
    </span><span class="n">dS</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="o">-</span><span class="n">beta</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">N</span><span class="w">
    </span><span class="n">dI</span><span class="w"> </span><span class="o">&lt;-</span><span class="w">  </span><span class="n">beta</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">gamma</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">I</span><span class="w">
    </span><span class="n">dR</span><span class="w"> </span><span class="o">&lt;-</span><span class="w">  </span><span class="n">gamma</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">I</span><span class="w">

    </span><span class="n">S</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dS</span><span class="p">)</span><span class="w">
    </span><span class="n">I</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dI</span><span class="p">)</span><span class="w">
    </span><span class="n">R</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">R</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dR</span><span class="w">

    </span><span class="n">hasil</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">rbind</span><span class="p">(</span><span class="n">hasil</span><span class="p">,</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
      </span><span class="n">hari</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">S</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">S</span><span class="p">,</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">I</span><span class="p">,</span><span class="w"> </span><span class="n">R</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">R</span><span class="p">,</span><span class="w">
      </span><span class="n">kasus_baru</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">beta</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">hasil</span><span class="o">$</span><span class="n">S</span><span class="p">[</span><span class="n">nrow</span><span class="p">(</span><span class="n">hasil</span><span class="p">)])</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">N</span><span class="w">
    </span><span class="p">))</span><span class="w">

    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">I</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="m">0.5</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="w">  </span><span class="c1"># Wabah padam</span><span class="w">
  </span><span class="p">}</span><span class="w">
  </span><span class="n">hasil</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Berikutnya saya akan membandingkan penyakit campak dengan influenza dan
cacar air. Berikut adalah beberapa parameter dari ketiga penyakit ini
yang kelak akan saya masukkan ke dalam model:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Parameter penyakit dari literatur ────────────────────────────</span><span class="w">
</span><span class="c1">#</span><span class="w">
</span><span class="c1"># Campak: R0 = 15, masa infeksius = 8 hari -&gt; gamma = 1/8</span><span class="w">
</span><span class="c1">#         beta = R0 * gamma = 15 * (1/8) = 1.875</span><span class="w">
</span><span class="c1">#</span><span class="w">
</span><span class="c1"># Cacar Air: R0 = 9, masa infeksius = 7 hari</span><span class="w">
</span><span class="c1">#</span><span class="w">
</span><span class="c1"># Influenza: R0 = 2.5, masa infeksius = 5 hari</span><span class="w">

</span><span class="n">penyakit</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="w">
  </span><span class="n">Campak</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="w">
    </span><span class="n">beta</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="m">15</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="m">1</span><span class="o">/</span><span class="m">8</span><span class="p">),</span><span class="w">   </span><span class="c1"># R0=15, gamma=1/8</span><span class="w">
    </span><span class="n">gamma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="o">/</span><span class="m">8</span><span class="p">,</span><span class="w">
    </span><span class="n">R0</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="m">15</span><span class="p">,</span><span class="w">
    </span><span class="n">warna</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#C0392B'</span><span class="w">
  </span><span class="p">),</span><span class="w">
  </span><span class="n">`Cacar Air`</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="w">
    </span><span class="n">beta</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="m">9</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="m">1</span><span class="o">/</span><span class="m">7</span><span class="p">),</span><span class="w">    </span><span class="c1"># R0=9, gamma=1/7</span><span class="w">
    </span><span class="n">gamma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="o">/</span><span class="m">7</span><span class="p">,</span><span class="w">
    </span><span class="n">R0</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="m">9</span><span class="p">,</span><span class="w">
    </span><span class="n">warna</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#E67E22'</span><span class="w">
  </span><span class="p">),</span><span class="w">
  </span><span class="n">Influenza</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="w">
    </span><span class="n">beta</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="m">2.5</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="m">1</span><span class="o">/</span><span class="m">5</span><span class="p">),</span><span class="w">  </span><span class="c1"># R0=2.5, gamma=1/5</span><span class="w">
    </span><span class="n">gamma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="o">/</span><span class="m">5</span><span class="p">,</span><span class="w">
    </span><span class="n">R0</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="m">2.5</span><span class="p">,</span><span class="w">
    </span><span class="n">warna</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#2980B9'</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>Saya juga akan membuat kondisi awal sebagai berikut:</p>

<ol>
  <li>Populasi awal: 10.000 orang.</li>
  <li>Kasus awal: 5 orang.</li>
  <li>Cakupan vaksin: 80% (di bawah angka persentasi <em>herd immunity</em>
campak yang disarankan literatur).</li>
</ol>

<p>Oke, sekarang saya akan jalankan simulasinya:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Jalankan SIR untuk ketiga penyakit ───────────────────────────</span><span class="w">
</span><span class="n">df_SIR_all</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">lapply</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">penyakit</span><span class="p">),</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">nm</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="n">p</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">penyakit</span><span class="p">[[</span><span class="n">nm</span><span class="p">]]</span><span class="w">
  </span><span class="n">sim</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">simulasi_SIR</span><span class="p">(</span><span class="w">
    </span><span class="n">N</span><span class="w">          </span><span class="o">=</span><span class="w"> </span><span class="n">N_pop</span><span class="p">,</span><span class="w">
    </span><span class="n">I0</span><span class="w">         </span><span class="o">=</span><span class="w"> </span><span class="n">kasus_awal</span><span class="p">,</span><span class="w">
    </span><span class="n">beta</span><span class="w">       </span><span class="o">=</span><span class="w"> </span><span class="n">p</span><span class="o">$</span><span class="n">beta</span><span class="p">,</span><span class="w">
    </span><span class="n">gamma</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="n">p</span><span class="o">$</span><span class="n">gamma</span><span class="p">,</span><span class="w">
    </span><span class="n">vaksinasi</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="n">cakupan_vaksin</span><span class="p">,</span><span class="w">
    </span><span class="n">n_hari</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="m">365</span><span class="w">
  </span><span class="p">)</span><span class="w">
  </span><span class="n">sim</span><span class="o">$</span><span class="n">penyakit</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">nm</span><span class="w">
  </span><span class="n">sim</span><span class="w">
</span><span class="p">})</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w"> </span><span class="n">bind_rows</span><span class="p">()</span><span class="w">

</span><span class="c1"># Ringkasan puncak wabah</span><span class="w">
</span><span class="n">df_puncak</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">df_SIR_all</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
  </span><span class="n">group_by</span><span class="p">(</span><span class="n">penyakit</span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w">
  </span><span class="n">summarise</span><span class="p">(</span><span class="w">
    </span><span class="n">hari_puncak</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="n">hari</span><span class="p">[</span><span class="n">which.max</span><span class="p">(</span><span class="n">I</span><span class="p">)],</span><span class="w">
    </span><span class="n">puncak_kasus</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="nf">round</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="n">I</span><span class="p">)),</span><span class="w">
    </span><span class="n">total_terinfeksi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">round</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="n">R</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">N_pop</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">cakupan_vaksin</span><span class="p">),</span><span class="w">
    </span><span class="n">.groups</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'drop'</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>Berikut adalah visualisasi dari simulasi yang telah dijalankan.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-6-1.png" alt="" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== RINGKASAN PUNCAK WABAH ===

# A tibble: 3 × 4
  penyakit  hari_puncak puncak_kasus total_terinfeksi
  &lt;chr&gt;           &lt;dbl&gt;        &lt;dbl&gt;            &lt;dbl&gt;
1 Cacar Air          50          246             1481
2 Campak             29          633             1896
3 Influenza           0            5                9
</code></pre></div></div>

<p>Analisis data dari ketiga penyakit:</p>

<ol>
  <li>Cacar Air
    <ul>
      <li>Interpretasi: Penyebaran relatif lambat, mencapai puncak setelah
50 hari, tetapi memiliki dampak yang cukup signifikan dengan total
1.481 kasus.</li>
    </ul>
  </li>
  <li>Campak
    <ul>
      <li>Interpretasi: Penyebaran sangat cepat dan agresif! Mencapai puncak
hanya dalam 29 hari dengan jumlah kasus puncak tertinggi (633
orang). Total kasus juga paling tinggi di antara ketiga penyakit.</li>
    </ul>
  </li>
  <li>Influenza
    <ul>
      <li>Interpretasi: Penyebaran sangat terbatas. Kemungkinan ini
menunjukkan penyakit dengan tingkat penularan rendah atau populasi
yang sudah sebagian besar kebal.</li>
    </ul>
  </li>
</ol>

<h1 id="agent-based-modelling-simulasi-yang-lebih-realistis"><em>Agent Based Modelling</em>: Simulasi yang Lebih Realistis</h1>

<h2 id="mengapa-abm-lebih-menarik-dari-sir-biasa">Mengapa ABM Lebih Menarik dari SIR Biasa?</h2>

<p>Model SIR di atas mengasumsikan populasi yang <em>perfectly mixed</em> dimana
setiap orang punya peluang yang sama untuk bertemu orang lain. Di dunia
nyata, ini tidak terjadi. Kita berinteraksi dalam jaringan sosial:
keluarga, tetangga, teman sekolah, rekan kerja. <em>Agent Based Modelling</em>
(ABM) mensimulasikan setiap individu sebagai ‘agen’ yang bergerak,
berinteraksi, dan berubah statusnya secara mandiri. Hasilnya jauh lebih
kaya, yakni:</p>

<ol>
  <li>Kita bisa melihat cluster wabah,</li>
  <li>Efek jaringan sosial, dan</li>
  <li>Bagaimana kebijakan seperti karantina atau vaksinasi massal
berpengaruh.</li>
</ol>

<blockquote>
  <p>Berbeda dengan model SIR, Dalam ABM “penyakit” tidak dimodelkan secara
langsung. Yang dimodelkan adalah PERILAKU setiap individu: bergerak,
berinteraksi, menulari, sembuh. Pola wabah yang muncul adalah hasil
<em>emergent</em> dari interaksi ribuan agen sehingga persis seperti yang
terjadi di dunia nyata.</p>
</blockquote>

<h2 id="membangun-abm-campak-di-r">Membangun ABM Campak di <strong>R</strong></h2>

<p>Kita akan membangun ABM sederhana dengan 500 agen yang bergerak di ruang
dua dimensi. Setiap agen mewakili satu individu dengan status <strong>S</strong>,
<strong>I</strong>, atau <strong>R.</strong> Agen bergerak secara acak dan bisa menulari agen lain
yang berada dalam jarak tertentu.</p>

<p>Pertama-tama, saya akan membuat data awal sebagai berikut:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ══════════════════════════════════════════════════════════════════</span><span class="w">
</span><span class="c1"># AGENT-BASED MODEL — Penyebaran Campak</span><span class="w">
</span><span class="c1"># ══════════════════════════════════════════════════════════════════</span><span class="w">

</span><span class="c1"># ── Inisialisasi populasi agen ────────────────────────────────────</span><span class="w">
</span><span class="n">buat_populasi</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">n_agen</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="m">500</span><span class="p">,</span><span class="w">
                           </span><span class="n">pct_vaksin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.80</span><span class="p">,</span><span class="w">
                           </span><span class="n">n_infeksi_awal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">id</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">n_agen</span><span class="p">,</span><span class="w">
    </span><span class="n">x</span><span class="w">       </span><span class="o">=</span><span class="w"> </span><span class="n">runif</span><span class="p">(</span><span class="n">n_agen</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">100</span><span class="p">),</span><span class="w">   </span><span class="c1"># Posisi x (0-100)</span><span class="w">
    </span><span class="n">y</span><span class="w">       </span><span class="o">=</span><span class="w"> </span><span class="n">runif</span><span class="p">(</span><span class="n">n_agen</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">100</span><span class="p">),</span><span class="w">   </span><span class="c1"># Posisi y (0-100)</span><span class="w">
    </span><span class="c1"># Status: S=Susceptible, I=Infectious, R=Recovered, V=Vaccinated</span><span class="w">
    </span><span class="n">status</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="w">
      </span><span class="nf">rep</span><span class="p">(</span><span class="s1">'V'</span><span class="p">,</span><span class="w"> </span><span class="nf">round</span><span class="p">(</span><span class="n">n_agen</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">pct_vaksin</span><span class="p">)),</span><span class="w">
      </span><span class="nf">rep</span><span class="p">(</span><span class="s1">'I'</span><span class="p">,</span><span class="w"> </span><span class="n">n_infeksi_awal</span><span class="p">),</span><span class="w">
      </span><span class="nf">rep</span><span class="p">(</span><span class="s1">'S'</span><span class="p">,</span><span class="w"> </span><span class="n">n_agen</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nf">round</span><span class="p">(</span><span class="n">n_agen</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">pct_vaksin</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">n_infeksi_awal</span><span class="p">)</span><span class="w">
    </span><span class="p">)</span><span class="w"> </span><span class="o">%&gt;%</span><span class="w"> </span><span class="n">sample</span><span class="p">(),</span><span class="w">  </span><span class="c1"># Acak posisi status</span><span class="w">
    </span><span class="n">hari_infeksi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="w">
      </span><span class="n">sample</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">),</span><span class="w"> </span><span class="n">n_agen</span><span class="p">,</span><span class="w"> </span><span class="n">replace</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w">
             </span><span class="n">prob</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">n_infeksi_awal</span><span class="o">/</span><span class="n">n_agen</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">n_infeksi_awal</span><span class="o">/</span><span class="n">n_agen</span><span class="p">)),</span><span class="w">
      </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="kc">NA</span><span class="w">
    </span><span class="p">),</span><span class="w">
    </span><span class="c1"># Kecepatan gerak acak per agen</span><span class="w">
    </span><span class="n">vx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rnorm</span><span class="p">(</span><span class="n">n_agen</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">0.8</span><span class="p">),</span><span class="w">
    </span><span class="n">vy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rnorm</span><span class="p">(</span><span class="n">n_agen</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">0.8</span><span class="p">)</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Untuk <strong>sekali langkah</strong> (atau sekali iterasi waktu), saya akan buat
<em>function</em> berikut ini:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Satu langkah simulasi ABM ─────────────────────────────────────</span><span class="w">
</span><span class="n">langkah_ABM</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">pop</span><span class="p">,</span><span class="w"> </span><span class="n">hari</span><span class="p">,</span><span class="w">
                         </span><span class="n">radius_infeksi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">3</span><span class="p">,</span><span class="w">    </span><span class="c1"># Jarak menular (unit)</span><span class="w">
                         </span><span class="n">prob_infeksi</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="m">0.35</span><span class="p">,</span><span class="w"> </span><span class="c1"># Prob menular per kontak</span><span class="w">
                         </span><span class="n">masa_infeksius</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">8</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">  </span><span class="c1"># Hari infeksius</span><span class="w">

  </span><span class="c1"># 1. Gerakkan semua agen (dengan boundary reflection)</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">vx</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">rnorm</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">pop</span><span class="p">),</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">0.3</span><span class="p">)</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">vy</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">rnorm</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">pop</span><span class="p">),</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">0.3</span><span class="p">)</span><span class="w">

  </span><span class="c1"># Pantulkan di batas</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pmax</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">pmin</span><span class="p">(</span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="p">))</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pmax</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">pmin</span><span class="p">(</span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="p">))</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">vx</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="n">pop</span><span class="o">$</span><span class="n">vx</span><span class="p">,</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">vx</span><span class="p">)</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">vy</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="n">pop</span><span class="o">$</span><span class="n">vy</span><span class="p">,</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">vy</span><span class="p">)</span><span class="w">

  </span><span class="c1"># 2. Proses penularan: cek agen I ke agen S di sekitarnya</span><span class="w">
  </span><span class="n">agen_I</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="n">pop</span><span class="o">$</span><span class="n">status</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'I'</span><span class="p">)</span><span class="w">
  </span><span class="n">agen_S</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="n">pop</span><span class="o">$</span><span class="n">status</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'S'</span><span class="p">)</span><span class="w">

  </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">agen_I</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">agen_S</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">agen_I</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="c1"># Hitung jarak ke semua agen S</span><span class="w">
      </span><span class="n">dx</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="p">[</span><span class="n">agen_S</span><span class="p">]</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">x</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w">
      </span><span class="n">dy</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="p">[</span><span class="n">agen_S</span><span class="p">]</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">y</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w">
      </span><span class="n">jarak</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">sqrt</span><span class="p">(</span><span class="n">dx</span><span class="o">^</span><span class="m">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">dy</span><span class="o">^</span><span class="m">2</span><span class="p">)</span><span class="w">

      </span><span class="c1"># Agen S dalam radius infeksi</span><span class="w">
      </span><span class="n">dalam_radius</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">agen_S</span><span class="p">[</span><span class="n">jarak</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">radius_infeksi</span><span class="p">]</span><span class="w">

      </span><span class="c1"># Tularkan dengan probabilitas prob_infeksi</span><span class="w">
      </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">dalam_radius</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="n">tertular</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">dalam_radius</span><span class="p">[</span><span class="n">runif</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">dalam_radius</span><span class="p">))</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">prob_infeksi</span><span class="p">]</span><span class="w">
        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">tertular</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="n">pop</span><span class="o">$</span><span class="n">status</span><span class="p">[</span><span class="n">tertular</span><span class="p">]</span><span class="w">       </span><span class="o">&lt;-</span><span class="w"> </span><span class="s1">'I'</span><span class="w">
          </span><span class="n">pop</span><span class="o">$</span><span class="n">hari_infeksi</span><span class="p">[</span><span class="n">tertular</span><span class="p">]</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">hari</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">

  </span><span class="c1"># 3. Recovery: agen I yang sudah melewati masa infeksius</span><span class="w">
  </span><span class="n">sudah_waktunya</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="o">!</span><span class="nf">is.na</span><span class="p">(</span><span class="n">pop</span><span class="o">$</span><span class="n">hari_infeksi</span><span class="p">)</span><span class="w"> </span><span class="o">&amp;</span><span class="w">
                    </span><span class="p">(</span><span class="n">hari</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pop</span><span class="o">$</span><span class="n">hari_infeksi</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">masa_infeksius</span><span class="w">
  </span><span class="n">pop</span><span class="o">$</span><span class="n">status</span><span class="p">[</span><span class="n">pop</span><span class="o">$</span><span class="n">status</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'I'</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">sudah_waktunya</span><span class="p">]</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="s1">'R'</span><span class="w">

  </span><span class="n">pop</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Sekarang saya akan jalankan modelnya untuk 120 hari dan berikut adalah
hasilnya:</p>

<h2 id="visualisasi-hasil-simulasi-abm">Visualisasi Hasil Simulasi ABM</h2>

<p>Plot pertama akan memperlihatkan kurva epidemi antara ketiga penyakit:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-10-1.png" alt="" /></p>

<p>Berikut adalah perbandingan lainnya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== PERBANDINGAN HASIL ABM ===

# A tibble: 3 × 6
  penyakit  puncak_kasus hari_puncak durasi_wabah total_terinfeksi attack_rate
  &lt;chr&gt;            &lt;int&gt;       &lt;int&gt;        &lt;int&gt;            &lt;int&gt;       &lt;dbl&gt;
1 Cacar Air           11           6          120               36          36
2 Campak              12           6          120               53          53
3 Influenza           10           0          120               19          19
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-11-1.png" alt="" /></p>

<h3 id="analisa-mendalam-tentang-campak">Analisa Mendalam tentang Campak</h3>

<p>Plot berikutnya akan menampilkan di mana wabah campak terjadi dalam
ruang dua dimensi:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-12-1.png" alt="" /></p>

<p>Plot berikutnya akan menampilkan komposisi populasi sepanjang waktu:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-13-1.png" alt="" /></p>

<h3 id="simulasi-intervensi-apa-yang-terjadi-kalau-kita-bertindak">Simulasi Intervensi: Apa yang Terjadi Kalau Kita Bertindak?</h3>

<p>Model yang kita bentuk di atas bukan hanya bisa digunakan untuk melihat
penyebaran tapi juga untuk menguji pertanyaan:</p>

<blockquote>
  <p><em>Bagaimana kalau kita melakukan sesuatu?</em></p>
</blockquote>

<p>Kita akan simulasikan empat skenario vaksinasi berbeda untuk campak.</p>

<p>Berikut adalah perbandingannya:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-15-1.png" alt="" /></p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/agent%20based/campak/draft_files/figure-commonmark/unnamed-chunk-15-2.png" alt="" /></p>

<p>Terlihat bahwa perbedaan imunitas komunal membentuk penyebaran yang
berbeda-beda.</p>

<h2 id="apa-yang-bisa-kita-pelajari-dari-simulasi-ini">Apa yang Bisa Kita Pelajari dari Simulasi Ini?</h2>

<ul>
  <li>Pelajaran 1: <strong>Campak Bergerak Lebih Cepat dari yang Kita Bayangkan</strong>
    <ul>
      <li>Dari simulasi ABM, campak mencapai puncak wabah jauh lebih cepat
dari cacar air atau influenza. Dalam kondisi cakupan vaksin 80%,
puncak kasus aktif campak muncul dalam hitungan beberapa minggu
(lebih cepat) dibandingkan influenza yang butuh lebih lama karena
<strong>R0</strong>-nya lebih rendah.</li>
      <li>Ini berarti <em>window of opportunity</em> untuk intervensi dini sangat
sempit. Ketika otoritas kesehatan baru menyadari ada klaster wabah,
boleh jadi sudah ada puluhan atau ratusan kasus baru yang sedang
dalam masa inkubasi.</li>
    </ul>
  </li>
  <li>Pelajaran 2: <strong>5% Perbedaan Vaksinasi = Ratusan Nyawa</strong>
    <ul>
      <li>Dari simulasi skenario intervensi, perbedaan cakupan vaksin 80% vs
95% menghasilkan perbedaan korban yang sangat signifikan dalam
populasi kecil 500 orang. Bayangkan skala ini diperbesar ke kota
dengan 500 ribu atau 5 juta penduduk.</li>
      <li>Pada 95% vaksinasi (<em>herd immunity threshold</em> campak), wabah padam
sendiri dengan sangat cepat walaupun ada kasus awal. Ini karena
setiap penderita tidak berhasil menemukan cukup orang rentan untuk
ditulari. Inilah esensi dari <em>herd immunity</em>, yakni melindungi yang
tidak bisa divaksin (bayi, <em>immunocompromised</em>) melalui perlindungan
kolektif.</li>
    </ul>
  </li>
  <li>Pelajaran 3: <strong>Pola Spasial Penting</strong>
    <ul>
      <li>Dari <em>snapshot</em> spasial ABM, kita bisa melihat sesuatu yang tidak
tertangkap oleh model SIR biasa: wabah tidak menyebar merata. Ia
bermula dari klaster, yakni sekelompok agen rentan yang berdekatan
kemudian <strong>meledak</strong> dari sana.</li>
      <li>Di dunia nyata, klaster ini adalah sekolah, pesantren, pasar
tradisional, atau kampung dengan cakupan vaksin rendah. Inilah
mengapa surveilans berbasis geografis dan respon cepat di tingkat
klaster sangat krusial.</li>
    </ul>
  </li>
</ul>

<h2 id="keterbatasan-model-yang-perlu-diingat">Keterbatasan Model yang Perlu Diingat</h2>

<ol>
  <li>Populasi kecil dan homogen. Model ini menggunakan 500 agen di ruang
dua dimensi yang <strong>homogen</strong>. Populasi nyata ratusan ribu jiwa,
dengan struktur usia, jaringan sosial, dan kepadatan yang sangat
beragam.</li>
  <li>Tidak ada struktur umur. Campak paling mematikan pada bayi dan
balita. Model ini tidak membedakan agen berdasarkan umur, sehingga
tidak menangkap vulnerability yang berbeda per kelompok usia.</li>
  <li>Gerak acak vs gerak terstruktur. Manusia tidak bergerak acak. Kita
pergi ke tempat yang sama berulang kali (rumah, kantor, sekolah).
Model dengan <em>network structure</em> akan lebih realistis tapi jauh
lebih kompleks.</li>
  <li>Parameter dari literatur. Nilai <em>beta</em>, <em>gamma</em>, dan <strong>R0</strong> yang
digunakan adalah estimasi dari berbagai studi (<strong>bukan data spesifik
Indonesia 2026</strong>). Konteks lokal (kepadatan, nutrisi, akses
kesehatan) bisa mengubah parameter ini secara signifikan.</li>
  <li>Tidak ada re-introduksi. Model ini tidak memodelkan kasus impor dari
daerah lain. Di Indonesia dengan mobilitas antardaerah yang tinggi,
re-introduksi kasus bisa terus memicu wabah baru.</li>
</ol>

<h1 id="epilog"><em>Epilog</em></h1>

<p>Campak bukan penyakit masa lalu. Penyakit ini masih ada, masih
berbahaya, dan dengan <strong>R0</strong> antara 12-18, penyakit tersebut adalah
salah satu patogen paling agresif yang pernah kita hadapi. Hal yang
membuat frustrasi adalah: kita punya alat untuk mengalahkannya (vaksin
MMR yang sudah terbukti aman dan sudah sangat efektif selama lebih dari
enam dekade) namun cakupan vaksinasinya masih belum maksimal.</p>

<p>Simulasi di atas, walau sederhana tapi bisa menunjukkan dengan jelas
bahwa <strong>perbedaan antara wabah yang meledak dan wabah yang padam sendiri
hanyalah beberapa persen cakupan vaksin</strong>.</p>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Simulasi" /><category term="Wabah" /><category term="Epidemiologi" /><category term="Campak" /><category term="Data" /><category term="Agent Based Modelling" /><category term="ABM" /><category term="SIR" /><category term="Modelling" /><category term="Influenza" /><summary type="html"><![CDATA[Campak Kembali dan Ini Bukan Hal Sepele]]></summary></entry><entry><title type="html">Nowcasting: Menebak Angka Sales Bulan Ini Sebelum Bulan Berakhir</title><link href="https://ikanx101.com/blog/nowcast-1/" rel="alternate" type="text/html" title="Nowcasting: Menebak Angka Sales Bulan Ini Sebelum Bulan Berakhir" /><published>2026-04-07T17:23:00+00:00</published><updated>2026-04-07T17:23:00+00:00</updated><id>https://ikanx101.com/blog/nowcast-1</id><content type="html" xml:base="https://ikanx101.com/blog/nowcast-1/"><![CDATA[<p>Suatu waktu, pada tanggal 20 saya sedang lewat area kerja tim <em>sales</em>
dan melihat salah seorang <em>sales manager</em> sedang menatap serius
laptopnya. Padahal waktu itu jam kerja belumlah dimulai. Karena iseng,
saya coba tanyakan ia sedang apa. Beliau berkata masih ada 10 hari lagi
sampai akhir bulan:</p>

<blockquote>
  <p><em>“Kira-kira kita bakal <strong>hit</strong> target bulan ini nggak? Angka akhir
bulan kita bakal di mana?”</em></p>
</blockquote>

<p>Bagi sebagian orang, pertanyaan ini bisa dijawab dengan insting:
<em>“Kayaknya sih bisa”</em> atau <em>“Agak berat nih”</em>. Tapi apakah ada cara
saintifik untuk menjawabnya? Menggunakan data yang sudah tersedia,
kemudian melakukan estimasi angka <em>sales</em> di akhir bulan.</p>

<p><strong>Inilah yang disebut <em>Nowcasting</em>.</strong></p>

<h1 id="apa-itu-nowcasting-">Apa Itu <em>Nowcasting</em> ?</h1>

<p>Kata <em>nowcasting</em> adalah gabungan dari <em>“now”</em> (sekarang) dan
<em>“forecasting”</em> (meramalkan). Kalau <em>forecasting</em> memprediksi masa depan
yang jauh (bulan depan, tahun depan), <em>nowcasting</em> menjawab pertanyaan
yang <strong>lebih dekat</strong>. Sehingga definisi sederhananya adalah
<strong>mengestimasi nilai suatu indikator pada periode SEKARANG (yang belum
selesai), menggunakan data parsial yang sudah tersedia hari ini</strong>.</p>

<p>Teknik ini awalnya populer di dunia makroekonomi. Bank sentral
menggunakannya untuk mengestimasi GDP kuartal ini sebelum data resmi
dirilis yang biasanya butuh berbulan-bulan setelah kuartal berakhir.
Mereka tidak mau menunggu; mereka butuh estimasi sekarang untuk membuat
kebijakan.</p>

<p>Konsep ini yang sangat relevan di dunia <em>sales</em> dan <em>marketing</em>,
contohnya:</p>

<p>• Melakukan estimasi total <em>sales</em> bulan ini berdasarkan data 20 hari
pertama. • Melakukan estimasi <em>revenue</em> Q3 di pertengahan Juli. •
Membuat prediksi apakah <em>campaign</em> iklan akan <em>hit target</em> sebelum
<em>campaign</em> berakhir. • Melakukan estimasi stok yang dibutuhkan
berdasarkan tren order masuk hari ini.</p>

<h2 id="perbedaan-nowcasting-vs-forecasting">Perbedaan <em>Nowcasting</em> vs <em>Forecasting</em></h2>

<table>
  <thead>
    <tr>
      <th>Aspek</th>
      <th><em>Nowcasting</em></th>
      <th><em>Forecasting</em></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Pertanyaan</td>
      <td><em>“Bulan ini kita akan jual berapa?”</em></td>
      <td><em>“Bulan depan kita akan jual berapa?</em></td>
    </tr>
    <tr>
      <td><em>Time range</em></td>
      <td>Saat ini (periode berjalan)</td>
      <td>Masa depan (minggu/bulan/tahun depan)</td>
    </tr>
    <tr>
      <td>Data yang digunakan</td>
      <td>Data historikal + data parsial</td>
      <td>Data historikal lengkap</td>
    </tr>
    <tr>
      <td>Output</td>
      <td>Estimasi nilai akhirperiode berjalan</td>
      <td>Prediksi nilai masa depan</td>
    </tr>
    <tr>
      <td>Metode yang digunakan</td>
      <td>Regresi, dll</td>
      <td>ARIMA, <em>prophet, dll</em></td>
    </tr>
  </tbody>
</table>

<p>Sekarang saya akan coba buat satu <em>study case</em> tentang estimasi <em>sales</em>
produk minuman di Jabodetabek.</p>

<h1 id="studi-kasus-estimasi-sales-minuman-di-jabodetabek">Studi Kasus: Estimasi <em>Sales</em> Minuman di Jabodetabek</h1>

<p>Misalkan kita adalah <em>data analyst</em> di sebuah perusahaan FMCG yang
menjual minuman buah kemasan. Setiap bulan ada target penjualan (dalam
satuan kuantitas yakni karton). Data penjualan harian tersedia di sistem
IT kantor dan bersifat <em>update</em> <em>real time</em> harian. Hari ini tanggal 20
dan tim <em>managerial sales</em> bertanya: <em>berapa estimasi total sales sampai
akhir bulan?</em></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- Produk: Minuman buah kemasan 500ml 
- Area: Jabodetabek
- Target bulan ini: 50.000 karton 
- Data tersedia: Penjualan harian hari ke-1 sampai hari ke-20
- Yang ingin diestimasi: Total penjualan hari ke-1 sampai hari ke-31
</code></pre></div></div>

<p>Kita memiliki 547 baris data harian (mulai 1 Januari 2024 hingga 30 Juni
2025) dan ini adalah sampel data yang dimiliki:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">tanggal</th>
      <th style="text-align: right">penjualan</th>
      <th style="text-align: right">tahun</th>
      <th style="text-align: right">bulan</th>
      <th style="text-align: right">hari</th>
      <th style="text-align: left">hari_minggu</th>
      <th style="text-align: left">bulan_label</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">2024-01-01</td>
      <td style="text-align: right">1871</td>
      <td style="text-align: right">2024</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">1</td>
      <td style="text-align: left">Mon</td>
      <td style="text-align: left">Jan 2024</td>
    </tr>
    <tr>
      <td style="text-align: left">2024-01-02</td>
      <td style="text-align: right">2003</td>
      <td style="text-align: right">2024</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">2</td>
      <td style="text-align: left">Tue</td>
      <td style="text-align: left">Jan 2024</td>
    </tr>
    <tr>
      <td style="text-align: left">2024-01-03</td>
      <td style="text-align: right">1819</td>
      <td style="text-align: right">2024</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">3</td>
      <td style="text-align: left">Wed</td>
      <td style="text-align: left">Jan 2024</td>
    </tr>
    <tr>
      <td style="text-align: left">2024-01-04</td>
      <td style="text-align: right">1952</td>
      <td style="text-align: right">2024</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">4</td>
      <td style="text-align: left">Thu</td>
      <td style="text-align: left">Jan 2024</td>
    </tr>
    <tr>
      <td style="text-align: left">2024-01-05</td>
      <td style="text-align: right">1967</td>
      <td style="text-align: right">2024</td>
      <td style="text-align: right">1</td>
      <td style="text-align: right">5</td>
      <td style="text-align: left">Fri</td>
      <td style="text-align: left">Jan 2024</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-06-26</td>
      <td style="text-align: right">2249</td>
      <td style="text-align: right">2025</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">26</td>
      <td style="text-align: left">Thu</td>
      <td style="text-align: left">Jun 2025</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-06-27</td>
      <td style="text-align: right">2044</td>
      <td style="text-align: right">2025</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">27</td>
      <td style="text-align: left">Fri</td>
      <td style="text-align: left">Jun 2025</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-06-28</td>
      <td style="text-align: right">3197</td>
      <td style="text-align: right">2025</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">28</td>
      <td style="text-align: left">Sat</td>
      <td style="text-align: left">Jun 2025</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-06-29</td>
      <td style="text-align: right">3258</td>
      <td style="text-align: right">2025</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">29</td>
      <td style="text-align: left">Sun</td>
      <td style="text-align: left">Jun 2025</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-06-30</td>
      <td style="text-align: right">2259</td>
      <td style="text-align: right">2025</td>
      <td style="text-align: right">6</td>
      <td style="text-align: right">30</td>
      <td style="text-align: left">Mon</td>
      <td style="text-align: left">Jun 2025</td>
    </tr>
  </tbody>
</table>

<p>Sedangkan berikut ini adalah rekapan <em>sales</em> bulanan dari data <em>sales</em>
harian:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># A tibble: 18 × 3
   label    total_penjualan rata_harian
   &lt;chr&gt;              &lt;dbl&gt;       &lt;dbl&gt;
 1 Jan 2024           57289        1848
 2 Feb 2024           53868        1858
 3 Mar 2024           60884        1964
 4 Apr 2024           57799        1927
 5 May 2024           59654        1924
 6 Jun 2024           59870        1996
 7 Jul 2024           62292        2009
 8 Aug 2024           64379        2077
 9 Sep 2024           61284        2043
10 Oct 2024           63149        2037
11 Nov 2024           62300        2077
12 Dec 2024           66288        2138
13 Jan 2025           66598        2148
14 Feb 2025           58706        2097
15 Mar 2025           68292        2203
16 Apr 2025           65420        2181
17 May 2025           68090        2196
18 Jun 2025           68734        2291
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/nowcasting/draft_files/figure-commonmark/unnamed-chunk-4-1.png" alt="" /></p>

<p>Sedangkan berikut ini adalah data <em>sales</em> 20 hari pertama di bulan Juli
2025:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">tanggal</th>
      <th style="text-align: right">penjualan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">2025-07-01</td>
      <td style="text-align: right">2195</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-02</td>
      <td style="text-align: right">2430</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-03</td>
      <td style="text-align: right">2209</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-04</td>
      <td style="text-align: right">2182</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-05</td>
      <td style="text-align: right">3176</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-06</td>
      <td style="text-align: right">2721</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-07</td>
      <td style="text-align: right">1941</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-08</td>
      <td style="text-align: right">1947</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-09</td>
      <td style="text-align: right">1902</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-10</td>
      <td style="text-align: right">2201</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-11</td>
      <td style="text-align: right">1725</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-12</td>
      <td style="text-align: right">2662</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-13</td>
      <td style="text-align: right">2550</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-14</td>
      <td style="text-align: right">1628</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-15</td>
      <td style="text-align: right">2030</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-16</td>
      <td style="text-align: right">2214</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-17</td>
      <td style="text-align: right">1954</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-18</td>
      <td style="text-align: right">2083</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-19</td>
      <td style="text-align: right">2605</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-20</td>
      <td style="text-align: right">2600</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-21</td>
      <td style="text-align: right">1787</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-22</td>
      <td style="text-align: right">2131</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-23</td>
      <td style="text-align: right">2115</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-24</td>
      <td style="text-align: right">1843</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-25</td>
      <td style="text-align: right">2501</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-26</td>
      <td style="text-align: right">3063</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-27</td>
      <td style="text-align: right">3006</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-28</td>
      <td style="text-align: right">2318</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-29</td>
      <td style="text-align: right">2131</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-30</td>
      <td style="text-align: right">2279</td>
    </tr>
    <tr>
      <td style="text-align: left">2025-07-31</td>
      <td style="text-align: right">2284</td>
    </tr>
  </tbody>
</table>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Penjualan Juli (hari 1-20): 44955 karton

Sisa hari yang belum ada datanya: 11 hari

Persentase bulan yang sudah terlewati: 64.5 %
</code></pre></div></div>

<p><strong>Catatan</strong>: Saya sebenarnya sudah membuat data lengkap 1 - 31 Juli 2025
yang kemudian nanti akan digunakan sebagai <em>benchmark</em> seberapa bagus
model <em>nowcasting</em> yang dibuat.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Aktual penjualan Juli 2025 (full bulan): 70413 karton
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/nowcasting/draft_files/figure-commonmark/unnamed-chunk-6-1.png" alt="" /></p>

<h2 id="pendekatan-nowcasting-yang-akan-dicoba">Pendekatan <em>Nowcasting</em> yang Akan Dicoba</h2>

<p>Kita akan membangun tiga model <em>nowcasting</em> dari yang paling sederhana
sampai yang lebih canggih, lalu membandingkan hasilnya:</p>

<ol>
  <li><strong>Model 1</strong> — <strong><em>Simple Scaling</em></strong>: Extrapolasi linier dari data
parsial.</li>
  <li><strong>Model 2</strong> — <strong><em>Regression-based</em></strong>: Pakai pola historis untuk
koreksi.</li>
  <li><strong>Model 3</strong> — <strong><em>MIDAS-lite</em></strong>: Manfaatkan <em>leading indicator</em>
harian.</li>
</ol>

<h3 id="model-1--simple-scaling-paling-sederhana">Model 1 — <em>Simple Scaling</em> (Paling Sederhana)</h3>

<p>Model paling sederhana. Konsepnya sama seperti melakukan ekstrapolasi
harian: asumsikan sisa hari akan berjalan seperti rata-rata hari yang
sudah ada. Kalau 20 hari pertama rata-ratanya X karton/hari, maka 11
hari sisanya juga X karton/hari.</p>

<p><strong>Estimasi Total = Penjualan Parsial + (Rata-rata Harian Parsial × Sisa
Hari)</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== MODEL 1: SIMPLE SCALING ===

Rata-rata harian (H1-H20)  : 2248 karton/hari

Estimasi total Juli 2025   : 69680 karton

Aktual total Juli 2025     : 70413 karton

Error                      : -1.04 %
</code></pre></div></div>

<p>Model ini cepat, mudah, dan sangat sederhana tapi ada kelemahan. Model
ini tidak mempertimbangkan bahwa hari-hari tertentu (misalnya akhir
bulan atau akhir pekan) ada pola berbeda dari rata-rata.</p>

<h3 id="model-2--regression-based-nowcasting">Model 2 — <em>Regression-Based Nowcasting</em></h3>

<p>Model ini lebih “cerdas” dibanding sebelumnya. Idenya adalah kita punya
data historis 18 bulan. Dari setiap bulan itu, kita tahu berapa
penjualan di hari ke-1 sampai ke-20 (parsial), dan berapa total
penjualan akhir bulan (penuh). Kemudia kita akan membuat model regresi:</p>

<p><strong>total_penuh ~ parsial_20_hari</strong></p>

<p>Lalu gunakan model itu untuk memprediksi Juli 2025 dari data parsialnya.</p>

<p>Kalau kita tahu bulan-bulan sebelumnya bahwa ‘penjualan 20 hari pertama
biasanya 64% dari total bulan’, maka kita bisa balik hitung:</p>

<p><strong>total estimasi = parsial / 0.64</strong></p>

<p>Regresi adalah cara ilmiah untuk menemukan angka 0.64 itu — plus
memperhitungkan faktor lain seperti momen gajian.</p>

<p>Oke, pertama-tama saya akan hitung berapa rasio parsial dari semua data
yang ada:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Rata-rata rasio parsial/total: 0.6462 

Range rasio: 0.6214 - 0.7171 
</code></pre></div></div>

<p>Berikut adalah visualisasi dari rasio 20 hari vs total hari dari semua
data bulanan:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/nowcasting/draft_files/figure-commonmark/unnamed-chunk-9-1.png" alt="" /></p>

<p>Perlu saya ingatkan kembali bahwa kita punya data dua tahun pada bulan
Januari - Juni, maka dari itu bentuk grafik pada bulan-bulan tersebut
berbeda dengan bulan lainnya.</p>

<p>Oke, sekarang saatnya kita membuat model regresinya. Akan ada dua model
regresi sebagai berikut:</p>

<ol>
  <li>Model sederhana berisi <strong>total_penuh ~ parsial_20</strong>.</li>
  <li>Model lengkap berisi <strong>total_penuh ~ parsial_20 + factor(bulan) +
hariraya</strong>.
    <ul>
      <li>Kita tambahkan variabel bulan biasa dan bulan hari raya (lebaran
dan natal).</li>
    </ul>
  </li>
</ol>

<!-- -->

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>R-squared model simple  : 0.7706 

R-squared model lengkap : 0.9775 


Call:
lm(formula = total_penuh ~ parsial_20 + factor(bulan) + hariraya, 
    data = df_historis_regresi)

Residuals:
    Min      1Q  Median      3Q     Max 
-1323.5  -114.5     0.0   114.5  1277.9 

Coefficients: (1 not defined because of singularities)
                  Estimate Std. Error t value Pr(&gt;|t|)    
(Intercept)      6.861e+03  4.691e+02  14.628  &lt; 2e-16 ***
parsial_20       1.395e+00  1.171e-02 119.129  &lt; 2e-16 ***
factor(bulan)2  -5.567e+03  1.140e+02 -48.843  &lt; 2e-16 ***
factor(bulan)3   1.020e+03  1.124e+02   9.074  &lt; 2e-16 ***
factor(bulan)4  -1.494e+03  1.129e+02 -13.235  &lt; 2e-16 ***
factor(bulan)5   4.182e+02  1.123e+02   3.725 0.000216 ***
factor(bulan)6  -3.252e+02  1.147e+02  -2.835 0.004752 ** 
factor(bulan)7   5.243e+02  1.366e+02   3.838 0.000139 ***
factor(bulan)8  -3.089e+02  1.385e+02  -2.230 0.026182 *  
factor(bulan)9  -1.893e+02  1.382e+02  -1.370 0.171267    
factor(bulan)10  1.758e+02  1.369e+02   1.284 0.199559    
factor(bulan)11 -2.061e+03  1.396e+02 -14.766  &lt; 2e-16 ***
factor(bulan)12  1.106e+03  1.393e+02   7.941 1.19e-14 ***
hariraya                NA         NA      NA       NA    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 621.1 on 534 degrees of freedom
Multiple R-squared:  0.9775,    Adjusted R-squared:  0.977 
F-statistic:  1937 on 12 and 534 DF,  p-value: &lt; 2.2e-16
</code></pre></div></div>

<p>Dari nilai <img src="https://latex.codecogs.com/svg.latex?R%5E2" alt="R^2" title="R^2" />,
kita dapatkan kedua model baik dan sangat baik. Berdasarkan itu, saya
akan buat prediksi <em>nowcasting</em> dari model lengkap.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== MODEL 2: REGRESSION-BASED ===

Estimasi total Juli 2025   : 70108 karton

Interval bawah (95%)       : 68862 karton

Interval atas (95%)        : 71354 karton

Aktual total Juli 2025     : 70413 karton

Error                      : -0.43 %
</code></pre></div></div>

<h3 id="model-3--midas-lite-menggunakan-leading-indicator">Model 3 — <em>MIDAS-lite</em>: Menggunakan <em>Leading Indicator</em></h3>

<p>Model ketiga ini sedikit lebih canggih. Kita manfaatkan <em>leading
indicator</em>, yakni sinyal-sinyal yang muncul lebih awal dan berkorelasi
dengan penjualan untuk meningkatkan akurasi estimasi.</p>

<p><em>MIDAS</em> (<em>Mixed Data Sampling</em>) adalah teknik formal untuk menggabungkan
data dengan frekuensi berbeda (misalnya: data harian dan data bulanan).
Di sini kita buat versi sederhananya. <em>Leading indicator</em> yang kita
gunakan dalam simulasi ini:</p>

<ol>
  <li><em>Search index</em>: <em>Proxy</em> dari Google Trends untuk kata kunci terkait
produk kita.</li>
  <li>Cuaca: Suhu rata-rata harian (minuman lebih laku saat panas).</li>
  <li>Momentum awal bulan: Apakah 5 hari pertama lebih tinggi dari
rata-rata historis?</li>
</ol>

<p>Indikator pertama dan kedua akan saya simulasikan datanya, sedangkan
indikator ketiga akan dihitung dari data yang ada.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Korelasi indikator vs total penjualan:

  total_penuh    parsial_20     suhu_rata  search_index momentum_awal 
        1.000         0.878        -0.194        -0.040         0.750 
</code></pre></div></div>

<p>Sekarang kita buat model MIDAS-nya menjadi: <strong>total_penuh ~ parsial_20 +
suhu_rata + search_index + momentum_awal + factor(bulan) + hariraya</strong>.</p>

<p>Berikut ini hasilnya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>R-squared model MIDAS-lite: 0.9958 


=== MODEL 3: MIDAS-LITE ===

Estimasi total Juli 2025   : 67099 karton

Interval bawah (95%)       : 66506 karton

Interval atas (95%)        : 67692 karton

Aktual total Juli 2025     : 70413 karton

Error                      : -4.71 %
</code></pre></div></div>

<p><img src="https://latex.codecogs.com/svg.latex?R%5E2" alt="R^2" title="R^2" /> yang dihasilkan
sangat bagus.</p>

<h2 id="perbandingan-tiga-model-nowcasting">Perbandingan Tiga Model <em>Nowcasting</em></h2>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Model</th>
      <th style="text-align: right">Estimasi</th>
      <th style="text-align: right">CI_Bawah</th>
      <th style="text-align: right">CI_Atas</th>
      <th style="text-align: left">Error_pct</th>
      <th style="text-align: left">Hit_target</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Model 1: Simple Scaling</td>
      <td style="text-align: right">69680</td>
      <td style="text-align: right">NA</td>
      <td style="text-align: right">NA</td>
      <td style="text-align: left">-1.04</td>
      <td style="text-align: left">YA ✓</td>
    </tr>
    <tr>
      <td style="text-align: left">Model 2: Regression</td>
      <td style="text-align: right">70108</td>
      <td style="text-align: right">68862</td>
      <td style="text-align: right">71354</td>
      <td style="text-align: left">-0.43</td>
      <td style="text-align: left">YA ✓</td>
    </tr>
    <tr>
      <td style="text-align: left">Model 3: MIDAS-lite</td>
      <td style="text-align: right">67099</td>
      <td style="text-align: right">66506</td>
      <td style="text-align: right">67692</td>
      <td style="text-align: left">-4.71</td>
      <td style="text-align: left">YA ✓</td>
    </tr>
    <tr>
      <td style="text-align: left">Aktual (Ground Truth)</td>
      <td style="text-align: right">70413</td>
      <td style="text-align: right">NA</td>
      <td style="text-align: right">NA</td>
      <td style="text-align: left"> </td>
      <td style="text-align: left"> </td>
    </tr>
  </tbody>
</table>

<p>Dari ketiga model yang sudah dibuat, kita bisa dapatkan:</p>

<ol>
  <li>Ketiga model memberikan estimasi yang berada di bawah nilai aktual
(<em>under estimate</em>).
    <ul>
      <li><strong>Menurut keyakinan saya</strong>, <em>under</em> estimasi justru memberikan
rasa aman pada tim <em>sales</em> pada laporannya dibandingkan nilai yang
<em>over estimate</em>.</li>
    </ul>
  </li>
  <li>Ternyata <strong>model kedua (regresi)</strong> memberikan estimasi dengan
persentase <em>error</em> terkecil.</li>
</ol>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/nowcasting/draft_files/figure-commonmark/unnamed-chunk-15-1.png" alt="" /></p>

<h1 id="model-keempat-nowcasting-rolling">Model Keempat: <em>Nowcasting Rolling</em></h1>

<p>Ada model <em>nowcasting</em> keempat yang bisa kita buat, yakni model yang
bisa melakukan <em>update</em> estimasi setiap hari sejak awal bulan. Hasilnya
adalah kurva yang semakin lama semakin akurat seiring lebih banyak data
tersedia.</p>

<p>Ada dua model yang akan kita coba, yakni:</p>

<ol>
  <li><em>Simple scaling</em>, sama seperti model pertama tapi di-<em>update</em> rasio
parsial secara harian.</li>
  <li><em>Regresi</em>, sama seperti model kedua tapi di-<em>update</em> rasio parsial
secara harian.</li>
</ol>

<p>Berikut ini hasilnya:</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/nowcasting/draft_files/figure-commonmark/unnamed-chunk-17-1.png" alt="" /></p>

<p>Model regresi memberikan <em>nowcasting</em> total penjualan akhir bulan yang
selalu <em>under estimate</em> dibandingkan dengan model <em>simple scaling</em> yang
pada awal-awal <em>nowcasting</em> selalu <em>over estimate</em>. <strong>Namun</strong> kedua
model tersebut memberikan konvergensi yang ke satu nilai yang
mirip-mirip dan mendekati nilai aktual bulanannya.</p>

<h1 id="langkah-strategic-dari-hasil-nowcasting">Langkah <em>Strategic</em> dari Hasil <em>Nowcasting</em></h1>

<p>Bagi tim <em>managerial sales</em>, angka estimasi hasil <em>nowcasting</em> bisa
dijadikan langkah <em>strategic</em> bagi mereka untuk memastikan <em>sales</em>
berjalan sesuai dengan target yang sudah ditetapkan. Bagaimana caranya?
Perhatikan tabel berikut ini:</p>

<table>
  <thead>
    <tr>
      <th>Kondisi estimasi</th>
      <th>SInyal</th>
      <th>Hal yang perlu dilakukan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Estimasi &gt;&gt; target</td>
      <td>Over-track</td>
      <td>Pastikan stok cukup, jangan sampai <em>out-of-stock</em> di akhir bulan. Siapkan <em>reorder</em>.</td>
    </tr>
    <tr>
      <td>Estimasi sedikit di atas target</td>
      <td>On-track</td>
      <td><em>Maintain</em> momentum. Monitor harian, tidak perlu intervensi besar.</td>
    </tr>
    <tr>
      <td>Estimasi sedikit di bawah target</td>
      <td>At risk</td>
      <td>Aktivasi <em>trade promo</em> di channel yang <em>under-perform</em>. <em>Push</em> ke distributor.</td>
    </tr>
    <tr>
      <td>Estimasi &lt;&lt; target</td>
      <td>Off track</td>
      <td>Eskalasi ke manajemen. Pertimbangkan <em>flash sale</em>, subsidi harga sementara, atau revisi target.</td>
    </tr>
  </tbody>
</table>

<p>Pertanyaan berikutnya adalah:</p>

<blockquote>
  <p><strong>Kapan kita harus mempercayai hasil estimasi dari <em>nowcasting</em>?</strong></p>
</blockquote>

<p>Dari grafik <em>rolling nowcasting</em>, kita bisa lihat bahwa estimasi
biasanya cukup stabil setelah hari ke-10 (sekitar 30% bulan terlewati).
Sebelum itu, masih terlalu banyak <em>noise</em>. Idealnya, mulai jadikan
<em>nowcasting</em> sebagai acuan keputusan mulai hari ke-10, dan jadikan dasar
eskalasi mulai hari ke-15.</p>

<h2 id="limitasi">Limitasi</h2>

<p>Tentu sebagaimana yang sering saya katakan, setiap model perhitungan
(termasuk prediksi dan <em>nowcasting</em>) pasti memiliki limitasi yang perlu
kita perhatikan saat menyimpulkan hasil dan mengambil keputusan. Berikut
ini adalah beberapa limitasi dari <em>nowcasting</em>:</p>

<ol>
  <li><em>Nowcasting</em> bukan sulap.
    <ul>
      <li>Jika ada kejadian tak terduga di sisa bulan, seperti: bencana
alam, kompetitor tiba-tiba diskon besar, atau produk kita viral di
<strong>TikTok</strong> maka model tidak akan bisa memprediksinya dari data
parsial.</li>
    </ul>
  </li>
  <li>Kualitas model bergantung data historis.
    <ul>
      <li>Model regresi kita butuh setidaknya 12 bulan historis agar pola
musiman tertangkap dengan baik.</li>
      <li>Untuk produk baru yang belum punya riwayat panjang, Model
menggunakan <em>Simple Scaling</em> mungkin lebih aman.</li>
    </ul>
  </li>
  <li>Perhatikan perubahan pola. Kalau ada perubahan besar dalam bisnis
(ekspansi ke kota baru, ganti distributor, <em>launching</em> SKU baru),
pola historis mungkin tidak lagi relevan. Model perlu di-<em>update</em>.</li>
  <li>Bukan pengganti <em>judgment</em>.
    <ul>
      <li><em>Nowcasting</em> adalah alat bantu, bukan pengganti pengetahuan
lapangan.</li>
      <li><em>Sales manager</em> yang tahu ada <em>event</em> besar di akhir bulan tetap
harus memasukkan informasi itu secara manual ke dalam estimasi.</li>
    </ul>
  </li>
</ol>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Market Riset" /><category term="Sales" /><category term="Artificial Intelligence" /><category term="Machine Learning" /><category term="Nowcasting" /><category term="Target" /><category term="Data" /><category term="Data historis" /><category term="MIDAS" /><category term="Regresi" /><summary type="html"><![CDATA[Suatu waktu, pada tanggal 20 saya sedang lewat area kerja tim sales dan melihat salah seorang sales manager sedang menatap serius laptopnya. Padahal waktu itu jam kerja belumlah dimulai. Karena iseng, saya coba tanyakan ia sedang apa. Beliau berkata masih ada 10 hari lagi sampai akhir bulan:]]></summary></entry><entry><title type="html">Mencari Strategi Terbaik untuk Mengambil Keputusan dengan The Secretary Problem</title><link href="https://ikanx101.com/blog/aturan-37/" rel="alternate" type="text/html" title="Mencari Strategi Terbaik untuk Mengambil Keputusan dengan The Secretary Problem" /><published>2026-04-02T12:33:00+00:00</published><updated>2026-04-02T12:33:00+00:00</updated><id>https://ikanx101.com/blog/aturan-37</id><content type="html" xml:base="https://ikanx101.com/blog/aturan-37/"><![CDATA[<p>Pada lebaran kemarin, saya pergi ke <em>mall</em> di sore harinya untuk mencari
tempat makan untuk saya dan keluarga. Saat masuk ke <em>basement</em> parkiran,
saya melihat satu <em>slot</em> kosong di dekat pintu masuk. Saya berpikir:</p>

<blockquote>
  <p><em>“Mungkin masih ada yang lebih dekat ke pintu masuk.”</em></p>
</blockquote>

<p>Saya terus melaju dan ternyata tidak ada <em>slot</em> kosong. Akhirnya saya
kembali ke <em>slot</em> yang pertama kali saya lihat dan <em>alhamdulillah</em> masih
ada.</p>

<p>Di bulan lalu, perusahaan saya membuka <em>vacancy</em> untuk posisi
<em>management trainee</em>. Kebetulan saya dan beberapa rekan mendapatkan
kesempatan untuk mewawancarai beberapa kandidat yang diproyeksikan bisa
di-<em>assign</em> ke tim market riset. Kandidat pertama bagus, kandidat kedua
juga oke, kandidat berikutnya juga bagus, berikutnya juga bagus
<em>banget</em>. Saya dan rekan-rekan belum yakin apakah harus langsung pilih
yang sudah ada atau terus mencari.</p>

<blockquote>
  <p><strong>Bisa jadi terlalu cepat memilih mengakibatkan kami menyesal karena
mungkin ada kandidat setelahnya yang lebih baik. TAPI terlalu lama
mencari bisa mengakibatkan kami membuang waktu dan bisa kehilangan
kandidat bagus yang sudah lewat.</strong></p>
</blockquote>

<p>Kedua contoh dilema ini sebenarnya adalah satu problem matematika yang
sudah punya jawaban optimal. Dan jawabannya mengandung angka yang
mengejutkan:</p>

<blockquote>
  <p><strong>37% atau lebih tepatnya 1/e ≈ 0.3679.</strong></p>
</blockquote>

<p>Ini adalah proporsi optimal untuk fase ‘hanya observasi’ sebelum Anda
mulai membuat keputusan. Aturan ini berlaku di banyak situasi kehidupan
nyata yang punya struktur serupa. Bagaimana penjelasannya? Simak paparan
berikut ini ya.</p>

<h1 id="apa-itu-aturan-37">Apa itu Aturan 37%</h1>

<h2 id="asal-usul-the-secretary-problem">Asal usul <em>the Secretary Problem</em></h2>

<p><strong>Aturan 37%</strong> berasal dari sebuah problem klasik matematika yang
dikenal dengan beberapa nama: <em>Secretary Problem</em>, <em>Marriage Problem</em>,
atau <em>Optimal Stopping Problem</em>. Problem ini pertama kali dipublikasikan
secara luas pada tahun 1960 oleh Martin Gardner di kolom <em>Mathematical
Games</em>-nya di <em>Scientific American</em>.</p>

<p>Ini adalah formulasi awalnya: <strong>kita ingin merekrut satu sekretaris
terbaik dari <em>N</em> kandidat. Kandidat datang satu per satu dalam urutan
acak. Setelah mewawancarai setiap kandidat, Anda harus langsung
memutuskan: terima atau tolak. Kandidat yang ditolak tidak bisa
dipanggil kembali.</strong></p>

<blockquote>
  <p><strong>Bagaimana strategi optimal untuk memaksimalkan probabilitas mendapat
kandidat terbaik?</strong></p>
</blockquote>

<p>Ternyata, jawaban matematisnya adalah strategi dua fase yang sangat
elegan:</p>

<ol>
  <li>Fase Eksplorasi: Amati (dan tolak) <strong>37%</strong> kandidat pertama. Catat
siapa yang terbaik sejauh ini. <em>List</em> kandidat ini jadi patokan
kita.</li>
  <li>Fase Eksploitasi: Mulai dari kandidat ke-<strong>38%</strong>, terima kandidat
PERTAMA yang lebih baik dari patokan tadi.</li>
</ol>

<p>Dengan strategi ini, probabilitas Anda mendapat kandidat terbaik secara
keseluruhan adalah tepat <strong>1/e ≈ 37%</strong>. Menariknya, ini adalah
probabilitas tertinggi yang bisa dicapai — tidak ada strategi lain yang
bisa mengalahkannya.</p>

<h2 id="mengapa-1e-">Mengapa <strong>1/e</strong> ?</h2>

<p>Angka <strong>1/e</strong> muncul dari kalkulus optimasi. Ketika <em>N</em> cukup besar,
batas optimal <em>r/N</em> (di mana <em>r</em> adalah jumlah kandidat yang diobservasi
dulu) konvergen ke <strong>1/e</strong>.</p>

<h2 id="asumsi-yang-perlu-dipahami">Asumsi yang Perlu Dipahami</h2>

<p>Sebelum lanjut ke simulasi di <strong>R</strong>, penting untuk memahami asumsi di
balik aturan ini agar kita tidak salah aplikasikan:</p>

<table>
  <thead>
    <tr>
      <th>Asumsi</th>
      <th>Artinya</th>
      <th>Contoh <em>Real</em></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Urutan acak</td>
      <td>Kandidat datang dalam urutan yang tidak bisa diprediksi</td>
      <td><em>CV</em> yang masuk tidak diurutkan dari yang terbaik duluan</td>
    </tr>
    <tr>
      <td>Keputusan seketika</td>
      <td>Setelah menolak, tidak bisa memanggil kembali</td>
      <td>Kandidat yang ditolak langsung ambil tawaran lain</td>
    </tr>
    <tr>
      <td>N diketahui</td>
      <td>Jumlah total kandidat sudah diketahui sebelumnya</td>
      <td>Anda tahu ada tepat 20 pelamar</td>
    </tr>
    <tr>
      <td>Bisa membandingkan</td>
      <td>Anda bisa meranking kandidat secara relatif</td>
      <td>Anda bisa bilang ‘kandidat ini lebih baik dari kandidat yang sebelumnya’</td>
    </tr>
    <tr>
      <td>Satu pilihan</td>
      <td>Hanya memilih satu dari <em>N</em></td>
      <td>Satu posisi yang tersedia, satu apartemen yang disewa</td>
    </tr>
  </tbody>
</table>

<p>Di dunia nyata, asumsi-asumsi ini jarang terpenuhi sempurna. Tapi
<strong>aturan 37%</strong> tetap berguna sebagai panduan <em>heuristik</em> mengambil
keputusan yang masuk akal meski tidak optimal secara persis.</p>

<h1 id="pembuktian-dengan-simulasi-di-r">Pembuktian dengan Simulasi di <strong>R</strong></h1>

<p>Agar lebih jelas lagi, maka saya akan buatkan satu simulasi untuk
memperlihatkan bahwa <strong>aturan 37%</strong> adalah strategi pengambilan
keputusan terbaik.</p>

<p>Saya akan menggunakan beberapa <em>study cases</em> sebagai bahan simulasi.</p>

<h2 id="kasus-i-simulasi-wawancara-kandidat">KASUS I: Simulasi Wawancara Kandidat</h2>

<p>Bayangkan kita harus memilih 1 orang terbaik dari 100 pelamar. Pelamar
datang satu per satu. Kita simulasikan 10.000 kali (prinsip Monte Carlo)
dengan berbagai nilai <em>r</em> (berapa yang diobservasi dulu) dan lihat
berapa probabilitas mendapat kandidat terbaik.</p>

<p>Pertama-tama, saya akan membuat beberapa <em>function</em> berikut ini:</p>

<p>Sekarang saya akan mulai simulasinya dengan <em>flow</em> sebagai berikut:</p>

<ol>
  <li>Saya akan buat 100 orang kandidat.</li>
  <li>Saya akan definisikan <em>r</em> tertentu, mulai dari 1 hingga 99.
    <ol>
      <li>Misalkan <em>r = 10</em>, artinya saya akan mewawancarai 10 orang
kandidat pertama. Lalu kandidat terbaik dari 10 orang tersebut
akan saya jadikan <em>basis</em>.</li>
      <li>Kemudian saya akan mewawancarai kandidat ke <strong>11</strong>, jika
kandidat tersebut lebih baik dari <em>basis</em>, maka saya akan <em>hire</em>
kandidat tersebut.</li>
      <li>Jika kandidat ke <strong>11</strong> tidak lebih baik dari <em>basis</em>, saya akan
wawancarai kandidat selanjutnya. Kandidat dengan kualitas lebih
baik dari <em>basis</em> akan langsung saya <em>hire</em>.</li>
    </ol>
  </li>
</ol>

<p>Proses ini akan diulang-ulang dengan berbagai nilai <em>r</em> sebanyak 10 ribu
kali.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Simulasi untuk berbagai nilai r ──────────────────────────────</span><span class="w">
</span><span class="n">N</span><span class="w">         </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">100</span><span class="w">     </span><span class="c1"># Jumlah kandidat</span><span class="w">
</span><span class="n">n_sim</span><span class="w">     </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">10000</span><span class="w">   </span><span class="c1"># Jumlah simulasi per nilai r</span><span class="w">
</span><span class="n">r_values</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="p">(</span><span class="n">N</span><span class="m">-1</span><span class="p">)</span><span class="w"> </span><span class="c1"># Coba semua kemungkinan r</span><span class="w">

</span><span class="c1"># Untuk setiap nilai r, hitung probabilitas dapat kandidat terbaik</span><span class="w">
</span><span class="n">hasil_sim</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">r_values</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">r</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="n">sukses</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">replicate</span><span class="p">(</span><span class="n">n_sim</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="c1"># Buat urutan acak: nilai kandidat dari distribusi uniform</span><span class="w">
    </span><span class="n">kandidat</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">runif</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w">
    </span><span class="c1"># Jalankan strategi</span><span class="w">
    </span><span class="n">pilihan</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">kandidat</span><span class="p">,</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w">
    </span><span class="c1"># Apakah yang dipilih adalah yang terbaik?</span><span class="w">
    </span><span class="n">dapat_terbaik</span><span class="p">(</span><span class="n">kandidat</span><span class="p">,</span><span class="w"> </span><span class="n">pilihan</span><span class="p">)</span><span class="w">
  </span><span class="p">})</span><span class="w">
  </span><span class="n">mean</span><span class="p">(</span><span class="n">sukses</span><span class="p">)</span><span class="w">  </span><span class="c1"># Proporsi sukses = probabilitas estimasi</span><span class="w">
</span><span class="p">})</span><span class="w">

</span><span class="n">df_hasil</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
  </span><span class="n">r</span><span class="w">           </span><span class="o">=</span><span class="w"> </span><span class="n">r_values</span><span class="p">,</span><span class="w">
  </span><span class="n">pct_r</span><span class="w">       </span><span class="o">=</span><span class="w"> </span><span class="n">r_values</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">N</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="m">100</span><span class="p">,</span><span class="w">
  </span><span class="n">prob_sukses</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">hasil_sim</span><span class="w">
</span><span class="p">)</span><span class="w">

</span><span class="c1"># Temukan r optimal dari simulasi</span><span class="w">
</span><span class="n">r_optimal_sim</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">df_hasil</span><span class="o">$</span><span class="n">r</span><span class="p">[</span><span class="n">which.max</span><span class="p">(</span><span class="n">df_hasil</span><span class="o">$</span><span class="n">prob_sukses</span><span class="p">)]</span><span class="w">
</span><span class="n">prob_optimal</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">df_hasil</span><span class="o">$</span><span class="n">prob_sukses</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>Berikut hasilnya:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r optimal (simulasi)  : 37 dari 100 kandidat

Persentase            : 37 %

Probabilitas sukses   : 0.3741 

Nilai teoritis 1/e    : 0.3679 
</code></pre></div></div>

<p>Hasil simulasi memberikan informasi bahwa pada <em>r =</em> 37, kita
mendapatkan peluang tertinggi (sebesar 37%) bahwa kandidat selanjutnya
adalah kandidat terbaik <em>compared to</em> kandidat terbaik dari 37 yang
dijadikan basis.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/secretary_problem/draft_files/figure-commonmark/unnamed-chunk-5-1.png" alt="" /></p>

<h2 id="kasus-ii-simulasi-pencarian-apartemen">KASUS II: Simulasi Pencarian Apartemen</h2>

<p>Misalkan Anda pindah kerja ke Dubai dan harus menyewa apartemen. Ada 20
unit yang sudah masuk <em>shortlist</em> dan bisa dilihat satu per satu. Begitu
Anda menolak satu unit, Anda tidak bisa kembali (unit tersebut sudah
diambil orang lain). Kapan Anda harus mulai memutuskan? Berdasarkan
<strong>aturan 37%</strong>, maka:</p>

<blockquote>
  <p>Banyaknya apartemen yang harus dilihat dulu tanpa dipilih sama sekali
adalah: (20 × 0.37) ~ 8 unit. Maka setelah melihat 8 unit pertama,
catat unit apartemen terbaik sejauh ini. Mulai dari unit ke-9, pilih
unit PERTAMA yang lebih baik dari 8 unit tadi.</p>
</blockquote>

<p>Saya juga akan bandingkan saat:</p>

<ol>
  <li>Anda terburu-buru mengambil keputusan dengan <em>r = 2</em>. Lihat 2 unit
apartemen, lalu langsung memilih.</li>
  <li>Anda terlalu lama mengambil keputusan dengan <em>r = 15</em>. Lihat 15 unit
apartemen, lalu langsung memilih.</li>
</ol>

<p>Oke, sekarang saya buat skrip simulasinya:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Kasus 2: Mencari Apartemen ────────────────────────────────────</span><span class="w">
</span><span class="c1"># Simulasi: 20 apartemen, nilai kualitas dari 1-100</span><span class="w">

</span><span class="n">simulasi_apartemen</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">n_apartemen</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">20</span><span class="p">,</span><span class="w"> </span><span class="n">n_sim</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">50000</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="n">r_optimal</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">ceiling</span><span class="p">(</span><span class="n">n_apartemen</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nf">exp</span><span class="p">(</span><span class="m">1</span><span class="p">))</span><span class="w">

  </span><span class="c1"># Bandingkan tiga strategi:</span><span class="w">
  </span><span class="c1"># 1. Aturan 37% (r = ceiling(N/e))</span><span class="w">
  </span><span class="c1"># 2. Terlalu cepat (r = 2, hanya lihat 2 dulu)</span><span class="w">
  </span><span class="c1"># 3. Terlalu lama  (r = 15, lihat 15 dulu baru pilih)</span><span class="w">

  </span><span class="n">hasil</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">replicate</span><span class="p">(</span><span class="n">n_sim</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">apt</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">n_apartemen</span><span class="p">,</span><span class="w"> </span><span class="n">n_apartemen</span><span class="p">)</span><span class="w">  </span><span class="c1"># Urutan acak</span><span class="w">

    </span><span class="n">pilih_37</span><span class="w">  </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">apt</span><span class="p">,</span><span class="w"> </span><span class="n">r_optimal</span><span class="p">)</span><span class="w">
    </span><span class="n">pilih_awal</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">apt</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
    </span><span class="n">pilih_lama</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">apt</span><span class="p">,</span><span class="w"> </span><span class="m">15</span><span class="p">)</span><span class="w">

    </span><span class="nf">c</span><span class="p">(</span><span class="w">
      </span><span class="n">terbaik_37</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="n">apt</span><span class="p">[</span><span class="n">pilih_37</span><span class="p">]</span><span class="w">  </span><span class="o">==</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">apt</span><span class="p">),</span><span class="w">
      </span><span class="n">terbaik_awal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">apt</span><span class="p">[</span><span class="n">pilih_awal</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">apt</span><span class="p">),</span><span class="w">
      </span><span class="n">terbaik_lama</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">apt</span><span class="p">[</span><span class="n">pilih_lama</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">apt</span><span class="p">),</span><span class="w">
      </span><span class="n">rank_37</span><span class="w">      </span><span class="o">=</span><span class="w"> </span><span class="n">rank</span><span class="p">(</span><span class="o">-</span><span class="n">apt</span><span class="p">)[</span><span class="n">pilih_37</span><span class="p">],</span><span class="w">   </span><span class="c1"># Rank 1 = terbaik</span><span class="w">
      </span><span class="n">rank_awal</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="n">rank</span><span class="p">(</span><span class="o">-</span><span class="n">apt</span><span class="p">)[</span><span class="n">pilih_awal</span><span class="p">],</span><span class="w">
      </span><span class="n">rank_lama</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="n">rank</span><span class="p">(</span><span class="o">-</span><span class="n">apt</span><span class="p">)[</span><span class="n">pilih_lama</span><span class="p">]</span><span class="w">
    </span><span class="p">)</span><span class="w">
  </span><span class="p">})</span><span class="w">

  </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">strategi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'Aturan 37% (r=7)'</span><span class="p">,</span><span class="w">
                 </span><span class="s1">'Terlalu Cepat (r=2)'</span><span class="p">,</span><span class="w">
                 </span><span class="s1">'Terlalu Lama (r=15)'</span><span class="p">),</span><span class="w">
    </span><span class="n">prob_terbaik</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'terbaik_37'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'terbaik_awal'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'terbaik_lama'</span><span class="p">,])),</span><span class="w">
    </span><span class="n">rata_rank</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'rank_37'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'rank_awal'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'rank_lama'</span><span class="p">,]))</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="n">set.seed</span><span class="p">(</span><span class="m">101</span><span class="p">)</span><span class="w">
</span><span class="n">hasil_apt</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">simulasi_apartemen</span><span class="p">()</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== SIMULASI CARI APARTEMEN (N=20) ===

             strategi prob_terbaik rata_rank
1    Aturan 37% (r=7)        38.3%      5.36
2 Terlalu Cepat (r=2)        25.3%      4.54
3 Terlalu Lama (r=15)        22.4%      8.53
</code></pre></div></div>

<p><strong>Aturan 37%</strong> memberikan peluang terbaik kita akan mendapatkan unit
terbaik dari 20 unit yang ada di <em>shortlist</em>.</p>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/secretary_problem/draft_files/figure-commonmark/unnamed-chunk-8-1.png" alt="" /></p>

<h2 id="kasus-iii-simulasi-pencarian-vendor">KASUS III: Simulasi Pencarian <em>Vendor</em></h2>

<p>Tim <em>procurement</em> sedang memilih vendor untuk proyek IT senilai Rp 2
miliar. Ada 15 vendor yang sudah diundang untuk mengajukan penawaran.
Penawaran datang satu per satu. Mereka ingin memilih <em>vendor</em> dengan
harga dan kualitas terbaik, tapi <em>vendor</em> yang sudah ditolak tidak bisa
diajak kembali ke meja negosiasi. Bagaimana cara terbaik memilihnya?
Dengan <strong>aturan 37%</strong>:</p>

<blockquote>
  <p><em>r</em> sebesar (15 × 0.37) = 6 vendor. Evaluasi 6 penawaran pertama,
tolak semua (tapi catat yang terbaik sebagai <em>benchmark</em> / <em>basis</em>).
Mulai dari penawaran ke-7, pilih penawaran pertama yang lebih baik
dari <em>basis</em> tersebut.</p>
</blockquote>

<p>Pada simulasi ini, saya berikan juga nilai <em>random</em> masing-masing
<em>vendor</em> untuk kemudian saya bandingkan juga strategi pemilihan jika
terburu-buru atau terlalu lama:</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Kasus 3: Seleksi Vendor ───────────────────────────────────────</span><span class="w">

</span><span class="c1"># Dalam seleksi vendor, 'nilai' adalah kombinasi harga dan kualitas</span><span class="w">
</span><span class="c1"># Kita simulasikan nilai gabungan (semakin tinggi semakin baik)</span><span class="w">

</span><span class="n">simulasi_vendor</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">n_vendor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">15</span><span class="p">,</span><span class="w"> </span><span class="n">n_sim</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">50000</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="n">r_37</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">ceiling</span><span class="p">(</span><span class="n">n_vendor</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nf">exp</span><span class="p">(</span><span class="m">1</span><span class="p">))</span><span class="w">

  </span><span class="n">hasil</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">replicate</span><span class="p">(</span><span class="n">n_sim</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="c1"># Setiap vendor punya nilai gabungan harga-kualitas</span><span class="w">
    </span><span class="n">nilai_vendor</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">runif</span><span class="p">(</span><span class="n">n_vendor</span><span class="p">,</span><span class="w"> </span><span class="m">50</span><span class="p">,</span><span class="w"> </span><span class="m">100</span><span class="p">)</span><span class="w">

    </span><span class="n">pilihan_37</span><span class="w">   </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">nilai_vendor</span><span class="p">,</span><span class="w"> </span><span class="n">r_37</span><span class="p">)</span><span class="w">
    </span><span class="n">pilihan_awal</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">nilai_vendor</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w">
    </span><span class="n">pilihan_lama</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">optimal_stopping</span><span class="p">(</span><span class="n">nilai_vendor</span><span class="p">,</span><span class="w"> </span><span class="m">12</span><span class="p">)</span><span class="w">

    </span><span class="c1"># Hitung nilai (skor) vendor yang dipilih</span><span class="w">
    </span><span class="nf">c</span><span class="p">(</span><span class="w">
      </span><span class="n">nilai_37</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="n">nilai_vendor</span><span class="p">[</span><span class="n">pilihan_37</span><span class="p">],</span><span class="w">
      </span><span class="n">nilai_awal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nilai_vendor</span><span class="p">[</span><span class="n">pilihan_awal</span><span class="p">],</span><span class="w">
      </span><span class="n">nilai_lama</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nilai_vendor</span><span class="p">[</span><span class="n">pilihan_lama</span><span class="p">],</span><span class="w">
      </span><span class="n">terbaik_37</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nilai_vendor</span><span class="p">[</span><span class="n">pilihan_37</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">nilai_vendor</span><span class="p">)</span><span class="w">
    </span><span class="p">)</span><span class="w">
  </span><span class="p">})</span><span class="w">

  </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">strategi</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'Aturan 37% (r=6)'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Terlalu Cepat (r=1)'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Terlalu Lama (r=12)'</span><span class="p">),</span><span class="w">
    </span><span class="n">rata_nilai</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'nilai_37'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'nilai_awal'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'nilai_lama'</span><span class="p">,])),</span><span class="w">
    </span><span class="n">prob_terbaik</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'terbaik_37'</span><span class="p">,]),</span><span class="w"> </span><span class="s2">"-"</span><span class="p">,</span><span class="w"> </span><span class="s2">"-"</span><span class="p">)</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="n">set.seed</span><span class="p">(</span><span class="m">101</span><span class="p">)</span><span class="w">
</span><span class="n">hasil_vendor</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">simulasi_vendor</span><span class="p">()</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== SIMULASI SELEKSI VENDOR (N=15) ===

             strategi rata_nilai prob_terbaik
1    Aturan 37% (r=6)      86.43      0.38898
2 Terlalu Cepat (r=1)      85.82           -
3 Terlalu Lama (r=12)      78.12           -
</code></pre></div></div>

<p>Ternyata didapatkan bahwa <strong>aturan 37%</strong> memberikan peluang terbaik bagi
tim <em>procurement</em> untuk menemukan <em>vendor</em> dengan <em>expected</em> nilai
kualitas dan harga tertinggi.</p>

<h1 id="berapa-nilai-r-untuk-n-yang-berbeda-beda">Berapa Nilai <em>r</em> untuk <strong>N</strong> yang Berbeda-beda?</h1>

<p>Salah satu pertanyaan yang selalu muncul adalah jika <strong>N</strong> saya bukan
100 tapi hanya 10 atau 20, apakah masih pakai 37%?</p>

<blockquote>
  <p>Jawaban singkatnya: ya karena prinsipnya sama.</p>
</blockquote>

<p>TAPI untuk <strong>N</strong> kecil, tentu ada penyesuaian karena bilangan bulat
tidak bisa mewakili 37% secara persis. Berikut tabel referensi yang bisa
digunakan:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    N r_teoritis r_praktis pct_r sisa_pilih
1   5   1.839397         2  40.0          3
2  10   3.678794         4  40.0          6
3  15   5.518192         6  40.0          9
4  20   7.357589         8  40.0         12
5  30  11.036383        12  40.0         18
6  50  18.393972        19  38.0         31
7 100  36.787944        37  37.0         63
8 200  73.575888        74  37.0        126
9 500 183.939721       184  36.8        316
</code></pre></div></div>

<p><img src="https://raw.githubusercontent.com/ikanx101/ikanx101.github.io/master/_posts/matematika%20ITB/secretary_problem/draft_files/figure-commonmark/unnamed-chunk-11-1.png" alt="" /></p>

<h1 id="bagaimana-jika-nilai-n-tidak-diketahui">Bagaimana Jika Nilai <strong>N</strong> Tidak Diketahui?</h1>

<p>Asumsi terberat dari <strong>aturan 37%</strong> adalah <strong>kita harus tahu N di
awal</strong>. Tapi di kehidupan nyata, seringkali kita tidak tahu berapa
banyak total pilihan yang tersedia. Misalnya: berapa lama Anda harus
mencari pasangan hidup sebelum memutuskan untuk berkomitmen? Anda tidak
tahu akan bertemu berapa orang sepanjang hidup Anda.</p>

<p>Untuk kasus ini, ada <strong>ekstensi aturan 37%</strong> yang menggunakan waktu
sebagai pengganti jumlah <strong>N</strong>. Bagaimana caranya? Prinsipnya seperti
ini:</p>

<blockquote>
  <p>Kalau Anda berencana mencari selama <em>T</em> tahun (atau bulan, atau hari),
habiskan 37% waktu pertama hanya untuk mengobservasi dan
membandingkan. Setelah itu, pilih opsi pertama yang lebih baik dari
semua yang sudah Anda lihat.</p>
</blockquote>

<p>Misalkan jika kita berencana mencari karyawan selama 3 bulan, gunakan
5-6 minggu pertama hanya untuk wawancara tanpa menerima siapapun.</p>

<p>Berikut adalah skrip untuk men-simulasikan hal tersebut:</p>

<p>Misalkan kita memiliki waktu pencarian kandidat karyawan selama 12
bulan.</p>

<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ── Simulasi: ketika N tidak diketahui (pakai batas waktu) ───────</span><span class="w">

</span><span class="c1"># Asumsi: kandidat datang dengan laju Poisson,</span><span class="w">
</span><span class="c1"># kita punya waktu T satuan, dan kandidat datang rata-rata lambda per satuan</span><span class="w">

</span><span class="n">simulasi_waktu</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">T_total</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">12</span><span class="p">,</span><span class="w">   </span><span class="c1"># 12 bulan</span><span class="w">
                            </span><span class="n">lambda</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="m">4</span><span class="p">,</span><span class="w">    </span><span class="c1"># rata-rata 4 kandidat/bulan</span><span class="w">
                            </span><span class="n">n_sim</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="m">30000</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="n">t_37</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">T_total</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nf">exp</span><span class="p">(</span><span class="m">1</span><span class="p">)</span><span class="w">  </span><span class="c1"># 37% dari total waktu</span><span class="w">

  </span><span class="n">hasil</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">replicate</span><span class="p">(</span><span class="n">n_sim</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="c1"># Simulasi waktu kedatangan kandidat (Poisson process)</span><span class="w">
    </span><span class="n">n_total</span><span class="w">    </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">rpois</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">lambda</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">T_total</span><span class="p">)</span><span class="w">
    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">n_total</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w"> </span><span class="nf">return</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">sukses_37</span><span class="o">=</span><span class="kc">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">sukses_50</span><span class="o">=</span><span class="kc">FALSE</span><span class="p">))</span><span class="w">

    </span><span class="n">waktu_datang</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">sort</span><span class="p">(</span><span class="n">runif</span><span class="p">(</span><span class="n">n_total</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">T_total</span><span class="p">))</span><span class="w">
    </span><span class="n">nilai</span><span class="w">        </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">runif</span><span class="p">(</span><span class="n">n_total</span><span class="p">)</span><span class="w">  </span><span class="c1"># Kualitas kandidat</span><span class="w">

    </span><span class="c1"># Strategi 37% waktu</span><span class="w">
    </span><span class="n">observasi_37</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">waktu_datang</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">t_37</span><span class="w">
    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">observasi_37</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="nf">return</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">sukses_37</span><span class="o">=</span><span class="kc">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">sukses_50</span><span class="o">=</span><span class="kc">FALSE</span><span class="p">))</span><span class="w">

    </span><span class="n">patokan_37</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">nilai</span><span class="p">[</span><span class="n">observasi_37</span><span class="p">])</span><span class="w">
    </span><span class="n">kandidat_eksploitasi</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="o">!</span><span class="n">observasi_37</span><span class="p">)</span><span class="w">

    </span><span class="n">pilih_37</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">n_total</span><span class="w">  </span><span class="c1"># default: kandidat terakhir</span><span class="w">
    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">kandidat_eksploitasi</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">nilai</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">patokan_37</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pilih_37</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="w"> </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">

    </span><span class="c1"># Strategi 50% waktu (untuk perbandingan)</span><span class="w">
    </span><span class="n">observasi_50</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">waktu_datang</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">T_total</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="m">0.5</span><span class="w">
    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">observasi_50</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="nf">return</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">sukses_37</span><span class="o">=</span><span class="kc">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">sukses_50</span><span class="o">=</span><span class="kc">FALSE</span><span class="p">))</span><span class="w">

    </span><span class="n">patokan_50</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">nilai</span><span class="p">[</span><span class="n">observasi_50</span><span class="p">])</span><span class="w">
    </span><span class="n">kandidat_eks50</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="o">!</span><span class="n">observasi_50</span><span class="p">)</span><span class="w">

    </span><span class="n">pilih_50</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">n_total</span><span class="w">
    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">kandidat_eks50</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">nilai</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">patokan_50</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">pilih_50</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">i</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="w"> </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">

    </span><span class="nf">c</span><span class="p">(</span><span class="w">
      </span><span class="n">sukses_37</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nilai</span><span class="p">[</span><span class="n">pilih_37</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">nilai</span><span class="p">),</span><span class="w">
      </span><span class="n">sukses_50</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nilai</span><span class="p">[</span><span class="n">pilih_50</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">nilai</span><span class="p">)</span><span class="w">
    </span><span class="p">)</span><span class="w">
  </span><span class="p">})</span><span class="w">

  </span><span class="n">data.frame</span><span class="p">(</span><span class="w">
    </span><span class="n">strategi</span><span class="w">     </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'37% waktu (t = 4.4 bln)'</span><span class="p">,</span><span class="w"> </span><span class="s1">'50% waktu (t = 6 bln)'</span><span class="p">),</span><span class="w">
    </span><span class="n">prob_sukses</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'sukses_37'</span><span class="p">,]),</span><span class="w">
                     </span><span class="n">mean</span><span class="p">(</span><span class="n">hasil</span><span class="p">[</span><span class="s1">'sukses_50'</span><span class="p">,]))</span><span class="w">
  </span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="n">set.seed</span><span class="p">(</span><span class="m">101</span><span class="p">)</span><span class="w">
</span><span class="n">hasil_waktu</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">simulasi_waktu</span><span class="p">()</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== SIMULASI BERBASIS WAKTU (T=12 bln, lambda=4/bln) ===

                 strategi prob_sukses
1 37% waktu (t = 4.4 bln)       36.5%
2   50% waktu (t = 6 bln)       34.7%
</code></pre></div></div>

<p>Dengan memanfaatkan <strong>aturan 37%</strong>, kita cukup menunggu selama 4.4 bulan
untuk mendapatkan kandidat terbaik dengan <em>expected</em> probabilitas
tertinggi dibandingkan dengan strategi lainnya.</p>

<h1 id="epilog-kapan-aturan-ini-tidak-cocok-dipakai">Epilog: Kapan Aturan Ini Tidak Cocok Dipakai?</h1>

<p>Dari banyak penjelasan di atas, <strong>aturan 37%</strong> bukan resep ajaib. Tapi
ia mengajarkan sesuatu yang sangat berharga, yakni ada <em>trade-off</em>
mendasar antara mengumpulkan informasi dan mengambil tindakan.</p>

<ul>
  <li>Terlalu sedikit informasi — keputusan jadi serampangan.</li>
  <li>Terlalu banyak menunggu — kesempatan berlalu.</li>
</ul>

<p>Hal yang menarik adalah matematika menunjukkan bahwa <em>trade-off</em> ini
punya titik optimal yang secara mengejutkan konsisten di berbagai ukuran
<strong>N</strong>. Yakni selalu sekitar 37% pertama hanya untuk mengamati, lalu
bertindak.</p>

<p><strong>Namun</strong>, perlu diingat kembali bahwa <strong>aturan 37%</strong> ini punya asumsi
dan limitasi sehingga tidak cocok digunakan saat kondisinya:</p>

<ol>
  <li>Ketika Anda bisa kembali ke pilihan sebelumnya. Kalau Anda masih
bisa menelepon kembali kandidat yang sudah ‘ditolak’, aturan ini
tidak diperlukan. Masalah <em>optimal stopping</em> hanya relevan ketika
keputusan benar-benar <em>irreversible</em>.</li>
  <li>Ketika <strong>N</strong> sangat kecil (N &lt; 5). Dengan 3-4 pilihan saja, 37%
dari N hanya 1 kandidat. Fase observasi dari 1 orang terlalu sedikit
untuk jadi patokan yang berarti. Lebih baik evaluasi semua, lalu
pilih.</li>
  <li>Ketika kualitas kandidat tidak independen. Kalau kandidat yang
datang belakangan cenderung lebih baik (misalnya CV yang masuk
setelah <em>deadline</em> perpanjangan), asumsi urutan acak dilanggar dan
aturan 37% bisa menyesatkan.</li>
  <li>Ketika ada informasi <em>prior</em> yang kuat. Kalau Anda sudah tahu
distribusi kualitas kandidat (misalnya: ‘dari 50 pelamar, biasanya
ada 3-5 yang sangat bagus’), pendekatan <strong>Bayesian</strong> bisa
menghasilkan strategi yang lebih baik dari <strong>aturan 37%</strong> murni.</li>
  <li>Ketika biaya observasi tinggi. Kalau setiap wawancara butuh 3 jam
persiapan, ‘buang’ 37% kandidat hanya untuk observasi bisa sangat
mahal. Dalam kasus ini, <em>r</em> optimal mungkin lebih kecil dari 37%.</li>
</ol>

<hr />

<p><code class="language-plaintext highlighter-rouge">if you find this article helpful, support this blog by clicking the ads.</code></p>]]></content><author><name>Bunch of Ideas, a little bit of Maths.</name></author><category term="Blog" /><category term="Market Riset" /><category term="Strategi" /><category term="Decision Making" /><category term="Decision Support System" /><category term="Matematika" /><category term="Data" /><category term="Sampling" /><summary type="html"><![CDATA[Pada lebaran kemarin, saya pergi ke mall di sore harinya untuk mencari tempat makan untuk saya dan keluarga. Saat masuk ke basement parkiran, saya melihat satu slot kosong di dekat pintu masuk. Saya berpikir:]]></summary></entry></feed>