numpy 查找数组中重复元素的索引

64jmpszr  于 11个月前  发布在  其他
关注(0)|答案(6)|浏览(167)

假设我有一个NumPy整数数组,如下所示:

[34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]

字符串
我想找到数组的开始和结束索引,其中一个值重复了x次以上(比如5次)。所以在上面的例子中,它是值22和6。重复的22的开始索引是3,结束索引是8。重复6也是如此。
Python中有没有一个特殊的工具可以帮助我们?否则,我会循环遍历数组index,然后将实际值与之前的值进行比较。

at0kjp5o

at0kjp5o1#

使用np.diff和@WarrenWeckesser给出的here方法在数组中查找零的游程:

import numpy as np

def zero_runs(a):  # from link
    iszero = np.concatenate(([0], np.equal(a, 0).view(np.int8), [0]))
    absdiff = np.abs(np.diff(iszero))
    ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
    return ranges

a = [34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]

zero_runs(np.diff(a))
Out[87]: 
array([[ 3,  8],
       [15, 22]], dtype=int32)

字符串
然后可以根据运行开始和结束之间的差异进行过滤:

runs = zero_runs(np.diff(a))

runs[runs[:, 1]-runs[:, 0]>5]  # runs of 7 or more, to illustrate filter
Out[96]: array([[15, 22]], dtype=int32)

bf1o4zei

bf1o4zei2#

下面是一个使用Python原生itertools的解决方案。
代码

import itertools as it

def find_ranges(lst, n=2):
    """Return ranges for `n` or more repeated values."""
    groups = ((k, tuple(g)) for k, g in it.groupby(enumerate(lst), lambda x: x[-1]))
    repeated = (idx_g for k, idx_g in groups if len(idx_g) >=n)
    return ((sub[0][0], sub[-1][0]) for sub in repeated)

lst = [34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]    
list(find_ranges(lst, 5))
# [(3, 8), (15, 22)]

字符串
测试

import nose.tools as nt

def test_ranges(f):
    """Verify list results identifying ranges."""
    nt.eq_(list(f([])), [])
    nt.eq_(list(f([0, 1,1,1,1,1,1, 2], 5)), [(1, 6)])
    nt.eq_(list(f([1,1,1,1,1,1, 2,2, 1, 3, 1,1,1,1,1,1], 5)), [(0, 5), (10, 15)])
    nt.eq_(list(f([1,1, 2, 1,1,1,1, 2, 1,1,1], 3)), [(3, 6), (8, 10)])    
    nt.eq_(list(f([1,1,1,1, 2, 1,1,1, 2, 1,1,1,1], 3)), [(0, 3), (5, 7), (9, 12)])
    
test_ranges(find_ranges)


本例捕获lst中的(index,element)对,然后按元素对它们进行分组。只保留重复的对。最后,对第一个和最后一个对进行切片,从每个重复的组中生成(start,end)索引。
另请参阅this post以使用itertools.groupby查找索引范围。

laawzig2

laawzig23#

其实并没有什么捷径可走。你可以这样做:

mult = 5
for elem in val_list:
    target = [elem] * mult
    found_at = val_list.index(target)

字符串
我将未找到的异常和较长的序列检测留给您。

4xrmg8kj

4xrmg8kj4#

如果你要在列表L中查找value重复n次,你可以这样做:

def find_repeat(value, n, L):
    look_for = [value for _ in range(n)]
    for i in range(len(L)):
        if L[i] == value and L[i:i+n] == look_for:
            return i, i+n

字符串

mxg2im7a

mxg2im7a5#

这里有一个相对快速,无误的解决方案,它还告诉你有多少个副本在运行中。

# Return the start and (1-past-the-end) indices of the first instance of
# at least min_count copies of element value in container l 
def find_repeat(value, min_count, l):
  look_for = [value for _ in range(min_count)]
  for i in range(len(l)):
    count = 0
    while l[i + count] == value:
      count += 1
    if count >= min_count:
      return i, i + count

字符串

cidc1ykv

cidc1ykv6#

我有一个类似的要求。这是我提出的,只使用理解列表:

A=[34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]

字符串
查找unique并返回其索引

_, ind = np.unique(A,return_index=True)


np.unique对数组进行排序,对索引进行排序以获得原始顺序的索引

ind = np.sort(ind)


ind包含重复组中第一个元素的索引,通过非连续索引可见它们的diff给出了组中元素的数量。使用np.diff(ind)>5过滤将给出一个布尔数组,其中True位于组的起始索引处。ind数组包含过滤列表中每个True之后的每个组的结束索引
创建一个dict,其中键作为重复元素,值作为该组的开始和结束索引的元组

rep_groups = dict((A[ind[i]], (ind[i], ind[i+1]-1)) for i,v in enumerate(np.diff(ind)>5) if v)

相关问题