给出3维布尔数据:
np.random.seed(13)
bool_data = np.random.randint(2, size=(2,3,6))
>> bool_data
array([[[0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]],
[[1, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 0],
[1, 1, 1, 0, 0, 0]]])
我希望计算每行(沿轴= 1)中被两个0包围的连续1的数目,并返回一个带有计数的数组。对于bool_data
,这将得到array([1, 1, 2, 4])
。
由于bool_data
的3D结构和每行的变量记数,我不得不笨拙地将记数转换为嵌套列表,使用itertools.chain
将其展平,然后将列表反向转换为一个数组:
# count consecutive 1's bounded by two 0's
def count_consect_ones(input):
return np.diff(np.where(input==0)[0])-1
# run tallies across all rows in bool_data
consect_ones = []
for i in range(len(bool_data)):
for j in range(len(bool_data[i])):
res = count_consect_ones(bool_data[i, j])
consect_ones.append(list(res[res!=0]))
>> consect_ones
[[], [1, 1], [], [2], [4], []]
# combines nested lists
from itertools import chain
consect_ones_output = np.array(list(chain.from_iterable(consect_ones)))
>> consect_ones_output
array([1, 1, 2, 4])
是否有更有效或更聪明的方法?
答案 0 :(得分:2)
consect_ones.append(list(res [res!= 0]))
如果改用.extend,则序列的内容将直接追加。这样就省去了随后合并嵌套列表的步骤:
consect_ones.extend(res[res!=0])
此外,您可以跳过索引编制,直接遍历维度:
consect_ones = []
for i in bool_data:
for j in i:
res = count_consect_ones(j)
consect_ones.extend(res[res!=0])
答案 1 :(得分:1)
我们可以使用技巧在列上填充零,然后在展平版本上查找上坡和下坡索引,最后过滤掉与边界索引相对应的索引,从而为自己提供矢量化解决方案,如下所示-
# Input 3D array : a
b = np.pad(a, ((0,0),(0,0),(1,1)), 'constant', constant_values=(0,0))
# Get ramp-up and ramp-down indices/ start-end indices of 1s islands
s0 = np.flatnonzero(b[...,1:]>b[...,:-1])
s1 = np.flatnonzero(b[...,1:]<b[...,:-1])
# Filter only valid ones that are not at borders
n = b.shape[2]
valid_mask = (s0%(n-1)!=0) & (s1%(n-1)!=a.shape[2])
out = (s1-s0)[valid_mask]
说明-
每行两端填充零作为“句法”的想法是,当我们获得一次性切片数组版本并进行比较时,我们可以使用b[...,1:]>b[...,:-1]
来检测上升和下降位置和b[...,1:]<b[...,:-1]
。因此,我们得到s0
和s1
作为1s
每个岛的开始和结束索引。现在,我们不需要边框的,因此我们需要使它们的列索引追溯到原始的未填充的输入数组,因此该位是s0%(n-1)
和s1%(n-1)
。我们需要删除所有1s
岛的开始都在左侧边界而1s
每个岛的终点都在右侧边界的所有情况。开始和结束是s0
和s1
。因此,我们使用它们来检查s0
是否为0
和s1
是否为a.shape[2]
。这些给我们有效的。岛的长度是通过s1-s0
获得的,因此请使用有效掩码对其进行掩码以获得所需的输出。
样本输入,输出-
In [151]: a
Out[151]:
array([[[0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]],
[[1, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 0],
[1, 1, 1, 0, 0, 0]]])
In [152]: out
Out[152]: array([1, 1, 2, 4])