Feragatname: Bu yazıyı çoğunlukla sözdizimsel düşünceler ve genel davranışları göz önünde bulundurarak yazıyorum. Tarif edilen yöntemlerin bellek ve CPU yönüne aşina değilim ve bu cevabı, enterpolasyon kalitesinin dikkate alınması gereken ana husus olabileceği şekilde, oldukça küçük veri kümelerine sahip olanları hedefliyorum. Çok büyük veri kümeleriyle çalışırken, daha iyi performans gösteren yöntemlerin (yani griddata
ve Rbf
) mümkün olmayabileceğinin farkındayım.
Üç çeşit çok boyutlu enterpolasyon yöntemini karşılaştıracağım ( interp2d
/ splines griddata
ve Rbf
). Bunları iki tür enterpolasyon görevine ve iki tür temel işleve tabi tutacağım (enterpolasyon yapılacak noktalar). Spesifik örnekler, iki boyutlu enterpolasyonu gösterecektir, ancak uygulanabilir yöntemler, keyfi boyutlarda uygulanabilir. Her yöntem çeşitli türde enterpolasyon sağlar; her durumda kübik enterpolasyon (veya 1'e yakın bir şey ) kullanacağım . Enterpolasyonu her kullandığınızda, ham verilerinize kıyasla önyargı oluşturduğunuzu ve kullanılan belirli yöntemlerin, sonuçta elde edeceğiniz yapıları etkilediğini unutmamak önemlidir. Her zaman bunun farkında olun ve sorumlu bir şekilde yorumlayın.
İki enterpolasyon görevi,
- yukarı örnekleme (giriş verileri dikdörtgen bir ızgarada, çıktı verileri daha yoğun bir ızgarada)
- Dağınık verilerin normal bir ızgaraya enterpolasyonu
İki işlev (etki alanı üzerinden [x,y] in [-1,1]x[-1,1]
)
- pürüzsüz ve dostça bir işlev
cos(pi*x)*sin(pi*y)
:; aralığı[-1, 1]
- kötü (ve özellikle sürekli olmayan) işlev:
x*y/(x^2+y^2)
başlangıç noktasına yakın 0,5 değerinde; aralığı[-0.5, 0.5]
İşte nasıl göründükleri:
Önce üç yöntemin bu dört test altında nasıl davrandığını göstereceğim, ardından üçünün de sözdizimini detaylandıracağım. Bir yöntemden ne beklemeniz gerektiğini biliyorsanız, sözdizimini öğrenerek (size bakarak interp2d
) zamanınızı boşa harcamak istemeyebilirsiniz .
Test verisi
Açıklık adına, giriş verilerini oluşturduğum kod burada. Bu özel durumda, verinin altında yatan işlevin açıkça farkındayken, bunu yalnızca enterpolasyon yöntemleri için girdi oluşturmak için kullanacağım. Kolaylık sağlamak için (ve çoğunlukla veri oluşturmak için) numpy kullanıyorum, ancak tek başına scipy de yeterli olacaktır.
import numpy as np
import scipy.interpolate as interp
# auxiliary function for mesh generation
def gimme_mesh(n):
minval = -1
maxval = 1
# produce an asymmetric shape in order to catch issues with transpositions
return np.meshgrid(np.linspace(minval,maxval,n), np.linspace(minval,maxval,n+1))
# set up underlying test functions, vectorized
def fun_smooth(x, y):
return np.cos(np.pi*x)*np.sin(np.pi*y)
def fun_evil(x, y):
# watch out for singular origin; function has no unique limit there
return np.where(x**2+y**2>1e-10, x*y/(x**2+y**2), 0.5)
# sparse input mesh, 6x7 in shape
N_sparse = 6
x_sparse,y_sparse = gimme_mesh(N_sparse)
z_sparse_smooth = fun_smooth(x_sparse, y_sparse)
z_sparse_evil = fun_evil(x_sparse, y_sparse)
# scattered input points, 10^2 altogether (shape (100,))
N_scattered = 10
x_scattered,y_scattered = np.random.rand(2,N_scattered**2)*2 - 1
z_scattered_smooth = fun_smooth(x_scattered, y_scattered)
z_scattered_evil = fun_evil(x_scattered, y_scattered)
# dense output mesh, 20x21 in shape
N_dense = 20
x_dense,y_dense = gimme_mesh(N_dense)
Düzgün işlev ve örnekleme
En kolay görevle başlayalım. Sorunsuz test işlevi için [6,7]
bir şekil ağından birine yukarı örnekleme nasıl yapılır [20,21]
:
Bu basit bir görev olsa da, çıktılar arasında halihazırda ince farklılıklar vardır. İlk bakışta üç çıktının tümü makul. Altta yatan işleve ilişkin önceki bilgilerimize dayanarak dikkat edilmesi gereken iki özellik vardır: orta durum griddata
, verileri en çok bozar. Grafiğin y==-1
sınırına dikkat edin ( x
etikete en yakın ): fonksiyon kesinlikle sıfır olmalıdır (çünkü y==-1
düzgün fonksiyon için düğüm çizgisidir), ancak durum böyle değildir griddata
. Ayrıca x==-1
grafiklerin sınırına da dikkat edin (arkada, solda): temeldeki fonksiyonun yerel maksimum değeri (sınırın yakınında sıfır gradyan olduğu anlamına gelir) [-1, -0.5]
, ancak griddata
çıktı bu bölgede açıkça sıfır olmayan gradyan gösterir. Etki inceliklidir, ancak bir önyargıdır. (SadakatRbf
dublajlı varsayılan radyal işlev seçimi ile daha da iyidir multiquadratic
.)
Kötü işlev ve örnekleme
Kötü işlevimiz üzerinde örnekleme yapmak biraz daha zor:
Üç yöntem arasında açık farklar ortaya çıkmaya başlıyor. Yüzey grafiklerine bakıldığında, çıkışta görünen açık sahte ekstremler var interp2d
(çizilen yüzeyin sağ tarafındaki iki tümseklere dikkat edin). İken griddata
ve Rbf
ilk bakışta benzer bir sonuç ortaya, ikincisi yakın daha derin asgari üretim görünüyor [0.4, -0.4]
bu temel işlevinden yoktur.
Bununla birlikte, Rbf
çok daha üstün olan çok önemli bir yön vardır : temelde yatan fonksiyonun simetrisine saygı duyar (bu, elbette numune ağının simetrisiyle de mümkün kılınmıştır). Çıktı griddata
, örnek noktalarının simetrisini bozar ve bu, düzgün durumda zaten zayıf bir şekilde görülebilir.
Düzgün işlev ve dağınık veriler
Çoğu zaman, dağınık veriler üzerinde enterpolasyon yapmak istenir. Bu nedenle bu testlerin daha önemli olmasını bekliyorum. Yukarıda gösterildiği gibi, numune noktaları ilgilenilen alanda sözde tekbiçimli seçilmiştir. Gerçekçi senaryolarda, her ölçümde ek gürültü olabilir ve başlangıçta ham verilerinizi enterpolasyona tabi tutmanın mantıklı olup olmadığını düşünmelisiniz.
Düzgün işlev için çıktı:
Şimdi zaten devam eden bir korku gösterisi var. En azından minimum miktarda bilgiyi korumak için çıktıyı yalnızca çizim interp2d
için arasına kırptım [-1, 1]
. Açıktır ki, altta yatan şeklin bir kısmı mevcutken, yöntemin tamamen bozulduğu çok büyük gürültülü bölgeler vardır. İkinci durum griddata
şekli oldukça güzel bir şekilde yeniden üretir, ancak kontur grafiğinin sınırındaki beyaz bölgelere dikkat edin. Bunun nedeni, griddata
yalnızca giriş veri noktalarının dışbükey gövdesi içinde çalışmasıdır (başka bir deyişle, herhangi bir ekstrapolasyon gerçekleştirmez ). Dışbükey gövdenin dışında yatan çıkış noktaları için varsayılan NaN değerini tuttum. 2 Bu özellikler göz önüne alındığında, Rbf
en iyi performansı gösteriyor gibi görünüyor.
Kötü işlev ve dağınık veriler
Ve hepimizin beklediği an:
Vazgeçen büyük bir sürpriz değil interp2d
. Aslında, interp2d
sizi aradığınızda RuntimeWarning
, spline'ın inşa edilmesinin imkansızlığı konusunda bazı dostların şikayet etmesini beklemelisiniz . Diğer iki yönteme gelince Rbf
, sonucun tahmin edildiği alan sınırlarının yakınında bile en iyi çıktıyı üretiyor gibi görünüyor.
Öyleyse, tercih sırasını azaltarak üç yöntem hakkında birkaç söz söyleyeyim (böylece en kötüsü, herkes tarafından okunma olasılığı en düşük olanıdır).
scipy.interpolate.Rbf
Rbf
Sınıf "radyal tabanlı fonksiyonlar" anlamına gelir. Dürüst olmak gerekirse, bu yazı için araştırmaya başlayana kadar bu yaklaşımı hiç düşünmedim, ancak gelecekte bunları kullanacağımdan oldukça eminim.
Tıpkı spline tabanlı yöntemlerde olduğu gibi (ileriye bakın), kullanım iki adımda gelir: Birincisi Rbf
, giriş verilerine dayalı olarak çağrılabilir bir sınıf örneği oluşturur ve daha sonra, enterpolasyonlu sonucu elde etmek için belirli bir çıktı ağı için bu nesneyi çağırır. Sorunsuz yukarı örnekleme testinden örnek:
import scipy.interpolate as interp
zfun_smooth_rbf = interp.Rbf(x_sparse, y_sparse, z_sparse_smooth, function='cubic', smooth=0) # default smooth=0 for interpolation
z_dense_smooth_rbf = zfun_smooth_rbf(x_dense, y_dense) # not really a function, but a callable class instance
Bu durumda hem giriş hem de çıkış noktalarının 2d diziler olduğunu ve çıktının herhangi bir çaba ile ve çaba olmadan z_dense_smooth_rbf
aynı şekle sahip olduğunu unutmayın . Ayrıca enterpolasyon için rastgele boyutları desteklediğini unutmayın .x_dense
y_dense
Rbf
Yani, scipy.interpolate.Rbf
- çılgın girdi verileri için bile iyi davranan çıktı üretir
- daha yüksek boyutlarda enterpolasyonu destekler
- Giriş noktalarının dışbükey gövdesi dışında tahminler yapar (elbette ekstrapolasyon her zaman bir kumardır ve genellikle buna hiç güvenmemelisiniz)
- ilk adım olarak bir enterpolatör oluşturur, bu nedenle onu çeşitli çıktı noktalarında değerlendirmek daha az ek çaba gerektirir
- rastgele şekle sahip çıktı noktalarına sahip olabilir (dikdörtgen ağlarla sınırlandırılmanın aksine, daha sonra bakın)
- giriş verilerinin simetrisini korumaya eğilimli
- Anahtar kelime için radyal fonksiyonların birden fazla türde destekler
function
: multiquadric
, inverse
, gaussian
, linear
, cubic
, quintic
, thin_plate
ve kullanıcı tanımlı keyfi
scipy.interpolate.griddata
Eski favorim, griddata
keyfi boyutlarda enterpolasyon için genel bir iş gücü. Düğüm noktalarının dışbükey gövdesi dışındaki noktalar için tek bir ön ayar değeri belirlemenin ötesinde bir ekstrapolasyon gerçekleştirmez, ancak ekstrapolasyon çok kararsız ve tehlikeli bir şey olduğundan, bu mutlaka bir con değildir. Kullanım örneği:
z_dense_smooth_griddata = interp.griddata(np.array([x_sparse.ravel(),y_sparse.ravel()]).T,
z_sparse_smooth.ravel(),
(x_dense,y_dense), method='cubic') # default method is linear
Biraz kludgy sözdizimine dikkat edin. Giriş noktaları [N, D]
, D
boyutlarda bir şekil dizisinde belirtilmelidir . Bunun için önce 2d koordinat dizilerimizi (kullanarak ravel
) düzleştirmeli , ardından dizileri birleştirmeli ve sonucu transpoze etmeliyiz . Bunu yapmanın birden çok yolu var, ancak hepsi hantal görünüyor. Giriş z
verilerinin de düzleştirilmesi gerekir. Çıktı noktaları söz konusu olduğunda biraz daha özgürlüğümüz var: bazı nedenlerden dolayı bunlar çok boyutlu dizilerin bir demeti olarak da belirtilebilir. Not bu help
bölgesinin griddata
, yanıltıcı aynı için de geçerli olduğu anlaşılacağı gibi giriş (en azından sürüm 0.17.0 için) noktaları:
griddata(points, values, xi, method='linear', fill_value=nan, rescale=False)
Interpolate unstructured D-dimensional data.
Parameters
----------
points : ndarray of floats, shape (n, D)
Data point coordinates. Can either be an array of
shape (n, D), or a tuple of `ndim` arrays.
values : ndarray of float or complex, shape (n,)
Data values.
xi : ndarray of float, shape (M, D)
Points at which to interpolate data.
Kısaca, scipy.interpolate.griddata
- çılgın girdi verileri için bile iyi davranan çıktı üretir
- daha yüksek boyutlarda enterpolasyonu destekler
- ekstrapolasyon yapmazsa, giriş noktalarının dışbükey gövdesi dışındaki çıktı için tek bir değer ayarlanabilir (bkz.
fill_value
)
- tek bir çağrıda enterpolasyonlu değerleri hesaplar, böylece birden fazla çıktı noktası kümesinin araştırılması sıfırdan başlar
- keyfi şekle sahip çıktı noktaları olabilir
- 1d ve 2d'de kübik, rastgele boyutlarda en yakın komşu ve doğrusal enterpolasyonu destekler. En yakın komşu ve lineer enterpolasyon kullanımı
NearestNDInterpolator
ve LinearNDInterpolator
sırasıyla başlık altında. 1d kübik enterpolasyon bir spline kullanır, 2d kübik enterpolasyon CloughTocher2DInterpolator
sürekli türevlenebilir parça parça kübik enterpolatör oluşturmak için kullanır .
- giriş verilerinin simetrisini ihlal edebilir
scipy.interpolate.interp2d
/scipy.interpolate.bisplrep
Tartışmamın tek nedeni interp2d
ve akrabalarını aldatıcı bir isme sahip olması ve insanların onu kullanmaya çalışması muhtemeldir. Spoiler uyarısı: kullanmayın (scipy sürüm 0.17.0'dan itibaren). Özellikle iki boyutlu enterpolasyon için kullanıldığı için önceki konulardan daha özeldir, ancak bunun çok değişkenli enterpolasyon için en yaygın durum olduğundan şüpheleniyorum.
Sözdizimine gelince, ilk olarak gerçek enterpolasyonlu değerleri sağlamak için çağrılabilen bir enterpolasyon örneği oluşturmaya ihtiyaç duyması interp2d
ile benzerdir Rbf
. Bununla birlikte, bir yakalama var: çıktı noktaları dikdörtgen bir ağ üzerinde konumlandırılmalıdır, bu nedenle, enterpolatöre yapılan çağrıya giden girdiler, aşağıdaki gibi çıktı ızgarasını kapsayan 1d vektörler olmalıdır numpy.meshgrid
:
# reminder: x_sparse and y_sparse are of shape [6, 7] from numpy.meshgrid
zfun_smooth_interp2d = interp.interp2d(x_sparse, y_sparse, z_sparse_smooth, kind='cubic') # default kind is 'linear'
# reminder: x_dense and y_dense are of shape [20, 21] from numpy.meshgrid
xvec = x_dense[0,:] # 1d array of unique x values, 20 elements
yvec = y_dense[:,0] # 1d array of unique y values, 21 elements
z_dense_smooth_interp2d = zfun_smooth_interp2d(xvec,yvec) # output is [20, 21]-shaped array
Kullanırken en yaygın hatalardan biri, interp2d
tam 2d ağlarınızı enterpolasyon çağrısına koymaktır, bu da aşırı bellek tüketimine ve umarım aceleye yol açar MemoryError
.
Şimdi, en büyük sorun, interp2d
çoğu zaman işe yaramamasıdır. Bunu anlamak için kaputun altına bakmamız gerekiyor. Bunun , FITPACK rutinleri (Fortran'da yazılmıştır) için sarmalayıcı olan interp2d
alt düzey işlevler bisplrep
+ için bir sarmalayıcı olduğu ortaya çıktı bisplev
. Önceki örneğe eşdeğer çağrı şöyle olacaktır:
kind = 'cubic'
if kind=='linear':
kx=ky=1
elif kind=='cubic':
kx=ky=3
elif kind=='quintic':
kx=ky=5
# bisplrep constructs a spline representation, bisplev evaluates the spline at given points
bisp_smooth = interp.bisplrep(x_sparse.ravel(),y_sparse.ravel(),z_sparse_smooth.ravel(),kx=kx,ky=ky,s=0)
z_dense_smooth_bisplrep = interp.bisplev(xvec,yvec,bisp_smooth).T # note the transpose
Şimdi, burada bir şey hakkında interp2d
(scipy sürümü 0.17.0 olarak) güzel vardır: yorum yapıninterpolate/interpolate.py
için interp2d
:
if not rectangular_grid:
# TODO: surfit is really not meant for interpolation!
self.tck = fitpack.bisplrep(x, y, z, kx=kx, ky=ky, s=0.0)
ve gerçekten de içinde interpolate/fitpack.py
, içinde bisplrep
var bazı kurulum ve sonuçta
tx, ty, c, o = _fitpack._surfit(x, y, z, w, xb, xe, yb, ye, kx, ky,
task, s, eps, tx, ty, nxest, nyest,
wrk, lwrk1, lwrk2)
Ve bu kadar. Altta yatan rutinler interp2d
gerçekten enterpolasyon gerçekleştirmek için tasarlanmamıştır. Yeterince iyi işlenmiş veriler için yeterli olabilirler, ancak gerçekçi koşullar altında muhtemelen başka bir şey kullanmak isteyeceksiniz.
Sadece sonuçlandırmak için, interpolate.interp2d
- iyi ayarlanmış verilerle bile yapaylıklara yol açabilir
- özellikle iki değişkenli problemler içindir (
interpn
bir ızgarada tanımlanan giriş noktaları için sınırlı olmasına rağmen )
- ekstrapolasyon yapar
- ilk adım olarak bir enterpolatör oluşturur, bu nedenle onu çeşitli çıktı noktalarında değerlendirmek daha az ek çaba gerektirir
- yalnızca dikdörtgen bir ızgara üzerinde çıktı üretebilir, dağınık çıktı için bir döngüde interpolatörü çağırmanız gerekir
- doğrusal, kübik ve beşli enterpolasyonu destekler
- giriş verilerinin simetrisini ihlal edebilir
1 ' in temel işlevlerinin cubic
ve linear
türünün Rbf
aynı adı taşıyan diğer aradeğerlere tam olarak karşılık gelmediğinden oldukça eminim .
2 Bu NaN'ler aynı zamanda yüzey grafiğinin bu kadar tuhaf görünmesinin nedenidir: matplotlib tarihsel olarak karmaşık 3 boyutlu nesneleri doğru derinlik bilgisiyle çizmekte zorluklar yaşamaktadır. Verilerdeki NaN değerleri oluşturucuyu karıştırır, bu nedenle yüzeyin arka tarafta olması gereken kısımları önde olacak şekilde çizilir. Bu, enterpolasyon değil, görselleştirme ile ilgili bir sorundur.