I have an array that is the concatenation of different chunks:
a = np.array([0, 1, 2, 10, 11, 20, 21, 22, 23])
# > < > < > <
chunks = np.array([3, 2, 4])
repeats = np.array([1, 3, 2])
Each segment starting with a new decade in the example above is a separate "chunk" that I would like to repeat. The chunk sizes and number of repetitions are known for each. I can't do a reshape followed by kron
or repeat
because the chunks are different sizes.
The result I would like is
np.array([0, 1, 2, 10, 11, 10, 11, 10, 11, 20, 21, 22, 23, 20, 21, 22, 23])
# repeats:> 1 < > 3 < > 2 <
This is easy to do in a loop:
in_offset = np.r_[0, np.cumsum(chunks[:-1])]
out_offset = np.r_[0, np.cumsum(chunks[:-1] * repeats[:-1])]
output = np.zeros((chunks * repeats).sum(), dtype=a.dtype)
for c in range(len(chunks)):
for r in range(repeats[c]):
for i in range(chunks[c]):
output[out_offset[c] + r * chunks[c] + i] = a[in_offset[c] + i]
This leads to the following vectorization:
regions = chunks * repeats
index = np.arange(regions.sum())
segments = np.repeat(chunks, repeats)
resets = np.cumsum(segments[:-1])
offsets = np.zeros_like(index)
offsets[resets] = segments[:-1]
offsets[np.cumsum(regions[:-1])] -= chunks[:-1]
index -= np.cumsum(offsets)
output = a[index]
Is there a more efficient way to vectorize this problem? Just so we are clear, I am not asking for a code review. I am happy with how these function calls work together. I would like to know if there is an entirely different (more efficient) combination of function calls I could use to achieve the same result.
This question was inspired by my answer to this question.