Scipy优化多元正态对数似然时协方差非正定报错如何解决
解决方案
方案1:参数空间变换(最通用,支持非正态分布推广)
直接把有约束的协方差交叉项通过可逆映射转换为无约束参数,避免优化过程跑出可行域。
二元场景下,协方差交叉项cov_xy的合法范围为[-sqrt(VAR_X*VAR_Y), sqrt(VAR_X*VAR_Y)],我们可以用tanh函数把任意实数值映射到这个合法区间:
import numpy as np from scipy.stats import multivariate_normal from scipy.optimize import minimize VAR_X = 0.4 VAR_Y = 0.32 MEAN_X = 1 MEAN_Y = 1.2 COV_BOUND = np.sqrt(VAR_X * VAR_Y) def log_likelihood_function(z, data): # 无约束参数z映射到合法cov_xy cov_xy = np.tanh(z[0]) * COV_BOUND log_likelihood = 0 sigma = [[VAR_X, cov_xy], [cov_xy, VAR_Y]] mu = [MEAN_X, MEAN_Y] for point in data: log_likelihood += multivariate_normal.logpdf(x=point, mean=mu, cov=sigma) return log_likelihood if __name__ == "__main__": some_data = [[1.1, 2.0], [1.2, 1.9], [0.8, 0.2], [0.7, 1.3]] guess = [0] # 最小化负对数似然 likelihood = lambda x: (-1)*log_likelihood_function(x, some_data) result = minimize(fun = likelihood, x0 = guess, options = {'disp': True}, method="SLSQP") # 把优化得到的z转换回实际的cov_xy optimal_cov_xy = np.tanh(result.x[0]) * COV_BOUND print("最优协方差交叉项:", optimal_cov_xy) print(result)
这种方法不需要依赖优化器的约束逻辑,不管目标分布是正态还是非正态都适用,是泛用性最高的解决方案。
方案2:添加边界惩罚项
如果不想修改参数映射,可以直接在目标函数中增加可行域判断,对超出合法范围的参数返回极高的损失值,引导优化算法避开非法区域:
def log_likelihood_function(x, data): cov_xy = x[0] # 非法参数直接返回极小的似然值,对应负对数似然为极大值 if abs(cov_xy) > COV_BOUND: return -1e18 log_likelihood = 0 sigma = [[VAR_X, cov_xy], [cov_xy, VAR_Y]] mu = [MEAN_X, MEAN_Y] for point in data: log_likelihood += multivariate_normal.logpdf(x=point, mean=mu, cov=sigma) return log_likelihood
方案3:换用支持边界约束的优化器
scipy.optimize.minimize的L-BFGS-B方法原生支持参数上下界约束,迭代过程中不会生成边界外的参数:
result = minimize( fun = likelihood, x0 = guess, bounds = [(-COV_BOUND, COV_BOUND)], options = {'disp': True}, method="L-BFGS-B" )
内容的提问来源于stack exchange,提问作者Grant Moore
相关产品推荐
相关产品推荐

