Julia使用Optim包的Nelder Mead算法时出现DomainError报错问题
问题根源
你代码的DomainError来自效用函数中c_d的非整数次幂运算,你仅对consumption < 0的情况做了返回兜底,但没有处理c_d < 0的情况:
- 你使用的
NelderMead是无约束优化算法,迭代过程中会自动探索参数空间的所有区域,包括x[2](也就是传入的c_d)为负的区间 - 当
c_d < 0时,c_d^(1-0.88) = c_d^0.12属于负数的非整数次幂运算,在实数域无定义,直接触发DomainError,不会走到你后续的逻辑分支
另外你当前用的zgrid数值更小,导致算法更容易探索到c_d为负的区间来最小化损失,所以才会在更换zgrid后复现报错。
修复方案
有两种常见的修复方式,你可以按需选择:
方案1:改用带边界约束的优化算法
直接限制优化变量c_a、c_d的下界为0,从根源上避免出现负数参数,代码修改如下:
using Optim V = fill(1.0, (18,14,5)) agrid = range(-2, stop=20, length=18) dgrid = range(0.01, stop=24, length=14) zgrid = [0.7739832502827438; 0.8797631785217791; 1.0; 1.1366695315439874; 1.2920176239404275] function adj_utility(V,s_a,s_d,s_z,i_z,c_a,c_d) consumption = s_z + 1.0125*s_a + (1-0.018)*s_d - c_a - c_d - 0.05*(1-0.018)*s_d if consumption >= 0 return (1/(1-2)) * (( (consumption^0.88) * (c_d^(1-0.88)) )^(1-2)) else return -99999999 end end # 优化部分修改为带边界约束的版本 i_a = 1 i_d = 3 i_z = 1 utility_adj(x) = -adj_utility(V,agrid[i_a],dgrid[i_d],zgrid[i_z],i_z,x[1],x[2]) # 定义变量下界、上界,c_a和c_d都不能小于0 lower = [0.0, 0.0] upper = [Inf, Inf] # 用Fminbox包裹NelderMead实现带约束优化 result1 = optimize(utility_adj, lower, upper, [1.0, 1.0], Fminbox(NelderMead()))
方案2:补全判断逻辑,覆盖所有非法参数情况
在效用函数开头增加c_d >= 0的判断,只要任意参数非法直接返回兜底值:
function adj_utility(V,s_a,s_d,s_z,i_z,c_a,c_d) # 先判断所有参数是否合法 if c_d < 0 return -99999999 end consumption = s_z + 1.0125*s_a + (1-0.018)*s_d - c_a - c_d - 0.05*(1-0.018)*s_d if consumption >= 0 return (1/(1-2)) * (( (consumption^0.88) * (c_d^(1-0.88)) )^(1-2)) else return -99999999 end end
这种方式不需要修改优化算法,但无约束优化可能会多探索一些无效区域,收敛速度略慢于带约束的方案。
内容的提问来源于stack exchange,提问作者Chang
相关产品推荐
相关产品推荐

