Konteks Penelitian
Penelitian ini
menganalisis faktor-faktor yang memengaruhi tingkat frekuensi
penggunaan layanan BNPL (Buy Now Pay Later) di Indonesia
menggunakan pendekatan regresi logistik ordinal dan
Partial Proportional Odds Model. Data berasal dari 433
responden pengguna aktif BNPL.
Belanja online di Indonesia semakin mudah dengan hadirnya fitur Buy Now Pay Later (BNPL). Layanan ini memungkinkan pengguna membeli barang terlebih dahulu, kemudian membayar di akhir bulan tanpa kartu kredit. OJK mencatat jumlah kontrak pembiayaan paylater di Indonesia mencapai 79,92 juta pada tahun 2023, melonjak dari 4,63 juta pada 2019, dengan rata-rata pertumbuhan tahunan 144,35%.
Penelitian ini bertujuan untuk:
Dataset
Dataset berasal dari
Zenodo (DOI: 10.5281/zenodo.15603120) dan memuat responden yang pernah
menggunakan BNPL/PayLater dalam transaksi e-commerce. Setelah
penyaringan, total sampel berjumlah 433 responden.
Frekuensi penggunaan PayLater/BNPL dalam satu bulan terakhir — bersifat ordinal dengan tiga kategori:
| Kode | Label Kategori | Tingkatan |
|---|---|---|
| 1 | < 2 kali per bulan | Rendah |
| 2 | 2–4 kali per bulan | Sedang |
| 3 | ≥ 5 kali per bulan | Tinggi |
Catatan: Penggabungan kategori “5–7 kali” dan “>7 kali” menjadi “≥5 kali” dilakukan untuk menghindari frekuensi sel yang terlalu kecil.
| Variabel | Skala | Kategori / Level (Referensi Dicetak Miring) |
|---|---|---|
| Usia | Nominal | Muda (<25 th), Dewasa Muda (25–34 th), Dewasa (35–44 th), Tua (≥45 th) |
| Gender | Nominal | Laki-laki, Perempuan |
| Pemasukan Bulanan | Nominal | <Rp3 juta, Rp3–5 juta, Rp5–10 juta, >Rp10 juta |
| Pendidikan Terakhir | Nominal | SMA ke bawah, Diploma/S1, S2/Profesi |
| Frekuensi E-commerce | Ordinal | 1–2 kali, 3–5 kali, >5 kali |
packages <- c("tidyverse", "MASS", "ordinal", "car",
"ggplot2", "dplyr", "knitr", "kableExtra",
"scales", "readxl")
for (pkg in packages) {
if (!require(pkg, character.only = TRUE, quietly = TRUE)) {
install.packages(pkg)
library(pkg, character.only = TRUE)
}
}# Palet warna mint & coral yang selaras dengan tema dokumen
clr_mint <- "#3AAFA9"
clr_coral <- "#E05C3A"
clr_gold <- "#D4A017"
clr_ink <- "#1A2E35"
theme_adk <- function() {
theme_minimal(base_family = "sans") +
theme(
plot.title = element_text(size = 14, face = "bold",
color = clr_ink, margin = margin(b = 8)),
plot.subtitle = element_text(size = 11, color = "#5D7A80",
margin = margin(b = 16)),
axis.title = element_text(size = 10, color = clr_ink),
axis.text = element_text(size = 9),
legend.title = element_text(size = 10, face = "bold"),
legend.text = element_text(size = 9),
strip.text = element_text(size = 10, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
panel.grid.major.y = element_line(color = "#C8E6E4", linewidth = 0.4),
plot.background = element_rect(fill = "white", color = NA),
panel.background = element_rect(fill = "white", color = NA)
)
}
# Palet untuk variabel BNPL (3 kategori)
pal_bnpl <- c("< 2 kali" = clr_mint,
"2-4 kali" = clr_gold,
">= 5 kali" = clr_coral)# Baca data dari file Excel
# Pastikan file "Data_project_ADK.xlsx" ada di working directory
data_raw <- read_excel("E:/KULIAH/Semester 4/ADK/.Project/Data project ADK.xlsx",
sheet = "Form Responses 1")
cat("Dimensi data mentah:", nrow(data_raw), "baris x", ncol(data_raw), "kolom\n")## Dimensi data mentah: 509 baris x 63 kolom
# Filter hanya responden pengguna BNPL
data_ord <- data_raw %>%
filter(`Apakah Anda pernah menggunakan Buy Now Pay Later/Paylater?` == "Ya")
# Pilih variabel yang diperlukan
data_ord <- data_ord %>%
dplyr::select(
Frekuensi_BNPL = `Seberapa sering Anda menggunakan Buy Now Pay Later dalam sebulan kemarin?`,
Gender = Gender,
Pendidikan = `Pendidikan Terakhir`,
Pemasukan = `Pemasukan Bulanan (Rupiah)`,
Usia = Usia,
Frekuensi_Ecommerce = `Seberapa sering Anda bertransaksi di platform e-commerce dalam sebulan terakhir?`
)
# ── Variabel Dependen: Frekuensi BNPL (ordinal) ──────────────────
data_ord$Frekuensi_BNPL <- factor(
dplyr::case_when(
data_ord$Frekuensi_BNPL == "< 2 kali" ~ "< 2 kali",
data_ord$Frekuensi_BNPL == "2- 4 kali" ~ "2-4 kali",
data_ord$Frekuensi_BNPL %in% c("5 - 7 kali", "> 7 kali") ~ ">= 5 kali"
),
levels = c("< 2 kali", "2-4 kali", ">= 5 kali"),
ordered = TRUE
)
# ── Gender ────────────────────────────────────────────────────────
data_ord$Gender <- factor(data_ord$Gender,
levels = c("Laki-laki", "Perempuan"))
# ── Pendidikan (3 kelompok, ref = SMA ke bawah) ───────────────────
data_ord$Pendidikan_cat <- factor(
case_when(
data_ord$Pendidikan %in% c("SMP/Sederajat", "SMA/Sederajat") ~ "SMA ke bawah",
data_ord$Pendidikan %in% c("Diploma", "S1") ~ "Diploma/S1",
TRUE ~ "S2/Profesi"
),
levels = c("SMA ke bawah", "Diploma/S1", "S2/Profesi")
)
# ── Pemasukan (nominal, ref = < 3.000.000) ───────────────────────
data_ord$Pemasukan <- factor(
data_ord$Pemasukan,
levels = c("< 3.000.000", "3.000.000 - 5.000.000",
"5.000.000 - 10.000.000", "> 10.000.000")
)
# ── Usia (nominal, ref = Muda <25) ───────────────────────────────
data_ord$Usia <- as.character(data_ord$Usia)
data_ord$Usia <- trimws(data_ord$Usia)
data_ord$Usia <- factor(
dplyr::case_when(
data_ord$Usia %in% c("< 18 Tahun", "18 - 24 Tahun") ~ "Muda (<25)",
data_ord$Usia %in% c("25 - 29 Tahun", "30 - 34 Tahun") ~ "Dewasa Muda (25-34)",
data_ord$Usia %in% c("35 - 39 Tahun", "40 - 44 Tahun") ~ "Dewasa (35-44)",
data_ord$Usia %in% c("45 - 49 Tahun", "50 - 55 Tahun", "> 55 Tahun") ~ "Tua (45+)",
TRUE ~ NA_character_
),
levels = c("Muda (<25)", "Dewasa Muda (25-34)", "Dewasa (35-44)", "Tua (45+)")
)
# ── Frekuensi E-commerce (ordinal) ───────────────────────────────
data_ord$Frekuensi_Ecommerce <- factor(
data_ord$Frekuensi_Ecommerce,
levels = c("1–2 kali", "3–5 kali", ">5 kali")
)
# Hapus NA dan level kosong
data_ord <- na.omit(data_ord)
data_ord <- droplevels(data_ord)
cat("Sampel setelah cleaning:", nrow(data_ord), "responden\n")## Sampel setelah cleaning: 433 responden
tbl_gender <- data_ord %>% count(Variabel = "Gender",
Kategori = as.character(Gender)) %>%
mutate(Proporsi = paste0(round(n/sum(n)*100,1), "%"))
tbl_usia <- data_ord %>% count(Variabel = "Usia",
Kategori = as.character(Usia)) %>%
mutate(Proporsi = paste0(round(n/sum(n)*100,1), "%"))
tbl_pendidikan <- data_ord %>% count(Variabel = "Pendidikan",
Kategori = as.character(Pendidikan_cat)) %>%
mutate(Proporsi = paste0(round(n/sum(n)*100,1), "%"))
tbl_pemasukan <- data_ord %>% count(Variabel = "Pemasukan Bulanan",
Kategori = as.character(Pemasukan)) %>%
mutate(Proporsi = paste0(round(n/sum(n)*100,1), "%"))
tbl_eco <- data_ord %>% count(Variabel = "Frekuensi E-commerce",
Kategori = as.character(Frekuensi_Ecommerce)) %>%
mutate(Proporsi = paste0(round(n/sum(n)*100,1), "%"))
tbl_prediktor <- bind_rows(tbl_gender, tbl_usia,
tbl_pendidikan, tbl_pemasukan, tbl_eco)
tbl_prediktor %>%
kable(caption = "Tabel 3. Distribusi Variabel Prediktor",
col.names = c("Variabel", "Kategori", "n", "Proporsi (%)")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = FALSE) %>%
column_spec(1, bold = TRUE)| Variabel | Kategori | n | Proporsi (%) |
|---|---|---|---|
| Gender | Laki-laki | 209 | 48.3% |
| Gender | Perempuan | 224 | 51.7% |
| Usia | Dewasa (35-44) | 101 | 23.3% |
| Usia | Dewasa Muda (25-34) | 248 | 57.3% |
| Usia | Muda (<25) | 70 | 16.2% |
| Usia | Tua (45+) | 14 | 3.2% |
| Pendidikan | Diploma/S1 | 351 | 81.1% |
| Pendidikan | S2/Profesi | 28 | 6.5% |
| Pendidikan | SMA ke bawah | 54 | 12.5% |
| Pemasukan Bulanan | 3.000.000 - 5.000.000 | 139 | 32.1% |
| Pemasukan Bulanan | 5.000.000 - 10.000.000 | 191 | 44.1% |
| Pemasukan Bulanan | < 3.000.000 | 9 | 2.1% |
| Pemasukan Bulanan | > 10.000.000 | 94 | 21.7% |
| Frekuensi E-commerce | 1–2 kali | 149 | 34.4% |
| Frekuensi E-commerce | 3–5 kali | 221 | 51% |
| Frekuensi E-commerce | >5 kali | 63 | 14.5% |
Sampel didominasi oleh responden perempuan (51,7%), berusia dewasa muda 25–34 tahun (57,3%), berpendidikan Diploma/S1 (81,1%), dengan pemasukan bulanan Rp5–10 juta (44,1%), serta frekuensi transaksi e-commerce 3–5 kali per bulan (51,0%).
dist_bnpl <- data_ord %>%
count(Frekuensi_BNPL) %>%
mutate(Proporsi = paste0(round(n / sum(n) * 100, 1), "%"))
dist_bnpl %>%
kable(caption = "Tabel 4. Distribusi Frekuensi Penggunaan BNPL",
col.names = c("Frekuensi BNPL", "n", "Proporsi (%)")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)| Frekuensi BNPL | n | Proporsi (%) |
|---|---|---|
| < 2 kali | 70 | 16.2% |
| 2-4 kali | 247 | 57% |
| >= 5 kali | 116 | 26.8% |
dist_bnpl_plot <- data_ord %>%
count(Frekuensi_BNPL) %>%
mutate(Proporsi = n / sum(n))
ggplot(dist_bnpl_plot,
aes(x = Frekuensi_BNPL, y = Proporsi, fill = Frekuensi_BNPL)) +
geom_col(width = 0.60, alpha = 0.92, color = "white") +
geom_text(aes(label = scales::percent(Proporsi, accuracy = 0.1)),
vjust = -0.5, fontface = "bold", color = clr_ink, size = 4) +
scale_y_continuous(labels = scales::percent_format(), limits = c(0, 0.68)) +
scale_fill_manual(values = c("< 2 kali" = clr_mint,
"2-4 kali" = clr_gold,
">= 5 kali" = clr_coral)) +
labs(title = "Distribusi Frekuensi Penggunaan BNPL",
subtitle = "Variabel dependen ordinal — 433 responden",
x = NULL, y = "Proporsi") +
theme_adk() +
theme(legend.position = "none")Gambar: Distribusi Frekuensi Penggunaan BNPL
Distribusi frekuensi penggunaan BNPL didominasi kategori sedang (2–4 kali per bulan) sebesar 57,0% (247 orang), diikuti kategori tinggi (≥5 kali) 26,8% (116 orang), dan rendah (<2 kali) 16,2% (70 orang).
Model Kumulatif Logit (Proportional Odds)
Misalkan \(Y\) adalah variabel respons ordinal dengan \(J = 3\) kategori dan \(\mathbf{x}\) adalah vektor variabel prediktor. Model dirumuskan:
\[\text{logit}\,P(Y \leq j \mid \mathbf{x}) = \log\frac{P(Y \leq j \mid \mathbf{x})}{P(Y > j \mid \mathbf{x})} = \alpha_j - \boldsymbol{\beta}^\top \mathbf{x}, \quad j = 1, 2\]
Probabilitas kumulatif: \[P(Y \leq j \mid \mathbf{x}) = \frac{\exp(\alpha_j - \boldsymbol{\beta}^\top \mathbf{x})}{1 + \exp(\alpha_j - \boldsymbol{\beta}^\top \mathbf{x})}\]
Probabilitas marginal: \[P(Y = j \mid \mathbf{x}) = P(Y \leq j \mid \mathbf{x}) - P(Y \leq j-1 \mid \mathbf{x})\]
Estimasi Parameter (MLE)
\[\ell(\alpha, \beta) = \sum_{i=1}^{n} \sum_{j=1}^{J} \mathbf{1}(y_i = j)\, \log P(Y = j \mid \mathbf{x}_i)\]
Optimisasi dilakukan secara numerik menggunakan algoritma
Newton–Raphson melalui fungsi polr().
Cumulative Link Model (CLM) — Partial Proportional Odds
\[\text{logit}\,P(Y \leq j \mid \mathbf{x}, \mathbf{z}) = \alpha_j - \boldsymbol{\beta}^\top \mathbf{x} - \boldsymbol{\gamma}_j^\top \mathbf{z}, \quad j = 1, \dots, J-1\]
di mana \(\mathbf{z}\) adalah subset variabel dengan koefisien bebas per titik potong (efek nominal), sedangkan \(\mathbf{x}\) tetap mengikuti asumsi proportional odds.
Odds Ratio dan Interval Kepercayaan
\[OR_k = e^{\hat{\beta}_k}, \qquad CI\left(e^{\hat{\beta}_k}\right) = \left(e^{\hat{\beta}_k - 1.96\cdot SE(\hat{\beta}_k)},\; e^{\hat{\beta}_k + 1.96\cdot SE(\hat{\beta}_k)}\right)\]
data_vif <- data_ord %>%
mutate(
Y_num = as.numeric(Frekuensi_BNPL),
Pendidikan_num = as.numeric(Pendidikan_cat),
Pemasukan_num = as.numeric(Pemasukan),
Usia_num = as.numeric(Usia),
Frekuensi_Ecommerce_num = as.numeric(Frekuensi_Ecommerce),
Gender_num = ifelse(Gender == "Laki-laki", 1, 0)
)
vif_model <- lm(Y_num ~ Gender_num + Pendidikan_num + Pemasukan_num +
Usia_num + Frekuensi_Ecommerce_num, data = data_vif)
vif_values <- vif(vif_model)
vif_df <- data.frame(
Variabel = c("Gender", "Tingkat Pendidikan", "Pemasukan Bulanan",
"Usia", "Frekuensi E-commerce"),
VIF = round(vif_values, 3),
Keterangan = ifelse(vif_values < 5, "Tidak multikolinear", "Bermasalah")
)
vif_df %>%
kable(caption = "Tabel 5. Uji Multikolinearitas Variabel Prediktor",
row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
column_spec(3, color = ifelse(vif_df$Keterangan == "Tidak multikolinear",
"#2B7A78", "#E05C3A"),
bold = TRUE)| Variabel | VIF | Keterangan |
|---|---|---|
| Gender | 1.047 | Tidak multikolinear |
| Tingkat Pendidikan | 1.396 | Tidak multikolinear |
| Pemasukan Bulanan | 1.702 | Tidak multikolinear |
| Usia | 1.393 | Tidak multikolinear |
| Frekuensi E-commerce | 1.324 | Tidak multikolinear |
Seluruh nilai VIF berada di rentang 1–5 (nilai tertinggi = 1,702 pada variabel pemasukan bulanan). Tidak terdapat masalah multikolinearitas — estimasi koefisien regresi bebas dari bias inflasi varians.
fit_ord <- MASS::polr(
Frekuensi_BNPL ~ Gender + Pendidikan_cat + Pemasukan + Usia + Frekuensi_Ecommerce,
data = data_ord,
method = "logistic",
Hess = TRUE
)
summary(fit_ord)## Call:
## MASS::polr(formula = Frekuensi_BNPL ~ Gender + Pendidikan_cat +
## Pemasukan + Usia + Frekuensi_Ecommerce, data = data_ord,
## Hess = TRUE, method = "logistic")
##
## Coefficients:
## Value Std. Error t value
## GenderPerempuan 0.1557 0.2071 0.7516
## Pendidikan_catDiploma/S1 0.1763 0.3401 0.5183
## Pendidikan_catS2/Profesi -0.9877 0.6375 -1.5493
## Pemasukan3.000.000 - 5.000.000 -1.3720 0.8439 -1.6258
## Pemasukan5.000.000 - 10.000.000 -1.9758 0.8861 -2.2297
## Pemasukan> 10.000.000 -1.6505 0.9145 -1.8048
## UsiaDewasa Muda (25-34) 1.6225 0.3650 4.4453
## UsiaDewasa (35-44) 2.0470 0.4058 5.0437
## UsiaTua (45+) 0.5688 0.7473 0.7611
## Frekuensi_Ecommerce3–5 kali 1.5376 0.2668 5.7622
## Frekuensi_Ecommerce>5 kali 3.4476 0.4209 8.1910
##
## Intercepts:
## Value Std. Error t value
## < 2 kali|2-4 kali -0.9455 0.8242 -1.1472
## 2-4 kali|>= 5 kali 2.5582 0.8366 3.0578
##
## Residual Deviance: 686.4818
## AIC: 712.4818
fit_null <- MASS::polr(Frekuensi_BNPL ~ 1, data = data_ord, Hess = TRUE)
lrt_global <- anova(fit_null, fit_ord, test = "Chisq")
print(lrt_global)## Likelihood ratio tests of ordinal regression models
##
## Response: Frekuensi_BNPL
## Model Resid. df
## 1 1 431
## 2 Gender + Pendidikan_cat + Pemasukan + Usia + Frekuensi_Ecommerce 420
## Resid. Dev Test Df LR stat. Pr(Chi)
## 1 837.9988
## 2 686.4818 1 vs 2 11 151.517 0
n <- nrow(data_ord)
ll_null_val <- as.numeric(logLik(fit_null))
ll_full_val <- as.numeric(logLik(fit_ord))
pseudo_r2 <- data.frame(
Ukuran = c("McFadden R²", "Cox & Snell R²", "Nagelkerke R²"),
Nilai = c(
round(1 - (ll_full_val / ll_null_val), 4),
round(1 - exp((2 / n) * (ll_null_val - ll_full_val)), 4),
round((1 - exp((2 / n) * (ll_null_val - ll_full_val))) /
(1 - exp((2 / n) * ll_null_val)), 4)
),
Interpretasi = c("Memadai", "Sedang", "Sedang–Baik")
)
pseudo_r2 %>%
kable(caption = "Tabel 7. Nilai Pseudo R² pada Model") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)| Ukuran | Nilai | Interpretasi |
|---|---|---|
| McFadden R² | 0.1808 | Memadai |
| Cox & Snell R² | 0.2953 | Sedang |
| Nagelkerke R² | 0.3451 | Sedang–Baik |
LRT: χ²(11) = 151,517; p < 0,001 — model secara
keseluruhan signifikan.
Nagelkerke
R² = 0,3451 → variabel prediktor mampu menjelaskan
~34,5% variasi frekuensi penggunaan BNPL.
## AIC: 712.48
## BIC: 765.4
fit_clm_po <- ordinal::clm(
Frekuensi_BNPL ~ Gender + Pendidikan_cat + Pemasukan + Usia + Frekuensi_Ecommerce,
data = data_ord,
link = "logit"
)
nominal_test_result <- ordinal::nominal_test(fit_clm_po)
print(nominal_test_result)## Tests of nominal effects
##
## formula: Frekuensi_BNPL ~ Gender + Pendidikan_cat + Pemasukan + Usia + Frekuensi_Ecommerce
## Df logLik AIC LRT Pr(>Chi)
## <none> -343.24 712.48
## Gender 1 -342.96 713.91 0.5668 0.4515380
## Pendidikan_cat 2 -342.56 715.12 1.3656 0.5051960
## Pemasukan 3 -336.27 704.55 13.9319 0.0029994 **
## Usia 3 -333.54 699.09 19.3947 0.0002265 ***
## Frekuensi_Ecommerce 2 -340.41 710.82 5.6631 0.0589204 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
p_col <- grep("Pr", names(nominal_test_result), value = TRUE)[1]
p_min <- min(nominal_test_result[[p_col]], na.rm = TRUE)
cat("\np-value minimum nominal_test:", round(p_min, 4), "\n")##
## p-value minimum nominal_test: 2e-04
tbl_po <- data.frame(
Variabel = c("Gender", "Tingkat Pendidikan", "Pemasukan Bulanan",
"Usia", "Frekuensi E-commerce"),
df = c(1, 2, 3, 3, 2),
LRT = c(0.567, 1.366, 13.932, 19.395, 5.663),
`p-value` = c(0.452, 0.505, 0.003, 0.000, 0.059),
Keterangan = c("Terpenuhi", "Terpenuhi", "Tidak Terpenuhi",
"Tidak Terpenuhi", "Terpenuhi (marginal)"),
check.names = FALSE
)
tbl_po %>%
kable(caption = "Tabel 6. Uji Proportional Odds Variabel Prediktor") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
column_spec(5,
color = ifelse(grepl("Tidak", tbl_po$Keterangan), "#E05C3A", "#2B7A78"),
bold = TRUE)| Variabel | df | LRT | p-value | Keterangan |
|---|---|---|---|---|
| Gender | 1 | 0.567 | 0.452 | Terpenuhi |
| Tingkat Pendidikan | 2 | 1.366 | 0.505 | Terpenuhi |
| Pemasukan Bulanan | 3 | 13.932 | 0.003 | Tidak Terpenuhi |
| Usia | 3 | 19.395 | 0.000 | Tidak Terpenuhi |
| Frekuensi E-commerce | 2 | 5.663 | 0.059 | Terpenuhi (marginal) |
Pelanggaran Asumsi
Variabel
Pemasukan Bulanan (p = 0,003) dan Usia
(p < 0,001) melanggar asumsi proportional odds. Model
Proportional Odds standar tidak sesuai — digunakan
Partial Proportional Odds Model melalui
clm() dengan nominal = ~Pemasukan.
if (p_min > 0.05) {
message("Asumsi proportional odds terpenuhi. Model final: Proportional Odds (polr).")
model_final <- fit_ord
jenis_model <- "polr"
ord_coef <- coef(summary(model_final))
result_final <- as.data.frame(ord_coef) %>%
tibble::rownames_to_column("Parameter") %>%
dplyr::rename(Estimate = Value, SE = `Std. Error`, z_value = `t value`) %>%
dplyr::mutate(
p_value = round(2 * (1 - pnorm(abs(z_value))), 4),
Jenis = ifelse(grepl("\\|", Parameter), "Cutpoint", "Koefisien"),
OR = ifelse(Jenis == "Koefisien", round(exp(Estimate), 4), NA),
CI_low = ifelse(Jenis == "Koefisien", round(exp(Estimate - 1.96 * SE), 4), NA),
CI_high = ifelse(Jenis == "Koefisien", round(exp(Estimate + 1.96 * SE), 4), NA),
Signifikansi = ifelse(Jenis == "Koefisien",
ifelse(p_value < 0.05, "Signifikan", "Tidak signifikan"), NA)
)
} else {
message("Asumsi proportional odds TIDAK terpenuhi. Model final: CLM dengan efek nominal.")
model_final <- ordinal::clm(
Frekuensi_BNPL ~ Gender + Pendidikan_cat + Usia + Frekuensi_Ecommerce,
nominal = ~ Pemasukan,
data = data_ord,
link = "logit"
)
jenis_model <- "clm_nominal"
coef_clm <- coef(summary(model_final))
result_final <- as.data.frame(coef_clm) %>%
tibble::rownames_to_column("Parameter") %>%
dplyr::rename(Estimate = Estimate, SE = `Std. Error`,
z_value = `z value`, p_value = `Pr(>|z|)`) %>%
dplyr::mutate(
p_value = round(p_value, 4),
OR = round(exp(Estimate), 4),
CI_low = round(exp(Estimate - 1.96 * SE), 4),
CI_high = round(exp(Estimate + 1.96 * SE), 4),
Signifikansi = ifelse(p_value < 0.05, "Signifikan", "Tidak signifikan")
)
}
cat("Jenis model yang digunakan:", jenis_model, "\n")## Jenis model yang digunakan: clm_nominal
## formula: Frekuensi_BNPL ~ Gender + Pendidikan_cat + Usia + Frekuensi_Ecommerce
## nominal: ~Pemasukan
## data: data_ord
##
## link threshold nobs logLik AIC niter max.grad cond.H
## logit flexible 433 -336.27 704.55 6(0) 1.93e-09 1.0e+03
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## GenderPerempuan 0.1648 0.2103 0.784 0.433
## Pendidikan_catDiploma/S1 0.1635 0.3412 0.479 0.632
## Pendidikan_catS2/Profesi -0.9802 0.6238 -1.571 0.116
## UsiaDewasa Muda (25-34) 1.6483 0.3927 4.197 2.70e-05 ***
## UsiaDewasa (35-44) 2.0803 0.4335 4.798 1.60e-06 ***
## UsiaTua (45+) 0.6494 0.7579 0.857 0.392
## Frekuensi_Ecommerce3–5 kali 1.6136 0.2765 5.837 5.33e-09 ***
## Frekuensi_Ecommerce>5 kali 3.4575 0.4215 8.202 2.36e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Threshold coefficients:
## Estimate Std. Error z value
## < 2 kali|2-4 kali.(Intercept) 0.09452 0.79334 0.119
## 2-4 kali|>= 5 kali.(Intercept) 1.55159 0.80309 1.932
## < 2 kali|2-4 kali.Pemasukan3.000.000 - 5.000.000 0.34140 0.82004 0.416
## 2-4 kali|>= 5 kali.Pemasukan3.000.000 - 5.000.000 2.46076 0.86554 2.843
## < 2 kali|2-4 kali.Pemasukan5.000.000 - 10.000.000 0.62990 0.89533 0.704
## 2-4 kali|>= 5 kali.Pemasukan5.000.000 - 10.000.000 3.24915 0.88911 3.654
## < 2 kali|2-4 kali.Pemasukan> 10.000.000 1.39648 0.94066 1.485
## 2-4 kali|>= 5 kali.Pemasukan> 10.000.000 2.51129 0.91124 2.756
result_final %>%
dplyr::select(Parameter, Estimate, SE, z_value, p_value,
OR, CI_low, CI_high, Signifikansi) %>%
dplyr::mutate(across(where(is.numeric), ~round(.x, 4))) %>%
kable(caption = "Tabel 8. Estimasi Model Akhir Regresi Logistik Ordinal",
col.names = c("Parameter", "Est.", "SE", "z", "p-value",
"OR", "CI Low", "CI High", "Signifikansi")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = TRUE) %>%
column_spec(9,
color = ifelse(result_final$Signifikansi == "Signifikan", "#2B7A78", "#5D7A80"),
bold = ifelse(result_final$Signifikansi == "Signifikan", TRUE, FALSE))| Parameter | Est. | SE | z | p-value | OR | CI Low | CI High | Signifikansi |
|---|---|---|---|---|---|---|---|---|
| < 2 kali|2-4 kali.(Intercept) | 0.0945 | 0.7933 | 0.1191 | 0.9052 | 1.0991 | 0.2321 | 5.2042 | Tidak signifikan |
| 2-4 kali|>= 5 kali.(Intercept) | 1.5516 | 0.8031 | 1.9320 | 0.0534 | 4.7190 | 0.9778 | 22.7746 | Tidak signifikan |
| < 2 kali|2-4 kali.Pemasukan3.000.000 - 5.000.000 | 0.3414 | 0.8200 | 0.4163 | 0.6772 | 1.4069 | 0.2820 | 7.0194 | Tidak signifikan |
| 2-4 kali|>= 5 kali.Pemasukan3.000.000 - 5.000.000 | 2.4608 | 0.8655 | 2.8430 | 0.0045 | 11.7137 | 2.1475 | 63.8928 | Signifikan |
| < 2 kali|2-4 kali.Pemasukan5.000.000 - 10.000.000 | 0.6299 | 0.8953 | 0.7035 | 0.4817 | 1.8774 | 0.3247 | 10.8563 | Tidak signifikan |
| 2-4 kali|>= 5 kali.Pemasukan5.000.000 - 10.000.000 | 3.2491 | 0.8891 | 3.6544 | 0.0003 | 25.7683 | 4.5109 | 147.2015 | Signifikan |
| < 2 kali|2-4 kali.Pemasukan> 10.000.000 | 1.3965 | 0.9407 | 1.4846 | 0.1377 | 4.0410 | 0.6394 | 25.5384 | Tidak signifikan |
| 2-4 kali|>= 5 kali.Pemasukan> 10.000.000 | 2.5113 | 0.9112 | 2.7559 | 0.0059 | 12.3208 | 2.0653 | 73.5021 | Signifikan |
| GenderPerempuan | 0.1648 | 0.2103 | 0.7839 | 0.4331 | 1.1792 | 0.7809 | 1.7806 | Tidak signifikan |
| Pendidikan_catDiploma/S1 | 0.1635 | 0.3412 | 0.4791 | 0.6319 | 1.1776 | 0.6034 | 2.2983 | Tidak signifikan |
| Pendidikan_catS2/Profesi | -0.9802 | 0.6238 | -1.5712 | 0.1161 | 0.3752 | 0.1105 | 1.2745 | Tidak signifikan |
| UsiaDewasa Muda (25-34) | 1.6483 | 0.3927 | 4.1972 | 0.0000 | 5.1980 | 2.4075 | 11.2231 | Signifikan |
| UsiaDewasa (35-44) | 2.0803 | 0.4335 | 4.7983 | 0.0000 | 8.0068 | 3.4230 | 18.7285 | Signifikan |
| UsiaTua (45+) | 0.6494 | 0.7579 | 0.8569 | 0.3915 | 1.9145 | 0.4334 | 8.4572 | Tidak signifikan |
| Frekuensi_Ecommerce3–5 kali | 1.6136 | 0.2765 | 5.8366 | 0.0000 | 5.0208 | 2.9204 | 8.6317 | Signifikan |
| Frekuensi_Ecommerce>5 kali | 3.4575 | 0.4215 | 8.2020 | 0.0000 | 31.7376 | 13.8915 | 72.5100 | Signifikan |
sig_result <- result_final %>%
dplyr::filter(
!grepl("\\|", Parameter),
!grepl("Intercept|\\|", Parameter),
p_value < 0.05
) %>%
dplyr::select(Parameter, OR, CI_low, CI_high, p_value, Signifikansi)
sig_result %>%
kable(caption = "Tabel 9. Variabel Prediktor Signifikan (p < 0,05)",
col.names = c("Parameter", "OR", "CI 95% Low", "CI 95% High",
"p-value", "Keterangan")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
column_spec(2, bold = TRUE, color = clr_coral)| Parameter | OR | CI 95% Low | CI 95% High | p-value | Keterangan |
|---|---|---|---|---|---|
| UsiaDewasa Muda (25-34) | 5.1980 | 2.4075 | 11.2231 | 0 | Signifikan |
| UsiaDewasa (35-44) | 8.0068 | 3.4230 | 18.7285 | 0 | Signifikan |
| Frekuensi_Ecommerce3–5 kali | 5.0208 | 2.9204 | 8.6317 | 0 | Signifikan |
| Frekuensi_Ecommerce>5 kali | 31.7376 | 13.8915 | 72.5100 | 0 | Signifikan |
Koefisien gender (Perempuan vs. Laki-laki): β = 0,165, OR = 1,179, p = 0,433. Gender tidak berpengaruh signifikan terhadap frekuensi penggunaan BNPL — tidak terdapat perbedaan nyata antara laki-laki dan perempuan dalam intensitas penggunaan.
Tingkat pendidikan tidak menunjukkan pengaruh signifikan. Arah koefisien negatif pada kelompok S2/Profesi (OR = 0,375) mengisyaratkan kecenderungan penggunaan BNPL yang lebih rendah dibanding SMA ke bawah, konsisten dengan literatur bahwa pendidikan lebih tinggi berasosiasi dengan perilaku keuangan yang lebih prudent.
Variabel pemasukan melanggar asumsi proportional odds, sehingga efeknya berbeda per transisi kategori:
Rp10 juta: OR = 12,321 (p = 0,006)
Pemasukan bukan faktor yang mendorong seseorang mulai menggunakan BNPL, melainkan faktor yang mendorong intensifikasi menuju penggunaan yang paling aktif.
Variabel usia menunjukkan pengaruh yang konsisten dan sangat signifikan (ref: Muda <25 tahun):
Temuan ini berlawanan dengan asumsi umum bahwa BNPL identik dengan anak muda — kelompok usia produktif 25–44 tahun justru lebih aktif.
Frekuensi e-commerce merupakan prediktor dengan kekuatan asosiasi terbesar dalam model:
BNPL dan aktivitas belanja di e-commerce tidak dapat dipisahkan — semakin tinggi intensitas belanja online, semakin besar kemungkinan menggunakan BNPL sebagai metode pembayaran utama.
aktual <- model.response(model.frame(model_final))
if (jenis_model == "polr") {
pred_class <- predict(model_final, type = "class")
} else {
pred_class <- factor(
predict(model_final, newdata = model.frame(model_final), type = "class")$fit,
levels = levels(aktual),
ordered = TRUE
)
}
conf_matrix <- table(Aktual = data_ord$Frekuensi_BNPL, Prediksi = pred_class)
print(conf_matrix)## Prediksi
## Aktual < 2 kali 2-4 kali >= 5 kali
## < 2 kali 32 34 4
## 2-4 kali 21 207 19
## >= 5 kali 6 51 59
accuracy <- sum(diag(conf_matrix)) / sum(conf_matrix)
cat("\nAkurasi:", round(accuracy * 100, 2), "%\n")##
## Akurasi: 68.82 %
Model menghasilkan akurasi klasifikasi 68,8% — kemampuan prediksi yang cukup baik untuk data respons ordinal dalam konteks penelitian perilaku konsumen.
# Model sederhana hanya Frekuensi_Ecommerce untuk keperluan visualisasi
data_simple <- data_ord
data_simple$Eco <- as.numeric(data_simple$Frekuensi_Ecommerce)
fit_simple <- MASS::polr(Frekuensi_BNPL ~ Eco, data = data_simple, Hess = TRUE)
pred_data <- data.frame(Eco = c(2, 3, 4))
prob_pred <- predict(fit_simple, newdata = pred_data, type = "probs")
colnames(prob_pred) <- levels(data_ord$Frekuensi_BNPL)
rownames(prob_pred) <- c("1–2 kali", "3–5 kali", ">5 kali")
prob_long <- as.data.frame(prob_pred) %>%
tibble::rownames_to_column("Frekuensi_Eco") %>%
tidyr::pivot_longer(-Frekuensi_Eco,
names_to = "Kategori_BNPL",
values_to = "Probabilitas") %>%
mutate(
Frekuensi_Eco = factor(Frekuensi_Eco,
levels = c("1–2 kali", "3–5 kali", ">5 kali")),
Kategori_BNPL = factor(Kategori_BNPL,
levels = levels(data_ord$Frekuensi_BNPL))
)
ggplot(prob_long,
aes(x = Frekuensi_Eco, y = Probabilitas, fill = Kategori_BNPL)) +
geom_col(width = 0.60, alpha = 0.93, color = "white") +
geom_text(aes(label = scales::percent(Probabilitas, accuracy = 0.1)),
position = position_stack(vjust = 0.5),
size = 3.5, color = "white", fontface = "bold") +
scale_fill_manual(values = c("< 2 kali" = clr_mint,
"2-4 kali" = clr_gold,
">= 5 kali" = clr_coral)) +
scale_y_continuous(labels = scales::percent_format()) +
labs(title = "Prediksi Probabilitas Frekuensi Penggunaan BNPL",
subtitle = "Berdasarkan kelompok frekuensi transaksi e-commerce (model ilustrasi)",
x = "Frekuensi E-commerce per Bulan",
y = "Probabilitas",
fill = "Frekuensi BNPL") +
theme_adk()Gambar 1. Prediksi Probabilitas Frekuensi BNPL Berdasarkan Frekuensi E-Commerce
Pada kelompok e-commerce 1–2 kali: proporsi BNPL sering (≥5 kali) hanya 28,4%. Sebaliknya, pada kelompok >5 kali: proporsi BNPL sering mendominasi hingga 91,7% — pergeseran distribusi yang sangat tajam mengkonfirmasi frekuensi e-commerce sebagai prediktor paling dominan.
x_range <- seq(1, 4, length.out = 100)
pred_probs <- predict(fit_simple, newdata = data.frame(Eco = x_range), type = "probs")
cum_logit <- data.frame(
Ecommerce = rep(x_range, 2),
Logit = c(
qlogis(pred_probs[, 1]),
qlogis(pred_probs[, 1] + pred_probs[, 2])
),
Batas = factor(
rep(c("P(Y ≤ <2 kali)", "P(Y ≤ 2–4 kali)"), each = length(x_range)),
levels = c("P(Y ≤ <2 kali)", "P(Y ≤ 2–4 kali)")
)
)
ggplot(cum_logit, aes(x = Ecommerce, y = Logit, color = Batas)) +
geom_line(linewidth = 1.4) +
scale_color_manual(values = c("P(Y ≤ <2 kali)" = clr_mint,
"P(Y ≤ 2–4 kali)" = clr_coral)) +
labs(title = "Cumulative Logit vs Frekuensi E-Commerce",
subtitle = "Garis paralel → asumsi proportional odds terpenuhi untuk variabel ini",
x = "Frekuensi E-commerce (2 = 1–2×, 3 = 3–5×, 4 = >5×)",
y = "Logit peluang kumulatif",
color = "Batas kumulatif") +
theme_adk()Gambar 2. Ilustrasi Cumulative Logit vs Frekuensi E-Commerce
Kedua kurva logit kumulatif membentuk garis yang relatif sejajar (paralel) — mengkonfirmasi bahwa asumsi proportional odds terpenuhi untuk variabel frekuensi e-commerce, konsisten dengan hasil nominal_test (p = 0,059).
## ========== RINGKASAN HASIL ANALISIS ==========
## Ukuran sampel : 433 responden
cat("Model yang digunakan :",
ifelse(jenis_model == "polr",
"Proportional Odds (polr)",
"Partial Proportional Odds — CLM dengan efek nominal"), "\n")## Model yang digunakan : Partial Proportional Odds — CLM dengan efek nominal
cat("VIF maksimum :", round(max(vif_values), 3),
ifelse(max(vif_values) < 5, "— Terpenuhi", "— Bermasalah"), "\n")## VIF maksimum : 1.702 — Terpenuhi
cat("Proportional odds p-min:", round(p_min, 4),
ifelse(p_min > 0.05, "— Terpenuhi",
"— TIDAK Terpenuhi (PPO digunakan)"), "\n")## Proportional odds p-min: 2e-04 — TIDAK Terpenuhi (PPO digunakan)
akurasi <- mean(pred_class == aktual)
cat("Akurasi model :", paste0(round(akurasi * 100, 1), "%"), "\n")## Akurasi model : 68.8%
## AIC : 712.48
## McFadden R² : 0.1808
cat("Nagelkerke R² :", round(
(1 - exp((2/n)*(ll_null_val - ll_full_val))) /
(1 - exp((2/n)*ll_null_val)), 4), "\n")## Nagelkerke R² : 0.3451
## ==============================================
Kesimpulan Utama
Penelitian ini berhasil mengidentifikasi faktor-faktor yang memengaruhi frekuensi penggunaan layanan Buy Now Pay Later (BNPL) menggunakan pendekatan Regresi Logistik Ordinal. Berdasarkan hasil pengujian asumsi, model yang paling sesuai adalah Partial Proportional Odds (PPO) karena variabel usia dan pemasukan bulanan tidak memenuhi asumsi proportional odds.
Model yang dibangun terbukti layak digunakan untuk analisis. Hasil Likelihood Ratio Test (LRT) menunjukkan model signifikan (p < 0,001), dengan Nagelkerke R² sebesar 34,5% dan akurasi klasifikasi sebesar 68,8%, sehingga model memiliki kemampuan yang cukup baik dalam menjelaskan variasi frekuensi penggunaan BNPL.
Dari seluruh variabel yang diteliti, terdapat tiga variabel yang berpengaruh signifikan, yaitu usia, frekuensi transaksi e-commerce, dan pemasukan bulanan. Sementara itu, gender dan tingkat pendidikan tidak menunjukkan pengaruh yang signifikan terhadap frekuensi penggunaan BNPL.
Variabel usia menunjukkan bahwa kelompok usia produktif merupakan pengguna BNPL yang paling aktif. Responden berusia 25–34 tahun memiliki peluang sekitar 5,2 kali lebih besar, sedangkan kelompok 35–44 tahun memiliki peluang sekitar 8 kali lebih besar untuk berada pada kategori penggunaan BNPL yang lebih tinggi dibandingkan kelompok usia di bawah 25 tahun.
Variabel frekuensi transaksi e-commerce menjadi faktor yang paling dominan dalam model. Responden yang bertransaksi 3–5 kali per bulan memiliki peluang 5 kali lebih besar menggunakan BNPL lebih sering, sedangkan responden yang bertransaksi lebih dari 5 kali per bulan memiliki peluang 31,7 kali lebih besar untuk menjadi pengguna BNPL dengan intensitas tinggi.
Variabel pemasukan bulanan berpengaruh terhadap peningkatan penggunaan BNPL pada kategori penggunaan yang lebih intensif. Kelompok dengan pendapatan Rp5–10 juta per bulan memiliki peluang tertinggi, yaitu sekitar 25,8 kali lebih besar untuk menjadi pengguna BNPL intensif dibandingkan kelompok berpendapatan kurang dari Rp3 juta per bulan.
Secara umum, profil pengguna BNPL yang paling aktif di Indonesia adalah individu yang berusia 25–44 tahun, memiliki pendapatan menengah ke atas, dan aktif bertransaksi di platform e-commerce. Temuan ini dapat menjadi dasar bagi penyedia layanan BNPL dalam menyusun strategi pemasaran yang lebih tepat sasaran serta bagi regulator dalam mengawasi potensi risiko penggunaan BNPL yang berlebihan.
Gender dan tingkat pendidikan tidak menunjukkan pengaruh signifikan setelah dikontrol variabel lain.
Referensi Utama
Analisis dilakukan dengan R · Paket: MASS, ordinal, car, tidyverse, kableExtra · Template: Mint & Deep Coral · Statistika FMIPA Unpad