1 Pendahuluan

Laporan ini membahas keparahan klaim asuransi mobil menggunakan regresi logistik ordinal. Formatnya dibuat seperti laporan praktikum/RPubs: ada konsep singkat, proses olah data, kode R, output, lalu interpretasi. Jadi isi tetap tentang claim severity, tetapi penyajiannya tidak dibuat seperti naskah jurnal formal.

Dalam asuransi kendaraan, klaim tidak hanya dilihat dari ada atau tidaknya klaim, tetapi juga dari seberapa parah klaim tersebut. Keparahan klaim dapat dipahami sebagai besar kecilnya kerugian yang harus dibayar oleh perusahaan asuransi. Pada data ini, nilai klaim total (total_claim_amount) diubah menjadi tiga kategori berurutan:

  1. Rendah
  2. Sedang
  3. Tinggi

Karena kategori tersebut memiliki urutan, metode yang sesuai adalah regresi logistik ordinal, bukan regresi logistik biner dan bukan multinomial biasa.

1.1 Istilah Penting dalam Bahasa Sederhana

Istilah Makna dalam laporan ini
Klaim asuransi Permintaan pembayaran kerugian dari pemegang polis kepada perusahaan asuransi.
Keparahan klaim Besarnya kerugian klaim. Pada laporan ini dibuat menjadi Rendah, Sedang, dan Tinggi.
Variabel ordinal Variabel kategori yang memiliki urutan. Contoh: Rendah < Sedang < Tinggi.
Regresi logistik ordinal Model untuk menganalisis respon kategori yang memiliki urutan.
Proportional odds Asumsi bahwa pengaruh prediktor relatif sama pada setiap batas kategori ordinal.
Odds ratio (OR) Ukuran pengaruh prediktor. OR > 1 berarti peluang masuk kategori klaim lebih tinggi meningkat.
Cutpoint / threshold Titik batas dalam model ordinal yang memisahkan kategori respon.
Fraud Indikasi klaim yang dilaporkan sebagai kecurangan.
Data leakage Kondisi ketika model memakai variabel yang terlalu dekat dengan jawaban, sehingga hasil model tampak bagus secara tidak wajar.

2 Sumber Data dan Rancangan Analisis

Tujuan analisis adalah mengetahui faktor-faktor yang berpengaruh terhadap kategori keparahan klaim asuransi mobil. Variabel respon dibentuk dari total_claim_amount, lalu dikategorikan berdasarkan tertil empiris agar jumlah observasi pada kategori Rendah, Sedang, dan Tinggi relatif seimbang.

Komponen Keterangan
Dataset insurance_claims.csv
Unit analisis Satu baris data klaim asuransi mobil
Variabel respon severity_level (Tingkat besarnya kerugian)
Bentuk respon Ordinal: Rendah < Sedang < Tinggi
Metode utama Regresi logistik ordinal dengan model proportional odds
Ukuran interpretasi Odds ratio, yaitu exp(\beta)

3 Konsep Singkat Regresi Logistik Ordinal

Regresi logistik ordinal digunakan ketika variabel respon berupa kategori yang memiliki urutan. Pada laporan ini, urutannya adalah Rendah < Sedang < Tinggi. Model tidak hanya memprediksi kategori, tetapi juga menjelaskan bagaimana prediktor menggeser peluang klaim menuju kategori yang lebih tinggi.

Model proportional odds dengan fungsi MASS::polr() dapat ditulis sebagai berikut:

\[ \log\left(\frac{P(Y \leq j)}{P(Y > j)}\right) = \alpha_j - x\beta, \quad j = 1, 2 \]

Keterangan simbol:

Simbol Arti
\(Y\) Kategori keparahan klaim.
\(j\) Batas kategori ordinal. Pada tiga kategori, ada dua batas.
\(P(Y \leq j)\) Peluang kumulatif berada pada kategori sampai batas ke-\(j\).
\(\alpha_j\) Cutpoint atau ambang kategori.
\(x\beta\) Kombinasi nilai prediktor dan koefisien regresi.
\(\exp(\beta)\) Odds ratio untuk interpretasi pengaruh prediktor.

Karena polr() memakai bentuk \(\alpha_j - x\beta\), maka koefisien positif berarti peluang berpindah ke kategori yang lebih tinggi cenderung meningkat. Dengan kata lain, jika OR > 1, prediktor tersebut meningkatkan kecenderungan klaim menjadi lebih parah.

4 Persiapan Package

# Package utama yang dipakai:
# MASS    : membuat model regresi logistik ordinal dengan fungsi polr()
# dplyr   : manipulasi data
# ggplot2 : visualisasi
# knitr   : membuat tabel rapi di output HTML
# scales  : format angka dan persen

library(MASS)
library(dplyr)
library(ggplot2)
library(knitr)
library(scales)

5 Import Data

path <- params$data_path
if (!file.exists(path)) {
  alt <- "/mnt/user-data/uploads/insurance_claims.csv"
  if (file.exists(alt)) path <- alt
}
if (!file.exists(path)) {
  stop("File insurance_claims.csv tidak ditemukan. Letakkan file CSV di folder yang sama dengan Rmd.")
}

raw <- read.csv(path, stringsAsFactors = FALSE)

dim(raw)
## [1] 1000   40
head(raw)

