Alright Eric, I have not tested if this is faster but it does it without a for loop and using all numpy. I’m guessing its pretty fast, assuming you sufficient memory for the preallocation and tiling. Might be a better function than numpy.matlib.repmat
, I used it because most of my calculations at this level (matrices/arrays) are more familiar with Matlab. I usually am in pandas land using DataFrames
.
The as_strided
function might not be necessary either, there is a big warning on it from the numpy docs. I used it because when I first read your problem, sliding windows came to mind. Be careful with it, if you use a smaller int then you have to change the stride
arg, defaults to (8,)
meaning steps of 8 bytes.
Also np.vectorize
is a misnomer. Depends how you define vectorize i.e. do you define it using vectorized operations that allow loop unrolling in the cpu/SIMD instructions or do you define it as a single call doing multiple things (a lot of people consider that vectorizing). Anyway, np.vectorize
is pretty much just a wrapper around a for-loop if I remember correctly from my readings on it. Its supposedly not fast at all, similar to using pandas.DataFrame.apply
in certain situations.
EDIT: You could certainly do this with just tiling and reshaping, no weird view tricks, see flank2
. I don’t know which is faster, I don’t feel like profiling it. Sorry. Would be a good exercise for you to do probably though. Its really the only way to know. You should compare your way with mine and any others.
import numpy as np
from numpy.lib.stride_tricks import as_strided
from numpy.matlib import repmat
def flank(arr, lngth):
window_size = 1 + 2*lngth
num_points = len(arr) * window_size
prealloc = np.zeros((num_points,), dtype=np.int64)
tiled = repmat(arr.reshape(1, -1).T, 1, lngth)
view = as_strided(prealloc, shape=(len(arr), window_size), writeable=True)
view[:, :] = tiled + np.arange(-lngth, lngth + 1, 1)
return prealloc
tst = np.arange(5, 35, 5)
print(flank(tst, 1))
def flank2(arr, lngth):
num_points = len(arr) * (1 + 2*lngth)
tiled = repmat(arr.reshape(1, -1).T, 1, lngth)
return (tiled + np.arange(-lngth, lngth + 1, 1)).reshape(-1, num_points)[0]
print(flank2(tst, 1))