python - 如何找到从一个系列到另一个系列的最近邻索引

标签 python python-3.x vectorization knn nearest-neighbor

我有一个目标数组 A,它表示 NCEP 再分析数据中的等压压力水平。 我还有将云观察为长时间序列的压力,B。

我正在寻找的是一个 k 最近邻查找,它返回那些最近邻居的索引,类似于 Matlab 中的 knnsearch 可以在 python 中表示相同,例如:索引,距离 = knnsearch(A, B, n) 其中 indicesA 中最近的 n 索引,对于 B 中的每个值,以及 distanceB 中的值与 A 中最近的值的距离,AB可以有不同的长度(这是我迄今为止发现的大多数解决方案的瓶颈,因此我必须循环 B 中的每个值以返回我的 indices距离)

import numpy as np

A = np.array([1000, 925, 850, 700, 600, 500, 400, 300, 250, 200, 150, 100, 70, 50, 30, 20, 10]) # this is a fixed 17-by-1 array
B = np.array([923, 584.2, 605.3, 153.2]) # this can be any n-by-1 array
n = 2

我想从 indices, distance = knnsearch(A, B, n) 返回的是这样的:

indices = [[1, 2],[4, 5] etc...] 

A中的923首先匹配A[1]=925,然后是A[2]=850A 中的 584.2 首先匹配到 A[4]=600 然后是 A[5]=500

distance = [[72, 77],[15.8, 84.2] etc...]

其中 72 表示 B 中的查询值与 A 中最接近的值之间的距离,例如距离[0, 0] == np.abs(B[0] - A[1])

我能想出的唯一解决办法是:

import numpy as np


def knnsearch(A, B, n):
    indices = np.zeros((len(B), n))
    distances = np.zeros((len(B), n))

    for i in range(len(B)):
        a = A
        for N in range(n):
            dif = np.abs(a - B[i])
            ind = np.argmin(dif)

            indices[i, N] = ind + N
            distances[i, N] = dif[ind + N]
            # remove this neighbour from from future consideration
            np.delete(a, ind)

    return indices, distances


array_A = np.array([1000, 925, 850, 700, 600, 500, 400, 300, 250, 200, 150, 100, 70, 50, 30, 20, 10])
array_B = np.array([923, 584.2, 605.3, 153.2])
neighbours = 2

indices, distances = knnsearch(array_A, array_B, neighbours)

print(indices)
print(distances)

返回:

[[ 1.  2.]
 [ 4.  5.]
 [ 4.  3.]
 [10. 11.]]

[[  2.   73. ]
 [ 15.8  84.2]
 [  5.3  94.7]
 [  3.2  53.2]]

必须有一种方法来删除 for 循环,因为如果我的 A 和 B 数组包含数千个元素和许多最近的邻居,我需要性能......

求助!谢谢:)

最佳答案

第二个循环很容易被向量化。最直接的方法是使用 np.argsort 并选择对应于 n 个最小 dif 值的索引。但是,对于大型数组,因为只需要对 n 个值进行排序,所以最好使用 np.argpartition。 .

因此,代码看起来像这样:

def vector_knnsearch(A, B, n):
    indices = np.empty((len(B), n))
    distances = np.empty((len(B), n))

    for i,b in enumerate(B):
        dif = np.abs(A - b)
        min_ind = np.argpartition(dif,n)[:n] # Returns the indexes of the 3 smallest
                                             # numbers but not necessarily sorted
        ind = min_ind[np.argsort(dif[min_ind])] # sort output of argpartition just in case
        indices[i, :] = ind
        distances[i, :] = dif[ind]

    return indices, distances

正如评论中所说,第一个循环也可以使用 meshgrid 删除,但是,额外使用内存和计算时间来构造 meshgrid 使得这种方法对于我尝试的维度来说更慢(而且这可能会变得更糟对于大型阵列并最终出现内存错误)。此外,代码的可读性降低。总的来说,这可能会使这种方法不那么 pythonic。

def mesh_knnsearch(A, B, n):
    m = len(B)
    rng = np.arange(m).reshape((m,1))
    Amesh, Bmesh = np.meshgrid(A,B)
    dif = np.abs(Amesh-Bmesh)
    min_ind = np.argpartition(dif,n,axis=1)[:,:n]
    ind = min_ind[rng,np.argsort(dif[rng,min_ind],axis=1)]

    return ind, dif[rng,ind]

并不是为了检索 a[rng[0],ind[0]] 将此 rng 定义为二维数组很重要, a[rng[1],ind[1]] 等并保持数组的维度,与检索 a[: ,ind[0]], a[:,ind[1]]

关于python - 如何找到从一个系列到另一个系列的最近邻索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49964379/

相关文章:

python - 哪种导入机制更快?

python - pdf2image 不适用于gunicorn/flask

python - 如何在 __repr__ 函数中返回一个列表?

numpy - 拆分数字并分配给 numpy 数组中的行中的元素

python - 如何检查一个numpy数组的所有元素是否在另一个numpy数组中

python - 在 numpy 数组中查找切片的位置

Python For 循环在增加迭代次数后速度变慢

python - python中的重复导入路径模式

django - 多个Django View 之间的fakeredis

r - 识别一行中不同元素数量的有效方法