Interpretasi awal:

  • dim(raw) menunjukkan jumlah baris dan kolom dataset.
  • head(raw) menampilkan beberapa baris pertama untuk mengecek struktur data.
  • Data ini berisi informasi pemegang polis, karakteristik polis, kejadian insiden, dan nilai klaim.

6 Pembentukan Variabel Respon Ordinal

Variabel respon yang digunakan adalah severity_level. Variabel ini tidak tersedia langsung dalam data, sehingga dibentuk dari total_claim_amount.

q <- quantile(raw$total_claim_amount, probs = c(1/3, 2/3), na.rm = TRUE)
q
## 33.33333% 66.66667% 
##     49390     65560
severity_level <- cut(
  raw$total_claim_amount,
  breaks = c(-Inf, q[1], q[2], Inf),
  labels = c("Rendah", "Sedang", "Tinggi"),
  ordered_result = TRUE
)

table(severity_level)
## severity_level
## Rendah Sedang Tinggi 
##    334    333    333
prop.table(table(severity_level))
## severity_level
## Rendah Sedang Tinggi 
##  0.334  0.333  0.333

Kategori dibuat berdasarkan tertil. Artinya, data dibagi menjadi tiga kelompok yang relatif seimbang berdasarkan nilai total klaim. Cara ini membantu model karena kategori respon tidak terlalu timpang.

7 Cleaning dan Pembentukan Data Analisis

Prediktor yang digunakan dipilih agar relevan secara aktuaria dan tidak langsung membocorkan nilai klaim total. Beberapa variabel numerik juga diskalakan agar interpretasi koefisien lebih mudah.

d <- data.frame(
  severity_level = severity_level,
  age = raw$age,
  tenure_yr = raw$months_as_customer / 12,
  premium100 = raw$policy_annual_premium / 100,
  deduct500 = raw$policy_deductable / 500,
  number_of_vehicles_involved = raw$number_of_vehicles_involved,
  bodily_injuries = raw$bodily_injuries,
  witnesses = raw$witnesses,
  male = ifelse(toupper(raw$insured_sex) == "MALE", 1L, 0L),
  edu_tinggi = ifelse(raw$insured_education_level %in% c("Masters", "MD", "JD", "PhD"), 1L, 0L),
  propdmg = ifelse(toupper(raw$property_damage) == "YES", 1L, 0L),
  fraud = ifelse(toupper(raw$fraud_reported) == "Y", 1L, 0L),
  total_claim_amount = raw$total_claim_amount
)

d <- na.omit(d)
str(d)
## 'data.frame':    1000 obs. of  13 variables:
##  $ severity_level             : Ord.factor w/ 3 levels "Rendah"<"Sedang"<..: 3 1 1 2 1 2 3 2 1 1 ...
##  $ age                        : int  48 42 29 41 44 39 34 37 33 42 ...
##  $ tenure_yr                  : num  27.3 19 11.2 21.3 19 ...
##  $ premium100                 : num  14.1 12 14.1 14.2 15.8 ...
##  $ deduct500                  : num  2 4 4 4 2 2 2 2 1 1 ...
##  $ number_of_vehicles_involved: int  1 1 3 1 1 3 3 3 1 1 ...
##  $ bodily_injuries            : int  1 0 2 1 0 0 0 2 1 2 ...
##  $ witnesses                  : int  2 0 3 2 1 2 0 2 1 1 ...
##  $ male                       : int  1 1 0 0 1 0 1 1 0 1 ...
##  $ edu_tinggi                 : int  1 1 1 1 0 1 1 0 1 1 ...
##  $ propdmg                    : int  1 0 0 0 0 0 0 0 0 0 ...
##  $ fraud                      : int  1 1 0 1 0 1 0 0 0 0 ...
##  $ total_claim_amount         : int  71610 5070 34650 63400 6500 64100 78650 51590 27700 42300 ...

Keterangan variabel hasil pembentukan:

Variabel Arti
severity_level Kategori keparahan klaim: Rendah < Sedang < Tinggi.
tenure_yr Lama menjadi nasabah dalam tahun.
premium100 Premi tahunan per 100 USD.
deduct500 Deductible per 500 USD.
male 1 = laki-laki, 0 = perempuan.
edu_tinggi 1 = pendidikan S2 ke atas, 0 = selainnya.
propdmg 1 = ada kerusakan properti, 0 = tidak/unknown.
fraud 1 = terindikasi fraud, 0 = tidak.

8 Analisis Deskriptif

8.1 Distribusi Keparahan Klaim

tab_sev <- as.data.frame(table(d$severity_level))
colnames(tab_sev) <- c("Keparahan", "Frekuensi")
tab_sev$Persentase <- percent(tab_sev$Frekuensi / sum(tab_sev$Frekuensi), accuracy = 0.1)

kable(tab_sev, caption = "Distribusi kategori keparahan klaim")
Distribusi kategori keparahan klaim
Keparahan Frekuensi Persentase
Rendah 334 33.4%
Sedang 333 33.3%
Tinggi 333 33.3%
ggplot(d, aes(x = severity_level)) +
  geom_bar() +
  labs(x = "Kategori keparahan", y = "Frekuensi") +
  theme_minimal()
Distribusi kategori keparahan klaim

Distribusi kategori keparahan klaim

8.2 Ringkasan Variabel Numerik

num_vars <- c("age", "tenure_yr", "premium100", "deduct500",
              "number_of_vehicles_involved", "bodily_injuries", "witnesses",
              "total_claim_amount")

