2. R语言基础
在精算建模与保险数据分析中,R语言之所以成为主流工具,核心在于它围绕“数据结构”构建了一整套高效、可复用的分析范式。精算工作面对的数据往往同时包含数值型保费、分类型险种、字符型保单号、时间型承保日期,以及由多个字段组合而成的复杂赔付记录。理解R的数据类型与容器结构,是后续完成经验分析、损失分布拟合、准备金评估和GLM定价的前提。
一、核心原理:R的数据对象是“类型+结构”的组合
R中每一个对象都同时具有数据类型和数据结构两个属性。数据类型决定单个元素如何存储与运算,包括数值型(numeric)、整型(integer)、字符型(character)、逻辑型(logical)、复数型(complex)等;数据结构决定多个元素如何组织,包括向量、矩阵、数组、数据框和列表。精算建模中最常见的误区,是把“数据框”误认为一种数据类型,实际上它是列表的一种特殊形式,每一列可以是不同类型。
向量是R中最基本的容器,要求所有元素类型一致;若混合类型,R会执行强制转换,例如数值与字符混合时全部转为字符。矩阵是二维的同类型向量,适合存放赔付额矩阵、转移概率矩阵或相关系数矩阵。数据框是精算数据集的默认形态,行表示保单或赔案,列表示变量。列表则允许元素类型和长度完全不同,常用于存放模型对象、参数估计结果和多个表格。
二、方法流程:从原始数据到可建模对象
在保险数据分析中,建议按以下流程组织R对象:第一步,用c()创建向量,录入保费、赔付额等基础序列;第二步,用matrix()或array()构造多维同类型数据,例如险种间的转移矩阵;第三步,用data.frame()或read.csv()整合为保单—赔案表;第四步,用factor()将险种、地区、渠道等字符变量转为因子,供建模使用;第五步,用list()封装模型输出、参数和诊断结果。
# 1. 向量:录入10张保单的保费
premium <- c(1200, 980, 1500, 760, 2100, 1350, 890, 1750, 640, 1980)
# 2. 因子:险种分类
line <- factor(c("车险","车险","寿险","寿险","车险",
"健康险","健康险","车险","寿险","健康险"))
# 3. 数据框:整合为保单数据集
policy <- data.frame(
policy_id = paste0("P", 1001:1010),
premium = premium,
line = line,
claim = c(0, 500, 0, 1200, 800, 0, 300, 0, 0, 1500)
)
# 4. 矩阵:险种间转移频数
trans_mat <- matrix(c(50, 10, 5,
8, 40, 12,
6, 9, 35), nrow = 3, byrow = TRUE,
dimnames = list(c("车险","寿险","健康险"),
c("车险","寿险","健康险")))
# 5. 列表:封装分析结果
result <- list(
data = policy,
mean_premium = mean(policy$premium),
claim_rate = mean(policy$claim > 0),
trans = trans_mat
)
三、案例场景:用数据框与因子完成险种经验分析
假设我们需要按险种计算平均保费与出险率。数据框的列选择、因子分组和聚合函数是精算汇总的核心操作。以下代码展示如何用tapply()与aggregate()完成分组统计,并输出可读结果。
# 按险种计算平均保费
tapply(policy$premium, policy$line, mean)
# 按险种汇总保费与出险次数
agg <- aggregate(cbind(premium, claim) ~ line,
data = policy,
FUN = function(x) c(mean = mean(x), sum = sum(x)))
print(agg)
# 查看因子水平与频数
table(policy$line)
levels(policy$line)
该案例中,factor不仅用于分组,还决定了建模时参照组的设置。若险种因子水平顺序不合理,GLM系数解释会发生变化。因此,精算建模前应使用relevel()明确基准水平,例如将“车险”设为参照组。
stringsAsFactors默认改为FALSE。读取CSV时建议显式指定stringsAsFactors = FALSE,再按需手动转换因子,避免意外编码。
四、常用函数清单与误区复盘
| 函数 | 作用 | 精算场景 |
|---|---|---|
c() | 创建向量 | 录入保费、赔付额序列 |
matrix() | 创建矩阵 | 转移概率、相关系数矩阵 |
data.frame() | 创建数据框 | 保单—赔案主表 |
list() | 创建列表 | 封装模型结果与参数 |
factor() | 创建因子 | 险种、地区、渠道分类 |
str() | 查看对象结构 | 检查数据类型是否正确 |
summary() | 描述性统计 | 保费与赔付分布概览 |
tapply() | 分组聚合 | 按险种计算均值 |
aggregate() | 多列分组汇总 | 险种维度经验分析 |
subset() | 条件筛选 | 提取已决赔案子集 |
as.numeric()直接转换因子,会得到水平序号而非原始数值,正确做法是先转字符再转数值;第三,矩阵按列填充而byrow默认FALSE,构造转移矩阵时若忽略该参数会导致行列错位;第四,列表用[ ]提取返回子列表,用[[ ]]才返回元素本身,建模取参时需特别注意。