为 numpy 数组的行中的每个点找到最近的 k 个点
Find closest k points for every point in row of numpy array
我有一个 np 数组 X,大小为 1000 x 1000,其中每个元素都是实数。我想为这个 np 数组的每一行中的每个点找到 5 个最近的点。这里的距离度量可以只是 abs(x-y)。我试过了
for i in range(X.shape[0]):
knn = NearestNeighbors(n_neighbors=5)
knn.fit(X[i])
for j in range(X.shape[1])
d = knn.kneighbors(X[i,j], return_distance=False)
但是,这对我不起作用,我不确定它的效率如何。有没有解决的办法?我见过很多用于比较向量的方法,但没有看到任何用于比较单个元素的方法。我知道我可以使用 for 循环并循环并找到最小的 k,但这在计算上会很昂贵。 KD 树可以解决这个问题吗?我试过类似
的方法
Finding index of nearest point in numpy arrays of x and y coordinates
但是,我无法让它工作。是否有一些我不知道的 numpy 函数可以实现这个?
我不太确定您希望最终结果如何。但这绝对能满足您的需求。
np.random.seed([3,1415])
X = np.random.rand(1000, 1000)
获取上三角索引以跟踪每行点的每个组合
x1, x2 = np.triu_indices(X.shape[1], 1)
生成所有距离的数组
d = np.abs(X[:, x1] - X[:, x2])
为每一行找到最接近的 5 个
tpos = np.argpartition(d, 5)[:, :5]
然后 x1[tpos]
给出最近对中第一个点的行位置,而 x2[tpos]
给出最近对中的第二个位置。
为你的每一行数据构造一个 scipy.spatial.cKDTree
的 kdtree。
import numpy as np
import scipy.spatial
def nearest_neighbors(arr, k):
k_lst = list(range(k + 2))[2:] # [2,3]
neighbors = []
for row in arr:
# stack the data so each element is in its own row
data = np.vstack(row)
# construct a kd-tree
tree = scipy.spatial.cKDTree(data)
# find k nearest neighbors for each element of data, squeezing out the zero result (the first nearest neighbor is always itself)
dd, ii = tree.query(data, k=k_lst)
# apply an index filter on data to get the nearest neighbor elements
closest = data[ii].reshape(-1, k)
neighbors.append(closest)
return np.stack(neighbors)
N = 1000
k = 5
A = np.random.random((N, N))
nearest_neighbors(A, k)
这是一个 argsort
ing 解决方案,它努力利用简单的指标:
def nn(A, k):
out = np.zeros((A.shape[0], A.shape[1] + 2*k), dtype=int)
out[:, k:-k] = np.argsort(A, axis=-1)
out[:, :k] = out[:, -k-1, None]
out[:, -k:] = out[:, k, None]
strd = stride_tricks.as_strided(
out, strides=out.strides + (out.strides[-1],), shape=A.shape + (2*k+1,))
delta = A[np.arange(A.shape[0])[:, None, None], strd]
delta -= delta[..., k, None]
delta = np.abs(delta)
s = np.argpartition(delta,(0, k), axis = -1)[..., 1:k+1]
inds = tuple(np.ogrid[:strd.shape[0], :strd.shape[1], :0][:2])
res = np.empty(A.shape + (k,), dtype=int)
res[np.arange(strd.shape[0])[:, None, None], out[:, k:-k, None],
np.arange(k)[None, None, :]] = strd[inds + (s,)]
return res
N = 1000
k = 5
r = 10
A = np.random.random((N, N))
# crude test
print(np.abs(A[np.arange(N)[:, None, None], res]-A[..., None]).mean())
# timings
print(timeit(lambda: nn(A, k), number=r) / r)
输出:
# 0.00150537172454
# 0.4567880852999224
我有一个 np 数组 X,大小为 1000 x 1000,其中每个元素都是实数。我想为这个 np 数组的每一行中的每个点找到 5 个最近的点。这里的距离度量可以只是 abs(x-y)。我试过了
for i in range(X.shape[0]):
knn = NearestNeighbors(n_neighbors=5)
knn.fit(X[i])
for j in range(X.shape[1])
d = knn.kneighbors(X[i,j], return_distance=False)
但是,这对我不起作用,我不确定它的效率如何。有没有解决的办法?我见过很多用于比较向量的方法,但没有看到任何用于比较单个元素的方法。我知道我可以使用 for 循环并循环并找到最小的 k,但这在计算上会很昂贵。 KD 树可以解决这个问题吗?我试过类似
的方法Finding index of nearest point in numpy arrays of x and y coordinates
但是,我无法让它工作。是否有一些我不知道的 numpy 函数可以实现这个?
我不太确定您希望最终结果如何。但这绝对能满足您的需求。
np.random.seed([3,1415])
X = np.random.rand(1000, 1000)
获取上三角索引以跟踪每行点的每个组合
x1, x2 = np.triu_indices(X.shape[1], 1)
生成所有距离的数组
d = np.abs(X[:, x1] - X[:, x2])
为每一行找到最接近的 5 个
tpos = np.argpartition(d, 5)[:, :5]
然后 x1[tpos]
给出最近对中第一个点的行位置,而 x2[tpos]
给出最近对中的第二个位置。
为你的每一行数据构造一个 scipy.spatial.cKDTree
的 kdtree。
import numpy as np
import scipy.spatial
def nearest_neighbors(arr, k):
k_lst = list(range(k + 2))[2:] # [2,3]
neighbors = []
for row in arr:
# stack the data so each element is in its own row
data = np.vstack(row)
# construct a kd-tree
tree = scipy.spatial.cKDTree(data)
# find k nearest neighbors for each element of data, squeezing out the zero result (the first nearest neighbor is always itself)
dd, ii = tree.query(data, k=k_lst)
# apply an index filter on data to get the nearest neighbor elements
closest = data[ii].reshape(-1, k)
neighbors.append(closest)
return np.stack(neighbors)
N = 1000
k = 5
A = np.random.random((N, N))
nearest_neighbors(A, k)
这是一个 argsort
ing 解决方案,它努力利用简单的指标:
def nn(A, k):
out = np.zeros((A.shape[0], A.shape[1] + 2*k), dtype=int)
out[:, k:-k] = np.argsort(A, axis=-1)
out[:, :k] = out[:, -k-1, None]
out[:, -k:] = out[:, k, None]
strd = stride_tricks.as_strided(
out, strides=out.strides + (out.strides[-1],), shape=A.shape + (2*k+1,))
delta = A[np.arange(A.shape[0])[:, None, None], strd]
delta -= delta[..., k, None]
delta = np.abs(delta)
s = np.argpartition(delta,(0, k), axis = -1)[..., 1:k+1]
inds = tuple(np.ogrid[:strd.shape[0], :strd.shape[1], :0][:2])
res = np.empty(A.shape + (k,), dtype=int)
res[np.arange(strd.shape[0])[:, None, None], out[:, k:-k, None],
np.arange(k)[None, None, :]] = strd[inds + (s,)]
return res
N = 1000
k = 5
r = 10
A = np.random.random((N, N))
# crude test
print(np.abs(A[np.arange(N)[:, None, None], res]-A[..., None]).mean())
# timings
print(timeit(lambda: nn(A, k), number=r) / r)
输出:
# 0.00150537172454
# 0.4567880852999224