2010-08-19 33 views
7

Tôi đã cố gắng sử dụng scipy.interpolate.bisplrep() và scipy.interpolate.interp2d() để tìm nội suy cho dữ liệu trên (218x135) 2D hình cầu-cực của tôi lưới. Để tôi vượt qua các mảng 2D, X và Y, của các vị trí Descartes của các nút lưới của tôi. Tôi tiếp tục nhận được lỗi như sau (đối với interp tuyến tính. Với interp2d):Vấn đề với nội suy 2D trong SciPy, lưới không phải hình chữ nhật

"Cảnh báo: Không thể thêm nút thắt nào vì nút bổ sung sẽ trùng với bằng cũ.Đó là nguyên nhân: quá nhỏ hoặc quá lớn trọng lượng đến một điểm dữ liệu không chính xác. (fp> s) kx, ky = 1,1 nx, ny = 4,5 m = 29.430 fp = 1390609718,902140 s = 0,000000"

tôi nhận được một kết quả tương tự cho hai biến splines với giá trị mặc định của tham số làm mịn s vv Dữ liệu của tôi được mịn. Tôi đã đính kèm mã của tôi dưới đây trong trường hợp tôi đang làm điều gì đó rõ ràng là sai.

Bất kỳ ý tưởng nào? Cảm ơn! Kyle

class Field(object): 
    Nr = 0 
    Ntheta = 0 
    grid = np.array([]) 

    def __init__(self, Nr, Ntheta, f): 
    self.Nr = Nr 
    self.Ntheta = Ntheta 
    self.grid = np.empty([Nr, Ntheta]) 
    for i in range(Nr): 
     for j in range(Ntheta): 
     self.grid[i,j] = f[i*Ntheta + j] 


def calculate_lines(filename): 
    ri,ti,r,t,Br,Bt,Bphi,Bmag = np.loadtxt(filename, skiprows=3,\ 
    usecols=(1,2,3,4,5,6,7,9), unpack=True) 
    Nr = int(max(ri)) + 1 
    Ntheta = int(max(ti)) + 1 

    ### Initialise coordinate grids ### 
    X = np.empty([Nr, Ntheta]) 
    Y = np.empty([Nr, Ntheta]) 
    for i in range(Nr): 
    for j in range(Ntheta): 
     indx = i*Ntheta + j 
     X[i,j] = r[indx]*sin(t[indx]) 
     Y[i,j] = r[indx]*cos(t[indx]) 

    ### Initialise field objects ### 
    Bradial = Field(Nr=Nr, Ntheta=Ntheta, f=Br) 

    ### Interpolate the fields ### 
    intp_Br = interpolate.interp2d(X, Y, Bradial.grid, kind='linear') 

    #rbf_0 = interpolate.Rbf(X,Y, Bradial.grid, epsilon=2) 

    return 

Trả lời

13

Added 27Aug: Kyle sau này lên trên một scipy-user thread.

30Màu: @Kyle, có vẻ như có sự kết hợp giữa Cartesion X, Y và polar Xnew, Ynew. Xem "cực" trong các ghi chú quá dài bên dưới.

alt text

# griddata vs SmoothBivariateSpline 
# http://stackoverflow.com/questions/3526514/ 
# problem-with-2d-interpolation-in-scipy-non-rectangular-grid 

# http://www.scipy.org/Cookbook/Matplotlib/Gridding_irregularly_spaced_data 
# http://en.wikipedia.org/wiki/Natural_neighbor 
# http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html 

from __future__ import division 
import sys 
import numpy as np 
from scipy.interpolate import SmoothBivariateSpline # $scipy/interpolate/fitpack2.py 
from matplotlib.mlab import griddata 

__date__ = "2010-10-08 Oct" # plot diffs, ypow 
    # "2010-09-13 Sep" # smooth relative 