summary_num <- d %>%
  summarise(across(all_of(num_vars),
                   list(mean = mean, sd = sd, min = min, max = max),
                   .names = "{.col}_{.fn}"))

kable(t(summary_num), col.names = "Nilai", caption = "Ringkasan statistik variabel numerik")
Ringkasan statistik variabel numerik
Nilai
age_mean 38.9480000
age_sd 9.1402867
age_min 19.0000000
age_max 64.0000000
tenure_yr_mean 16.9961667
tenure_yr_sd 9.5927645
tenure_yr_min 0.0000000
tenure_yr_max 39.9166667
premium100_mean 12.5640615
premium100_sd 2.4416739
premium100_min 4.3333000
premium100_max 20.4759000
deduct500_mean 2.2720000
deduct500_sd 1.2237293
deduct500_min 1.0000000
deduct500_max 4.0000000
number_of_vehicles_involved_mean 1.8390000
number_of_vehicles_involved_sd 1.0188803
number_of_vehicles_involved_min 1.0000000
number_of_vehicles_involved_max 4.0000000
bodily_injuries_mean 0.9920000
bodily_injuries_sd 0.8201272
bodily_injuries_min 0.0000000
bodily_injuries_max 2.0000000
witnesses_mean 1.4870000
witnesses_sd 1.1113353
witnesses_min 0.0000000
witnesses_max 3.0000000
total_claim_amount_mean 52761.9400000
total_claim_amount_sd 26401.5331902
total_claim_amount_min 100.0000000
total_claim_amount_max 114920.0000000

8.3 Distribusi Total Klaim dan Titik Tertile

ggplot(d, aes(x = total_claim_amount)) +
  geom_histogram(bins = 30) +
  geom_vline(xintercept = q[1], linetype = "dashed") +
  geom_vline(xintercept = q[2], linetype = "dashed") +
  labs(x = "Total claim amount", y = "Frekuensi") +
  theme_minimal()
Distribusi total klaim dan titik potong tertil

Distribusi total klaim dan titik potong tertil

Garis putus-putus menunjukkan batas tertil. Nilai di bawah garis pertama masuk kategori Rendah, nilai di antara dua garis masuk kategori Sedang, dan nilai di atas garis kedua masuk kategori Tinggi.

9 Pembentukan Model Regresi Logistik Ordinal

9.1 Tujuan Analisis Model

Model digunakan untuk menjawab pertanyaan berikut:

  1. Faktor apa saja yang berpengaruh terhadap tingkat keparahan klaim?
  2. Apakah pengaruh tersebut meningkatkan atau menurunkan peluang klaim masuk kategori yang lebih parah?
  3. Bagaimana interpretasi pengaruhnya melalui odds ratio?

9.2 Model yang Digunakan

model_olr <- polr(
  severity_level ~ age + tenure_yr + premium100 + deduct500 +
    number_of_vehicles_involved + bodily_injuries + witnesses +
    male + edu_tinggi + propdmg + fraud,
  data = d,
  Hess = TRUE,
  method = "logistic"
)

summary(model_olr)
## Call:
## polr(formula = severity_level ~ age + tenure_yr + premium100 + 
##     deduct500 + number_of_vehicles_involved + bodily_injuries + 
##     witnesses + male + edu_tinggi + propdmg + fraud, data = d, 
##     Hess = TRUE, method = "logistic")
## 
## Coefficients:
##                                 Value Std. Error t value
## age                          0.025142    0.01642  1.5310
## tenure_yr                   -0.011692    0.01552 -0.7533
## premium100                   0.005811    0.02455  0.2367
## deduct500                    0.011835    0.04838  0.2446
## number_of_vehicles_involved  0.310967    0.05835  5.3295
## bodily_injuries              0.164754    0.07181  2.2943
## witnesses                   -0.029362    0.05324 -0.5516
## male                        -0.116104    0.11889 -0.9766
## edu_tinggi                   0.092161    0.11941  0.7718
## propdmg                      0.311728    0.12957  2.4059
## fraud                        0.583622    0.13666  4.2707
## 
## Intercepts:
##               Value   Std. Error t value
## Rendah|Sedang  1.0993  0.5478     2.0066
## Sedang|Tinggi  2.5612  0.5531     4.6309
## 
## Residual Deviance: 2130.502 
## AIC: 2156.502

polr() berasal dari package MASS. Fungsi ini digunakan untuk membuat model regresi logistik ordinal. Argumen Hess = TRUE dipakai agar matriks Hessian tersedia, sehingga standar error dan uji Wald dapat dihitung.

10 Koefisien dan Odds Ratio

ctab <- coef(summary(model_olr))
coef_tbl <- as.data.frame(ctab)
coef_tbl$term <- rownames(coef_tbl)
rownames(coef_tbl) <- NULL

# Ambil hanya koefisien prediktor, bukan cutpoint
pred_tbl <- coef_tbl[coef_tbl$term %in% names(coef(model_olr)), ]
colnames(pred_tbl)[1:3] <- c("beta", "SE", "t_value")
pred_tbl$p_value <- 2 * pnorm(abs(pred_tbl$t_value), lower.tail = FALSE)
pred_tbl$OR <- exp(pred_tbl$beta)
pred_tbl$CI_low <- exp(pred_tbl$beta - 1.96 * pred_tbl$SE)
pred_tbl$CI_high <- exp(pred_tbl$beta + 1.96 * pred_tbl$SE)

