[英]Performance issues with Nearest Neighbor Search and VPTrees
我已经读过这个Q / A- 在python中具有大稀疏矩阵的knn,我有一个类似的问题。 我的雷达数据稀疏数组,大小为125930,经度和纬度具有相同的形状。 只有5%的数据不是NULL。 其余全为NULL。
数据在球体上可用,因此我使用VPTree和大圆距来计算距离。 网格间距是不规则的,我想将此数据插值到球面上的规则网格中,该球面在纬度和经度方向上的距离为0.05度。 在粗网格中,两个纬度之间的间距为0.01,两个经度之间的间距为0.09。 因此,我按照以下方式创建了网格网格,并且我具有以下网格点数-基于不规则网格的经度和纬度的最大值,总计为12960000。
latGrid = np.arange(minLat,maxLat,0.05)
lonGrid = np.arange(minLo,maxLo,0.05)
gridLon,gridLat = np.meshgrid(lonGrid,latGrid)
grid_points = np.c_[gridLon.ravel(),gridLat.ravel()]
radar_data = radar_element[np.nonzero(radar_element)]
lat_surface = lat[np.nonzero(radar_element)]
lon_surface = lon[np.nonzero(radar_element)]
points = np.c_[lon_surface,lat_surface]
if points.size > 0:
tree = vptree.VPTree(points,greatCircleDistance)
for grid_point in (grid_points):
indices = tree.get_all_in_range(grid_point,4.3)
args.append(indices)
问题是查询
get_all_in_range
以上数据的每次通过目前需要12分钟才能运行,我总共有175次通过,总时间为35小时,这是不可接受的。是否有任何方法可以减少网格点的数量(基于一些相似性)发送给查询的索引,因为返回的大部分索引为null? 我还使用了Scikit-learn的BallTree,其性能甚至比这还差。 我不确定FLANN是否适合我的问题。
我只是将其转换为3D坐标并使用欧几里得距离。
您可以使用类似Annoy的方式 (公开:我是作者)
我构建的示例: https : //github.com/erikbern/ping/blob/master/plot.py
首先,我将您的雷达观测值作为纬度/经度放入空间索引中。 为了使用Python,让我们使用R-Tree。 我会遵循以下概念:
http://toblerity.org/rtree/tutorial.html#using-rtree-as-a-cheapo-spatial-database
加载雷达观测值:
for id, (y, x, m) in enumerate(observations):
index.insert(id=id, bounds=(x, y, x, y), obj=(y,x,m))
然后,对于您所需的大圆弧距离,我将计算一个“安全”欧几里德距离以滤除候选点。
您可以在R树中查询输出网格点(x,y)附近的候选点:
candidates = idx.intersection((x - safe_distance, y - safe_distance, x + safe_distance, y+safe distance), objects=True)]
这将为您提供候选点列表,形式为[(y, x, m),...]
现在使用Great Circle计算过滤候选对象。 然后,您可以对其余点对象进行插值。
这是另一种解决问题的策略。 我认为这是一种更好的方法,原因如下:
观测数据的格式为(X,Y,M)( 经度,纬度,测量值 )。
输出是一个具有规则间距的网格,例如每.1度。
首先为您的靠近观测值的输出网格点创建字典:
output = {}
然后获取一个观察点,并在大圆环距离之内找到附近的点。 在附近的输出点开始检查,并按行/列向外迭代,直到在GCD中找到所有可能的观察点。
这将为您提供X和Y的GCD内的网格点列表。类似:
get_points(X,Y) ----> [[x1, y1], [x2,y2]....]
现在,我们将其翻转。 我们要存储每个输出点和附近的观察点列表。 要将点存储在输出字典中,我们需要某种唯一键。 对此,geohash (可将纬度和经度交织并生成唯一的字符串)非常适合。
对于每个输出点(x n ,y n ),计算出geohash,并使用(x n ,y n )将条目添加到输出字典中,并开始(或附加到)观测列表:
key = Geohash.encode(y,x)
if key not in output:
output[key] = { 'coords': [x, y], 'observations' = [[X,Y,M]] }
else:
output[key][observations].append([X,Y,M])
我们存储原始的x,y而不是反转geohash并失去准确性。
运行完所有观测值后,您将拥有一个需要计算的所有输出点的字典,每个点都具有GCD要求范围内的观测值列表。
然后,您可以遍历这些点并计算输出数组的索引和内插值,并将其写入输出数组:
def get_indices(x,y):
''' converts a x,y to row,column in the output array '''
....
return row, column
def get_weighted value(point):
''' takes a point entry and performs inverse distance weighting
using the point's coordinates and list of observations '''
....
return value
for point in output:
row, column = get_indices(point['coords'])
idw = get_weighted_value(point)
outarray[column,row] = idw
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.