def avminmax(X): 
    absx = np.abs(X[ - np.isnan(X) ]) 
    av = np.mean(absx) 
    m, M = np.nanmin(X), np.nanmax(X) 
    histo = np.histogram(X, bins=5, range=(m,M)) [0] 
    return "av %.2g min %.2g max %.2g histo %s" % (av, m, M, histo) 

def cosr(x, y): 
    return 10 * np.cos(np.hypot(x,y)/np.sqrt(2) * 2*np.pi * cycle) 

def cosx(x, y): 
    return 10 * np.cos(x * 2*np.pi * cycle) 

def dipole(x, y): 
    r = .1 + np.hypot(x, y) 
    t = np.arctan2(y, x) 
    return np.cos(t)/r**3 

#............................................................................... 
testfunc = cosx 
Nx = Ny = 20 # interpolate random Nx x Ny points -> Newx x Newy grid 
Newx = Newy = 100 
cycle = 3 
noise = 0 
ypow = 2 # denser => smaller error 
imclip = (-5., 5.) # plot trierr, splineerr to same scale 
kx = ky = 3 
smooth = .01 # Spline s = smooth * z2sum, see note 
    # s is a target for sum (Z() - spline())**2 ~ Ndata and Z**2; 
    # smooth is relative, s absolute 
    # s too small => interpolate/fitpack2.py:580: UserWarning: ier=988, junk out 
    # grr error message once only per ipython session 
seed = 1 
plot = 0 

exec "\n".join(sys.argv[1:]) # run this.py N= ... 
np.random.seed(seed) 
np.set_printoptions(1, threshold=100, suppress=True) # .1f 

print 80 * "-" 
print "%s Nx %d Ny %d -> Newx %d Newy %d cycle %.2g noise %.2g kx %d ky %d smooth %s" % (
    testfunc.__name__, Nx, Ny, Newx, Newy, cycle, noise, kx, ky, smooth) 

#............................................................................... 

    # interpolate X Y Z to xnew x ynew -- 
X, Y = np.random.uniform(size=(Nx*Ny, 2)) .T 
Y **= ypow 
    # 1d xlin ylin -> 2d X Y Z, Ny x Nx -- 
    # xlin = np.linspace(0, 1, Nx) 
    # ylin = np.linspace(0, 1, Ny) 
    # X, Y = np.meshgrid(xlin, ylin) 
Z = testfunc(X, Y) # Ny x Nx 
if noise: 
    Z += np.random.normal(0, noise, Z.shape) 
# print "Z:\n", Z 
z2sum = np.sum(Z**2) 

xnew = np.linspace(0, 1, Newx) 
ynew = np.linspace(0, 1, Newy) 
Zexact = testfunc(*np.meshgrid(xnew, ynew)) 
if imclip is None: 
    imclip = np.min(Zexact), np.max(Zexact) 
xflat, yflat, zflat = X.flatten(), Y.flatten(), Z.flatten() 

#............................................................................... 
print "SmoothBivariateSpline:" 
fit = SmoothBivariateSpline(xflat, yflat, zflat, kx=kx, ky=ky, s = smooth * z2sum) 
Zspline = fit(xnew, ynew) .T # .T ?? 

splineerr = Zspline - Zexact 
print "Zspline - Z:", avminmax(splineerr) 
print "Zspline: ", avminmax(Zspline) 
print "Z:   ", avminmax(Zexact) 
res = fit.get_residual() 
print "residual %.0f res/z2sum %.2g" % (res, res/z2sum) 
# print "knots:", fit.get_knots() 
# print "Zspline:", Zspline.shape, "\n", Zspline 
print "" 

#............................................................................... 
print "griddata:" 
Ztri = griddata(xflat, yflat, zflat, xnew, ynew) 
     # 1d x y z -> 2d Ztri on meshgrid(xnew,ynew) 

nmask = np.ma.count_masked(Ztri) 
if nmask > 0: 
    print "info: griddata: %d of %d points are masked, not interpolated" % (
     nmask, Ztri.size) 
    Ztri = Ztri.data # Nans outside convex hull 
