Mengukur Seberapa Sensitif Konsumen terhadap Perubahan Harga dari Data Transaksi
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:
“Kalau harga kita naikkan 10%, kira-kira penjualan kita akan turun berapa persen?”
Sering kali, jawaban yang muncul pada saat meeting tersebut hanyalah tebakan berbasis intuisi: “Mungkin turun sedikit” atau “Kompetitor juga naik kok, harusnya aman”.
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: Price Elasticity of Demand, cara menghitungnya dari data transaksi, dan bagaimana hasilnya bisa langsung dipakai untuk keputusan pricing.
Apa Itu Price Elasticity of Demand?
Sebagaimana apa yang pernah saya ulas di tulisan saya sebelumnya, Price Elasticity of Demand (PED) adalah ukuran seberapa besar persentase perubahan sales quantity yang diminta ketika harga berubah sebesar satu persen.
Rumus dasarnya sederhana:
PED = (% Perubahan Kuantitas) / (% Perubahan Harga) Atau dalam bentuk yang lebih operasional: PED = (dQ/Q) / (dP/P) = (dQ/dP) x (P/Q)
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:
| Nilai PED | Kategori | Artinya | Contoh kategori produk |
|---|---|---|---|
> 1 |
Elastis | Konsumen sangat sensitif terhadap harga | Minuman ringan, snack premium, pakaian |
= 1 |
Unit elastis | % perubahan sales quantity sama dengan % perubahan harga | Kondisi khusus, jarang terjadi di dunia nyata |
0 < abs(PED) < 1 |
Inelastis | Konsumen kurang sensitif terhadap harga | Beras, garam, BBM, obat-obatan |
= 0 |
Perfectly inelastis | Harga naik berapapun, sales quantity tidak berubah | Sangat jarang terjadi. Biasanya obat-obatan khusus. |
Implikasi Langsung untuk Revenue
Inilah bagian yang paling actionable. Jika kita tahu nilai PED, maka kita bisa tahu apa yang akan terjadi pada revenue kalau harga kita ubah.
| Kondisi | Jika harga naik | Jika harga turun |
|---|---|---|
| Elastis | Revenue TURUN karena sales qty turun lebih besar dari kenaikan harga | Revenue NAIK karena sales qty naik lebih besar dari penurunan harga |
| Inelastis | Revenue NAIK karena sales qty turun tapi tidak cukup mengimbangi kenaikan harga | Revenue TURUN karena penurunan harga lebih besar dari kenaikan sales qty |
Kalau produk kamu inelastis (konsumen tidak terlalu sensitif harga), kenaikan harga justru meningkatkan revenue. Kalau elastis, kenaikan harga akan memangkas revenue karena konsumen langsung kabur ke kompetitor atau berhenti beli.
Metode Perhitungan
Salah satu metode perhitungan yang bisa digunakan adalah log-log regression. Metode ini paling populer dan paling mudah diinterpretasikan. Model ini dikenal sebagai constant elasticity model. Ide dasarnya adalah alih-alih meregresikan sales qty langsung terhadap price, kita meregresikan log(sales qty) terhadap log(price). Model log-log:
log(Qty) = α + β × log(Harga) + ε
Di mana β adalah koefisien yang langsung bisa dibaca sebagai price
elasticity. Jika β = -1.5 berarti setiap kenaikan harga 1% maka
akan ada penurunan volume 1.5%.
Mengapa log-log lebih disukai dari regresi linier biasa? Ada tiga alasan utama:
- Koefisien bisa langsung direpresentasikan sebagai indeks elastisitas. Tidak perlu melakukan konversi apapun.
- Hubungan price dan sales qty di dunia nyata lebih sering bersifat multiplikatif (persentase) daripada aditif (unit absolut). Log-log menangkap ini lebih natural.
- Transformasi logaritmik
log( )sering menstabilkan variansi (membuat data lebih compact) dan membuat distribusi residual lebih mendekati normal.
Case Study Menggunakan Data Simulasi
Untuk membantu menjelaskan tentang model ini, saya akan menggunakan data simulasi berdasarkan suatu skenario yang saya buat. Berikut adalah skenarionya:
Kita adalah data analyst 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.
Data yang saat ini tersedia adalah sales qty 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 robust.
Kita buat data transaksi yang realistis (lengkap dengan efek musiman, promosi, noise, dan beberapa kali kenaikan harga yang jelas).
Dimensi data: 36550 baris x 13 kolom
Periode: 19723 - 20453
Rows: 36,550
Columns: 13
$ tanggal <date> 2024-01-01, 2024-01-02, 2024-01-03, 2024-01-04, 2024-01-05…
$ gerai_id <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ skala_base <dbl> 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,…
$ tipe <chr> "Residensial", "Residensial", "Residensial", "Residensial",…
$ harga <dbl> 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500, 5500,…
$ hari_ke <dbl> 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6,…
$ efek_hari <dbl> 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 <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ efek_bulan <dbl> 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15, 1.15,…
$ harga_ref <dbl> 5875, 5875, 5875, 5875, 5875, 5875, 5875, 5875, 5875, 5875,…
$ elas <dbl> -1.35, -1.35, -1.35, -1.35, -1.35, -1.35, -1.35, -1.35, -1.…
$ qty_true <dbl> 91.76809, 91.76809, 91.76809, 91.76809, 100.94490, 119.2985…
$ qty <dbl> 81, 95, 79, 93, 100, 149, 126, 86, 86, 75, 97, 101, 140, 12…
Berikut adalah sampel datanya:
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
Jika digambarkan ke dalam line chart, berikut adalah total sales qty dari seluruh gerai di berbagai tipe harga:

