该公式在文档中可用,并在此answer中指出。但是,当我尝试应用它时,没有得到匹配的答案。我确定我在某个地方犯了一些愚蠢的错误,因此感谢您的支持:
设置
说我有2个矩阵:
X: array([[0, 1, 0],
[1, 1, 1]])
X2: array([[1, 1, 0],
[1, 1, 1],
[1, 2, 0]])
现在应用Xans = scipy.spatial.distance.cdist(X, X2, 'seuclidean')
可以得到:
Xans: array([[2.23606798, 2.88675135, 3.16227766],
[1.82574186, 0. , 2.88675135]])
让我们仅关注Xans[0][0] = 2.23606798
,应该通过应用seuclidean(X[0], X2[0])
获得。
方法1:使用pdist
我尝试通过pdist
进行此操作,但得到了NaN:
In [104]: scipy.spatial.distance.pdist([X[0], X2[0]], metric='seuclidean')
Out[104]: array([nan])
为什么会这样?
方法2:直接应用公式
我尝试使用上面答案中链接的公式进行了以下尝试:
In [107]: (((X[0] - X2[0])**2).sum()/(np.var([X[0], X2[0]])))**0.5
Out[107]: 2.0
可以看出这给出了2.0吗?
我显然做错了什么-这是什么?
答案 0 :(得分:2)
标准化欧几里德距离权重每个变量,且具有独立的方差。如果不使用V
参数提供方差,它将从输入数组计算方差。 **kwargs
下“参数”部分的pdist
docstring中提到了这一点,它显示:
V : ndarray
The variance vector for standardized Euclidean.
Default: var(X, axis=0, ddof=1)
例如:
In [39]: A
Out[39]:
array([[3, 0, 2],
[2, 1, 2],
[0, 0, 1],
[3, 1, 2],
[1, 0, 0]])
In [40]: from scipy.spatial.distance import pdist
In [41]: pdist(A, metric='seuclidean')
Out[41]:
array([ 1.98029509, 2.55814731, 1.82574186, 2.71163072, 2.63368079,
0.76696499, 2.9868995 , 3.14284123, 1.35581536, 3.26898677])
如果提供按照文档字符串所述计算的方差,我们将得到相同的结果:
In [42]: pdist(A, metric='seuclidean', V=np.var(A, axis=0, ddof=1))
Out[42]:
array([ 1.98029509, 2.55814731, 1.82574186, 2.71163072, 2.63368079,
0.76696499, 2.9868995 , 3.14284123, 1.35581536, 3.26898677])
当然,如果提供的所有方差均为1,则将得到常规的欧几里德距离:
In [43]: pdist(A, metric='seuclidean', V=np.ones(A.shape[1]))
Out[43]:
array([ 1.41421356, 3.16227766, 1. , 2.82842712, 2.44948974,
1. , 2.44948974, 3.31662479, 1.41421356, 3. ])
In [44]: pdist(A, metric='euclidean')
Out[44]:
array([ 1.41421356, 3.16227766, 1. , 2.82842712, 2.44948974,
1. , 2.44948974, 3.31662479, 1.41421356, 3. ])
“方法1”的问题在于,在只有两个点(即[X[0], X2[0]]
)的输入数组中,点的第二和第三部分不变,因此与这些部分相关的方差是0:
In [45]: p = np.array([X[0], X2[0]])
In [46]: p
Out[46]:
array([[0, 1, 0],
[1, 1, 0]])
In [47]: np.var(p, axis=0, ddof=1)
Out[47]: array([ 0.5, 0. , 0. ])
当seuclidean
的代码除以这些方差时,结果为无穷大或NaN-如果分子也为0,则后者为NaN,在输入{{1 }}。
要解决此问题,您必须决定如何处理组件方差为0的情况,并明确地处理它。例如,如果您希望它在这种情况下表现为方差为1(为了避免除以0),则可以执行以下操作。
假设[X[0], X2[0]]
是我们的点数组。 B
的第三列全为1。
B
计算列的方差:
In [63]: B
Out[63]:
array([[3, 0, 1],
[2, 1, 1],
[0, 0, 1],
[3, 1, 1],
[1, 0, 1]])
将1的方差替换为1:
In [64]: V = np.var(B, axis=0, ddof=1)
In [65]: V
Out[65]: array([ 1.7, 0.3, 0. ])
使用In [66]: V[V == 0] = 1
In [67]: V
Out[67]: array([ 1.7, 0.3, 1. ])
计算标准化的欧几里得距离:
V
这与简单地删除常量列具有相同的效果:
In [68]: pdist(B, metric='seuclidean', V=V)
Out[68]:
array([ 1.98029509, 2.30089497, 1.82574186, 1.53392998, 2.38459106,
0.76696499, 1.98029509, 2.93725228, 0.76696499, 2.38459106])
您的“方法2”是错误的,因为您的公式是错误的。您必须保留每个组件的差异。 In [69]: pdist(B[:, :2], metric='seuclidean')
Out[69]:
array([ 1.98029509, 2.30089497, 1.82574186, 1.53392998, 2.38459106,
0.76696499, 1.98029509, 2.93725228, 0.76696499, 2.38459106])
计算输入中所有值的(单个)方差。相反,您需要使用上面显示的np.var([X[0], X2[0]])
和axis
参数。