Scipy Gaussian KDE报错:矩阵非正定,如何估算样本密度?
嘿,这个问题我之前处理过,根源在于你的样本量太小啦!
问题原因分析
你给出的示例里只有3个3D数据点,样本数量刚好等于数据维度。这种情况下,样本的协方差矩阵是奇异的(秩不足),而scipy.stats.gaussian_kde默认会基于样本协方差矩阵做Cholesky分解——但奇异矩阵不是正定的,自然就抛出LinAlgError了。哪怕是实际数据,如果样本量接近或小于维度,也会碰到这个问题。
解决方案
下面给你几种可行的修复方法,按需选择:
方法1:给协方差矩阵加正则化项
直接给协方差矩阵添加一个极小的对角矩阵,强制让它变成正定矩阵,这样就能顺利完成Cholesky分解了:
from scipy.stats import gaussian_kde import numpy as np A = np.array([[0.078377 , 0.76737392, 0.45038174], [0.65990129, 0.13154658, 0.30770917], [0.46068406, 0.22751313, 0.28122463]]) B = np.array([[0.40209377, 0.21063273, 0.75885516], [0.91709997, 0.79303252, 0.65156937]]) # 初始化KDE对象 kde = gaussian_kde(A.T) # 添加正则化:给协方差矩阵加一个极小的单位矩阵倍数 epsilon = 1e-6 kde.covariance = kde.covariance + epsilon * np.eye(kde.d) # 现在可以正常计算密度了 result = kde(B.T) print(result)
你也可以通过调整covariance_factor来增大带宽,让密度估计更平滑,间接避免奇异矩阵问题:
# 自定义带宽因子(比默认值大,会让密度更平滑) kde.covariance_factor = lambda: 0.5 # 更新协方差矩阵 kde._compute_covariance() # 再计算密度 result = kde(B.T)
方法2:改用sklearn的KernelDensity类
sklearn.neighbors.KernelDensity对小样本/高维数据的兼容性更好,支持直接设置带宽,不需要手动处理协方差矩阵:
from sklearn.neighbors import KernelDensity import numpy as np A = np.array([[0.078377 , 0.76737392, 0.45038174], [0.65990129, 0.13154658, 0.30770917], [0.46068406, 0.22751313, 0.28122463]]) B = np.array([[0.40209377, 0.21063273, 0.75885516], [0.91709997, 0.79303252, 0.65156937]]) # 初始化KDE,设置合适的带宽(可根据数据调整) kde = KernelDensity(kernel='gaussian', bandwidth=0.5) kde.fit(A) # 计算对数密度,再转换为原始密度 log_density = kde.score_samples(B) result = np.exp(log_density) print(result)
方法3:针对极小样本的特殊处理
如果你的实际数据样本量确实远小于维度,核密度估计可能不是最优选择。可以考虑:
- 先对数据做降维(比如PCA),降低维度后再做密度估计
- 改用**混合高斯模型(GMM)**来拟合数据分布,再计算点的密度
内容的提问来源于stack exchange,提问作者usernumber
相关产品推荐
相关产品推荐

