使用scipy.optimize.minimize优化正态分布损失函数报错如何解决?
核心问题梳理
- 标准差σ的约束缺失/不合理
σ作为正态分布的标准差,取值必须严格大于0,优化过程中如果σ被迭代到0或负数,会直接触发除零报错。即使你加了边界,如果边界下界设为0也依然会出现除零问题,需要给σ设置大于0的下界(比如1e-6)。
- 标准差σ的约束缺失/不合理
- 运算符优先级错误
你代码里幂运算的逻辑完全不符合正态分布概率密度的计算规则:Python中**是右结合优先级,你写的e**-a**b实际计算的是e**(-(a**b)),如果你要实现「正态分布密度的b次方」,正确写法应该是(e**-a)**b,或者直接用括号明确运算顺序,这是你计算数值异常的核心原因之一。
- 运算符优先级错误
- 目标函数逻辑错误
你当前写的目标函数在数值上天然会走向发散:当u和σ被迭代得越来越大时,x0=0和样本点的密度都会趋近于0,f0 = -1/(f(x0)**b)会趋近于负无穷,乘以同样趋近于0的f(x[i])会直接生成nan,导致优化失败。大概率是你手写的公式和你实际要优化的目标不一致,比如估计正态参数常规是最小化负对数似然,你当前的函数逻辑完全不满足参数估计的收敛条件。
- 目标函数逻辑错误
- 数值计算精度问题
你用3.14代替π、2.718代替自然指数e,本身就引入了不必要的精度损失,直接调用numpy内置的np.pi、np.exp()或者scipy封装好的正态密度函数scipy.stats.norm.pdf可以避免这类低级错误。
- 数值计算精度问题
修正示例代码
如果你是要做最大似然估计正态分布的参数,可以参考以下代码:
import numpy as np from scipy.optimize import minimize x = np.array([1,2,3,4,5]) # 负对数似然函数,最小化这个等价于最大化似然 def neg_log_likelihood(theta, x): mu = theta[0] sigma = theta[1] # sigma必须大于0,加小常数防除零 if sigma <= 1e-6: return np.inf ll = np.sum(np.log(1/(sigma * np.sqrt(2*np.pi))) - ((x - mu)**2)/(2*sigma**2)) return -ll # 初始化参数用样本均值和方差,更容易收敛 theta_init = [np.mean(x), np.std(x)] # 给sigma加边界,必须大于0 bounds = [(None, None), (1e-6, None)] res = minimize(neg_log_likelihood, theta_init, args=(x,), bounds=bounds) print(res)
运行后会得到接近样本均值3、样本标准差√2的结果,符合预期。如果你确实要使用自定义的目标函数,需要先确认函数的有界性:也就是参数在合理范围变化时,函数值不会出现无穷大/无穷小的情况,否则任何优化器都无法收敛。
内容的提问来源于stack exchange,提问作者James Shady
相关产品推荐
相关产品推荐

