1.3 사망률의 두 가지 역할#
이 챕터에서 배우는 것
엔진 전반을 관통하는
mortality_annual(보유계약 감쇠) 의 역할사망 보장 청구가 별도의 슬롯 으로 계산되는 이유
단순 정기보험 (일반사망) 에서 두 율이 같고, 질병 / 재해 같은 cause-specific 사망 보장에서 명시적으로 달라지는 이유
손계산 / cookbook 예제가 두 슬롯에 같은 callable 을 공유하는 안전한 입력 연결 패턴
이 챕터를 읽고 나면 다음 챕터 (1.4 보장 청구 메커니즘) 의 inforce × rate × benefit 식에서 각 슬롯의 rate 가 무엇을 의미하는지 명확해집니다.
1.3.1 사망률 = 엔진의 보편 감쇠#
엔진의 모든 cash flow 는 한 가지 양에 비례합니다 — 그 시점의 보유계약
수 inforce. 그리고 inforce 를 매월 줄이는 단 하나의 사망 관련
입력이 mortality_annual 입니다.
inforce[t+1] = inforce[t] × (1 - mortality_annual_monthly) × (1 - lapse_monthly)
contract 당 한 값. 어느 원인으로든 사람이 in-force 에서 빠지는 전체
율. 사람이 죽으면 보험료 납입도 멈추고 사업비도 발생을 멈추고 만기금도
사라지고 청구도 더 이상 못 받습니다. 그래서 mortality_annual 은 엔진
어디서도 비켜갈 수 없는 보편적 감쇠 — 보험료 cash flow, 사업비 cash
flow, 만기금 cash flow, 그리고 모든 보장의 청구 cash flow 가 같은
inforce 에 묶여 함께 줄어듭니다.
basis = fcf.Basis(
mortality_annual = lambda s, a, d: ..., # all-cause 감쇠
...
)
워크북에서는 segments 시트의 mortality_table 컬럼이 가리키는
mortality_tables 시트가 이 입력의 출처입니다. 회사별 / 성별 / 연령별
all-cause 사망률 테이블 한 장.
이 한 슬롯이 가장 큰 가정 — mortality_annual 을 +10% shock 하면
거의 모든 cash flow 가 함께 흔들립니다.
1.3.2 사망 보장의 청구는 별도 슬롯#
위 1.3.1 까지가 엔진의 보편 감쇠 이야기입니다. 그런데 사망 보장의 청구 금액 을 계산하는 자리는 따로 있습니다.
생각해보면 그래야 합니다. 사람이 죽는 사건은 mortality_annual 로 이미
inforce 에서 빠지는 효과를 냈습니다. 그 사람에게 얼마의 사망보험금이
지급되느냐 는 별개의 질문 — 보장의 약관, 면책 / 감액, 보험금액 등의
함수. 그래서 엔진은 사망 보장의 청구를 그 보장의 약관에 묶인 별도 rate
로 계산합니다.
claim_DEATH[t] = inforce[t] × DEATH.rate × DEATH.benefit
이 DEATH.rate 는 1.3.1 의 mortality_annual 과 같은 mortality 의
일종이지만, 다른 입력 슬롯:
basis = fcf.Basis(
mortality_annual = ..., # 1.3.1 의 감쇠
coverages = (fcf.CoverageRate("DEATH", rate_fn),) # 사망 보장 청구율
)
워크북에서도 다른 schema path — coverages 시트의 rate_table 컬럼이
가리키는 mortality_tables 또는 incidence_rate_tables 시트. 같은
워크북에서도 별개의 슬롯 입니다.
이 별개의 슬롯이 필요한 이유는 다음 두 절에서 사례로 확인합니다.
1.3.3 같은 숫자일 때 — 일반사망 보장 하나#
가장 단순한 정기보험을 봅시다. 사망 보장이 일반사망 (all-cause) 하나만
붙은 경우. 어느 원인으로든 사람이 죽으면 두 일이 동시에 일어납니다 —
보유계약에서 한 명 빠지고 (mortality_annual 의 일), 그 사람에게
사망보험금이 지급됨 (DEATH 보장 청구). 같은 사건의 같은 빈도라 두 율이
자연히 같은 숫자가 됩니다.
cookbook 의 손계산 예제 (1.4 / 2.1) 가 바로 이 경우라, 두 슬롯에 같은 callable 을 넘깁니다:
import numpy as np
import fastcashflow as fcf
# 사망률 함수 -- 월 사망률 1% 의 연 환산 (모든 sex/age/duration 에 동일)
death_fn = lambda s, a, d: np.full(a.shape, 1 - (1 - 0.01) ** 12)
# 해지율 함수 -- 해지 없음
lapse_fn = lambda s, a, d: np.full(d.shape, 0.0)
basis = fcf.Basis(
mortality_annual = death_fn, # 보유계약 감쇠 (all-cause)
lapse_annual = lapse_fn, # 해지율 (없음)
discount_annual = 0.03, # 할인율
ra_confidence = 0.75, # 위험조정 신뢰수준
mortality_cv = 0.10, # 사망률 변동계수
coverages = (fcf.CoverageRate("DEATH", death_fn),) # 일반사망 청구율
)
한 변수 death_fn 을 두 슬롯에 공유. “두 율이 같다” 는 사실을 코드에
명시하는 동시에, 한 쪽만 바꾸는 silent 어긋남이 구조적으로 차단됩니다.
1.3.4 다른 숫자일 때#
두 율이 명시적으로 달라지는 경우는 흔합니다. 핵심은 all-cause vs cause-specific 의 구분.
경우 1 — cause-specific 사망 보장 하나만 있을 때
사망 보장이 질병사망 / 재해사망 같은 cause-specific 이면, 보장이 하나뿐이어도 두 율이 다릅니다.
mortality_annual = rate_all_cause # 보유계약 감쇠 (all-cause)
coverages = (
fcf.CoverageRate("ADB", rate_accident), # 재해사망만 (예: 연 0.3%)
)
보유계약은 어느 원인으로든 사람이 죽으면 빠지니까 감쇠율은 all-cause (예: 연 1.2%). 하지만 사망보험금 청구는 재해 사고로 죽은 경우만 — 청구율 (0.3%) 이 all-cause 보다 훨씬 낮음. 두 율이 다른 숫자.
경우 2 — 다종 사망 보장이 함께 붙을 때
한 계약에 일반사망 + 질병사망 + 재해사망 세 보장이 함께 붙으면:
mortality_annual = rate_all_cause # all-cause (예: 연 1.2%)
coverages = (
fcf.CoverageRate("DEATH", rate_all_cause), # 일반사망 (1.2%)
fcf.CoverageRate("DISEASE_DEATH", rate_disease), # 질병사망 (0.9%)
fcf.CoverageRate("ADB", rate_accident), # 재해사망 (0.3%)
)
사람은 한 번만 죽으므로 inforce 는 all-cause 율로 한 번 감쇠. 그 한
번의 사망 사건이 여러 보장 의 청구를 동시 트리거 (재해로 죽으면 일반
사망금 + 재해사망금 둘 다 지급). 두 cause-specific 의 합 (0.9 + 0.3 =
1.2) 이 all-cause 와 일치 — 같은 사망 사건의 원인별 분해라서.
mortality_annual 을 분리하지 않고 보장 청구 식 안에 묶었다면 세 사망
보장 중 어느 하나의 rate 로만 in-force 를 감쇠해야 했을 겁니다. 분리되어
있으니 감쇠는 contract 전체에 한 번, 청구는 보장마다 자기 율.
경우 3 — calibration 출처가 다를 때
같은 일반사망 보장이어도 두 율의 source 가 다른 경우. 보유계약 감쇠는 경험률표 (실측 자료) 로 calibrate, 사망보험금 지급률은 공시 표준 mortality table (규제 의무) 로. 두 표가 다른 숫자라 두 슬롯도 다른 숫자.
1.3.5 손계산 입력 연결의 안전 패턴#
위 사례들이 fastcashflow 가 분리한 이유. 단순 정기보험 손계산은 두 값이 같지만, 두 슬롯에 별개의 값을 실수로 넘기면 결과가 silent 로 어긋납니다.
잘못된 연결 |
결과 |
|---|---|
|
보유계약 안 줄고 매월 사망보험금 청구. 무한 사망. BEL 과대평가. |
|
보유계약은 줄고 사망보험금 없음. BEL 과소평가. |
두 패턴 모두 에러 없이 통과 — 조용히 어긋나는 함정. 한 변수 공유 패턴 (death_fn
을 두 슬롯에) 이 구조적 방어.
워크북 로더는 자동 처리
fcf.read_basis("basis.xlsx") 로 워크북에서 가정을 읽으면,
segments 시트의 mortality_table 컬럼이 두 슬롯 (mortality_annual /
coverages 의 DEATH rate_table) 를 같은 table_id 로 자동 매핑.
손계산 / 단위테스트로 직접 Basis(...) 를 채울 때만 주의.
1.3.6 다음 챕터로#
이 분리를 이해하고 1.4 보장 청구 메커니즘 으로
가면, inforce × rate × benefit 식의 inforce 는 mortality_annual
이 감쇠시키는 공유 풀, 각 보장의 rate 는 그 보장의 청구 빈도임이
자연스럽게 읽힙니다. DIAGNOSIS 가 별도 undiagnosed 풀을 갖는 이유도
같은 결.