【问题标题】:Finding unique sets without subsets in python array在python数组中查找没有子集的唯一集
【发布时间】:2018-07-18 09:09:55
【问题描述】:

我有一个数据集需要输出布尔样式数据,只有 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]

我需要在这里找到 1 个 5 组,从索引 2 开始,1 个 3 组,从索引 9 开始,并且不返回 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 的组,并有效地使用 1 和 0 的矩阵来指示索引是否有一个从它开始的组,只要我们想要。

希望有人可以指出我缺少什么来完成这项工作。谢谢!

【问题讨论】:

    标签: python arrays list numpy matching


    【解决方案1】:

    这样的?

    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]}
    

    【讨论】:

    • 我对字典没有经验。我怎样才能用他们的钥匙把它们拉出来。如果我把它列成一个列表,我只会从这个例子中得到 1、3、5。但是要将它放入我的矩阵中,我需要通过它们的数值循环这些值。您能否对提取进行一些澄清?谢谢!
    • docs.python.org/2/tutorial/datastructures.html#dictionaries 如果您想要所有具有 3 个重复值为 1 的项目的索引,可以通过以下方式获得:indicies = results[3]
    • 这个方法似乎工作得很好,除了一个问题。如果任何长度的组,例如 1 或 3,位于列表的末尾,即组中的 1 之一是最后一个元素,它报告错误的索引,它告诉我它是一个比它更早的索引.因此,如果我将您生成的列表移回最后一个 #1,它会正确地告诉我它是索引 16,但实际上,它现在是索引 17,并且说它是索引 17。不知道如何解决这个问题。跨度>
    【解决方案2】:

    这是一个 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]
    

    【讨论】:

      【解决方案3】:

      使用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 个”,等等。


      详情

      作为dictionary,您可以提取不同种类的信息:

      >>> # 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]
      

      【讨论】:

      • 谢谢,这很有帮助!将其合并到我的代码中后效果很好。
      猜你喜欢
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      相关资源
      最近更新 更多