Python 为numpy数组行中的每个点查找最近的k点

Python 为numpy数组行中的每个点查找最近的k点,python,sorting,numpy,knn,Python,Sorting,Numpy,Knn,我有一个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_di

我有一个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循环和loop over来找到最小的k,但是这在计算上会很昂贵。KD树可以用于此吗?我尝试过类似的方法


然而,我不能让这个工作。是否有一些我不知道的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]
给出最接近对的第二个位置。

为数据的每一行构建一个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

“最近的”是什么意思?价值最接近?那么“点”是什么呢?假设r行=[1,10,11,15,18,16,19,18]。对于r中的每个元素,我想找到r中的k个其他元素,它们的值与我们正在查看的元素最接近。所以我们看1,找到最接近它的k个数。然后我们看10,找到与之最接近的k个数,然后。。。。然后是18,并找到与之最接近的k个数字。是的,这是一个预测矩阵,因此行是人,列是项。对于每一行,您希望得到一个1000x5数组作为结果?因为您的度量非常简单,您不能只对行进行
sort
(或
argsort
)吗?这会立即将候选最近邻的数量减少到每点2k,其中k是示例中的5。干得好,也打败我吧。我要补充的是,与通过循环中元素和行之间的差异对向量进行
np.argpartition
的方法相比,这要快6-7倍。(~3秒~18秒)。我认为较新版本的scipy在
树中有一个
n_jobs
参数。我的版本没有这个参数,但这可能会提高性能。