用 R 也能做精算—actuar 包学习笔记
李 皞
中国人民大学统计学院
风险管理与精算
Email: kimbooland@gmail.com
Contents
1 引言
2 数据描述
2.1 构造分组数据对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 分组数据分布图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3 计算数据经验矩 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 损失分布
3.1 损失分布种类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 损失分布的估计 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 损失随机变量的修正 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 风险理论
4.1 复合分布 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 连续分布的离散化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3 复合分布的计算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4 VaR 和 TVaR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 保单组合的模拟
5.1 复合层次模型的模拟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 模拟结果的处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6 信度理论
6.1 信度理论简述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2 层次信度模型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3 信度回归模型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
3
3
6
7
11
11
13
18
22
22
22
24
28
29
29
32
37
37
38
44
1
Chapter 1
引言
本文是对 R 中精算学专用包 actuar 使用的一个简单教程。actuar 项目开始于 2005 年,在
2006 年 2 月首次提供公开下载,其目的就是将一些常用的精算功能引入 R 系统,截止到目前,
最新的版本是 1.1-1,且该包仍在不断完善中。actuar 是一个集成化的精算函数系统,虽然其他
R 包中的很多函数可以供精算师使用,但是为了达到某个目的而寻找某个包的某个函数是一个
费时费力的过程,因此,actuar 将精算建模中常用的函数汇集到一个包中,方便了人们的使用。
目前,该包提供的函数主要涉及风险理论,损失分布和信度理论,特别是为非寿险研究提供了
很多方便的工具。
如题所示,本文是我在学习 actuar 包过程中的学习笔记,主要涉及这个包中一些函数的使
用方法和细节,对一些方法的结论也有稍许探讨,因此能简略的地方简略,而讨论的地方可能
讲的会比较详细。文章主要是针对 R 语言的初学者,因此每种函数或数据的结构进行了尽可能
直白的描述,以便于理解,如有描述不清或者错漏之处,敬请各位指正。闲话少提,下面就正
式开始咯!
2
Chapter 2
数据描述
2.1 构造分组数据对象
损失数据的类型主要分为分组数据和非分组数据。对于非分组数据的描述方法大家会比较
熟悉,无论是数量上,还是图形上的,比如均值、方差、直方图、柱形图还有核密度估计等。
因此下文的某些部分只介绍如何处理分组数据。
分组数据是精算研究中经常见到的数据类型,虽然原始的损失数据比分组数据包含有更多
的信息,但是某些情况下受条件所限,只能获得某个损失所在的范围。与此同时,将数据分组
也是处理原始数据的基本方法,通过将数据分到不同的组中,我们可以看到各组中数据的相
对频数,有助于对数据形成直观的印象 (比如我们对连续变量绘制直方图);而且在生存函数
的估计中,数据量经常成千上万,一种处理方法是选定合适的时间或损失额度间隔,对数据进
行分组,然后再使用分组数据进行生存函数的估计,这样可以有效减小计算量。现在假设我
们要把一组连续变量分为 r 组: (c0, c1], (c1, c2], . . . , (cr−1, cr],那么就需要定义 r + 1 个边界
c0, c1, . . . , cr。实际中的损失数据或生存数据都是取非负值,因此 c0 经常取 0。
对于分组数据来说,只需要知道每个组的数值范围及落在该组的观测频数,因此要构造一
个完整的分组数据只需要提供上面两个信息即可。下面是分组数据的构造函数,注意这个函数
是构造一个分组数据的结构,而非对现有连续数据进行分组,该函数返回一个分组数据的对象
(grouped data object)。
函数语法:
gouped.data(Group=c(…),freq1=c(…),freq2=c(….),…
,right=TRUE,row.names=NULL)
使用说明:
1. Group 定义的是分组的边界值,freq1 和 freq2(还可以定义 freq3 及更多) 是每条分组数据
的频数。Group,freq1 和 freq2 可以随意命名,比如我们可以将 Group 改为“分数档”,
将 freq1,freq2 改为“一班”,“二班”等,那么“一班”,“二班”就是两条分组数据,有
着共同的分组数据边界值。要注意,一定要把边界值向量放在第一个参数的位置!
2. Group 向量要比 freq 向量多出一个长度 (边界数比组数多 1)。
3. 默认分组区间是左开右闭,如果想变为左闭右开可以设置 right=FALSE。row.names 可以
自定义行的名称。
4. 返回的是一个数据框。特别要注意对第一列的处理,见下面例子。
3
例子:
> library(actuar)
> options(digits = 4)
> x = grouped.data(Group = c(0, 25, 50, 100, 150, 250, 500), Line.1 = c(30,
+
> x
31, 57, 42, 65, 84), Line.2 = c(26, 33, 31, 19, 16, 11))
Group Line.1 Line.2
26
33
31
19
16
11
1
(0, 25]
2 (25, 50]
3 (50, 100]
4 (100, 150]
5 (150, 250]
6 (250, 500]
30
31
57
42
65
84
改成左闭右开区间,并自定义行名称。
> x1 = grouped.data(Group = c(0, 25, 50, 100, 150, 250, 500), Line.1 = c(30,
+
+
> x1
31, 57, 42, 65, 84), Line.2 = c(26, 33, 31, 19, 16, 11),
right = F, row.names = LETTERS[1:6])
Group Line.1 Line.2
26
33
31
19
16
11
[0, 25)
A
B [25, 50)
C [50, 100)
D [100, 150)
E [150, 250)
F [250, 500)
30
31
57
42
65
84
为避免修改原始数据 x,以下我们将 x 赋值到 x2,对 x2 进行操作。
> x2 = x
提取某个组的数据 (某行)。
> x2[1, ]
Group Line.1 Line.2
26
30
1 (0, 25]
提取第一条分组数据 (某列)。
> x2[, 2]
[1] 30 31 57 42 65 84
提取各组的边界值。如果引用第一列你期待会出现什么结果呢?
> x2[, 1]
4
[1]
0 25
50 100 150 250 500
如同任何对数据框的操作,也可以对数据框中的数据进行修改。特别需要注意的是对第一
列的修改,一定要同时指定分组区间的左右的边界值。比如下面这条命令将第一组的右边界由
25 改为 20,同时第二组的左边界也同时变为 20:
> (x2[1, 1] = c(0, 20))
[1] 0 20
体会这样修改波及的范围。
> (x2[c(3, 4), 1] = c(55, 110, 160))
[1] 55 110 160
如果只指定一个边界的话,那就默认左右边界值相同,所以不要这样做。下面这条命令将
会导致第一组的左右边界都变为 10。
> (x2[1, 1] = 10)
[1] 10
到这里可能有人会问,如果现在我手中只有一组连续数据,如何实现对数据的分组并统计
数据落在每组中的频数呢?答案就是使用 cut 函数。
例子:
生成 100 个服从均值为 5 的指数分布的随机数。
> set.seed(5)
> z = rexp(100, rate = 0.2)
指定边界点,也是划分点。
> break.points = c(0, 1, 4, 8, 14, Inf)
> (tz = table(cut(z, breaks = break.points)))
(0,1]
16
(1,4]
35
(4,8]
26
(8,14] (14,Inf]
5
18
用汇总结果直接构造分组数据对象。
> grouped.data(Group = break.points, freq = as.matrix(tz))
Group freq
16
35
26
18
5
1]
1 (0,
4]
2 (1,
3 (4,
8]
4 (8, 14]
5 (14, Inf]
5
2.2 分组数据分布图
有了 grouped.data 对象,我们就可以对该对象进行一系列操作。首先是绘制分组数据的经
验密度函数——直方图,和经验分布函数——拱形图。
1)绘制直方图。由于数据已经被划分好组别,因此 R 会应用分组数据对象 x 的第一列划
分组距并绘制直方图,这在绘制非等距直方图时是十分方便的。由于每次只能绘制一组频率,
因此绘图时需要指定频率所在的列,如果不指定,默认绘制第一组频率 (数据框的第二列)。
例子:
> layout(matrix(1:3, 1, 3))
> hist(x[, -3], main = "Histogram of Line.1")
> hist(x[, -2], main = "Histogram of Line.2")
> hist(x, main = "Histogram for Unspecified Line")
2)绘制拱形图。如同对连续的随机变量可以绘制经验分布函数图一样,对于分组数据也可
以绘制“拱形图”(ogive),也就是令分组临界点的函数值等于累计频率,对临界点间的函数值
使用线性插值的方法构造的一条曲线。累计频率曲线的公式如下:
0
1
~Fn(x) =
(cj−x)Fn(cj1)+(x−cj1)Fn(cj )
cj−cj1
x ≤ c0
cj−1 < x ≤ cj
x > cr
(2.1)
函数 ogive(x) 输入的是分组数据对象 x,返回的是一个阶梯函数对象 (Step Function
Class),也就是说实现了分组数据对象向阶梯函数对象的转换。如果给定函数的横坐标,就可
以返回相对应的函数值,这点和 ecdf 是相同的。我们可以通过 konts 返回阶梯函数对象的临界
点/间断点,通过 plot 绘制阶梯函数。
例子:
得到一个阶梯函数。
> Fnt = ogive(x)
返回临界点。
> knots(Fnt)
[1]
0
25
50 100 150 250 500
返回临界点对应的累积频率值。
6
Histogram of Line.1x[, −3]Density01002003004005000.0000.0010.0020.0030.004Histogram of Line.2x[, −2]Density01002003004005000.0000.0040.008Histogram for Unspecified LinexDensity01002003004005000.0000.0010.0020.0030.004
> Fnt(knots(Fnt))
[1] 0.00000 0.09709 0.19741 0.38188 0.51780 0.72816 1.00000
对函数作图,得到 ogive 曲线。
> plot(Fnt)
2.3 计算数据经验矩
首先是计算经验1一阶矩。函数 mean 是一个泛型函数 (generic function)2,除可以作用于
通常的非分组数据向量对象 (vector) 以外,还可以作用于分组数据对象 (grouped.data),计算
分组数据的均值。非分组数据的经验均值就是将所有数据算术平均,分组数据的经验均值定义
为:
r∑
j=1
1
n
nj(
cj−1 + cj
2
)
(2.2)
该公式使用每组观测数乘以两端边界点的均值,得到该组的总值,将所有 r 个组的总值相加再
除以样本量 n,就得到每个观测均值的估计。该公式假设每组内的观测值分布是均匀的。
例子:
以上文中的分组数据对象 x 为例。
> x
Group Line.1 Line.2
26
33
31
(0, 25]
1
2 (25, 50]
3 (50, 100]
30
31
57
1文中经常会提到“经验 **”,比如经验分布函数,经验一阶矩等,个人理解所谓经验就是将样本当成总体去对待,
比如经验方差是除以样本量 n,而样本方差是除以 n-1,或者说在 bootstrap 方法中,使用经验分布函数去代替总体。
2又译作类函数,泛型函数将作用对象的属性也作为一个参数输入,对于不同的对象类别采用不同的方法,并得到不
同的输出。actuar 包中使得 mean 函数可以作用于 aggregateDist 和 grouped.data 对象,在加载 actuar 包后,可以
通过命令 methods(mean) 查看 mean 函数的所有方法。
7
lllllll01002003004005000.00.20.40.60.81.0ogive(x)xF(x)