Skip to contents

영어 원본 보기: Backtesting projections against held-out diagonals

1. 동기

준비금 산출과 추정(projection) 방법은 관측된 자료에 적합되지만, 실무적 가치는 과거 valuation 시점(평가 시점)에서 그 방법이 어떻게 작동했을지에 달려 있다. backtest() 는 triangle 에서 holdout 으로 지정한 만큼의 최근 대각선 (calendar diagonal)을 마스킹한 뒤, 이전 부분에 모형을 재적합하고, 그 추정값을 마스킹된 셀의 실제값과 비교함으로써 이 질문에 답한다. 이는 경과 기간 단위 홀드아웃이 아니라 대각선 단위 홀드아웃인데, “K 개월 전 valuation 시점에서 모형은 무엇이라 말했을까?” 를 모사하기 때문이다. 셀 단위 지표는 AEG (Actual-Expected Gap, 실제-예측 차이) 이며, 표준 actuarial A/E 관용에 맞춰 aeg=vactual/vpred1\mathrm{aeg} = v_{\mathrm{actual}} / v_{\mathrm{pred}} - 1 로 정의한다. 양수는 과소 추정 (실제가 기대보다 큼), 음수는 과대 추정을 의미한다.

2. 기본 사용법

library(lossratio)
data(experience)
exp     <- as_experience(experience)
tri_sur <- build_triangle(exp[cv_nm == "SUR"], cv_nm)

bt <- backtest(tri_sur, holdout = 6L)
print(bt)
#> <Backtest>
#>   fit_fn      : fit_lr
#>   value_var   : clr
#>   holdout     : 6 calendar diagonals
#>   held-out    : 123 cells
#>   AEG         : mean -13.05% / median -7.28%

기본 적합 함수는 단계 적응형(stage-adaptive, SA) 손해율 추정 (fit_lr(method = "sa")) 이며, 기본 비교 컬럼은 value_var = "clr" 이다 (누적 손해율). 반환되는 객체는 "Backtest" 리스트이며, 주요 슬롯은 다음과 같다.

  • aeg — 셀 단위 data.table (cohort, dev, actual, pred, aeg, calendar_idx).
  • col_summarydev 별로 집계된 AEG.
  • diag_summary — 대각선별로 집계된 AEG.
  • masked — 적합에 사용된 triangle (최근 대각선이 제거됨).
  • fitfit_fn 이 반환한 적합 객체 (LRFit 또는 CLFit).

summary(bt) 는 호출 메타데이터와 함께 두 요약 표를 출력한다.

3. 마스킹 후 검증 범위

holdout 만큼의 최근 대각선을 마스킹하면 Triangle 의 우하단이 짧아진다. chain ladder 는 마스킹된 데이터에 남아 있는 가장 큰 dev 까지만 추정값을 만들 수 있으므로, 그 범위를 넘어가는 셀 — 가장 오래된 코호트의 후기 dev 셀들 — 은 비교할 추정값이 아예 생성되지 않는다. 이런 셀은 자동으로 제외되어, bt$aeg 에는 실제값과 추정값이 모두 존재하는 셀만 남는다.

실무적 함의: holdout 이 커질수록 가장 오래된 코호트의 후기 dev 영역이 가장 먼저 검증에서 빠진다. 이 영역은 chain ladder 가 외삽 (관측 범위 너머로의 추정) 에 의존하는 부분으로, 본래 검증이 가장 필요한 곳인데 오히려 가장 빨리 사라진다.

4. 출력 해석

col_summary — 경과 기간별 체계적 편향. 특정 dev 에서 AEG 의 부호가 일관되게 나타나면, 그 성숙도에서 모형과 자료 사이에 구조적 불일치가 있음을 시사한다. 초기 dev 의 양의 값은 보통 부풀려진 link factor 를 반영하고, 후기 dev 의 값은 꼬리 미보정(miscalibration) 을 시사한다.