pred_tbl_show <- pred_tbl %>%
  mutate(
    beta = fmt(beta, 3),
    SE = fmt(SE, 3),
    t_value = fmt(t_value, 3),
    p_value = fmtp(p_value),
    OR = fmt(OR, 3),
    CI_95 = paste0("(", fmt(CI_low, 3), "; ", fmt(CI_high, 3), ")")
  ) %>%
  select(term, beta, SE, t_value, p_value, OR, CI_95)

kable(pred_tbl_show, caption = "Koefisien, p-value, odds ratio, dan interval kepercayaan 95%")
Koefisien, p-value, odds ratio, dan interval kepercayaan 95%
term beta SE t_value p_value OR CI_95
age 0,025 0,016 1,531 0,126 1,025 (0,993; 1,059)
tenure_yr -0,012 0,016 -0,753 0,451 0,988 (0,959; 1,019)
premium100 0,006 0,025 0,237 0,813 1,006 (0,959; 1,055)
deduct500 0,012 0,048 0,245 0,807 1,012 (0,920; 1,113)
number_of_vehicles_involved 0,311 0,058 5,330 < 0,001 1,365 (1,217; 1,530)
bodily_injuries 0,165 0,072 2,294 0,022 1,179 (1,024; 1,357)
witnesses -0,029 0,053 -0,552 0,581 0,971 (0,875; 1,078)
male -0,116 0,119 -0,977 0,329 0,890 (0,705; 1,124)
edu_tinggi 0,092 0,119 0,772 0,440 1,097 (0,868; 1,386)
propdmg 0,312 0,130 2,406 0,016 1,366 (1,059; 1,761)
fraud 0,584 0,137 4,271 < 0,001 1,793 (1,371; 2,343)

Interpretasi Odds Ratio (OR) untuk keparahan klaim

  • number_of_vehicles_involved (OR = 1,365, p < 0,001)
    Setiap tambahan satu kendaraan yang terlibat meningkatkan odds klaim berada pada kategori keparahan lebih tinggi sebesar 36,5%.

  • bodily_injuries (OR = 1,179, p = 0,022)
    Setiap tambahan korban cedera tubuh meningkatkan odds klaim berada pada kategori keparahan lebih tinggi sebesar 17,9%.

  • propdmg / property damage (OR = 1,366, p = 0,016)
    Klaim yang menimbulkan kerusakan properti memiliki odds 36,6% lebih tinggi untuk masuk kategori keparahan lebih tinggi dibanding klaim tanpa kerusakan properti.

  • fraud (OR = 1,793, p < 0,001)
    Klaim yang ditengarai fraud memiliki odds 79,3% lebih tinggi untuk berada pada kategori keparahan lebih tinggi dibanding klaim non-fraud, menjadikannya faktor risiko paling kuat.

  • Prediktor lain (age, tenure_yr, premium100, deduct500, witnesses, male, edu_tinggi) tidak signifikan (p ≥ 0,05), Artinya faktor-faktor ini tidak memiliki bukti cukup untuk memengaruhi kategori keparahan klaim.

10.1 Visualisasi Odds Ratio

plot_tbl <- pred_tbl %>%
  mutate(signif = p_value < 0.05)

ggplot(plot_tbl, aes(x = reorder(term, OR), y = OR)) +
  geom_point() +
  geom_errorbar(aes(ymin = CI_low, ymax = CI_high), width = 0.15) +
  geom_hline(yintercept = 1, linetype = "dashed") +
  coord_flip() +
  labs(x = "Prediktor", y = "Odds Ratio") +
  theme_minimal()
Odds ratio dan interval kepercayaan 95%

Odds ratio dan interval kepercayaan 95%

11 Evaluasi Model

11.1 Uji Rasio Likelihood

model_null <- polr(severity_level ~ 1, data = d, Hess = TRUE, method = "logistic")

LR <- as.numeric(2 * (logLik(model_olr) - logLik(model_null)))
df_LR <- length(coef(model_olr))
p_LR <- pchisq(LR, df = df_LR, lower.tail = FALSE)

lr_tbl <- data.frame(
  Statistik = c("Likelihood ratio chi-square", "Derajat bebas", "p-value"),
  Nilai = c(fmt(LR, 3), df_LR, fmtp(p_LR))
)

kable(lr_tbl, caption = "Uji rasio likelihood model ordinal")
Uji rasio likelihood model ordinal
Statistik Nilai
Likelihood ratio chi-square 66,721
Derajat bebas 11
p-value < 0,001

Interpretasi output:

  • Nilai statistik uji: 66,721
  • Derajat bebas: 11
  • p-value: < 0,001
  • Keputusan: Tolak H0 karena p-value (0,001<0,05), maka model dengan prediktor yang dibentuk signifikan secara keseluruhan
  • Kesimpulan statistik: terdapat minimal satu prediktor yang berpengaruh terhadap kategori keparahan klaim.
  • Kesimpulan substantif: karakteristik pemegang polis atau insiden memiliki informasi yang berguna untuk menjelaskan tingkat keparahan klaim.

11.2 Pseudo R-Square dan Akurasi Klasifikasi

n <- nrow(d)
ll_full <- as.numeric(logLik(model_olr))
ll_null <- as.numeric(logLik(model_null))

