我正在研究模拟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或类似的?
答案 0 :(得分:0)
我已经仔细研究过这个问题了,我想我已经找到了一个很好的解决方案,我想分享,尽管这意味着我将回答我自己的问题。
首先,我突然意识到,我可以找到两个值之间的插值,而不是使用其中一个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 :(最好3)15.1秒
使用InterpolatedUnivariateSpline(k = 1)而不是@ M.T建议的interp1d :(最好3)7.25秒
使用two_value_interpolation函数:(最好为3)1.34秒
使用Cython实现two_value_interpolation_c :(最好3)0.113秒