SciPy 二维正态 CDF 只填协方差下三角,结果却变了
二维正态 CDF 的快速路径读取协方差上三角元素,与仅使用下三角的文档约定存在差异。以完整对称协方差输入可避免两个三角部分不一致,不能把 Cholesky 因子当协方差补齐。
同一个二维正态模型,把完整协方差矩阵换成“只填写下三角”的矩阵,multivariate_normal.cdf() 的结果从约三分之一变成四分之一。若上三角只是占位零,先检查二维 CDF 的读取路径,而不是把差异归为积分随机误差。
SciPy 1.18.1 的 multivariate_normal 文档约定只使用下三角且不检查对称性,但二维快速路径 _bvn 会读取上三角的 cov[0, 1]。上下三角一致的完整协方差不会暴露这项差异;只填下三角的输入则可能让相关项被当成零。
这两个数组表达的意图相同,读取结果却不同
from scipy.stats import multivariate_normal
full_cov = [[1.0, 0.5], [0.5, 1.0]]
lower_only = [[1.0, 0.0], [0.5, 1.0]]
p_full = multivariate_normal.cdf([0.0, 0.0], cov=full_cov)
p_lower = multivariate_normal.cdf([0.0, 0.0], cov=lower_only)
如果以填写完整的协方差为准,两个变量的相关系数是 0.5。在这个零均值、单位方差的对照中,联合概率约为三分之一;上三角的零被用作交叉协方差时,却对应不相关情形,概率成为四分之一。这不是可以通过多增加积分点自动纠正的采样误差。
这里的 lower_only 是用下三角保存协方差条目的形式,不是 Cholesky 分解因子。两种对象虽然都可能是下三角数组,数学含义不同。
按输入契约补出完整对称协方差
当业务明确以下三角为有效协方差、上三角为占位内容时,可从下三角重建对称矩阵,再传给 CDF:
import numpy as np
raw = np.array(lower_only, dtype=float)
lower = np.tril(raw)
cov = lower + lower.T - np.diag(np.diag(lower))
probability = multivariate_normal.cdf([0.0, 0.0], cov=cov)
这段接续前面的输入,用减去一次对角线避免将方差加倍。若原输入本来是完整、但上下三角因数据错误而不一致的矩阵,应先查清哪个值正确;不能一律用平均值或随意选择一边来掩盖错误。
若持有的是 Cholesky 因子 L,协方差应按它的分解约定计算,例如实数情形的 L @ L.T,而不是把 L 镜像补齐。相关矩阵、协方差和分解因子不能互相按外观替换。
重建后仍须满足协方差的维数、有限性与正半定条件。允许奇异矩阵是单独的模型与接口选择;对角线为负或输入并非合法协方差时,不能通过对称化解决。
用完整矩阵对照同一事件
验收固定均值、积分上下界与完整协方差,比较直接完整输入和按协议补齐的输入。先用相关系数为零和非零的二维小例子检查,再回到业务数据。转置一次数组偶然恢复数值,并不表示输入契约已经稳定。
这一条件针对二维 CDF 快速路径。PDF、高维 CDF 或协方差对象可能走不同实现,不应拿其中一个接口的正常结果替代另一个接口的验收。已经根据错误相关项生成的联合概率,需要用保留的协方差重新计算。


