[英]Finding unique sets without subsets in python array
我有一个数据集,需要输出布尔样式数据,无论是true还是true,仅输出1和0。 我试图解析经过处理的简单数据集,以在numpy数组中查找信息的子集,该数组在一个方向上大约100,000个元素,在另一个方向上大约20个元素。 我只需要沿20轴进行搜索,但是我需要对100,000个条目中的每个条目进行搜索,并获取可以映射的输出。
我制作了一个由零组成的大小的数组,目的是简单地将匹配的索引指示符标记为1。主要的障碍是,如果我找到一个长集(我正在处理长集到小集) ),则无需包含其中的任何较小的集合。
样本:[0,0,1,1,1,1,1,0,0,1,1,1,0,0,0,1,0,1]
我需要在这里找到从索引2开始有1组5,从索引9开始有3的一组,并且不返回5组的任何子集,就好像它是4组或一组3的结果,因此保留所有已经覆盖的值的结果。 例如,对于3组,索引2、3、4、5和6都将保持零。 它不需要太高效,我不在乎它是否仍在搜索,我只需要保留结果即可。
目前,我正在使用基本上像这样的代码块进行简单搜索:
values = numpy.array([0,1,1,1,1,1,0,0,1,1,1])
searchval = [1,2]
N = len(searchval)
possibles = numpy.where(values == searchval[0])[0]
print(possibles)
solns = []
for p in possibles:
check = values[p:p+N]
if numpy.all(check == searchval):
solns.append(p)
print(solns)
我一直在绞尽脑汁,想出一种方法来重组此代码或类似代码以产生期望的结果。 最终目标是搜索9到3的组,并有效地使用1s和0s的矩阵来指示索引是否有一个我们想要的起始组。
希望有人可以指出我要完成这项工作所缺少的内容。 谢谢!
像这样吗
from collections import defaultdict
sample = [0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1]
# Keys are number of consecutive 1's, values are indicies
results = defaultdict(list)
found = 0
for i, x in enumerate(samples):
if x == 1:
found += 1
elif i == 0 or found == 0:
continue
else:
results[found].append(i - found)
found = 0
if found:
results[found].append(i - found + 1)
assert results == {1: [15, 17], 3: [9], 5: [2]}
使用more_itertools
,一个第三方库( pip install more_itertools
):
import more_itertools as mit
sample = [0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1]
groups = [list(c) for c in mit.consecutive_groups((mit.locate(sample)))]
d = {group[0]: len(group) for group in groups}
d
# {2: 5, 9: 3, 15: 1, 17: 1}
该结果显示为“索引2
是5个一组。索引9
是3个一组,等等”。
细节
more_itertools.locate
默认情况下查找真实项目的索引。 more_itertools.consecutive_groups
连续的数字组合在一起。 作为字典 ,您可以提取各种信息:
>>> # List of starting indices
>>> list(d)
[2, 9, 15, 17]
>>> # List indices for all lonely groups
>>> [k for k, v in d.items() if v == 1]
[15, 17]
>>> # List indices of groups greater the 2 items
>>> [k for k, v in d.items() if v > 1]
[2, 9]
这是一个numpy的解决方案。 我使用一个小示例进行演示,但是它很容易扩展(在我比较适中的笔记本电脑上, 20 x 100,000
需要25毫秒,请参阅本文结尾处的计时):
>>> import numpy as np
>>>
>>>
>>> a = np.random.randint(0, 2, (5, 10), dtype=np.int8)
>>> a
array([[0, 1, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 1, 1, 0, 1, 0, 1, 0, 0, 0],
[1, 0, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 1, 1, 1, 0, 0]], dtype=int8)
>>>
>>> padded = np.pad(a,((1,1),(0,0)), 'constant')
# compare array to itself with offset to mark all switches from
# 0 to 1 or from 1 to 0
# then use 'where' to extract the coordinates
>>> colinds, rowinds = np.where((padded[:-1] != padded[1:]).T)
>>>
# the lengths of sets are the differences between switch points
>>> lengths = rowinds[1::2] - rowinds[::2]
# now we have the lengths we are free to throw the off-switches away
>>> colinds, rowinds = colinds[::2], rowinds[::2]
>>>
# admire
>>> from pprint import pprint
>>> pprint(list(zip(colinds, rowinds, lengths)))
[(0, 2, 1),
(1, 0, 2),
(2, 1, 2),
(2, 4, 1),
(3, 2, 1),
(4, 0, 5),
(5, 0, 1),
(5, 2, 1),
(5, 4, 1),
(6, 1, 1),
(6, 3, 2),
(7, 4, 1)]
时序:
>>> def find_stretches(a):
... padded = np.pad(a,((1,1),(0,0)), 'constant')
... colinds, rowinds = np.where((padded[:-1] != padded[1:]).T)
... lengths = rowinds[1::2] - rowinds[::2]
... colinds, rowinds = colinds[::2], rowinds[::2]
... return colinds, rowinds, lengths
...
>>> a = np.random.randint(0, 2, (20, 100000), dtype=np.int8)
>>> from timeit import repeat
>>> kwds = dict(globals=globals(), number=100)
>>> repeat('find_stretches(a)', **kwds)
[2.475784719004878, 2.4715258619980887, 2.4705517270049313]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.