Raf*_*ida 60 python numpy scipy
scipy.spatial.distance.pdist
返回压缩距离矩阵.从文档:
返回压缩距离矩阵Y.对于每个和(where),度量dist(u = X [i],v = X [j])被计算并存储在条目ij中.
我以为ij
是的意思i*j
.但我想我可能错了.考虑
X = array([[1,2], [1,2], [3,4]])
dist_matrix = pdist(X)
Run Code Online (Sandbox Code Playgroud)
然后文档说dist(X[0], X[2])
应该是dist_matrix[0*2]
.但是,dist_matrix[0*2]
它应该是0 - 而不是2.8.
我应该使用什么公式来获取两个向量的相似性,给定i
和j
?
War*_*ser 80
你可以这样看:假设x
是m乘n.m
一次选择两个的可能的行对itertools.combinations(range(m), 2)
,例如用于m=3
:
>>> import itertools
>>> list(combinations(range(3),2))
[(0, 1), (0, 2), (1, 2)]
Run Code Online (Sandbox Code Playgroud)
因此,如果d = pdist(x)
,k
th元组combinations(range(m), 2))
给出了x
与之关联的行的索引d[k]
.
例:
>>> x = array([[0,10],[10,10],[20,20]])
>>> pdist(x)
array([ 10. , 22.36067977, 14.14213562])
Run Code Online (Sandbox Code Playgroud)
第一个元素是dist(x[0], x[1])
,第二个是dist(x[0], x[2])
,第三个是dist(x[1], x[2])
.
或者您可以将其视为方形距离矩阵的上三角形部分中的元素,将它们串联成一维数组.
例如
>>> squareform(pdist(x))
array([[ 0. , 10. , 22.361],
[ 10. , 0. , 14.142],
[ 22.361, 14.142, 0. ]])
>>> y = array([[0,10],[10,10],[20,20],[10,0]])
>>> squareform(pdist(y))
array([[ 0. , 10. , 22.361, 14.142],
[ 10. , 0. , 14.142, 10. ],
[ 22.361, 14.142, 0. , 22.361],
[ 14.142, 10. , 22.361, 0. ]])
>>> pdist(y)
array([ 10. , 22.361, 14.142, 14.142, 10. , 22.361])
Run Code Online (Sandbox Code Playgroud)
lum*_*ric 32
pdist返回的压缩距离矩阵可以通过以下方式转换为全距离矩阵scipy.spatial.distance.squareform
:
>>> import numpy as np
>>> from scipy.spatial.distance import pdist, squareform
>>> points = np.array([[0,1],[1,1],[3,5], [15, 5]])
>>> dist_condensed = pdist(points)
>>> dist_condensed
array([ 1. , 5. , 15.5241747 , 4.47213595,
14.56021978, 12. ])
Run Code Online (Sandbox Code Playgroud)
使用squareform
转换到全矩阵:
>>> dist = squareform(dist_condensed)
array([[ 0. , 1. , 5. , 15.5241747 ],
[ 1. , 0. , 4.47213595, 14.56021978],
[ 5. , 4.47213595, 0. , 12. ],
[ 15.5241747 , 14.56021978, 12. , 0. ]])
Run Code Online (Sandbox Code Playgroud)
点i,j之间的距离存储在dist [i,j]中:
>>> dist[2, 0]
5.0
>>> np.linalg.norm(points[2] - points[0])
5.0
Run Code Online (Sandbox Code Playgroud)
可以将用于访问方阵的元素的索引转换为压缩矩阵中的索引:
def square_to_condensed(i, j, n):
assert i != j, "no diagonal elements in condensed matrix"
if i < j:
i, j = j, i
return n*j - j*(j+1)/2 + i - 1 - j
Run Code Online (Sandbox Code Playgroud)
例:
>>> square_to_condensed(1, 2, len(points))
3
>>> dist_condensed[3]
4.4721359549995796
>>> dist[1,2]
4.4721359549995796
Run Code Online (Sandbox Code Playgroud)
另外,没有sqaureform就可以实现另一个方向,这在运行时和内存消耗方面更好:
import math
def calc_row_idx(k, n):
return int(math.ceil((1/2.) * (- (-8*k + 4 *n**2 -4*n - 7)**0.5 + 2*n -1) - 1))
def elem_in_i_rows(i, n):
return i * (n - 1 - i) + (i*(i + 1))/2
def calc_col_idx(k, i, n):
return int(n - elem_in_i_rows(i + 1, n) + k)
def condensed_to_square(k, n):
i = calc_row_idx(k, n)
j = calc_col_idx(k, i, n)
return i, j
Run Code Online (Sandbox Code Playgroud)
例:
>>> condensed_to_square(3, 4)
(1.0, 2.0)
Run Code Online (Sandbox Code Playgroud)
>>> import numpy as np
>>> from scipy.spatial.distance import pdist, squareform
>>> points = np.random.random((10**4,3))
>>> %timeit dist_condensed = pdist(points)
1 loops, best of 3: 555 ms per loop
Run Code Online (Sandbox Code Playgroud)
创建sqaureform结果非常慢:
>>> dist_condensed = pdist(points)
>>> %timeit dist = squareform(dist_condensed)
1 loops, best of 3: 2.25 s per loop
Run Code Online (Sandbox Code Playgroud)
如果我们正在搜索具有最大距离的两个点,那么在完整矩阵中搜索是O(n)而在浓缩形式中仅搜索O(n/2)并不奇怪:
>>> dist = squareform(dist_condensed)
>>> %timeit dist_condensed.argmax()
10 loops, best of 3: 45.2 ms per loop
>>> %timeit dist.argmax()
10 loops, best of 3: 93.3 ms per loop
Run Code Online (Sandbox Code Playgroud)
在两种情况下获得两点的内容几乎没有时间,但当然计算压缩索引有一些开销:
>>> idx_flat = dist.argmax()
>>> idx_condensed = dist.argmax()
>>> %timeit list(np.unravel_index(idx_flat, dist.shape))
100000 loops, best of 3: 2.28 µs per loop
>>> %timeit condensed_to_square(idx_condensed, len(points))
100000 loops, best of 3: 14.7 µs per loop
Run Code Online (Sandbox Code Playgroud)
sha*_*unc 18
压缩矩阵的矢量对应于方阵的底部三角形区域.要转换该三角形区域中的点,您需要计算三角形中左侧的点数,以及列中上方的数字.
您可以使用以下函数进行转换:
q = lambda i,j,n: n*j - j*(j+1)/2 + i - 1 - j
Run Code Online (Sandbox Code Playgroud)
校验:
import numpy as np
from scipy.spatial.distance import pdist, squareform
x = np.random.uniform( size = 100 ).reshape( ( 50, 2 ) )
d = pdist( x )
ds = squareform( d )
for i in xrange( 1, 50 ):
for j in xrange( i ):
assert ds[ i, j ] == d[ q( i, j, 50 ) ]
Run Code Online (Sandbox Code Playgroud)
我有同样的问题。我发现使用起来更简单numpy.triu_indices
:
import numpy as np
from scipy.spatial.distance import pdist, squareform
N = 10
# Calculate distances
X = np.random.random((N,3))
dist_condensed = pdist(X)
# Get indexes: matrix indices of dist_condensed[i] are [a[i],b[i]]
a,b = np.triu_indices(N,k=1)
# Fill distance matrix
dist_matrix = np.zeros((N,N))
for i in range(len(dist_condensed)):
dist_matrix[a[i],b[i]] = dist_condensed[i]
dist_matrix[b[i],a[i]] = dist_condensed[i]
# Compare with squareform output
np.all(dist_matrix == squareform(distances))
Run Code Online (Sandbox Code Playgroud)
这是上三角版本(i <j),对某些人来说应该很有趣:
condensed_idx = lambda i,j,n: i*n + j - i*(i+1)/2 - i - 1
Run Code Online (Sandbox Code Playgroud)
这很容易理解:
i*n + j
你去广场上形成矩阵的位置;- i*(i+1)/2
删除下三角(包括对角线)中之前,我的所有行;- i
您删除对角线之前的第i行中的头寸时;- 1
您卸下对角线行我的位置。校验:
import scipy
from scipy.spatial.distance import pdist, squareform
condensed_idx = lambda i,j,n: i*n + j - i*(i+1)/2 - i - 1
n = 50
dim = 2
x = scipy.random.uniform(size = n*dim).reshape((n, dim))
d = pdist(x)
ds = squareform(d)
for i in xrange(1, n-1):
for j in xrange(i+1, n):
assert ds[i, j] == d[condensed_idx(i, j, n)]
Run Code Online (Sandbox Code Playgroud)
如果有人正在寻找逆变换(即给定一个元素索引idx
,找出(i, j)
对应于它的元素),这里有一个合理的向量解决方案:
def actual_indices(idx, n):
n_row_elems = np.cumsum(np.arange(1, n)[::-1])
ii = (n_row_elems[:, None] - 1 < idx[None, :]).sum(axis=0)
shifts = np.concatenate([[0], n_row_elems])
jj = np.arange(1, n)[ii] + idx - shifts[ii]
return ii, jj
n = 5
k = 10
idx = np.random.randint(0, n, k)
a = pdist(np.random.rand(n, n))
b = squareform(a)
ii, jj = actual_indices(idx, n)]
assert np.allclose(b[ii, jj, a[idx])
Run Code Online (Sandbox Code Playgroud)
我用它来计算矩阵中最接近的行的索引。
m = 3 # how many closest
lowest_dist_idx = np.argpartition(-a, -m)[-m:]
ii, jj = actual_indices(lowest_dist_idx, n) # rows ii[0] and jj[0] are closest
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
38583 次 |
最近记录: |