我有几个值在同一个不规则网格(x, y, z)
上定义,我想要插入到新网格(x1, y1, z1)
上。即,我有f(x, y, z), g(x, y, z), h(x, y, z)
,我想计算f(x1, y1, z1), g(x1, y1, z1), h(x1, y1, z1)
。
目前我正在使用scipy.interpolate.griddata
执行此操作并且效果很好。但是,因为我必须单独执行每个插值并且有很多点,所以它很慢,计算中有大量重复(即找到哪些点最接近,设置网格等...)。 p>
有没有办法加快计算速度并减少重复计算?即沿着定义两个网格的线,然后改变插值的值?
答案 0 :(得分:36)
每次拨打scipy.interpolate.griddata
时都会发生一些事情:
sp.spatial.qhull.Delaunay
以对不规则网格坐标进行三角测量。对于所有插值,前三个步骤是相同的,因此如果您可以为每个新网格点存储封闭单形的顶点索引和插值的权重,则可以最小化计算量很多。遗憾的是,直接使用可用的功能并不容易,尽管确实可行:
import scipy.interpolate as spint
import scipy.spatial.qhull as qhull
import itertools
def interp_weights(xyz, uvw):
tri = qhull.Delaunay(xyz)
simplex = tri.find_simplex(uvw)
vertices = np.take(tri.simplices, simplex, axis=0)
temp = np.take(tri.transform, simplex, axis=0)
delta = uvw - temp[:, d]
bary = np.einsum('njk,nk->nj', temp[:, :d, :], delta)
return vertices, np.hstack((bary, 1 - bary.sum(axis=1, keepdims=True)))
def interpolate(values, vtx, wts):
return np.einsum('nj,nj->n', np.take(values, vtx), wts)
函数interp_weights
执行上面列出的前三个步骤的计算。然后函数interpolate
使用这些计算值非常快地执行第4步:
m, n, d = 3.5e4, 3e3, 3
# make sure no new grid point is extrapolated
bounding_cube = np.array(list(itertools.product([0, 1], repeat=d)))
xyz = np.vstack((bounding_cube,
np.random.rand(m - len(bounding_cube), d)))
f = np.random.rand(m)
g = np.random.rand(m)
uvw = np.random.rand(n, d)
In [2]: vtx, wts = interp_weights(xyz, uvw)
In [3]: np.allclose(interpolate(f, vtx, wts), spint.griddata(xyz, f, uvw))
Out[3]: True
In [4]: %timeit spint.griddata(xyz, f, uvw)
1 loops, best of 3: 2.81 s per loop
In [5]: %timeit interp_weights(xyz, uvw)
1 loops, best of 3: 2.79 s per loop
In [6]: %timeit interpolate(f, vtx, wts)
10000 loops, best of 3: 66.4 us per loop
In [7]: %timeit interpolate(g, vtx, wts)
10000 loops, best of 3: 67 us per loop
首先,它与griddata
相同,这很好。其次,设置插值,即计算vtx
和wts
与调用griddata
大致相同。但第三,您现在几乎可以立即在同一网格上插入不同的值。
此处未考虑griddata
做的唯一事情是将fill_value
分配给必须外推的点。您可以通过检查至少一个权重为负数的点来做到这一点,例如:
def interpolate(values, vtx, wts, fill_value=np.nan):
ret = np.einsum('nj,nj->n', np.take(values, vtx), wts)
ret[np.any(wts < 0, axis=1)] = fill_value
return ret
答案 1 :(得分:4)
非常感谢Jaime的解决方案(即使我真的不明白如何完成重心计算......)
在这里,您将找到一个根据他的案例改编自2D的例子:
import scipy.interpolate as spint
import scipy.spatial.qhull as qhull
import numpy as np
def interp_weights(xy, uv,d=2):
tri = qhull.Delaunay(xy)
simplex = tri.find_simplex(uv)
vertices = np.take(tri.simplices, simplex, axis=0)
temp = np.take(tri.transform, simplex, axis=0)
delta = uv - temp[:, d]
bary = np.einsum('njk,nk->nj', temp[:, :d, :], delta)
return vertices, np.hstack((bary, 1 - bary.sum(axis=1, keepdims=True)))
def interpolate(values, vtx, wts):
return np.einsum('nj,nj->n', np.take(values, vtx), wts)
m, n = 101,201
mi, ni = 1001,2001
[Y,X]=np.meshgrid(np.linspace(0,1,n),np.linspace(0,2,m))
[Yi,Xi]=np.meshgrid(np.linspace(0,1,ni),np.linspace(0,2,mi))
xy=np.zeros([X.shape[0]*X.shape[1],2])
xy[:,0]=Y.flatten()
xy[:,1]=X.flatten()
uv=np.zeros([Xi.shape[0]*Xi.shape[1],2])
uv[:,0]=Yi.flatten()
uv[:,1]=Xi.flatten()
values=np.cos(2*X)*np.cos(2*Y)
#Computed once and for all !
vtx, wts = interp_weights(xy, uv)
valuesi=interpolate(values.flatten(), vtx, wts)
valuesi=valuesi.reshape(Xi.shape[0],Xi.shape[1])
print "interpolation error: ",np.mean(valuesi-np.cos(2*Xi)*np.cos(2*Yi))
print "interpolation uncertainty: ",np.std(valuesi-np.cos(2*Xi)*np.cos(2*Yi))
可以应用图像变换,例如使用udge加速的图像映射
您不能使用相同的函数定义,因为新坐标会在每次迭代时更改,但您可以计算三角测量一次性。
import scipy.interpolate as spint
import scipy.spatial.qhull as qhull
import numpy as np
import time
# Definition of the fast interpolation process. May be the Tirangulation process can be removed !!
def interp_tri(xy):
tri = qhull.Delaunay(xy)
return tri
def interpolate(values, tri,uv,d=2):
simplex = tri.find_simplex(uv)
vertices = np.take(tri.simplices, simplex, axis=0)
temp = np.take(tri.transform, simplex, axis=0)
delta = uv- temp[:, d]
bary = np.einsum('njk,nk->nj', temp[:, :d, :], delta)
return np.einsum('nj,nj->n', np.take(values, vertices), np.hstack((bary, 1.0 - bary.sum(axis=1, keepdims=True))))
m, n = 101,201
mi, ni = 101,201
[Y,X]=np.meshgrid(np.linspace(0,1,n),np.linspace(0,2,m))
[Yi,Xi]=np.meshgrid(np.linspace(0,1,ni),np.linspace(0,2,mi))
xy=np.zeros([X.shape[0]*X.shape[1],2])
xy[:,1]=Y.flatten()
xy[:,0]=X.flatten()
uv=np.zeros([Xi.shape[0]*Xi.shape[1],2])
# creation of a displacement field
uv[:,1]=0.5*Yi.flatten()+0.4
uv[:,0]=1.5*Xi.flatten()-0.7
values=np.zeros_like(X)
values[50:70,90:150]=100.
#Computed once and for all !
tri = interp_tri(xy)
t0=time.time()
for i in range(0,100):
values_interp_Qhull=interpolate(values.flatten(),tri,uv,2).reshape(Xi.shape[0],Xi.shape[1])
t_q=(time.time()-t0)/100
t0=time.time()
values_interp_griddata=spint.griddata(xy,values.flatten(),uv,fill_value=0).reshape(values.shape[0],values.shape[1])
t_g=time.time()-t0
print "Speed-up:", t_g/t_q
print "Mean error: ",(values_interp_Qhull-values_interp_griddata).mean()
print "Standard deviation: ",(values_interp_Qhull-values_interp_griddata).std()
在我的笔记本电脑上,加速时间在20到40倍之间!
希望可以帮助某人
答案 2 :(得分:0)
您可以尝试使用Pandas,因为它提供了高性能的数据结构。
插值方法确实是scipy插值的包装器但是可能通过改进的结构可以获得更好的速度。
import pandas as pd;
wp = pd.Panel(randn(2, 5, 4));
wp.interpolate();
interpolate()
使用different methods填充Panel数据集中的NaN值。希望它比Scipy快。
如果不起作用,有一种方法可以提高性能(而不是使用代码的并行化版本):使用Cython并在C中实现小例程在Python代码中使用。 Here你有一个关于此的例子。
答案 3 :(得分:0)
我遇到了同样的问题(网格数据极慢,许多插值网格保持不变),我最喜欢解决方案described here,主要是因为它很容易理解和应用。
它正在使用LinearNDInterpolator
,在这里可以通过仅需计算一次的Delaunay三角剖分。复制并粘贴该帖子(所有功劳均归功于xdze2):
from scipy.spatial import Delaunay
from scipy.interpolate import LinearNDInterpolator
tri = Delaunay(mesh1) # Compute the triangulation
# Perform the interpolation with the given values:
interpolator = LinearNDInterpolator(tri, values_mesh1)
values_mesh2 = interpolator(mesh2)
这使我的计算速度提高了大约2倍。