Sebelum membangun model regresi, kita perlu mengeksplorasi data secara visual. Ini penting untuk memastikan apakah ada signal yang bisa ditangkap dan tidak ada anomali yang merusak analisis. Pertama-tama saya akan membuat analisa sederhana dan visualisasi distribusi sales qty per price level:
=== RINGKASAN VOLUME PER HARGA ===
# A tibble: 3 × 5
harga n_observasi rata_qty median_qty sd_qty
<dbl> <int> <dbl> <dbl> <dbl>
1 5500 18150 104. 104 31.3
2 6000 9200 86.0 86 25.4
3 6500 9200 77.6 77 23.2

Berikut adalah visualisasi scatterplot antara log(price) dan log(sales qty):

Sekarang kita akan membuat beberapa model price elasticity dengan log-log regression. Pada tulisan ini, saya tidak akan membahas tentang goodness of fit dan uji asumsi dari model regresi yang dihasilkan.
Model 1: Regresi Agregat (Baseline)
Kita mulai dari model paling sederhana dulu: regresikan log(sales qty) terhadap log(price) menggunakan seluruh data tanpa memisahkan per tipe gerai.
# ── Model 1: Log-log regresi sederhana ──────────────────────────
model1 <- lm(log_qty ~ log_harga, data = df_weekly)
=== 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(>|t|)
(Intercept) 20.08356 0.49624 40.47 <2e-16 ***
log_harga -1.79761 0.05719 -31.43 <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: < 2.2e-16
Estimasi Elastisitas (Model 1): -1.798
Interpretasi: kenaikan harga 1% -> -1.798 % perubahan volume
Model 2: Regresi dengan Kontrol Musiman dan Tipe Gerai
Model pertama mengabaikan faktor-faktor yang juga mempengaruhi sales qty seperti seasonal, hari dalam minggu, dan tipe gerai. Ini bisa membuat estimasi elastisitas bias (confounding). Kita tambahkan variabel kontrol seperti:
- Apakah sedang bulan Ramadhan.
- Apakah musim lbiuran?
- Faktor tipe gerai dijadikan faktor.
# ── Persiapan variabel kontrol ───────────────────────────────────
df_weekly <- df_weekly %>%
mutate(
bulan = month(minggu),
# Dummy musiman
is_ramadan = as.integer(bulan %in% c(3, 4)),
is_liburan = as.integer(bulan %in% c(6, 7, 12, 1)),
# Log gerai size: kontrol skala tiap gerai
# Proxy: rata-rata volume saat harga paling rendah
tipe = factor(tipe, levels = c('Residensial',
'Perkantoran', 'Sekolah'))
)
# ── Model 2: Dengan kontrol lengkap ──────────────────────────────
model2 <- lm(
log_qty ~ log_harga +
tipe + # Kontrol tipe gerai
is_ramadan + # Kontrol efek Ramadan
is_liburan + # Kontrol efek liburan
factor(month(minggu)) # Kontrol musiman bulanan
,
data = df_weekly
)
=== 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(>|t|)
(Intercept) 15.390587 0.973631 15.807 < 2e-16 ***
log_harga -1.262097 0.111339 -11.336 < 2e-16 ***
tipePerkantoran 0.043300 0.009124 4.746 2.13e-06 ***
tipeSekolah -0.145998 0.009407 -15.520 < 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: < 2.2e-16
Estimasi Elastisitas (Model 2): -1.262
Interpretasi: kenaikan harga 1% -> -1.262 % perubahan volume
Model 3: Elastisitas per Tipe Gerai (Interaction Model)
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.
Oleh karena itu, kita tambahkan interaction term antara log(price) dan tipe gerai. Caranya adalah dengan mengalikan kedua variabel tersebut.
# ── Model 3: Interaksi harga x tipe gerai ────────────────────────
model3 <- lm(
log_qty ~ log_harga * tipe + # Interaksi: elastisitas berbeda per tipe
is_ramadan +
is_liburan +
factor(month(minggu))
,
data = df_weekly
)
=== 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(>|t|)
(Intercept) 15.731942 1.062017 14.813 < 2e-16 ***
log_harga -1.301438 0.121602 -10.702 < 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: < 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
Bagi gerai residensial, harga naik 10% mengakibatkan sales qty turun sekitar 13% sehingga revenue ikut turun. Kita harus hati-hati naikkan harga di gerai ini.
Bagi gerai perkantoran, harga naik 10% mengakibatkan sales qty turun sekitar 8% saja sehingga revenue bisa tetap naik. Gerai bertipe ini lebih aman untuk dinaikkan harganya sampai level harga tertentu.
Bagi gerai sekolah, paling sensitif. Harga naik 10% mengakibatkan sales qty turun sekitar 16%. Kita harus mempertimbangkan harga yang lebih kompetitif di sini.
Visualisasi Hasil Elastisitas
Berikutnya kita bisa melakukan simulasi jika harga naik X%, apa yang akan terjadi dengan sales qty? Inilah bagian yang paling langsung berguna pada saat meeting membahas pricing strategy. Kita buat kalkulator sederhana: berikan beberapa skenario kenaikan/penurunan harga, dan lihat dampaknya terhadap sales qty dan revenue. Perlu saya ingatkan kembali bahwa harga produk saat ini adalah Rp6.500.
Hasilnya, pertama-tama adalah visualisasi demand curve: Berapa Sales Qty pada Tiap Level Harga?

Kemudian dari grafik di atas, kita bisa menghitung harga optimal sehingga revenue yang dihasilkan tinggi. Revenue curve: Harga Berapa yang Memaksimalkan Pendapatan?
=== HARGA OPTIMAL PER TIPE GERAI ===
# A tibble: 3 × 4
# Groups: tipe [3]
tipe harga qty_pred revenue_per_gerai
<fct> <dbl> <dbl> <dbl>
1 Residensial 4500 116 520638
2 Perkantoran 8000 66 530207
3 Sekolah 4500 109 492672

Bentuk lain dari grafik di atas, saya bisa membuat revenue index vs persentase perubahan harga.

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