如何在包含重复项的排序列表的非连续浮点元素之间填充零?
How can one pad zeroes in-between non-consecutive float elements of a sorted list that contains duplicates?
我有一个表示观察时间的浮点值列表。 (每个浮点值实际上可以表示为一个整数,但我希望对未来可能的情况进行概括)。
list_hrs = [4,6,8,8,10] # actual list is thousands of floats
我试图用零填充与其索引不匹配的值,同时只计算一次重复条目的出现。根据示例列表,我想要
list_hrs = [0,0,0,0,4,0,6,0,8,8,0,10]
前四项是0
,因为从0
到3
共有四个数字。需要 4
和 6
之间的 0
,因为缺少 5
; 6
和 8
之间的 0
也类似。 8
和 10
之间的 0
在那里是需要的,因为缺少值 9
。此外,重复的 8
保持不变,因为稍后将在我的代码中处理它们;在填充 0
之前,只应计算一次重复的 8
。
我的第一次尝试是尝试这个:
for index in range(len(list_hrs)):
if list_hrs != index:
list_hrs.insert(index, 0)
>> [0, 0, 0, 0, 0, 4, 6, 8, 8, 10]
然后我阅读了不同的 SO 帖子,并留下了这样的印象,即最好先列出 0
的列表,其长度应等于所考虑的数据点数。然后,非零条目可以替换 0
条目。所以,我尝试了以下方法:
def make_zeros(hrs=list_hrs): # make list of 0's
num_zer = int(max(hrs))
list_zer = [0 for index in range(num_zer+1)]
return list_zer
但我不确定在这一点之后如何实施条件以达到预期的结果。我在想有一种方法可以使用 enumerate
检查索引是否与该索引处的值匹配,但由于重复条目(例如示例中的 8
,我不确定如何继续以上)。
这种方法是继续前进的好方向,还是有更有效/更简单的方法来达到预期的结果?任何帮助或建议将不胜感激。
这是一种矢量化方法 -
def make_zeros_vectorized(A, dtype=float):
a = np.asarray(A).astype(int)
idx = a + np.r_[0, (a[1:] == a[:-1]).cumsum()]
out = np.zeros(idx[-1]+1,dtype=dtype)
out[idx] = A
return out
样本 运行s -
In [95]: A
Out[95]: [4.0, 6.0, 8.0, 8.0, 10.0, 10.0, 10.0, 14.0, 16.0]
In [96]: make_zeros_vectorized(A)
Out[96]:
array([ 0., 0., 0., 0., 4., 0., 6., 0., 8., 8., 0.,
10., 10., 10., 0., 0., 0., 14., 0., 16.])
In [100]: A
Out[100]: [4.0, 4.0, 4.0, 4.0, 6.0, 8.0, 8.0, 10.0, 10.0, 10.0, 14.0, 16.0]
In [101]: make_zeros_vectorized(A)
Out[101]:
array([ 0., 0., 0., 0., 4., 4., 4., 4., 0., 6., 0.,
8., 8., 0., 10., 10., 10., 0., 0., 0., 14., 0.,
16.])
涉及的步骤
输入列表
In [71]: A = [4.0,6.0,8.0,8.0,10.0,10.0,10.0,14.0,16.0]
转换为数组
In [72]: a = np.asarray(A).astype(int)
In [73]: a
Out[73]: array([ 4, 6, 8, 8, 10, 10, 10, 14, 16])
创建一个重复的掩码。是这种方法的核心,因为我们计划稍后使用累积求和。将重复项表示为 True,当累积求和时将产生增量值,用作将输入数组值放入输出数组的增量索引
In [74]: a[1:] == a[:-1]
Out[74]: array([False, False, True, False, True, True, False, False], dtype=bool)
In [75]: (a[1:] == a[:-1]).cumsum()
Out[75]: array([0, 0, 1, 1, 2, 3, 3, 3])
在开头附加一个零,因为较早的 "a[1:] == a[:-1]" 会导致少一个元素的数组
In [76]: np.r_[0, (a[1:] == a[:-1]).cumsum()]
Out[76]: array([0, 0, 0, 1, 1, 2, 3, 3, 3])
最后,添加到输入数组,使重复项 shifted/added 一个,从而为我们提供要分配输出数组的索引
In [77]: a + np.r_[0, (a[1:] == a[:-1]).cumsum()]
Out[77]: array([ 4, 6, 8, 9, 11, 12, 13, 17, 19])
后面的步骤基本上是创建一个输出数组,并使用之前获得的索引将 a
中的值分配给它。
如果您需要零掩码或那些索引,这里有一个修改版本 -
def get_zeros_mask(A):
a = np.asarray(A).astype(int)
idx = a + np.r_[0, (a[1:] == a[:-1]).cumsum()]
mask = np.ones(idx[-1]+1,dtype=bool)
mask[idx] = 0
return mask
样本运行-
In [93]: A
Out[93]: [4.0, 6.0, 8.0, 8.0, 10.0, 10.0, 10.0, 14.0, 16.0]
In [94]: make_zeros_vectorized(A)
Out[94]:
array([ 0., 0., 0., 0., 4., 0., 6., 0., 8., 8., 0.,
10., 10., 10., 0., 0., 0., 14., 0., 16.])
In [95]: get_zeros_mask(A)
Out[95]:
array([ True, True, True, True, False, True, False, True, False,
False, True, False, False, False, True, True, True, False,
True, False], dtype=bool)
In [96]: np.flatnonzero(get_zeros_mask(A))
Out[96]: array([ 0, 1, 2, 3, 5, 7, 10, 14, 15, 16, 18])
再举一个例子:
list_hrs = [4,6,8,8,10]
lh = iter(list_hrs)
fit = range(int(max(list_hrs))+1)
result = [0 if i not in list_hrs else next(lh) for i in fit for _ in range(list_hrs.count(i)) or [1]]
我有一个表示观察时间的浮点值列表。 (每个浮点值实际上可以表示为一个整数,但我希望对未来可能的情况进行概括)。
list_hrs = [4,6,8,8,10] # actual list is thousands of floats
我试图用零填充与其索引不匹配的值,同时只计算一次重复条目的出现。根据示例列表,我想要
list_hrs = [0,0,0,0,4,0,6,0,8,8,0,10]
前四项是0
,因为从0
到3
共有四个数字。需要 4
和 6
之间的 0
,因为缺少 5
; 6
和 8
之间的 0
也类似。 8
和 10
之间的 0
在那里是需要的,因为缺少值 9
。此外,重复的 8
保持不变,因为稍后将在我的代码中处理它们;在填充 0
之前,只应计算一次重复的 8
。
我的第一次尝试是尝试这个:
for index in range(len(list_hrs)):
if list_hrs != index:
list_hrs.insert(index, 0)
>> [0, 0, 0, 0, 0, 4, 6, 8, 8, 10]
然后我阅读了不同的 SO 帖子,并留下了这样的印象,即最好先列出 0
的列表,其长度应等于所考虑的数据点数。然后,非零条目可以替换 0
条目。所以,我尝试了以下方法:
def make_zeros(hrs=list_hrs): # make list of 0's
num_zer = int(max(hrs))
list_zer = [0 for index in range(num_zer+1)]
return list_zer
但我不确定在这一点之后如何实施条件以达到预期的结果。我在想有一种方法可以使用 enumerate
检查索引是否与该索引处的值匹配,但由于重复条目(例如示例中的 8
,我不确定如何继续以上)。
这种方法是继续前进的好方向,还是有更有效/更简单的方法来达到预期的结果?任何帮助或建议将不胜感激。
这是一种矢量化方法 -
def make_zeros_vectorized(A, dtype=float):
a = np.asarray(A).astype(int)
idx = a + np.r_[0, (a[1:] == a[:-1]).cumsum()]
out = np.zeros(idx[-1]+1,dtype=dtype)
out[idx] = A
return out
样本 运行s -
In [95]: A
Out[95]: [4.0, 6.0, 8.0, 8.0, 10.0, 10.0, 10.0, 14.0, 16.0]
In [96]: make_zeros_vectorized(A)
Out[96]:
array([ 0., 0., 0., 0., 4., 0., 6., 0., 8., 8., 0.,
10., 10., 10., 0., 0., 0., 14., 0., 16.])
In [100]: A
Out[100]: [4.0, 4.0, 4.0, 4.0, 6.0, 8.0, 8.0, 10.0, 10.0, 10.0, 14.0, 16.0]
In [101]: make_zeros_vectorized(A)
Out[101]:
array([ 0., 0., 0., 0., 4., 4., 4., 4., 0., 6., 0.,
8., 8., 0., 10., 10., 10., 0., 0., 0., 14., 0.,
16.])
涉及的步骤
输入列表
In [71]: A = [4.0,6.0,8.0,8.0,10.0,10.0,10.0,14.0,16.0]
转换为数组
In [72]: a = np.asarray(A).astype(int)
In [73]: a
Out[73]: array([ 4, 6, 8, 8, 10, 10, 10, 14, 16])
创建一个重复的掩码。是这种方法的核心,因为我们计划稍后使用累积求和。将重复项表示为 True,当累积求和时将产生增量值,用作将输入数组值放入输出数组的增量索引
In [74]: a[1:] == a[:-1]
Out[74]: array([False, False, True, False, True, True, False, False], dtype=bool)
In [75]: (a[1:] == a[:-1]).cumsum()
Out[75]: array([0, 0, 1, 1, 2, 3, 3, 3])
在开头附加一个零,因为较早的 "a[1:] == a[:-1]" 会导致少一个元素的数组
In [76]: np.r_[0, (a[1:] == a[:-1]).cumsum()]
Out[76]: array([0, 0, 0, 1, 1, 2, 3, 3, 3])
最后,添加到输入数组,使重复项 shifted/added 一个,从而为我们提供要分配输出数组的索引
In [77]: a + np.r_[0, (a[1:] == a[:-1]).cumsum()]
Out[77]: array([ 4, 6, 8, 9, 11, 12, 13, 17, 19])
后面的步骤基本上是创建一个输出数组,并使用之前获得的索引将 a
中的值分配给它。
如果您需要零掩码或那些索引,这里有一个修改版本 -
def get_zeros_mask(A):
a = np.asarray(A).astype(int)
idx = a + np.r_[0, (a[1:] == a[:-1]).cumsum()]
mask = np.ones(idx[-1]+1,dtype=bool)
mask[idx] = 0
return mask
样本运行-
In [93]: A
Out[93]: [4.0, 6.0, 8.0, 8.0, 10.0, 10.0, 10.0, 14.0, 16.0]
In [94]: make_zeros_vectorized(A)
Out[94]:
array([ 0., 0., 0., 0., 4., 0., 6., 0., 8., 8., 0.,
10., 10., 10., 0., 0., 0., 14., 0., 16.])
In [95]: get_zeros_mask(A)
Out[95]:
array([ True, True, True, True, False, True, False, True, False,
False, True, False, False, False, True, True, True, False,
True, False], dtype=bool)
In [96]: np.flatnonzero(get_zeros_mask(A))
Out[96]: array([ 0, 1, 2, 3, 5, 7, 10, 14, 15, 16, 18])
再举一个例子:
list_hrs = [4,6,8,8,10]
lh = iter(list_hrs)
fit = range(int(max(list_hrs))+1)
result = [0 if i not in list_hrs else next(lh) for i in fit for _ in range(list_hrs.count(i)) or [1]]