【问题标题】:Vectorizing nearest neighbor computation向量化最近邻计算
【发布时间】:2017-05-08 17:46:14
【问题描述】:

我有以下函数,它返回一个计算最近邻的数组:

def p_batch(U,X,Y):
    return [nearest(u,X,Y) for u in U]

我想用 numpy 替换 for 循环。我一直在研究 numpy.vectorize() 因为这似乎是正确的方法,但我无法让它工作。这是我迄今为止尝试过的:

def n_batch(U,X,Y):
    vbatch = np.vectorize(nearest)
    return vbatch(U,X,Y)

谁能告诉我哪里出错了?

编辑:

最近的实现:

def nearest(u,X,Y):
    return Y[np.argmin(np.sqrt(np.sum(np.square(np.subtract(u,X)),axis=1)))]

U,X,Y 的函数(M=20,N=100,d=50):

U = numpy.random.mtrand.RandomState(123).uniform(0,1,[M,d])
X = numpy.random.mtrand.RandomState(456).uniform(0,1,[N,d])
Y = numpy.random.mtrand.RandomState(789).randint(0,2,[N])

【问题讨论】:

  • 分享nearest 的实现还是从某个库/包中导入它?另外,为了性能,你可以寻找np.vectorize以外的其他方式。
  • 仅当您向我们展示 nearestUXY 时。
  • np.vectorize 可能永远不是正确的方法。我猜KD-tree 你会更好,至少它在文档中是这样说的:“kd-tree for quick nearest-neighbor lookup”
  • @Divakar 最近的实现已添加!
  • @aryamccarthy:我已经在原始问题中添加了它们!

标签: python arrays numpy vector vectorization


【解决方案1】:

方法#1

您可以使用Scipy's cdist 生成所有这些欧式距离,然后只需使用argmin 并索引到Y -

from scipy.spatial.distance import cdist

out = Y[cdist(U,X).argmin(1)]

示例运行 -

In [76]: M,N,d = 5,6,3
    ...: U = np.random.mtrand.RandomState(123).uniform(0,1,[M,d])
    ...: X = np.random.mtrand.RandomState(456).uniform(0,1,[N,d])
    ...: Y = np.random.mtrand.RandomState(789).randint(0,2,[N])
    ...: 

# Using a loop comprehension to verify values
In [77]: [nearest(U[i], X,Y) for i in range(len(U))]
Out[77]: [1, 0, 0, 1, 1]

In [78]: Y[cdist(U,X).argmin(1)]
Out[78]: array([1, 0, 0, 1, 1])

方法 #2

sklearn.metrics.pairwise_distances_argmin_min 的另一种方式直接给我们那些argmin 索引 -

from sklearn.metrics import pairwise

Y[pairwise.pairwise_distances_argmin(U,X)]

使用M=20,N=100,d=50 进行运行时测试-

In [90]: M,N,d = 20,100,50
    ...: U = np.random.mtrand.RandomState(123).uniform(0,1,[M,d])
    ...: X = np.random.mtrand.RandomState(456).uniform(0,1,[N,d])
    ...: Y = np.random.mtrand.RandomState(789).randint(0,2,[N])
    ...: 

cdistpairwise_distances_argmin 之间进行测试-

In [91]: %timeit cdist(U,X).argmin(1)
10000 loops, best of 3: 55.2 µs per loop

In [92]: %timeit pairwise.pairwise_distances_argmin(U,X)
10000 loops, best of 3: 90.6 µs per loop

针对循环版本的计时 -

In [93]: %timeit [nearest(U[i], X,Y) for i in range(len(U))]
1000 loops, best of 3: 298 µs per loop

In [94]: %timeit Y[cdist(U,X).argmin(1)]
10000 loops, best of 3: 55.6 µs per loop

In [95]: %timeit Y[pairwise.pairwise_distances_argmin(U,X)]
10000 loops, best of 3: 91.1 µs per loop

In [96]: 298.0/55.6   # Speedup with cdist over loopy one
Out[96]: 5.359712230215827

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-03
    • 2015-04-27
    • 2020-05-05
    • 2019-05-26
    • 2021-02-21
    • 2015-03-21
    • 2016-06-03
    • 2020-09-10
    相关资源
    最近更新 更多