Поскольку значения y, которые нужно найти, должны быть 1d, я не вижу способа не перебирать np.arrays. Если растры и массивы interpRasters изменяются так, как в функции, можно использовать один l oop без явного индексирования. Это дало примерно 10% -ное улучшение скорости для моих готовых тестовых данных.
import numpy as np
frames = 10
rows = 5
cols = 10
channels = 3
np.random.seed(1234)
rasters = np.random.randint(0,256, size=(frames, rows, cols, channels))
chrons = np.random.randint(0, 256, size = 10 )
# The original function.
def interp_rasters(rasters, chrons, sampleFactor = 1):
nFrames = round(len(chrons) * sampleFactor)
interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)
frames, rows, cols, channels = rasters.shape
interpRasters = np.zeros((nFrames, rows, cols, channels), dtype = 'uint8')
outs = []
for row in range(rows):
for col in range(cols):
for channel in range(channels):
pixelSeries = rasters[:, row, col, channel]
interpRasters[:, row, col, channel] = np.interp(
interpChrons,
chrons,
pixelSeries
)
return interpRasters
def interp_rasters2(rasters, chrons, sampleFactor = 1):
nFrames = round(len(chrons) * sampleFactor)
interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)
frames, rows, cols, channels = rasters.shape
interpRasters = np.zeros((nFrames, rows, cols, channels), dtype = 'uint8')
# Create reshaped arrays pointing to the same data
dat_in = rasters.reshape(frames, rows*cols*channels).T
# shape (r*c*c, frames)
dat_out = interpRasters.reshape(nFrames, rows*cols*channels).T
# shape (r*c*c, frames)
for pixelseries, row_out in zip(dat_in, dat_out):
# Loop through all data in one loop.
row_out[:] = np.interp( interpChrons, chrons, pixelseries )
return interpRasters
# As dat_out and interpRasters share the same data return interpRasters
print(np.isclose(interp_rasters(rasters, chrons), interp_rasters2(rasters, chrons)).all())
# True # The results are the same from the two functions.
%timeit interp_rasters(rasters, chrons)
# 568 µs ± 2.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit interp_rasters2(rasters, chrons)
# 520 µs ± 239 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Редактировать Есть также np.apply_along_axis. Это удаляет все явные циклы for, уменьшает объем кода, но медленнее, чем в предыдущих решениях.
def interp_rasters3(rasters, chrons, sampleFactor = 1):
nFrames = round(len(chrons) * sampleFactor)
interpChrons = np.linspace(np.min(chrons), np.max(chrons), nFrames)
def func( arr ): # Define the function to apply along the axis
return np.interp( interpChrons, chrons, arr )
return np.apply_along_axis( func, 0, rasters ).astype( np.uint8 )
print(np.isclose(interp_rasters(rasters, chrons), interp_rasters3(rasters, chrons)).all())
# True
Я думаю, что я бы лучше понял версию 3, чем версию 1 или 2, через 6 месяцев, если скорость не будет не критично
HTH