Вот 3 альтернативы, один с использованием cdist, два с помощью scipy.spatial.cKDTree:
import itertools as IT
import numpy as np
import scipy.spatial as spatial
import scipy.spatial.distance as dist
np.random.seed(2016)
points1 = np.random.randint(100, size=(10**5, 3))
points2 = np.random.randint(100, size=(1529, 3))
cutoff = 5
def using_cdist(points1, points2, cutoff):
indices = np.where(dist.cdist(points1, points2) <= cutoff)[0]
indices = np.unique(indices)
return indices
def using_kdtree(points1, points2, cutoff):
# build the KDTree using the *smaller* points array
tree = spatial.cKDTree(points2)
groups = tree.query_ball_point(points1, cutoff)
indices = np.unique([i for i, grp in enumerate(groups) if len(grp)])
return indices
def using_kdtree2(points1, points2, cutoff):
# build the KDTree using the *larger* points array
tree = spatial.cKDTree(points1)
groups = tree.query_ball_point(points2, cutoff)
indices = np.unique(IT.chain.from_iterable(groups))
return indices
cdist_result = using_cdist(points1, points2, cutoff)
kdtree_result = using_kdtree(points1, points2, cutoff)
kdtree_result2 = using_kdtree2(points1, points2, cutoff)
assert np.allclose(cdist_result, kdtree_result)
assert np.allclose(cdist_result, kdtree_result2)
Из этих 3-х альтернатив, using_kdtree2
является самым быстрым:
In [80]: %timeit using_kdtree3(points1, points2, cutoff)
10 loops, best of 3: 92.4 ms per loop
In [103]: %timeit using_kdtree(points1, points2, cutoff)
1 loops, best of 3: 938 ms per loop
In [104]: %timeit using_cdist(points1, points2, cutoff)
1 loops, best of 3: 1.51 s per loop
Моя интуиция о том, что будет быть самым быстрым, оказалось совершенно неправильным. I Мысль о создании KDTree с использованием меньшего массива точек будет быстрее всего. Даже если строить KDTree используя больше точек массива является несколько медленнее, вызывая tree.query_ball_point
на меньших точек массива гораздо быстрее:
In [68]: %timeit tree = spatial.cKDTree(points2)
1000 loops, best of 3: 312 µs per loop
In [69]: %timeit tree = spatial.cKDTree(points1)
10 loops, best of 3: 45.7 ms per loop
In [66]: %timeit tree = spatial.cKDTree(points2); groups = tree.query_ball_point(points1, cutoff)
1 loops, best of 3: 933 ms per loop
In [67]: %timeit tree = spatial.cKDTree(points1); groups = tree.query_ball_point(points2, cutoff)
10 loops, best of 3: 89.3 ms per loop
Обратите внимание, что существуют некоторые проблемы, связанные с использованием
def orig(points1, points2, cutoff):
return np.argwhere(dist.cdist(points1, points2).min(axis=0) < cutoff)
Во-первых, позвонив по номеру min(axis=0)
, вы теряете информацию, если две точки в points1
находятся в пределах cutoff
точки в points2
. Вы получите только индекс ближайшей точки. Другая проблема заключается в том, что, вызывая min
по оси 0, все, что остается, является 1-ой осью, которая связана с points2
. Таким образом, orig
возвращает индексы в points2
, а не points1
.
Если два пункта в 'point1' находятся в' cutoff' одной и той же точки в 'points2', вам нужен индекс обеих точек или только ближе? – unutbu
Мне нужен индекс обеих точек - я беру большой pointcloud и небольшой pointcloud и удаляю громкость вокруг маленькой pointcloud из большой pointcloud. – TDN169
Деревья помогут. Я не делал KD-деревья (только quad/octrees), но если вы не добавляете в список, дайте KD выстрел.С предложенной мной второй мыслью, это ускорило мой код до 200%, что было еще медленным. Я добавил деревья, чтобы работать вместе с ним, и общее увеличение скорости было таким же, как 2000%, за 8000 очков (и, по экспоненте, лучше для большего количества очков), поэтому определенно стоит усилий. Это, вероятно, не очень актуально, но вот сообщение, которое я сделал с кодом - http://codereview.stackexchange.com/questions/118299/n-dimensional-maze-generation-with-octrees-and-pathfinding – Peter