gpt4 book ai didi

python - Scipy:通过 cdist 计算标准化欧几里德

转载 作者:行者123 更新时间:2023-12-02 17:07:26 28 4
gpt4 key购买 nike

该公式在文档中可用,并在此 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]) 获得.


方法一:使用pdist

我尝试通过 pdist 执行此操作,但得到的是 NaN:

In [104]: scipy.spatial.distance.pdist([X[0], X2[0]], metric='seuclidean')
Out[104]: array([nan])

为什么会这样?


方法二:直接公式应用

我尝试手动使用上面答案中链接的公式,如下所示:

In [107]: (((X[0] - X2[0])**2).sum()/(np.var([X[0], X2[0]])))**0.5
Out[107]: 2.0

可以看出这是给2.0吗?

我显然做错了什么 - 这是什么?

最佳答案

标准化欧几里德距离用单独的方差对每个变量进行加权。如果您不使用 V 参数提供方差,它会根据输入数组计算它们。 pdist docstring 中提到了这一点在 **kwargs 下的“Parameters”部分,它显示:

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,则为后者,输入的第三个分量就是这种情况[X[0], X2[0]].

要解决此问题,您必须决定要如何处理组件方差为 0 的情况,并明确处理它。例如,如果您希望它在这种情况下表现得像方差为 1(只是为了避免除以 0),您可以执行如下操作。

假设 B 是我们的点数组。 B第三列全部为1

In [63]: B
Out[63]:
array([[3, 0, 1],
[2, 1, 1],
[0, 0, 1],
[3, 1, 1],
[1, 0, 1]])

计算列的方差:

In [64]: V = np.var(B, axis=0, ddof=1)

In [65]: V
Out[65]: array([ 1.7, 0.3, 0. ])

用 1 替换为 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])

这与简单地删除常量列具有相同的效果:

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])

你的“方法2”是错误的,因为你的公式是错误的。您必须保留每个组件的差异。 np.var([X[0], X2[0]]) 计算输入中所有值的(单个)方差。相反,您需要使用上面显示的 axisddof 参数。

关于python - Scipy:通过 cdist 计算标准化欧几里德,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50974217/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com