簡體   English   中英

查找數組中重復元素的索引(Python、NumPy)

[英]Find indexes of repeated elements in an array (Python, NumPy)

假設,我有一個 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 中是否有一個特殊的工具有用? 否則,我將遍歷索引的數組索引並將實際值與前一個值進行比較。

問候。

使用np.diffnp.diff此處給出的方法來查找數組中的零運行:

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)

這真的沒有什么捷徑可走。 您可以執行以下操作:

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

我將未找到的異常和更長的序列檢測留給您。

這是使用 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) 對,然后按元素對它們進行分組。 只保留重復的對。 最后,第一對和最后一對被切片,從每個重復的組中產生(開始,結束)索引。

另請參閱此帖子以使用itertools.groupby查找索引范圍。

如果您要在列表L查找重復n次的value ,您可以執行以下操作:

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

這是一個相對快速、無錯誤的解決方案,它還告訴您運行中的副本數。 其中一些代碼是從 KAL 的解決方案中借用的。

# 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

我也有類似的需求。 這就是我想出的,僅使用理解列表:

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]

找到唯一的並返回它們的索引

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

np.unique 對數組進行排序,對索引進行排序以按原始順序獲取索引

ind = np.sort(ind)

ind包含重復組中第一個元素的索引,通過非連續索引可見它們的diff給出了組中元素的數量。 使用np.diff(ind)>5過濾將在組的起始索引處給出一個帶有True的布爾數組。 ind數組包含過濾列表中每個True之后的每個組的結束索引

創建一個字典,以鍵作為重復元素,值作為該組的開始和結束索引的元組

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM