在R中使用fitdistrplus包拟合SGT等分布的MLE:解决参数标准误差NaN及初始值选择问题
解决SGT分布拟合中的初始值选择与标准误差NaN问题
我在处理分布拟合和风险度量的研究时也遇到过类似的SGT拟合问题,结合你的场景给你一些具体的解决方案:
一、合理选择SGT分布的初始值
SGT分布的参数(mu, sigma, lambda, p, q)有明确的物理意义,初始值不能随意设定,否则很容易导致收敛失败或参数估计不稳定:
mu和sigma:直接用样本的均值和标准差作为初始值最稳妥,这两个参数的含义和正态分布一致,样本统计量是天然的可靠起点。lambda:控制分布的偏度,取值范围是(-1,1)。你可以先计算样本偏度,若绝对值超过1就缩放到±0.99(避免触及边界),否则直接用样本偏度作为初始值。p和q:这两个形状参数控制尾部厚度和峰度,建议从更简单的嵌套分布入手获取参考值:- 先拟合t分布,得到自由度估计值——t分布是SGT当
lambda=0且p=q的特例,你可以把t分布的自由度直接作为p和q的初始值。 - 或者先拟合GT分布(SGT的对称版本,
lambda=0),得到p和q的估计后,再加入lambda拟合完整的SGT分布。
- 先拟合t分布,得到自由度估计值——t分布是SGT当
针对你的样本数据,先处理格式问题(注意数据用逗号做小数点,需要转换):
# 处理样本数据 raw_data <- c("0", "-1,008599424", "0,73180187", "0,443174024", "-0,351935172", "-1,318784086", "-2,171323799", "1,270243431", "-0,761354019", "0,417350946", "0,906432976", "-0,066736422", "-0,867085373", "-0,119914361", "-0,300989601", "0,482518259", "0,787365385", "-1,443105439", "-0,318546686", "-3,467674998", "1,041540157", "1,371281289", "-1,176752782", "-1,116893343", "-0,127522915", "-0,658070287", "1,098348016", "0,296391358", "-0,810635352", "-0,041779322", "0,353974233", "0,120090141", "0,304927119", "-1,22772592", "0,040768364", "1,182218724", "0,123136685", "-0,682709972", "-0,174093506", "-0,539704174", "0,579080595", "0,326346169", "0,205503526", "-0,771928642", "1,490828799", "0,734822712", "-0,025733101", "0,246531452", "-0,695585736", "-0,732413919", "0,806417952", "0,396105099", "0,024558388", "-0,791232528", "0,730410255", "-1,438890702", "0,668400286", "1,440996039", "0,731823553", "0,177515522", "0,740085418", "0,926248628", "-0,63516084", "-0,89996829", "1,655117371", "0,501033581", "0,06526534", "1,320866692", "-0,496350734", "-0,10157668", "0,022333393", "-1,236934596", "-1,070586427", "0,661662029", "0,871334714", "0,758891429", "0,064748766", "-0,305132153", "-0,424033661", "1,223444774", "-0,441840866", "-0,661390655", "-2,148399329", "0,843067435", "0,601099664", "-0,329590349", "0,210791225", "-0,341341769", "-0,555892395", "0,624026986", "0,218851965", "-0,015859171", "0,524283138", "-0,855634719", "0,339281481", "0,038507713", "-1,943784688", "0,315857689", "-0,368982834", "-1,111684011", "-0,2409217", "0,421815833", "-0,079319721", "0,915338199", "0,537387704", "-0,023004636", "-0,331854888", "0,702733882", "-1,084343115", "0,16901282", "0,559404916", "-0,538587484", "0,153683523", "-0,336562411", "-0,274946953", "0,862901957", "0,117407383", "1,205205829", "0,633347347", "0,058712615", "-0,083562948", "1,343190727", "1,281380185", "0,750972389", "-1,538678151", "0,228222073", "0,635385022", "0,037379479", "-0,491444798", "-1,220272752", "1,093162287", "1,499512169", "0,041394336", "-0,113330512", "0,657485999", "-0,264647978", "0,115056075", "-0,009763771", "0,454629881", "0,322398317", "0,347112494", "0,948127411", "0,461194301", "-0,407013048", "-0,469481931", "-0,536045151", "0,114726251", "0,396772868", "0,525885581") R <- as.numeric(gsub(",", ".", raw_data)) # 计算样本统计量作为初始值 sample_mu <- mean(R) sample_sigma <- sd(R) sample_skew <- moments::skewness(R) # 需要先安装moments包 lambda_init <- ifelse(abs(sample_skew) > 1, sign(sample_skew)*0.99, sample_skew) # 先拟合t分布,获取p和q的初始参考 t_fit <- fitdistrplus::fitdist(R, "t", method = "mle") t_df <- t_fit$estimate["df"] p_init <- t_df q_init <- t_df SGTstart <- list(mu = sample_mu, sigma = sample_sigma, lambda = lambda_init, p = p_init, q = q_init)
二、解决p和q标准误差为NaN的问题
出现NaN标准误差通常是因为MLE收敛到参数空间边界、海森矩阵奇异或者样本量不足以支撑复杂参数的估计,可以通过以下方法解决:
1. 添加参数约束,使用带约束的优化方法
SGT的参数有明确的取值范围:mu无约束,sigma>0,-1<lambda<1,p>0,q>0。在fitdist中指定lower和upper参数,并使用支持约束的优化方法(比如L-BFGS-B):
# 设置参数约束范围 lower_bounds <- c(mu = -Inf, sigma = 1e-6, lambda = -0.99, p = 1e-6, q = 1e-6) upper_bounds <- c(mu = Inf, sigma = Inf, lambda = 0.99, p = Inf, q = Inf) # 用带约束的优化方法拟合 SGTfit_R <- fitdistrplus::fitdist( data = R, distr = "sgt", method = "mle", start = SGTstart, lower = lower_bounds, upper = upper_bounds, optim.method = "L-BFGS-B" ) summary(SGTfit_R)
2. 检查收敛性并补充估计
查看拟合结果的收敛码(SGTfit_R$convergence):
- 若
code=0表示收敛成功,此时如果仍有NaN标准误差,可能是样本量太小,考虑用bootstrap方法估计参数标准误差:
# 使用bootstrap估计参数标准误差 boot_SGT <- fitdistrplus::bootdist(SGTfit_R, niter = 1000) summary(boot_SGT)
- 若
code!=0,说明收敛失败,需要进一步调整初始值,比如把p和q的初始值设为更保守的范围(比如p=2,q=4),或者先固定部分参数(比如先固定lambda为样本偏度,拟合其他参数,再逐步放开)。
3. 简化模型验证
如果SGT的拟合始终不稳定,你可以先验证嵌套的简单分布(如GT、t分布)是否能很好拟合你的数据,再判断是否需要引入SGT的额外参数——毕竟复杂模型需要更多数据支撑,样本量较小时,简单分布的估计可能更可靠。
三、附加建议
- 确保数据预处理正确:你的收益率数据用逗号作为小数点,一定要转换为点格式,否则会被识别为字符型,导致拟合失败。
- 对比不同分布的拟合优度:用
fitdistrplus的gofstat()函数对比所有候选分布的AIC、BIC等指标,判断SGT是否真的比其他分布更适合你的数据。
内容的提问来源于stack exchange,提问作者Enjo Faes
相关产品推荐
相关产品推荐

