R语言自定义函数绘图报错排查与二分法求根实现
报错原因
你遇到的长度不匹配报错本质是函数不支持向量化输入导致的:
curve()、plot()等绘图函数为了提升计算效率,会一次性传入一串默认长度为101的x向量,要求函数返回对应长度的y值向量- 你定义的原
eq函数仅支持单个标量x作为输入:当传入长度101的x向量时,长度为168的Ln.M_Return[,1]和x长度不是整数倍关系,R的向量循环规则会触发长度不匹配警告,最终返回的结果长度不符合绘图函数的输入要求,就会抛出错误。
可行实现方案
1. 改造函数支持向量化输入,完成绘图
首先把原函数改造为可以接收向量x输入的版本,用sapply遍历每个输入的x值单独计算即可:
# 改造后的支持向量输入的目标函数 eq <- function(x_val) { sapply(x_val, function(xi) { # 注意x=0会触发除0错误,所有场景下x都要取大于0的值 sum(exp(-Ln.M_Return[, 1] / xi)) / 168 - 1 }) }
之后就可以正常调用curve绘图,注意x轴范围只取正数,上下限根据你的收益率量级调整,保证覆盖根的所在区间即可:
# 绘制函数曲线 curve( eq(x), from = 0.001, # x下界,必须大于0 to = 2, # x上界,根据实际收益率量级调整 xlab = "AS风险指数候选值x", ylab = "函数值eq(x)", main = "Aumann-Serrano风险指数求解函数曲线" ) abline(h = 0, col = "red", lty = 2) # 绘制y=0参考线,和曲线的交点就是方程的根
2. 二分法求解方程的根
Aumann-Serrano风险指数对应的目标函数是严格单调的,完全满足二分法的使用条件。你可以先从绘制的图上找到y=0交点所在的区间(即区间两端点的函数值符号相反),再用二分法迭代求解:
# 二分法求根实现 bisection_root <- function(func, lower, upper, tol = 1e-7, max_iter = 1000) { f_lower <- func(lower) f_upper <- func(upper) # 校验区间合法性 if (f_lower * f_upper > 0) stop("区间两端函数值同号,请重新选择搜索区间") for (i in seq_len(max_iter)) { mid <- (lower + upper) / 2 f_mid <- func(mid) # 达到精度要求则返回结果 if (abs(f_mid) < tol) { return( list( AS_index = mid, iteration = i, final_error = f_mid ) ) } # 缩小区间范围 if (f_lower * f_mid < 0) { upper <- mid f_upper <- f_mid } else { lower <- mid f_lower <- f_mid } } warning("已达最大迭代次数,结果未收敛到指定精度") return(list(AS_index = (lower+upper)/2, iteration = max_iter, final_error = f_mid)) } # 调用示例:将lower和upper替换为你从图上确定的根所在区间 result <- bisection_root(eq, lower = 0.01, upper = 1) print(paste0("计算得到的Aumann-Serrano风险指数为:", round(result$AS_index, 6)))
如果不需要手动实现二分法,也可以直接调用R内置的一维求根函数uniroot,底层也是用二分法+线性插值实现的,效率更高:
# 内置函数求根调用示例 as_index <- uniroot(eq, interval = c(0.01, 1), tol = 1e-7)$root
内容的提问来源于stack exchange,提问作者Howard Shang
相关产品推荐
相关产品推荐