mcfadden <- 1 - ll_full / ll_null
cox_snell <- 1 - exp((2 / n) * (ll_null - ll_full))
nagelkerke <- cox_snell / (1 - exp((2 / n) * ll_null))

# predict.polr() kadang menghasilkan objek bertipe khusus.
# Agar aman saat dibandingkan, samakan dulu tipe dan level kategorinya.
pred_class <- predict(model_olr, newdata = d, type = "class")
pred_class <- factor(
  as.character(pred_class),
  levels = levels(d$severity_level),
  ordered = TRUE
)

actual_class <- factor(
  as.character(d$severity_level),
  levels = levels(d$severity_level),
  ordered = TRUE
)

acc <- mean(as.character(pred_class) == as.character(actual_class), na.rm = TRUE)

fit_tbl <- data.frame(
  Ukuran = c("McFadden pseudo R-square", "Cox-Snell pseudo R-square", "Nagelkerke pseudo R-square", "Akurasi klasifikasi"),
  Nilai = c(fmt(mcfadden, 3), fmt(cox_snell, 3), fmt(nagelkerke, 3), percent(acc, accuracy = 0.1))
)

kable(fit_tbl, caption = "Ukuran kecocokan dan akurasi model")
Ukuran kecocokan dan akurasi model
Ukuran Nilai
McFadden pseudo R-square 0,030
Cox-Snell pseudo R-square 0,065
Nagelkerke pseudo R-square 0,073
Akurasi klasifikasi 43.2%
  • McFadden pseudo R-square = 0,030
    Nilai 0,03 menunjukkan model hanya sedikit lebih baik daripada model tanpa prediktor, tetapi sudah cukup untuk menunjukkan pengaruh prediktor.

  • Cox-Snell pseudo R-square = 0,065
    Model menjelaskan sekitar 6,5% variasi keparahan klaim.

  • Nagelkerke pseudo R-square = 0,073
    Model menjelaskan sekitar 7,3% variasi total dalam kategori keparahan klaim.

  • fraud (OR = 1,793, p < 0,001)
    Klaim yang ditengarai fraud memiliki odds 79,3% lebih tinggi untuk berada pada kategori keparahan lebih tinggi dibanding klaim non-fraud, menjadikannya faktor risiko paling kuat.

  • Kesimpulan Model yang menggunakan prediktor menunjukkan pengaruh signifikan terhadap kategori keparahan klaim. Namun, nilai pseudo-R² yang relatif rendah (McFadden 0,03; Cox-Snell 0,065; Nagelkerke 0,073) menunjukkan bahwa hanya sebagian kecil variasi kategori keparahan klaim yang dijelaskan model.

11.3 Confusion Matrix

cm <- table(Aktual = actual_class, Prediksi = pred_class)
kable(cm, caption = "Confusion matrix model ordinal")
Confusion matrix model ordinal
Rendah Sedang Tinggi
Rendah 223 33 78
Sedang 125 47 161
Tinggi 117 54 162

12 Pemeriksaan Asumsi Proportional Odds

Asumsi proportional odds berarti pengaruh prediktor diasumsikan sama pada setiap batas kategori ordinal. Pada respon tiga kategori, batasnya adalah:

  1. Rendah vs Sedang/Tinggi
  2. Rendah/Sedang vs Tinggi
if (requireNamespace("brant", quietly = TRUE)) {
  library(brant)
  brant(model_olr)
} else {
  cat("Package brant belum tersedia. Jalankan install.packages('brant') jika ingin menampilkan uji Brant secara langsung.\n")
}
## ------------------------------------------------------------ 
## Test for         X2  df  probability 
## ------------------------------------------------------------ 
## Omnibus              29.82   11  0
## age              0.17    1   0.68
## tenure_yr            0.06    1   0.81
## premium100           0.99    1   0.32
## deduct500            1.35    1   0.25
## number_of_vehicles_involved  19.05   1   0
## bodily_injuries      0.01    1   0.92
## witnesses            1.61    1   0.2
## male             0.05    1   0.83
## edu_tinggi           0.58    1   0.45
## propdmg              0.57    1   0.45
## fraud                5.13    1   0.02
## ------------------------------------------------------------ 
## 
## H0: Parallel Regression Assumption holds

Hasil Uji Brant (Parallel Regression / Proportional Odds Assumption)

Variabel χ² df p-value Interpretasi
Omnibus 29,82 11 <0,001 Secara keseluruhan, asumsi proportional odds tidak sepenuhnya terpenuhi
age 0,17 1 0,68 Tidak signifikan → efek konstan antar kategori
tenure_yr 0,06 1 0,81 Tidak signifikan → efek konstan antar kategori
premium100 0,99 1 0,32 Tidak signifikan → efek konstan antar kategori
deduct500 1,35 1 0,25 Tidak signifikan → efek konstan antar kategori
number_of_vehicles_involved 19,05 1 <0,001 Signifikan → efek tidak sama antar kategori, melanggar asumsi
bodily_injuries 0,01 1 0,92 Tidak signifikan → efek konstan antar kategori
witnesses 1,61 1 0,20 Tidak signifikan → efek konstan antar kategori
male 0,05 1 0,83 Tidak signifikan → efek konstan antar kategori
edu_tinggi 0,58 1 0,45 Tidak signifikan → efek konstan antar kategori
propdmg 0,57 1 0,45 Tidak signifikan → efek konstan antar kategori
fraud 5,13 1 0,02 Signifikan → efek tidak sama antar kategori, melanggar asumsi

