Python 如何在列表的间隔之间填充元素
我有这样一份清单:Python 如何在列表的间隔之间填充元素,python,pandas,numpy,dataframe,Python,Pandas,Numpy,Dataframe,我有这样一份清单: 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] list_2 = [np.NaN, np.NaN, 1, 1, 1, 1, 0, np.NaN, 1, 1, 0, 1, 1, 0, np.NaN, 1, np.NaN] 因此,存在以1开始,以0结束的间隔。 如何将这些间隔中的值替换为1?结果如下:
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]
list_2 = [np.NaN, np.NaN, 1, 1, 1, 1, 0, np.NaN, 1, 1, 0, 1, 1, 0, np.NaN, 1, np.NaN]
因此,存在以1
开始,以0
结束的间隔。
如何将这些间隔中的值替换为1?结果如下:
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]
list_2 = [np.NaN, np.NaN, 1, 1, 1, 1, 0, np.NaN, 1, 1, 0, 1, 1, 0, np.NaN, 1, np.NaN]
在本例中,我使用了
NaN
,但是可以应用于任何值的通用解决方案也很好解决方案:
s = pd.Series(list_1)
s1 = s.eq(1)
s0 = s.eq(0)
m = (s1 | s0).where(s1.cumsum().ge(1),False).cumsum().mod(2).eq(1)
s.loc[m & s.isna()] = 1
print(s.tolist())
#[nan, nan, 1.0, 1.0, 1.0, 1.0, 0.0, nan, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, nan, 1.0, 1.0]
但是如果只有
1
、0
或NaN
可以执行以下操作:
s = pd.Series(list_1)
s.fillna(s.ffill().where(lambda x: x.eq(1))).tolist()
输出
[nan,
nan,
1.0,
1.0,
1.0,
1.0,
0.0,
nan,
1.0,
1.0,
0.0,
1.0,
1.0,
0.0,
nan,
1.0,
1.0]
您可以使用检索索引1和0,然后填充每个切片中的值:
将numpy导入为np
a=np.数组([np.NaN,np.NaN,1,np.NaN,np.NaN,0,np.NaN,1,np.NaN,0,1,np.NaN,0,np.NaN,1,np.NaN])
一=np.挤压(np.arg,其中(a==1))
零=np.压缩(np.arg,其中(a==0))
如果一[0]>零[0]:
零=零[1:]
值=-999
对于zip中的i,j(1,0):
a[i+1:j]=值
A.
数组([nan,nan,1.,-999.,-999.,-999.,0.,nan,1。,
-999,0,1.,-999,0,nan,1,nan])
以下是一种基于numpy的方法,使用:
这是一个代码,其中变量
replace
将确定是否应该替换元素,并且for
将从区间的0
迭代到len
,如果它找到1
则replace将为真,则元素将被替换,并且当它找到下一个0
replace时,将被替换在再次出现1
replace = False
for i in (len(interval)-1):
if interval[i]==1:
replace = True
elif interval[i]==0:
replace = False
if replace:
list[i]=inerval[i]
假设每个1后跟0(减去最后1): 输出:
[nan nan 1. 1. 1. 1. 0. nan 1. 1. 0. 1. 1. 0. nan 1. nan]
这是一个基于NumPy的-
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)
样本运行-
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])
使用阵列输入对NumPy解决方案进行基准测试
为了简单起见,我们将通过平铺和测试基于NumPy的示例,将给定的示例放大到10000x
其他NumPy解决方案-
#@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
时间安排-
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)
复制过程不会占用很多运行时间,因此可以忽略这一点-
In [51]: %timeit a.copy()
78.3 µs ± 571 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
1后面必须跟0吗?或者在连续的1-0对之间是否还有其他1?换句话说,每1后面是否有0?请不要只发布代码作为答案,还要解释代码的作用以及它如何解决问题。带有解释的答案通常质量更高,更容易吸引选票。
In [51]: %timeit a.copy()
78.3 µs ± 571 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)