我想在三维数组中插入一个数据轴。不同值的给定x值略有不同,但它们都应映射到相同的x值。
由于给定的x值不相同,目前我执行以下操作:
import numpy as np
from scipy import interpolate
axes_have = np.ones( ( 2, 72, 2001 ) )
axes_have *= np.linspace( 0, 100, 2001 )[None,None,:]
axes_have += np.linspace( -0.3, 0.3, 144 ).reshape( ( 2, 72 ) )[:,:,None]
arr = np.sin( axes_have )
arr *= np.random.random( (2, 72 ) )[:,:,None]
axis_want = np.linspace( 0, 100, 201 )
arr_ip = np.zeros( ( 2, 72, 201 ) )
for i in range( arr.shape[0] ):
for j in range( arr.shape[1] ):
ip_func = interpolate.PchipInterpolator( axes_have[i,j,:], arr[i,j,:], extrapolate=True )
arr_ip[i,j,:] = ip_func( axis_want )
使用两个嵌套的for
- 循环并不令人惊讶。
有没有办法提高速度?也许通过做一些NumPy数组魔术或并行化。
答案 0 :(得分:5)
我已经完成了一些初步测试,似乎你花费了大量的时间来生成实际的插值函数。看起来好像只是矢量化会使它加速一吨,但它确实很容易并行化(这确实会提高速度)。这是一个例子。
import numpy as np
from scipy import interpolate
import timeit
import multiprocessing
def myfunc(arg):
x, y = arg
return interpolate.PchipInterpolator(x,
y,
extrapolate=True)
p = multiprocessing.Pool(processes=8)
axes_have = np.ones((2, 72, 2001))
axes_have *= np.linspace(0, 100, 2001)[None, None, :]
axes_have += np.linspace(-0.3, 0.3, 144).reshape((2, 72))[:, :, None]
arr = np.sin(axes_have)
arr *= np.random.random((2, 72))[:, :, None]
axis_want = np.linspace(0, 100, 201)
arr_ip = np.zeros((2, 72, 201))
s_time1 = timeit.default_timer()
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
ip_func = interpolate.PchipInterpolator(axes_have[i, j, :],
arr[i, j, :],
extrapolate=True)
arr_ip[i, j, :] = ip_func(axis_want)
elapsed1 = timeit.default_timer() - s_time1
s_time2 = timeit.default_timer()
flatten_have = [y for x in axes_have for y in x]
flatten_arr = [y for x in arr for y in x]
interp_time = timeit.default_timer()
funcs = p.map(myfunc, zip(flatten_have, flatten_arr))
interp_elapsed = timeit.default_timer() - interp_time
arr_ip = np.asarray([func(axis_want) for func in funcs]).reshape(2, 72, 201)
elapsed2 = timeit.default_timer() - s_time2
print("Elapsed 1: {}".format(elapsed1))
print("Elapsed 2: {}".format(elapsed2))
print("Elapsed interp: {}".format(interp_elapsed))
典型结果(请注意,矢量化实现与没有并行化的速度完全相同,并且我有2个内核,因此您的运行时应该大致(原始时间/内核数)):
Elapsed 1: 10.4025919437
Elapsed 2: 5.11409401894
Elapsed interp: 5.10987687111
不要误解我的意思,可能有一种算法方法可以更快地完成这项工作,但这似乎是立即加速的最简单方法,因为这个问题令人尴尬地并行。