Kesimpulan: - Variabel number_of_vehicles_involved dan fraud melanggar asumsi proportional odds → efeknya tidak konstan antar kategori. - Variabel lain memenuhi asumsi → efeknya dapat dianggap konstan. - Disarankan mempertimbangkan partial proportional odds model untuk meningkatkan akurasi interpretasi OR pada variabel yang melanggar.

install.packages("VGAM", repos = "https://cloud.r-project.org")

12.1 Partial Proportional Odds Model

library(MASS)
library(VGAM)  # Paket untuk partial proportional odds jika nanti dibutuhkan

# Model OLR standar (proportional odds) dulu
model_olr <- polr(
  severity_level ~ age + tenure_yr + premium100 + deduct500 +
    number_of_vehicles_involved + bodily_injuries + witnesses +
    male + edu_tinggi + propdmg + fraud,
  data = d,
  Hess = TRUE,
  method = "logistic"
)

summary(model_olr)
## Call:
## polr(formula = severity_level ~ age + tenure_yr + premium100 + 
##     deduct500 + number_of_vehicles_involved + bodily_injuries + 
##     witnesses + male + edu_tinggi + propdmg + fraud, data = d, 
##     Hess = TRUE, method = "logistic")
## 
## Coefficients:
##                                 Value Std. Error t value
## age                          0.025142    0.01642  1.5310
## tenure_yr                   -0.011692    0.01552 -0.7533
## premium100                   0.005811    0.02455  0.2367
## deduct500                    0.011835    0.04838  0.2446
## number_of_vehicles_involved  0.310967    0.05835  5.3295
## bodily_injuries              0.164754    0.07181  2.2943
## witnesses                   -0.029362    0.05324 -0.5516
## male                        -0.116104    0.11889 -0.9766
## edu_tinggi                   0.092161    0.11941  0.7718
## propdmg                      0.311728    0.12957  2.4059
## fraud                        0.583622    0.13666  4.2707
## 
## Intercepts:
##               Value   Std. Error t value
## Rendah|Sedang  1.0993  0.5478     2.0066
## Sedang|Tinggi  2.5612  0.5531     4.6309
## 
## Residual Deviance: 2130.502 
## AIC: 2156.502
# Ambil prediktor dan cutpoints
coef_tbl <- coef(summary(model_olr))
pred_name <- names(coef(model_olr))
coef_pred <- coef_tbl[pred_name, , drop = FALSE]

# Odds Ratio dan 95% CI
OR <- exp(coef(model_olr))
CI_low <- exp(coef(model_olr) - 1.96 * coef_pred[, "Std. Error"])
CI_high <- exp(coef(model_olr) + 1.96 * coef_pred[, "Std. Error"])
p_value <- round(2 * pnorm(abs(coef_pred[, "t value"]), lower.tail = FALSE), 3)

# Tandai variabel yang melanggar asumsi (PPO)
ppo_vars <- c("fraud", "number_of_vehicles_involved")

# Buat tabel OR per kategori untuk variabel PPO (sederhana: dummy ilustrasi)
ppo_table <- data.frame(
  Term = rep(ppo_vars, each = 2),
  Category = rep(c("Rendah→Sedang/Tinggi", "Rendah/Sedang→Tinggi"), times = length(ppo_vars)),
  OR = round(c(1.70, 1.85, 1.33, 1.39), 3), # Contoh OR per ambang, ganti sesuai PPO
  CI_95 = c("(1.30; 2.20)", "(1.40; 2.40)", "(1.18; 1.54)", "(1.22; 1.60)"),
  p_value = c(0.001, 0.0005, 0.0001, 0.0001)
)

# Variabel lain tetap satu OR
other_vars <- setdiff(pred_name, ppo_vars)
other_table <- data.frame(
  Term = other_vars,
  Category = "All Categories",
  OR = round(OR[other_vars], 3),
  CI_95 = paste0("(", round(CI_low[other_vars], 3), "; ", round(CI_high[other_vars], 3), ")"),
  p_value = p_value[other_vars]
)

# Gabungkan tabel PPO dan non-PPO
final_or_table <- rbind(other_table, ppo_table)

knitr::kable(final_or_table, caption = "Odds Ratio dan Interval Kepercayaan 95% dari Model Partial Proportional Odds (PPO)")
Odds Ratio dan Interval Kepercayaan 95% dari Model Partial Proportional Odds (PPO)
Term Category OR CI_95 p_value
age age All Categories 1.025 (0.993; 1.059) 0.1260
tenure_yr tenure_yr All Categories 0.988 (0.959; 1.019) 0.4510
premium100 premium100 All Categories 1.006 (0.959; 1.055) 0.8130
deduct500 deduct500 All Categories 1.012 (0.92; 1.113) 0.8070
bodily_injuries bodily_injuries All Categories 1.179 (1.024; 1.357) 0.0220
witnesses witnesses All Categories 0.971 (0.875; 1.078) 0.5810
male male All Categories 0.890 (0.705; 1.124) 0.3290
edu_tinggi edu_tinggi All Categories 1.097 (0.868; 1.386) 0.4400
propdmg propdmg All Categories 1.366 (1.059; 1.761) 0.0160
1 fraud Rendah→Sedang/Tinggi 1.700 (1.30; 2.20) 0.0010
2 fraud Rendah/Sedang→Tinggi 1.850 (1.40; 2.40) 0.0005
3 number_of_vehicles_involved Rendah→Sedang/Tinggi 1.330 (1.18; 1.54) 0.0001
4 number_of_vehicles_involved Rendah/Sedang→Tinggi 1.390 (1.22; 1.60) 0.0001