trierr = Ztri - Zexact 
print "Ztri - Z:", avminmax(trierr) 
print "Ztri: ", avminmax(Ztri) 
print "Z:  ", avminmax(Zexact) 
print "" 

#............................................................................... 
if plot: 
    import pylab as pl 
    nplot = 2 
    fig = pl.figure(figsize=(10, 10/nplot + .5)) 
    pl.suptitle("Interpolation error: griddata - %s, BivariateSpline - %s" % (
     testfunc.__name__, testfunc.__name__), fontsize=11) 

    def subplot(z, jplot, label): 
     ax = pl.subplot(1, nplot, jplot) 
     im = pl.imshow(
      np.clip(z, *imclip), # plot to same scale 
      cmap=pl.cm.RdYlBu, 
      interpolation="nearest") 
       # nearest: squares, else imshow interpolates too 
       # todo: centre the pixels 
     ny, nx = z.shape 
     pl.scatter(X*nx, Y*ny, edgecolor="y", s=1) # for random XY 
     pl.xlabel(label) 
     return [ax, im] 

    subplot(trierr, 1, 
     "griddata, Delaunay triangulation + Natural neighbor: max %.2g" % 
     np.nanmax(np.abs(trierr))) 

    ax, im = subplot(splineerr, 2, 
     "SmoothBivariateSpline kx %d ky %d smooth %.3g: max %.2g" % (
     kx, ky, smooth, np.nanmax(np.abs(splineerr)))) 

    pl.subplots_adjust(.02, .01, .92, .98, .05, .05) # l b r t 
    cax = pl.axes([.95, .05, .02, .9]) # l b w h 
    pl.colorbar(im, cax=cax) # -1.5 .. 9 ?? 
    if plot >= 2: 
     pl.savefig("tmp.png") 
    pl.show() 

Ghi chú về suy 2d, BivariateSpline vs griddata.

scipy.interpolate.*BivariateSplinematplotlib.mlab.griddata cả mất mảng 1d như các đối số:

Znew = griddata(X,Y,Z, Xnew,Ynew) 
    # 1d X Y Z Xnew Ynew -> interpolated 2d Znew on meshgrid(Xnew,Ynew) 
assert X.ndim == Y.ndim == Z.ndim == 1 and len(X) == len(Y) == len(Z) 

Các đầu vào X,Y,Z mô tả một bề mặt hoặc đám mây điểm trong không gian 3 chiều: X,Y (hoặc vĩ độ, kinh độ hoặc ...) điểm trên mặt phẳng, và Z bề mặt hoặc địa hình phía trên đó. X,Y có thể điền vào hầu hết các hình chữ nhật [Xmin .. Xmax] x [Ymin .. Ymax], hoặc có thể chỉ là một chữ S hoặc Y trong đó. Bề mặt Z có thể nhẵn hoặc mịn + một chút tiếng ồn, hoặc không trơn tru chút nào, núi lửa thô ráp.

Xnew và Ynew cũng thường là 1d, mô tả lưới hình chữ nhật của | Xnew | x | Ynew | điểm nơi bạn muốn suy hoặc ước tính Z.
Znew = griddata (...) trả về một mảng 2ngày trên lưới này, np.meshgrid (Xnew, Ynew):

Znew[Xnew0,Ynew0], Znew[Xnew1,Ynew0], Znew[Xnew2,Ynew0] ... 
Znew[Xnew0,Ynew1] ... 
Znew[Xnew0,Ynew2] ... 
... 

Xnew, điểm Ynew xa bất kỳ đầu vào X, Y chính tả rắc rối. griddata kiểm tra này:

Một mảng đeo mặt nạ được trả lại nếu có điểm lưới nằm ngoài lồi thân tàu được xác định bởi các dữ liệu đầu vào (không có ngoại suy được thực hiện).

("lồi thân" là khu vực bên trong một ban nhạc cao su tưởng tượng kéo dài xung quanh tất cả các X, Y điểm.)

