同じ不規則なグリッド_(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
_を使用してこれを行っていますが、うまく機能しています。ただし、各補間を個別に実行する必要があり、ポイントが多いため、計算が非常に重複して(つまり、最も近いポイントを見つける、グリッドを設定するなど)、非常に時間がかかります。
計算を高速化し、重複する計算を減らす方法はありますか?つまり、2つのグリッドを定義し、補間の値を変更するという方針に沿った何かですか?
scipy.interpolate.griddata
に電話をかけるたびに、いくつかのことが起こっています。
sp.spatial.qhull.Delaunay
を呼び出して、不規則なグリッド座標を三角測量します。最初の3つの手順はすべての内挿で同じであるため、新しいグリッドポイントごとに、囲んでいるシンプレックスの頂点のインデックスと内挿の重みを格納できれば、計算量を大幅に最小限に抑えることができます。残念ながら、これは利用可能な機能を使用して直接行うのは簡単ではありませんが、実際には可能です。
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
は、上記の最初の3つのステップの計算を実行します。次に、関数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
の呼び出しとほぼ同じです。しかし第3に、同じグリッド上の異なる値を事実上短時間で補間できるようになりました。
ここで考慮されていないgriddata
が行う唯一のことは、外挿する必要のあるポイントにfill_value
を割り当てることです。これを行うには、重みの少なくとも1つが負であるポイントをチェックします。例:
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
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))
イメージマッピングなどの画像変換を適用することが可能です。
新しい座標は反復ごとに変更されるため、同じ関数定義を使用することはできませんが、三角測量を一度だけ計算することはできます。
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倍です!
それが誰かを助けることができることを願っています
高性能のデータ構造を提供するため、 Pandas を使用してみることができます。
補間方法がscipy補間のラッパーであることは事実ですが、構造が改善されていると、速度が向上する可能性があります。
_import pandas as pd;
wp = pd.Panel(randn(2, 5, 4));
wp.interpolate();
_
interpolate()
は、 さまざまなメソッド を使用してPanelデータセットのNaN値を入力します。 Scipyよりも速いことを願っています。
機能しない場合(コードの並列バージョンを使用する代わりに)パフォーマンスを向上させる1つの方法があります: Cython を使用し、Cで小さなルーチンを実装してPythonコード内で使用します。 ここ これに関する例があります。
私は同じ問題を抱えていました(グリッドデータは非常に遅く、グリッドは多くの補間で同じままです)そして私は解決策が好きでした ここで説明 主に理解と適用が非常に簡単であるためです。
LinearNDInterpolator
を使用しており、1回だけ計算する必要がある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倍高速化されます。