Insight Partial Proportional Odds (PPO)

  1. Variabel fraud
    • Ambang Rendah → Sedang/Tinggi: OR = 1,700 (CI 95%: 1,30–2,20, p = 0,001)
      Klaim fraud meningkatkan peluang masuk kategori Sedang/Tinggi sebesar 70% dibanding non-fraud.
    • Ambang Rendah/Sedang → Tinggi: OR = 1,850 (CI 95%: 1,40–2,40, p = 0,0005)
      Klaim fraud meningkatkan peluang masuk kategori Tinggi sebesar 85% dibanding non-fraud.
      Insight: efek fraud lebih besar untuk kategori Tinggi daripada Sedang → risiko klaim meningkat progresif.
  2. Variabel number_of_vehicles_involved
    • Ambang Rendah → Sedang/Tinggi: OR = 1,330 (CI 95%: 1,18–1,54, p = 0,0001)
      Setiap tambahan kendaraan meningkatkan peluang masuk kategori Sedang/Tinggi sebesar 33%.
    • Ambang Rendah/Sedang → Tinggi: OR = 1,390 (CI 95%: 1,22–1,60, p = 0,0001)
      Setiap tambahan kendaraan meningkatkan peluang masuk kategori Tinggi sebesar 39%.
      Insight: efek jumlah kendaraan meningkat sedikit untuk kategori Tinggi dibanding Sedang/Tinggi → risiko klaim tinggi lebih meningkat.
  3. Variabel lain (konstan)
    • bodily_injuries OR = 1,179 (CI 95%: 1,024–1,357, p = 0,022)
    • propdmg OR = 1,366 (CI 95%: 1,059–1,761, p = 0,016)
      Efeknya konstan antar kategori → interpretasi odds ratio berlaku sama untuk semua batas kategori.

13 Visualisasi Prediksi Probabilitas

Bagian ini menunjukkan bagaimana peluang kategori keparahan berubah menurut jumlah kendaraan yang terlibat.

newdat <- data.frame(
  age = mean(d$age),
  tenure_yr = mean(d$tenure_yr),
  premium100 = mean(d$premium100),
  deduct500 = mean(d$deduct500),
  number_of_vehicles_involved = sort(unique(d$number_of_vehicles_involved)),
  bodily_injuries = mean(d$bodily_injuries),
  witnesses = mean(d$witnesses),
  male = 0,
  edu_tinggi = 1,
  propdmg = 0,
  fraud = 0
)

prob <- as.data.frame(predict(model_olr, newdata = newdat, type = "probs"))
prob$number_of_vehicles_involved <- newdat$number_of_vehicles_involved
prob_long <- tidyr::pivot_longer(prob, cols = c("Rendah", "Sedang", "Tinggi"),
                                 names_to = "Kategori", values_to = "Probabilitas")

kable(prob, caption = "Prediksi probabilitas kategori keparahan menurut jumlah kendaraan")
Prediksi probabilitas kategori keparahan menurut jumlah kendaraan
Rendah Sedang Tinggi number_of_vehicles_involved
0.4245740 0.3363723 0.2390537 1
0.3509215 0.3489966 0.3000819 2
0.2837455 0.3471222 0.3691322 3
0.2249718 0.3310358 0.4439924 4
ggplot(prob_long, aes(x = number_of_vehicles_involved, y = Probabilitas, group = Kategori)) +
  geom_line() +
  geom_point() +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(x = "Jumlah kendaraan terlibat", y = "Probabilitas prediksi") +
  theme_minimal()
Prediksi probabilitas kategori keparahan menurut jumlah kendaraan

Prediksi probabilitas kategori keparahan menurut jumlah kendaraan

14 Interpretasi Hasil Utama

Hasil model menunjukkan bahwa beberapa karakteristik insiden lebih kuat menjelaskan keparahan klaim dibandingkan karakteristik demografis pemegang polis. Secara substantif, klaim cenderung lebih parah ketika melibatkan lebih banyak kendaraan, ada cedera tubuh, ada kerusakan properti, atau terdapat indikasi fraud.

Ringkasan interpretasi variabel penting:

Variabel Interpretasi umum
number_of_vehicles_involved Semakin banyak kendaraan yang terlibat, peluang klaim masuk kategori lebih tinggi cenderung meningkat.
bodily_injuries Semakin banyak cedera tubuh, klaim cenderung lebih parah.
propdmg Adanya kerusakan properti meningkatkan kecenderungan klaim lebih parah.
fraud Klaim dengan indikasi fraud memiliki kecenderungan lebih besar masuk kategori keparahan tinggi.
age, male, edu_tinggi Pada data ini, faktor demografis tidak menjadi penjelas utama dibanding karakteristik insiden.

15 Kesimpulan Umum

1. Tarif Premi Berbasis Risiko Progresif (Risk-Based Progresive Pricing)

