python - Scipy - Nan 计算马氏距离时

标签 python numpy statistics scipy mahalanobis

当我尝试使用以下 python 代码计算马哈拉诺比斯距离时,我在结果中得到了一些 Nan 条目。您知道为什么会发生这种情况吗? 我的 data.shape = (181, 1500)

from scipy.spatial.distance import pdist, squareform

data_log = log2(data + 1) # A log transform that I usually apply to my data
data_centered = data_log - data_log.mean(0) # zero centering
D = squareform( pdist(data_centered, 'mahalanobis' ) )

我也尝试过:

data_standard = data_centered / data_centered.std(0, ddof=1)
D = squareform( pdist(data_standard, 'mahalanobis' ) )

还有南斯。 输入没有损坏,并且可以很好地计算其他距离,例如相关距离。 由于某种原因,当我减少功能数量时,我就不再获得 Nans 了。例如,以下示例没有得到任何 Nan:

D = squareform( pdist(data_centered[:,:200], 'mahalanobis' ) )
D = squareform( pdist(data_centered[:,180:480], 'mahalanobis' ) )

而其他人则得到 Nans:

D = squareform( pdist(data_centered[:,:300], 'mahalanobis' ) )
D = squareform( pdist(data_centered[:,180:600], 'mahalanobis' ) )

有什么线索吗?如果不满足输入的某些条件,这是预期的行为吗?

最佳答案

您的观测值少于特征,因此 scipy 代码计算的协方差矩阵 V 是奇异的。代码不会检查这一点,而是盲目地计算协方差矩阵的“逆”。因为这个数值计算的逆基本上是垃圾,所以乘积 (x-y)*inv(V)*(x-y) (其中 xy 是观察)可能结果是负面的。然后该值的平方根得到nan

例如,此数组还会产生 nan:

In [265]: x
Out[265]: 
array([[-1. ,  0.5,  1. ,  2. ,  2. ],
       [ 2. ,  1. ,  2.5, -1.5,  1. ],
       [ 1.5, -0.5,  1. ,  2. ,  2.5]])

In [266]: squareform(pdist(x, 'mahalanobis'))
Out[266]: 
array([[ 0.        ,         nan,  1.90394328],
       [        nan,  0.        ,         nan],
       [ 1.90394328,         nan,  0.        ]])

这是“手动”完成的马哈拉诺比斯计算:

In [279]: V = np.cov(x.T)

理论上,V 是单数;以下值实际上为 0:

In [280]: np.linalg.det(V)
Out[280]: -2.968550671342364e-47

但是 inv 没有发现问题,并返回一个逆值:

In [281]: VI = np.linalg.inv(V)

让我们计算 x[0]x[2] 之间的距离,并验证我们是否获得了 返回的相同非 nan 值 (1.9039) pdist 当我们使用 VI 时:

In [295]: delta = x[0] - x[2]

In [296]: np.dot(np.dot(delta, VI), delta)
Out[296]: 3.625

In [297]: np.sqrt(np.dot(np.dot(delta, VI), delta))
Out[297]: 1.9039432764659772

当我们尝试计算 x[0]x[1] 之间的距离时,会发生以下情况:

In [300]: delta = x[0] - x[1]

In [301]: np.dot(np.dot(delta, VI), delta)
Out[301]: -1.75

然后该值的平方根给出nan


在 scipy 0.16(将于 2015 年 6 月发布)中,您将收到错误而不是 nan 或垃圾。错误消息描述了问题:

In [4]: x = array([[-1. ,  0.5,  1. ,  2. ,  2. ],
   ...:        [ 2. ,  1. ,  2.5, -1.5,  1. ],
   ...:        [ 1.5, -0.5,  1. ,  2. ,  2.5]])

In [5]: pdist(x, 'mahalanobis')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-a3453ff6fe48> in <module>()
----> 1 pdist(x, 'mahalanobis')

/Users/warren/local_scipy/lib/python2.7/site-packages/scipy/spatial/distance.pyc in pdist(X, metric, p, w, V, VI)
   1298                                      "singular. For observations with %d "
   1299                                      "dimensions, at least %d observations "
-> 1300                                      "are required." % (m, n, n + 1))
   1301                 V = np.atleast_2d(np.cov(X.T))
   1302                 VI = _convert_to_double(np.linalg.inv(V).T.copy())

ValueError: The number of observations (3) is too small; the covariance matrix is singular. For observations with 5 dimensions, at least 6 observations are required.

关于python - Scipy - Nan 计算马氏距离时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29717269/

相关文章:

python - 请为非常喜欢 LISP 的人提供有关 Ruby 与 Python 的建议

python - 通过 pandas 数据框进行有效循环

python - 使用 PyMC3 计算最大似然

python - Keras层输出和输入之间的差异

python - 用逗号或分号分隔成 Python 列表的值字符串

R - 如何按组进行回归并获取预测值?

r - 在 R 中使用 msSurv 包

python - Concat DataFrame Reindexing 仅对具有唯一值的 Index 对象有效

python - ufunc 算术表达式中的内存消耗

java - 计算二十一点中经销商破坏 S17 的概率