Reputation: 391
I was wondering if there was a vertorized way to use two arrays and based on the value of one continuously copy the value in a second array until a new value in the first array is found and then repeat the whole process.
here is an example
a = np.array([FALSE,TRUE,FALSE,FALSE, FALSE, TRUE, FALSE FALSE})
b = np.array([0,10,0,0,0,20,0,0,])
output = array([0,10,10,10,10,20,20,20])
I can use a loop which is much too slow for this.
for i in range(len(b)):
if b[i-1] and not b[i]:
b[i] = b[i-1]
Updated:
I tried this code below and increased the speed by 5x but I figure there should be a faster more elegant way of doing this.
import numpy as np
nz= np.concatenate((np.nonzero(b)[0], [len(b)]))
np.repeat(b[np.nonzero(b)], np.diff(nz))
Upvotes: 0
Views: 352
Reputation: 3824
This generalises to n dimensional arrays. It iterates through n-1d slices of the array.
In [26]: a=np.array([
...: [ 0, 0,10, 0, 0, 0,20,30, 0, 0],
...: [ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0],
...: [ 0, 5, 0, 6, 0, 7, 0, 8, 0, 9]])
In [27]: bfwd=0
...: for ix in range(a.shape[-1]):
...: sel=np.s_[... ,ix]
...: a[sel]=bfwd*(a[sel]==0)+a[sel] # If a is zero use bfwd else use a
...: bfwd=a[sel]
In [28]: a
Out[28]:
array([[ 0, 0, 10, 10, 10, 10, 20, 30, 30, 30],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 0, 5, 5, 6, 6, 7, 7, 8, 8, 9]])
HTH
Upvotes: 0
Reputation: 27201
Your example can be improved slightly:
b = np.array([0, 10, 0, 0, 0, 20, 0, 0])
nz = np.squeeze(np.nonzero(b))
diffs = np.empty_like(nz)
diffs[:-1] = np.diff(nz)
diffs[-1] = b.size - nz[-1]
result = np.repeat(b[nz], diffs)
...I'm not sure I understand the application though.
It might be wise to perftools your code and figure out what exactly is causing the bottleneck in your application. You might also wish to state the sizes of your arrays. (For instance, an itertools
solution might be faster for fewer elements.)
Upvotes: 1