fastest way to use numpy.interp on a 2-D array

穿精又带淫゛_ 提交于 2019-11-30 15:22:36

So basically you want output equivalent to

np.array([np.interp(x[i], xp, fp[i]) for i in range(x.size)])

But that for loop is going to make that pretty slow for large x.size

This should work:

def multiInterp(x, xp, fp):
    i, j = np.nonzero(np.diff(np.array(xp)[None,:] < x[:,None]))
    d = (x - xp[j]) / np.diff(xp)[j]
    return fp[i, j] + np.diff(fp)[i, j] * d

EDIT: This works even better and can handle bigger arrays:

def multiInterp2(x, xp, fp):
    i = np.arange(x.size)
    j = np.searchsorted(xp, x) - 1
    d = (x - xp[j]) / (xp[j + 1] - xp[j])
    return (1 - d) * fp[i, j] + fp[i, j + 1] * d

Testing:

multiInterp2(x, xp, fp)
Out: 
array([ 0.17196795,  0.73908678,  0.85459966,  0.49980648,  0.59893702,
        0.9344241 ,  0.19840596,  0.45777785,  0.92570835,  0.17977264])

Timing tests with original data:

    %timeit multiInterp2(x, xp, fp)
The slowest run took 6.87 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 25.5 µs per loop

%timeit np.concatenate([compiled_interp(x[[i]], xp, fp[i]) for i in range(fp.shape[0])])
The slowest run took 4.03 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 39.3 µs per loop

Seems to be faster even for a small size of x

Let's try something much, much bigger:

n = 10000
m = 10000

xp = np.linspace(0, 1, n)
x = np.random.rand(m)
fp = np.random.rand(m, n)

%timeit b()  # kazemakase's above
10 loops, best of 3: 38.4 ms per loop

%timeit multiInterp2(x, xp, fp)
100 loops, best of 3: 2.4 ms per loop

The advantages scale a lot better even than the complied version of np.interp

np.interp is basically a wrapper around the compiled numpy.core.multiarray.interp. We can shave off a bit of performance by using it directly:

from numpy.core.multiarray import interp as compiled_interp

def a(x=x, xp=xp, fp=fp):
    return np.array([np.interp(x[i], xp, fp[i]) for i in range(fp.shape[0])])

def b(x=x, xp=xp, fp=fp):
    return np.concatenate([compiled_interp(x[[i]], xp, fp[i]) for i in range(fp.shape[0])])

def multiInterp(x=x, xp=xp, fp=fp):
    i, j = np.nonzero(np.diff(xp[None,:] < x[:,None]))
    d = (x - xp[j]) / np.diff(xp)[j]
    return fp[i, j] + np.diff(fp)[i, j] * d

Timing tests show that for the example arrays this is en par with Daniel Forsman's nice solution:

%timeit a()
10000 loops, best of 3: 44.7 µs per loop

%timeit b()
10000 loops, best of 3: 32 µs per loop

%timeit multiInterp()
10000 loops, best of 3: 33.3 µs per loop

update

For somewhat larger arrays multiInterp owns the floor:

n = 100
m = 1000

xp = np.linspace(0, 1, n)
x = np.random.rand(m)
fp = np.random.rand(m, n)

%timeit a()
100 loops, best of 3: 4.14 ms per loop

%timeit b()
100 loops, best of 3: 2.97 ms per loop

%timeit multiInterp()
1000 loops, best of 3: 1.42 ms per loop

But for even larger ones it falls behind:

n = 1000
m = 10000

%timeit a()
10 loops, best of 3: 43.3 ms per loop

%timeit b()
10 loops, best of 3: 32.9 ms per loop

%timeit multiInterp()
10 loops, best of 3: 132 ms per loop

Finally, for very big arrays (I'm on 32 bit) temporary arrays become a problem:

n = 10000
m = 10000

%timeit a()
10 loops, best of 3: 46.2 ms per loop

%timeit b()
10 loops, best of 3: 32.1 ms per loop

%timeit multiInterp()
# MemoryError
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!