I have a list like this:
list_1 = [np.NaN, np.NaN, 1, np.NaN, np.NaN, np.NaN, 0, np.NaN, 1, np.NaN, 0, 1, np.NaN, 0, np.NaN, 1, np.NaN]
So the
Here's a NumPy based one -
def fill_inbetween(a):
m1 = a==1
m2 = a==0
id_ar = m1.astype(int)-m2
idc = id_ar.cumsum()
idc[len(m1)-m1[::-1].argmax():] = 0
return np.where(idc.astype(bool), 1, a)
Sample run -
In [44]: a # input as array
Out[44]:
array([nan, nan, 1., nan, nan, nan, 0., nan, 1., nan, 0., 1., nan,
0., nan, 1., nan])
In [45]: fill_inbetween(a)
Out[45]:
array([nan, nan, 1., 1., 1., 1., 0., nan, 1., 1., 0., 1., 1.,
0., nan, 1., nan])
To keep things simple, we will just scaled up the given sample to 10,000x
by tiling and test out the NumPy based ones.
Other NumPy solutions -
#@yatu's soln
def func_yatu(a):
ix0 = (a == 0).cumsum()
ix1 = (a == 1).cumsum()
dec = (ix1 - ix0).astype(float)
ix = len(a)-(a[::-1]==1).argmax()
last = ix1[-1]-ix0[-1]
if last > 0:
dec[ix:] = a[ix:]
out = np.where(dec==1, dec, a)
return out
# @FBruzzesi's soln (with the output returned in a separate array)
def func_FBruzzesi(a, value=1):
ones = np.squeeze(np.argwhere(a==1))
zeros = np.squeeze(np.argwhere(a==0))
if ones[0]>zeros[0]:
zeros = zeros[1:]
out = a.copy()
for i,j in zip(ones,zeros):
out[i+1:j] = value
return out
# @Ehsan's soln (with the output returned in a separate array)
def func_Ehsan(list_1):
zeros_ind = np.where(list_1 == 0)[0]
ones_ind = np.where(list_1 == 1)[0]
ones_ind = ones_ind[:zeros_ind.size]
indexer = np.r_[tuple([np.s_[i:j] for (i,j) in zip(ones_ind,zeros_ind)])]
out = list_1.copy()
out[indexer] = 1
return out
Timings -
In [48]: list_1 = [np.NaN, np.NaN, 1, np.NaN, np.NaN, np.NaN, 0, np.NaN, 1, np.NaN, 0, 1, np.NaN, 0, np.NaN, 1, np.NaN]
...: a = np.array(list_1)
In [49]: a = np.tile(a,10000)
In [50]: %timeit func_Ehsan(a)
...: %timeit func_FBruzzesi(a)
...: %timeit func_yatu(a)
...: %timeit fill_inbetween(a)
4.86 s ± 325 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
253 ms ± 29.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.39 ms ± 205 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.01 ms ± 168 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
The copying process doesn't take much of runtime, so that can be ignored -
In [51]: %timeit a.copy()
78.3 µs ± 571 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)