head(bt$col_summary, 8)
#>     cv_nm   dev     n   aeg_mean    aeg_med     aeg_wt
#>    <char> <int> <int>      <num>      <num>      <num>
#> 1:    SUR     2     1 -0.2210212 -0.2210212 -0.2210212
#> 2:    SUR     3     2 -0.6437701 -0.6437701 -0.6163919
#> 3:    SUR     4     3 -0.3511641 -0.1162380 -0.3498190
#> 4:    SUR     5     4 -0.3150824 -0.2157648 -0.3172642
#> 5:    SUR     6     5 -0.4607816 -0.4015157 -0.4605004
#> 6:    SUR     7     6 -0.3179501 -0.3459763 -0.3294385
#> 7:    SUR     8     6 -0.3943149 -0.4362693 -0.3951618
#> 8:    SUR     9     6 -0.3184528 -0.3718590 -0.3083244

aeg_mean 은 셀 단위 AEG 의 평균, aeg_med 는 중앙값, aeg_wt = sum(actual - pred) / sum(pred) 는 노출 가중 pooled A/E ratio 에서 1 을 뺀 값이다. 세 컬럼을 비교하면 소수의 큰 셀이 결과를 지배하는지 (aeg_wtaeg_med 와 크게 다른 경우) 또는 편향이 균일한지 식별할 수 있다.

diag_summary — 대각선 효과(calendar-year effect). 그 외에는 편향이 없는 출력에서 단 하나의 대각선만 나쁘게 나타난다면, 정적 chain ladder 가 구조상 볼 수 없는 calendar 사건 (요율 변경, 보험금 처리 방식의 변화, 일회성 충격) 을 가리킨다.

bt$diag_summary
#>     cv_nm calendar_idx     n   aeg_mean     aeg_med      aeg_wt
#>    <char>        <int> <int>      <num>       <num>       <num>
#> 1:    SUR           25    23 -0.1066364 -0.03677298 -0.07019853
#> 2:    SUR           26    22 -0.1401734 -0.05189725 -0.11335460
#> 3:    SUR           27    21 -0.1090998 -0.05853744 -0.10418242
#> 4:    SUR           28    20 -0.1311208 -0.07720194 -0.12745825
#> 5:    SUR           29    19 -0.1621096 -0.15960239 -0.16741775
#> 6:    SUR           30    18 -0.1402920 -0.10632300 -0.16505109

대각선을 가로지르는 단조로운 표류 (위 SUR 예시처럼 25, ..., 30 으로 가면서 AEG 가 점점 더 양수가 되는 패턴) 는 보통 가장 최근 대각선의 실적이 이전 코호트의 link factor 가 함의하는 수준보다 더 높게 진행되고 있음 — 즉 정적 모형이 흡수하지 못한 regime shift 가 발생했음을 시사한다.

aeg — 셀 단위 이상치. 특정 cohort × dev 셀을 진단하려면 bt$aeg 를 직접 살펴본다.

head(bt$aeg, 5)
#> Key: <cv_nm>
#>     cv_nm     cohort   dev value_actual value_pred          aeg calendar_idx
#>    <char>     <Date> <int>        <num>      <num>        <num>        <int>
#> 1:    SUR 2023-05-01    24     1.030446   1.156866 -0.109277544           25
#> 2:    SUR 2023-06-01    23     1.175862   1.182519 -0.005629942           25
#> 3:    SUR 2023-06-01    24     1.198728   1.292790 -0.072758288           26
#> 4:    SUR 2023-07-01    22     1.105530   1.113031 -0.006738881           25
#> 5:    SUR 2023-07-01    23     1.106120   1.118137 -0.010746990           26

5. 플롯 데모

"Backtest" 에는 네 가지 플롯 뷰가 등록되어 있다.

plot(bt, type = "col")    # dev 별 AEG (점 + 0 기준 점선)

plot(bt, type = "diag")   # 대각선별 AEG

plot(bt, type = "cell")   # dev 위에 그려진 코호트별 AEG 궤적

plot_triangle(bt)         # 홀드아웃 영역에 대한 발산형 팔레트 히트맵

