特徴よりも観測が少ないためV
、scipy コードによって計算された共分散行列は特異です。コードはこれをチェックせず、やみくもに共分散行列の「逆」を計算します。この数値的に計算された逆数は基本的にガベージであるため、積(x-y)*inv(V)*(x-y)
(x
とy
は観測値) は負になる可能性があります。次に、その値の平方根は になります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 や Garbage の代わりにエラーが発生します。エラーメッセージは問題を説明しています:
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.