SciPy interp2D for pairs of coordinates

2020-07-13 10:15发布

I'm using scipy.interpolate.interp2d to create an interpolation function for a surface. I then have two arrays of real data that I want to calculate interpolated points for. If I pass the two arrays to the interp2d function I get an array of all the points, not just the pairs of points.

My solution to this is to zip the two arrays into a list of coordinate pairs and pass this to the interpolation function in a loop:

f_interp = interpolate.interp2d(X_table, Y_table,Z_table, kind='cubic')

co_ords = zip(X,Y)
out = []
for i in range(len(co_ords)):
    X = co_ords[i][0]
    Y = co_ords[i][1]
    value = f_interp(X,Y)
    out.append(float(value))

My question is, is there a better (more elegant, Pythonic?) way of achieving the same result?

4条回答
一夜七次
2楼-- · 2020-07-13 10:57

For one, you can do

for Xtmp,Ytmp in zip(X,Y):
    ...

in your loop. Or even better, just

out = [float(f_interp(XX,YY)) for XX,YY in zip(X,Y)]

replacing the loop.

On a different note, I suggest using interpolate.griddata instead. It tends to behave much better than interp2d, and it accepts arbitrary-shaped points as input. As you've seen, interp2d interpolators will only return you values on a mesh.

查看更多
该账号已被封号
3楼-- · 2020-07-13 10:59

Passing all of your points at once will probably be quite a lot faster than looping over them in Python. You could use scipy.interpolate.griddata:

Z = interpolate.griddata((X_table, Y_table), Z_table, (X, Y), method='cubic')

or one of the scipy.interpolate.BivariateSpline classes, e.g. SmoothBivariateSpline:

itp = interpolate.SmoothBivariateSpline(X_table, Y_table, Z_table)
# NB: choose grid=False to get an (n,) rather than an (n, n) output
Z = itp(X, Y, grid=False)

CloughTocher2DInterpolator also works in a similar fashion, but without the grid=False parameter (it always returns a 1D output).

查看更多
成全新的幸福
4楼-- · 2020-07-13 10:59

Inspired by this thread where someone recommends using the internal weights of the interp2d function, I've created the following wrapper which has exactly the same interface as interp2d but the interpolant evaluate pairs of inputs and return a numpy array of the same shape of its inputs. The performances should be better than for loops or list comprehension, but when evaluated on a grid it will be slightly outperformed by the scipy interp2d.

import scipy.interpolate as si
def interp2d_pairs(*args,**kwargs):
    """ Same interface as interp2d but the returned interpolant will evaluate its inputs as pairs of values.
    """
    # Internal function, that evaluates pairs of values, output has the same shape as input
    def interpolant(x,y,f):
        x,y = np.asarray(x), np.asarray(y)
        return (si.dfitpack.bispeu(f.tck[0], f.tck[1], f.tck[2], f.tck[3], f.tck[4], x.ravel(), y.ravel())[0]).reshape(x.shape)
    # Wrapping the scipy interp2 function to call out interpolant instead
    return lambda x,y: interpolant(x,y,si.interp2d(*args,**kwargs))

# Create the interpolant (same interface as interp2d)
f = interp2d_pairs(X,Y,Z,kind='cubic')
# Evaluate the interpolant on each pairs of x and y values
z=f(x,y)
查看更多
Anthone
5楼-- · 2020-07-13 11:13

Try *args and tuple packing/unpacking

points = zip(X, Y)
out = []
for p in points:
    value = f_interp(*p)
    out.append(float(value))

or just

points = zip(X, Y)
out = [float(f_interp(*p)) for p in points]

or just

out = [float(f_interp(*p)) for p in zip(X, Y)]

as a side note, the "magic star" allows zip to be its own inverse!

points = zip(x, y)
x, y   = zip(*points)
查看更多
登录 后发表回答