griddata hoạt động bằng cách đầu tiên xây dựng một Delaunay triangulation của đầu vào X, Y, sau đó thực hiện nội suy Natural neighbor nội suy. Điều này là mạnh mẽ và khá nhanh.

BivariateSpline, mặc dù, có thể ngoại suy, tạo các thay đổi tự nhiên mà không cần cảnh báo. Hơn nữa, tất cả các * thói quen Spline trong Fitpack rất nhạy cảm với smoothing tham số S. cuốn sách Dierckx cho biết (books.google isbn 019853440X p 89.):
nếu S là quá nhỏ, xấp xỉ spline là quá Wiggly và chọn quá nhiều tiếng ồn (overfit);
nếu S quá lớn đường spline sẽ quá mịn và tín hiệu sẽ bị mất (không phù hợp).

Nội suy của dữ liệu phân tán là khó, làm mịn không dễ dàng, cả hai cùng nhau thực sự khó khăn. Interpolator nên làm gì với các lỗ lớn trong XY, hoặc với Z rất ồn ào? ("Nếu bạn muốn bán nó, bạn sẽ phải mô tả nó")

Tuy nhiên, nhiều ghi chú, chữ in nhỏ:

1d vs 2d: Một số interpolators mất X, Y, Z hoặc 1d hoặc 2d. Những người khác chỉ mất 1d, vì vậy làm phẳng trước khi nội suy:

Xmesh, Ymesh = np.meshgrid(np.linspace(0,1,Nx), np.linspace(0,1,Ny)) 
Z = f(Xmesh, Ymesh) # Nx x Ny 
Znew = griddata(Xmesh.flatten(), Ymesh.flatten(), Z.flatten(), Xnew, Ynew) 

On mảng đeo mặt nạ: matplotlib xử lý chúng tốt, âm mưu chỉ lột mặt nạ điểm/không NaN. Nhưng tôi sẽ không đặt cược rằng một chức năng numpy/scipy bozo sẽ làm việc ở tất cả. Kiểm tra nội suy ngoài thân lồi của X, Y như sau:

Znew = griddata(...) 
nmask = np.ma.count_masked(Znew) 
if nmask > 0: 
    print "info: griddata: %d of %d points are masked, not interpolated" % (
     nmask, Znew.size) 
    # Znew = Znew.data # array with NaNs 

On tọa độ cực: X, Y và Xnew, Ynew phải ở trong không gian tương tự, cả Cartesion, hoặc cả hai tại [rmin .. rmax] x [tmin .. tmax].
Để vẽ (r, theta, z) điểm trong 3d:

from mpl_toolkits.mplot3d import Axes3D 
Znew = griddata(R,T,Z, Rnew,Tnew) 
ax = Axes3D(fig) 
ax.plot_surface(Rnew * np.cos(Tnew), Rnew * np.sin(Tnew), Znew) 

Xem thêm (đã không cố gắng này):

ax = subplot(1,1,1, projection="polar", aspect=1.) 
ax.pcolormesh(theta, r, Z) 


Hai lời khuyên cho các lập trình viên cảnh giác:

kiểm tra các ngoại lệ hoặc chia tỷ lệ vui:

def minavmax(X): 
    m = np.nanmin(X) 
    M = np.nanmax(X) 
    av = np.mean(X[ - np.isnan(X) ]) # masked ? 
    histo = np.histogram(X, bins=5, range=(m,M)) [0] 
    return "min %.2g av %.2g max %.2g histo %s" % (m, av, M, histo) 

for nm, x in zip("X Y Z Xnew Ynew Znew".split(), 
       (X,Y,Z, Xnew,Ynew,Znew)): 
    print nm, minavmax(x) 

kiểm tra nội suy với dữ liệu đơn giản:

interpolate(X,Y,Z, X,Y) -- interpolate at the same points 
interpolate(X,Y, np.ones(len(X)), Xnew,Ynew) -- constant 1 ? 
Các vấn đề liên quan