Speed ​​up the Scipy RectBivariateSpline scoring function

My question is about using a function scipy.interpolate.RectBivariateSpline

to interpolate a 2D mesh. I am essentially trying to emulate the functionality of the Matlab interp2 function.

For a specific (lightweight) use case, I call RectBivariateSpline on vectors x and y that are regularly spaced, monotonically increasing vectors, like this:

x = np.arange(0., 20., 1.)  # shape (20,)
y = np.arange(0., 20., 1.)  # shape (20,)

      

and some two dimensional field, for example:

fld = np.reshape(np.arange(0., 400., 1.), (20, 20))  # shape (20, 20)

      

i.e:.

fn = sp.interpolate.RectBivariateSpline(x, y, fld)

      

To evaluate the interpolation, then at certain coordinates xi, yi (or arrays obeying multiple broadcasts), the documents advise calling a function RectBivariateSpline.ev

, i.e .:

val1 = fn.ev(1, 1)  # Ans: 21
val2 = fn.ev([1, 2], [1, 2])  # Ans: [21, 22]

      

This allows the user to find one interpolated value, for example (xi, yi) = (1.5, 1.5), or many interpolated values, for example, on a specific domain (regular or irregular grid).

My question is this: for large xi, yi arrays, how can I make the fn.ev call faster? Compared to calling Matlab, interp2

it is quite slow (by an order of magnitude or worse).

After calling the function in the debugger, I discovered what ev

is actually a wrapper for RectBivariateSpline.__call__

. This is again a wrapper for calling fitpack functions (in C / Fortran) that Scipy's interpolation function is based on. The function __call__

has an optional keyword grid

, a default value False

and is absent in ev

, which allows two vectors to be passed to define an orthogonal mesh. Calling c grid

, set to True

, results in a call to the fitpack subroutine bispev

, which is much faster than the documented function ev

that calls fitpack bispeu

. (I assume the performance gain is due to the fact that it bispev

uses a regular grid, whilebispeu

can just iterate over all pairs of indices ... although I'm not sure).

Anyway, I want to call the function .ev

in such a way that I can interpolate the grid, which may not be quite regular (but close), and it will be faster than the current call bispeu

. "Regularizing" the grid and transitioning with bispev

is an option, and the PRETTY end results are closed, and the procedure is much faster (20 times!) ... however, Matlab interp2

allows a slightly irregular grid and computes at the same speed. I thought about trying to write my own C function, but I very much doubt that as humble as I can do better than what is already in Scipi and written by geniuses. :)

So ... is there a way I can have my cake and eat it too? Is there some awful little tricky way I can call a spline evaluator? I thought about making my own wrapper for calls to fitpack ... but documentation for fitpack is not available (certainly not in the Scipy release I have) and I would like to avoid this extra work if possible. Also note that this problem is especially fierce because I have to call it twice, for real and imaginary components of my original field (Matlab accepts complex meshes). In the end, I want to give Matlab BOOT ... but this speed issue can be a killer.

Thank you for your time.

+3


source to share


1 answer


I know this is an old question, but I cannot reproduce what you described in MATLAB and python. First in MATLAB

grid_size = 100;
xrange = linspace(0, 1, grid_size);
yrange = linspace(0, 1, grid_size);

[x2D, y2D] = meshgrid(xrange, yrange);
z2D = x2D.^2 + y2D;

tic
samples = 1e5;
for j = 1:samples
    qinterp2(x2D,y2D,z2D,0.5,0.5);
end
fprintf('MATLAB qinterp2 %0.6f[us]\n',toc/samples*1e6);

tic
samples = 5000;
for j = 1:samples
    interp2(x2D,y2D,z2D,0.5,0.5);
end
fprintf('MATLAB interp2 %0.6f[us]\n',toc/samples*1e6);

      

yeilds:

MATLAB qinterp2 3.415404[us]
MATLAB interp2 228.489602[us]

      

This is using qinterp2 from https://www.mathworks.com/matlabcentral/fileexchange/10772-fast-2-dimensional-interpolation



In python:

from __future__ import division
import numpy as np
import time
from scipy.interpolate import RectBivariateSpline, interp2d


grid_size = 100
xrange = np.linspace(0, 1, grid_size)
yrange = np.linspace(0, 1, grid_size)
x2d, y2D = np.meshgrid(xrange, yrange, indexing='ij')

z2D = x2d ** 2.0 + y2D

i2d = interp2d(xrange, yrange, z2D, 'linear')
rbs = RectBivariateSpline(xrange, yrange, z2D)

samples = 100000

start = time.time()
for n in range(samples):
    i2d(0.5, 0.5)
end = time.time()
print 'Python interp2d: %0.4f [us]' % (((end-start)/samples)*1e6)

start = time.time()
for n in range(samples):
    rbs(0.5, 0.5)
end = time.time()
print 'Python RectBivariateSpline: %0.4f [us]' % (((end-start)/samples)*1e6)

      

profitability

Python interp2d: 13.5500 [us]
Python RectBivariateSpline: 2.6800 [us]

      

Am I missing something in the way I do these tests? It seems that RectBivariateSpline is faster than interp2d in python and much faster than interp2 in MATLAB and even qinterp2 in MATLAB. RectBivariateSpline is also of higher order and allows for non-uniform grid spacing.

0


source







All Articles