type = "col" 은 경과 기간별 체계적 편향을 살피기에 적합하다. type = "diag" 는 대각선 효과(calendar-year drift) 를 드러낸다. type = "cell" 은 어느 코호트가 편향에 기여하는지를 노출한다. plot_triangle() 은 셀 단위 AEG 값을 기저 적합의 plot_triangle() 과 동일한 삼각 배치 위에 올려놓으며, 빨간색이 과소 추정 (actual > pred) 을 표시하는 빨강/파랑 발산형 팔레트를 사용한다.

6. 홀드아웃 선택

holdout 은 다음 두 가지 상충 효과의 균형을 잡도록 선택한다.

  • 너무 큰 경우: 마스킹된 triangle 이 가장 최근 경험을 잃게 되어, 가장 오래된 코호트들은 후기 경과 기간에서 도달 가능 셀이 거의 또는 전혀 없게 된다. 검증 집합이 불균등하게 줄어들며 초기 dev 쪽으로 편향된다.
  • 너무 작은 경우: 홀드아웃 영역이 얇은 평행사변형 밴드에 불과해, 체계적 패턴을 드러내기에 충분한 셀을 포함하지 못할 수 있다.

월별 triangle 에서는 holdout = 6L (반년) 이 일반적이며, 24~30 개의 대각선 이력이 있는 triangle 에서는 더 강한 검증을 위해 holdout = 12L (1년) 을 사용한다.

7. 적합 함수 선택

기본값인 fit_fn = fit_lr (method = “sa”, value_var = “clr”) 은 손해율 관점의 진단을 직접 제공한다. fit_lr 의 method 와 value_var 를 바꾸면 다양한 변형을 백테스트할 수 있다.

value_var 에 대한 참고. backtest(value_var = ...)스코어 컬럼(score column) 이다. 즉, 셀 단위로 실제값과 추정값을 비교하는 대상 컬럼을 가리킨다. 이는 chain ladder 적합 함수의 value_var 인자 — triangle 에서 어느 컬럼을 누적해 쌓을지 선택하는 인자 — 와 일반적으로 같은 개념이 아니다. fit_fn = fit_cl 일 때는 backtest()value_var 를 그대로 fit_cl() 에 전달하므로 두 의미가 일치한다. 반면 fit_fn = fit_lr 일 때 fit_lr 자체는 value_var 를 받지 않으며 — 항상 closs, crp, clr 세 컬럼을 동시에 추정한다 — value_varfit_lr$full 의 세 추정 컬럼 중 어느 것을 홀드아웃 실제값과 비교할지를 선택하는 역할만 한다. 매핑은 다음과 같다.

value_var fit_lr$full 의 비교 컬럼
"closs" loss_proj
"crp" exposure_proj
"clr" lr_proj
bt_sa_clr   <- backtest(tri_sur, holdout = 6L)                      # default
bt_sa_loss  <- backtest(tri_sur, holdout = 6L, value_var = "closs")
bt_ed_clr   <- backtest(tri_sur, holdout = 6L, method = "ed")
bt_cl_clr   <- backtest(tri_sur, holdout = 6L, method = "cl")

print(bt_sa_clr)
#> <Backtest>
#>   fit_fn      : fit_lr
#>   value_var   : clr
#>   holdout     : 6 calendar diagonals
#>   held-out    : 123 cells
#>   AEG         : mean -13.05% / median -7.28%

clr 을 백테스팅하는 것이 보통 더 유익한 진단이 된다. 손해율은 단위가 없고 차원이 없어 규모가 크게 다른 코호트 간에도 일관되게 비교 가능하므로, aeg_meanaeg_med 가 triangle 전체에서 일관된 의미를 가진다. 반면 closs 를 백테스팅하면 결과가 홀드아웃 대각선에서 가장 큰 코호트 쪽으로 가중된다.

단일 컬럼만 추정하면 되는 경우 (누적손해 등 손해율 형태가 아닌 단일 지표) fit_fn = fit_cl 도 지원한다.