【问题标题】:Multiple 1d interpolations in pythonpython中的多个一维插值
【发布时间】:2016-02-25 03:19:37
【问题描述】:

我正在模拟 CCD 阵列中的陷阱。目前我正在使用 NumPy 和 Scipy,并且我已经能够对大多数调用进行矢量化,这给了我一些加速。 目前,我代码的瓶颈是我必须从代​​码内部循环中的大量不同插值中检索一个数字。这一特定步骤占用了约 97% 的计算时间。

我在这里做了一个简单的例子来说明我的问题:

import numpy as np
from scipy.interpolate import interp1d

# the CCD array containing values from 0-100
array = np.random.random(200)*100

# a number of traps at different positions in the CCD array 
n_traps = 100
trap_positions = np.random.randint(0,200,n_traps)

# xvalues for the interpolations
xval = [0,10,100]
# each trap has y values corresponding to the x values 
trap_yvals = [np.random.random(3)*100 for _ in range(n_traps)]
# The xval-to-yval interpolation is made for each trap
yval_interps = [interp1d(xval,yval) for yval in trap_yvals]

# moving the trap positions down over the array
for i in range(len(array)):
    # calculating new trap position
    new_trap_pos = trap_positions+i
    # omitting traps that are outside array
    trap_inside_array = new_trap_pos < len(array)
    # finding the array_vals (corresponding to the xvalues in the interpolations)
    array_vals = array[new_trap_pos[trap_inside_array]]

    # retrieving the interpolated y-values (this is the bottleneck)
    yvals = np.array([yval_interps[trap_inside_array[t]](array_vals[t]) 
                       for t in range(len(array_vals))])

    # some more operations using yvals

有没有办法可以优化,可能使用 Cython 或类似的?

【问题讨论】:

  • 请参阅this,而不是 interp1d,使用 InterpolatedUnivariateSpline。将性能提高几个数量级
  • 另一个重大改进是将数组作为参数传递给 interp1d/InterpolatedUnivariateSpline,而不是尽可能循环单个值
  • @M.T:感谢有关使用 InterpolatedUnivariateSpline 加速的提示。我在单个值上循环的原因是每个值都需要从不同的插值中提取,我没有找到解决这个问题的方法。

标签: python numpy scipy linear-interpolation


【解决方案1】:

我仔细考虑了这一点,我想我找到了一个非常好的解决方案,我想分享,尽管这意味着我将回答我自己的问题。

首先,我突然意识到,我可以找到两个值之间的插值,而不是使用其中一个 scipy.interpolation 函数。这个小功能就可以搞定

from bisect import bisect_left

def two_value_interpolation(x,y,val):
    index = bisect_left(x,val)
    _xrange = x[index] - x[index-1]
    xdiff = val - x[index-1]
    modolo = xdiff/_xrange
    ydiff = y[index] - y[index-1]
    return y[index-1] + modolo*ydiff

这给了我一些加速,但我想看看我是否可以做得更好,所以我将函数移植到 Cython 并在所有陷阱上添加了循环,所以我不必在 python 代码中这样做:

# cython: boundscheck=False
# cython: wraparound=False
# cython: cdivision=True

import numpy as np
cimport numpy as np

def two_value_interpolation_c(np.ndarray[np.float64_t] x, 
                                 np.ndarray[np.float64_t, ndim=2] y,
                                 np.ndarray[np.float64_t] val_array):
    cdef unsigned int index, trap
    cdef unsigned int ntraps=val_array.size
    cdef long double val, _xrange, xdiff, modolo, ydiff
    cdef np.ndarray y_interp = np.zeros(ntraps, dtype=np.float64)

    for trap in range(ntraps):
        index = 0
        val = val_array[trap]
        while x[index] <= val:
            index += 1

        _xrange = x[index] - x[index-1]
        xdiff = val - x[index-1]
        modolo = xdiff/_xrange
        ydiff = y[trap,index] - y[trap,index-1]
        y_interp[trap] = y[trap,index-1] + modolo*ydiff
    return y_interp

我对不同的方法进行了一些计时(使用了一些比原始问题中指示的更大的数组和更多的陷阱):

使用原来的方法,即 interp1d: (best of 3) 15.1 sec

使用 InterpolatedUnivariateSpline (k=1) 而不是 @M.T 建议的 interp1d:(最好的 3 个)7.25 秒

使用 two_value_interpolation 函数:(最好的 3 个)1.34 秒

使用 Cython 实现 two_value_interpolation_c:(最好的 3)0.113 秒

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-23
    • 2019-06-02
    • 2012-03-20
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多