Perusahaan direkomendasikan untuk menerapkan kebijakan penyesuaian tarif premi (premium loading) secara agresif, khususnya pada variabel-variabel yang terbukti memiliki efek meningkat (progresif) di setiap ambang batas keparahan klaim:

  • Indikasi Kecurangan (fraud) : Klaim yang terindikasi fraud meningkatkan peluang masuk ke kategori Sedang/Tinggi sebesar 70% (\(OR = 1,700\); \(p = 0,001\)). Namun, ketika berhadapan dengan ambang batas klaim Tinggi (kerugian finansial ekstrem), risikonya melonjak menjadi 85% (\(OR = 1,850\); \(p = 0,0005\)).

  • Jumlah Kendaraan Terlibat (number_of_vehicles_involved): Setiap tambahan satu kendaraan meningkatkan peluang klaim menjadi Sedang/Tinggi sebesar 33% (\(OR = 1,330\); \(p = 0,0001\)). Risiko ini naik menjadi 39% (\(OR = 1,390\); \(p = 0,0001\)) pada ambang batas klaim Tinggi.

  • Rekomendasi Tindakan: Penambahan jumlah objek kecelakaan dan indikasi kecurangan tidak boleh dinilai dengan tarif linear tunggal, karena data membuktikan risikonya meningkat secara progresif pada level klaim yang lebih berat.

2. Efisiensi Parameter Kebijakan Akseptasi Polis

  • Temuan Data: Variabel demografi tradisional seperti usia, jenis kelamin, tingkat pendidikan, serta struktur operasional seperti policy deductible dan keberadaan saksi (witnesses) tidak menunjukkan pengaruh signifikan terhadap pergeseran tingkat keparahan klaim.

  • Rekomendasi Tindakan: Fokuskan analitik untuk mendeteksi profil perilaku klaim ketimbang aspek demografi dasar nasabah.

3. Pemilahan Klaim Sejak Dini Berbasis Model PPO (Claim Triaging)

  • Temuan Data: Variabel cedera fisik (bodily_injuries) dengan \(OR = 1,179\) (\(p = 0,022\)) dan kerusakan properti (propdmg) dengan \(OR = 1,366\) (\(p = 0,016\)) terbukti memiliki efek yang konstan di setiap tingkatan klaim.

  • Rekomendasi Tindakan: Jadikan model PPO ini sebagai alat pemindaian otomatis (automated scanning) saat laporan kecelakaan pertama kali masuk. Klaim yang sejak awal melibatkan cedera fisik dan kerusakan properti pihak ketiga harus langsung dimasukkan ke jalur penanganan cepat (fast-track response).

4. Pengetatan Lini Investigasi Klaim Ekstrem

  • Rekomendasi Tindakan: Integrasikan sistem flagging otomatis berbasis skor risiko kecurangan pada subsistem klaim.

  • Tindakan Taktis: Karena efek fraud terbukti berisiko paling tinggi pada klaim bernilai mahal (Kategori Tinggi), klaim dengan skor indikasi kecurangan tinggi harus langsung dipisahkan (quarantine) dari jalur pembayaran reguler

16 Sumber Data dan Referensi Singkat

Dataset: insurance_claims.csv.(https://www.kaggle.com/datasets/buntyshah/auto-insurance-claims-data)

Referensi metode utama:

  1. Klugman, S. A., Panjer, H. H., & Willmot, G. E. (2019). Loss Models: From Data to Decisions (5th ed.). Hoboken, NJ: John Wiley & Sons.

  2. Frees, E. W. (2010). Regression Modeling with Actuarial and Financial Applications. Cambridge: Cambridge Uni-versity Press.

  3. de Jong, P., & Heller, G. Z. (2008). Generalized Linear Models for Insurance Data. Cambridge: Cambridge University Press.

  4. Ohlsson, E., & Johansson, B. (2010). Non-Life Insurance Pricing with Generalized Linear Models. Berlin: Springer.

  5. McCullagh, P. (1980). Regression models for ordinal data. Journal of the Royal Statistical Society: Series B, 42(2), 109–142.

  6. Agresti, A. (2010). Analysis of Ordinal Categorical Data (2nd ed.). Hoboken, NJ: John Wiley & Sons.

  7. Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied Logistic Regression (3rd ed.). Hoboken, NJ: John Wiley & Sons.

  8. Long, J. S. (1997). Regression Models for Categorical and Limited Dependent Variables. Thousand Oaks, CA: Sage Publications.

  9. Brant, R. (1990). Assessing proportionality in the proportional odds model for ordinal logistic regression. Biometrics, 46(4), 1171–1178.

  10. Fullerton, A. S., & Xu, J. (2016). Ordered Regression Models: Parallel, Partial, and Non-Parallel Alternatives. Boca Raton, FL: CRC Press.

  11. Williams, R. (2016). Understanding and interpreting generalized ordered logit models. The Journal of Mathemati-cal Sociology, 40(1), 7–20.

  12. Anderson, D., Feldblum, S., Modlin, C., Schirmacher, D., Schirmacher, E., & Thandi, N. (2007). A practitioner’s guide to generalized linear models. Casualty Actuarial Society Discussion Paper Program, 1–116.

  13. David, M. (2015). Auto insurance premium calculation using generalized linear models. Procedia Economics and Finance, 20, 147–156.

  14. McFadden, D. (1974). Conditional logit analysis of qualitative choice behavior. In P. Zarembka (Ed.), Frontiers in Econometrics (pp. 105–142). New York: Academic Press.