statsmodels:重复值列表中的 kde 错误

机器算法验证 协方差 箱形图 克德
2022-03-22 11:52:27

我正在使用 Python 的statsmodels模块来绘制一些数据的小提琴/豆图。每当从相同数字的重复实例列表中绘制单个小提琴图时,我都会KDE计算中收到错误“LinAlgError:奇异矩阵”常规箱线图工作得很好。

这是一个错误还是背后有原因?

/home/me/myscript.py in plot_data_in_violinplot()
   3435         plot_opts={'violin_fc':(0.8, 0.8, 0.8), 'cutoff':True, 
                         'bean_color':'#FF6F00', 'bean_mean_color':'#009D91',
                         'bean_median_color':'b', 'bean_median_marker':'+'}
-> 3436         sm.graphics.beanplot(data_to_boxplot, ax=ax, jitter=jitter, plot_opts=plot_opts)


/usr/local/lib/python2.7/dist-packages/statsmodels/graphics/boxplots.py in beanplot(data, ax, labels, positions, side, jitter, plot_opts)
    333     for pos_data, pos in zip(data, positions):
    334         # Draw violins.
--> 335         xvals, violin = _single_violin(ax, pos, pos_data, width, side, plot_opts)
    336 
    337         if jitter:

/usr/local/lib/python2.7/dist-packages/statsmodels/graphics/boxplots.py in _single_violin(ax, pos, pos_data, width, side, plot_opts)
    170     pos_data = np.asarray(pos_data)
    171     # Kernel density estimate for data at this position.
--> 172     kde = gaussian_kde(pos_data)
    173 
    174     # Create violin for pos, scaled to the available space.

/usr/local/lib/python2.7/dist-packages/scipy/stats/kde.pyc in __init__(self, dataset, bw_method)
    186 
    187         self.d, self.n = self.dataset.shape
--> 188         self.set_bandwidth(bw_method=bw_method)
    189 
    190     def evaluate(self, points):

/usr/local/lib/python2.7/dist-packages/scipy/stats/kde.pyc in set_bandwidth(self, bw_method)
    496             raise ValueError(msg)
    497 
--> 498         self._compute_covariance()
    499 
    500     def _compute_covariance(self):

/usr/local/lib/python2.7/dist-packages/scipy/stats/kde.pyc in _compute_covariance(self)
    507             self._data_covariance = atleast_2d(np.cov(self.dataset, rowvar=1,
    508                                                bias=False))
--> 509             self._data_inv_cov = linalg.inv(self._data_covariance)
    510 
    511         self.covariance = self._data_covariance * self.factor**2

/usr/local/lib/python2.7/dist-packages/scipy/linalg/basic.pyc in inv(a, overwrite_a, check_finite)
    381         inv_a, info = getri(lu, piv, lwork=lwork, overwrite_lu=1)
    382     if info > 0:
--> 383         raise LinAlgError("singular matrix")
    384     if info < 0:
    385         raise ValueError('illegal value in %d-th argument of internal '
LinAlgError: singular matrix
2个回答

我从来没有使用过 Python statsmodels 包,我也不熟悉它,但是根据错误消息,我想我对可能发生的事情有一个很好的猜测,这不是一个错误——问题在于您的输入。根据维基百科,核密度估计的一个关键步骤是带宽估计如链接中所述,对于高斯基函数(根据您的错误消息引用gaussian_kde(),这似乎是您实际上正在使用的),在一维 KDE 的特殊情况下,估计带宽的一种常见选择需要样本标准差作为输入。σ^

您提到会出现错误,特别是在您的输入是相同 number 的重复实例列表的情况下。想象一下计算相同数字列表的样本标准差,你会得到什么?好吧,基本上你在这种情况下模拟的是一个狄拉克三角函数,所以实际上你的样本标准差是基于这样一个事实,堆栈跟踪中的下一个错误,在被捕获的异常之下,发生在一个名为的方法中σ^=0gaussian_kde()set_bandwidth(),我想说的是,您正在为代码提供标准差为零的分布,并且代码正试图使用​​该值来计算 KDE 带宽参数的初始猜测,并且由于零而令人窒息不是真正的有效值。

“好的”,你回答,“但是你的解释没有提到任何关于线性代数或奇异矩阵的东西——为什么错误会在线性代数例程中表现出来,特别是?” 好问题。我不确定,但我怀疑正在发生的事情。标准差的概念,或其平方,方差,实际上是一个固有的一维概念。对多变量分布有效的更一般的概念是协方差矩阵您正在使用的代码可能被设计为尽可能通用,以便能够处理用户向其提供多变量分布的情况。事实上,当你在堆栈跟踪中进一步向下工作时,你会注意到下一个方法向下,在下面set_bandwidth()compute_covariance(). 如果您对协方差矩阵了解很多,事实证明,分析和思考它们的一种流行方法是将它们简化为所谓的主成分执行主成分分析后,其效果是将初始协方差矩阵对角化,创建一个有效等价的新矩阵,该矩阵已被转换为仅由一组仅沿对角线。这些方差可以被识别为原始非对角矩阵的特征值,而且事实证明,在线性代数中,矩阵的属性之一是那些通过具有相同特征值而相关的矩阵也不可避免地具有相同的特征值。决定因素

因此,我怀疑在您的情况下发生的情况是,通过为代码提供与输入相同值的重复实例,您正在创建一个协方差矩阵,该矩阵至少有一个特征值等于 0,而这种情况意味着行列式是也为零,因为在对角化矩阵的特殊情况下,行列式将只是对角线上所有值的乘积。那么,当矩阵的行列式为零时,我们怎么称呼它?根据可逆矩阵的定义,“不可逆的方阵称为奇异或退化。方阵是奇异的当且仅当其行列式为 0。” 这就是为什么你在堆栈跟踪的底部得到错误的原因——在某些时候,无论出于何种原因,代码都需要反转协方差矩阵(你可以看到跟踪底部的最终方法被调用_data_inv_cov())但是它不能这样做,因为矩阵是奇异的,因此是不可逆的。

最重要的是,实际上发生的是,通过为代码提供相同数字的重复实例以用作输入,您基本上生成了与被零除错误等效的线性代数。

Float32中只有 1e-6 的精度numpy,因此,如果您正在处理小数字,相似的实例可能会变得相同(或非常接近),从而产生奇异的或缩放不良的矩阵。这个问题特别棘手,因为没有代数原因导致所需的反转不可能。解决此问题的两种简单方法可能是按 10 的幂(即 10e6)缩放您的数据集,或者使用float64或使用双精度(精度为 1e-15)的numpy.

dataset.astype('float64') 是进行更改的简单方法。