我有一个非常大的数组,类似于格式的高程数据:
triplets = ((x0, y0, z0),
(x1, y1, z1),
... ,
(xn, yn, zn))
其中x,y,z都是以米为单位的浮点数。您可以使用以下命令创建与此格式匹配的合适测试数据:
x = np.arange(20, 40, dtype=np.float64)
y = np.arange(30, 50, dtype=np.float64)
z = np.random.random(20) * 25.0
triplets = np.hstack((x, y, z)).reshape((len(x),3))
我希望能够有效地找到给定(x,y)对的相应z值。到目前为止,我的研究引出了更多问题。这就是我所拥有的:
遍历所有三元组:
query = (a, b) # where a, b are the x and y coordinates we're looking for
for i in triplets:
if i[0] == query[0] and i[1] == query[1]:
result = i[2]
缺点:缓慢; a, b
必须存在,这是比较浮点数的问题。
使用scipy.spatial.cKDTree
查找最近的内容:
points = triplets[:,0:2] # drops the z column
tree = cKDTree(points)
idx = tree.query((a, b))[1] # this returns a tuple, we want the index
query = tree.data[idx]
result = triplets[idx, 2]
缺点:返回最近点而不是插值。
根据评论使用interp2d
:
f = interp2d(x, y, z)
result = f(a, b)
缺点:不适用于大型数据集。在真实数据上运行时,我得到OverflowError: Too many data points to interpolate
。 (我的实际数据大约是1100万点。)
所以问题是:是否有任何直截了当的做法让我忽视?有没有办法减少上述的弊端?
答案 0 :(得分:4)
如果你想插入结果,而不是只找到最近邻居的z值,我会考虑做以下的事情:
代码可能如下所示:
import numpy as np
from scipy.spatial import cKDTree
# some fake (x, y, z) data
XY = np.random.rand(10000, 2) - 0.5
Z = np.exp(-((XY ** 2).sum(1) / 0.1) ** 2)
# construct a k-d tree from the (x, y) coordinates
tree = cKDTree(XY)
# a random point to query
xy = np.random.rand(2) - 0.5
# find the k nearest neighbours (say, k=3)
distances, indices = tree.query(xy, k=3)
# the z-values for the k nearest neighbours of xy
z_vals = Z[indices]
# take the average of these z-values, weighted by 1 / distance from xy
dw_avg = np.average(z_vals, weights=(1. / distances))
值得玩一下 k 的值,这是最接近的邻居的平均数。这基本上是kernel density estimation的粗略形式,其中 k 的值控制着你对z值的基础分布强加的'平滑度'。较大的 k 会导致更平滑。
同样,您可能想要根据与(xi,yi)的距离来衡量点的贡献,具体取决于您对 z的相似性的看法随着 x,y 距离的增加而减小。例如,您可能希望按(1 / distances ** 2)
而不是(1 / distances)
加权。
在绩效方面,constructing and searching k-d trees are both very efficient。请记住,您只需要为数据集构建一次树,如果需要,您可以通过将(N,2)数组传递给tree.query()
来一次查询多个点。 / p>
近似最近邻搜索的工具(例如FLANN)可能会更快,但在数据维数非常高的情况下,这些工具通常会更有用。
答案 1 :(得分:3)
我不了解你的cKDTree代码,你得到idx
,为什么再次循环for?您可以通过result = triplets[idx, 2]
获得结果。
from scipy.spatial import cKDTree
x = np.arange(20, 40, dtype=np.float64)
y = np.arange(30, 50, dtype=np.float64)
z = np.random.random(20) * 25.0
triplets = np.hstack((x, y, z)).reshape((len(x),3))
a = 30.1
b = 40.5
points = triplets[:,0:2] # drops the z column
tree = cKDTree(points)
idx = tree.query((a, b))[1] # this returns a tuple, we want the index
result = triplets[idx, 2]
答案 2 :(得分:0)
您可以创建稀疏矩阵并使用简单的索引。
In [1]: import numpy as np
In [2]: x = np.arange(20, 40, dtype=np.float64)
In [3]: y = np.arange(30, 50, dtype=np.float64)
In [4]: z = np.random.random(20) * 25.0
In [9]: from scipy.sparse import coo_matrix
In [12]: m = coo_matrix((z, (x, y))).tolil()
In [17]: m[25,35]
Out[17]: 17.410532044604292