簡體   English   中英

使用位掩碼查找數據間隙

[英]Finding data gaps with bit masking

我面臨着在一系列數字中找到給定長度的不連續性(間隙)的問題。 因此,例如,給定[1,2,3,7,8,9,10]length=3的間隙,我將找到[4,5,6] 如果差距為length=4 ,我什么也找不到。 當然,真正的順序要長得多。 我已經在很多文章中看到了這個問題,並且它具有各種應用程序和可能的實現。

我認為一種可行且應相對較快的方法是將完整集表示為一個位數組,其中包含1表示可用數字,0表示缺失-因此上面的內容看起來像[1,1,1,0,0,0,1,1,1,1] 然后可能會運行一個窗口函數,該函數將對具有完整集合的給定長度的數組進行XOR屏蔽,直到所有位置均等於1。這將需要對整個序列進行單次遍歷,大約為O(n),再加上開銷每次運行都遮罩。

這是我設法提出的:

def find_gap(array, start=0, length=10):
    """
    array:  assumed to be of length MAX_NUMBER and contain 0 or 1 
            if the value is actually present
    start:  indicates what value to start looking from
    length: what the length the gap should be
    """

    # create the bitmask to check against
    mask = ''.join( [1] * length )

    # convert the input 0/1 mapping to bit string
    # e.g - [1,0,1,0] -> '1010'
    bits =''.join( [ str(val) for val in array ] )

    for i in xrange(start, len(bits) - length):

        # find where the next gap begins
        if bits[i] != '0': continue

        # gap was found, extract segment of size 'length', compare w/ mask
        if (i + length < len(bits)):
            segment = bits[i:i+length]

            # use XOR between binary masks
            result  = bin( int(mask, 2) ^ int(segment, 2) )

            # if mask == result in base 2, gap found
            if result == ("0b%s" % mask): return i

    # if we got here, no gap exists
    return -1

大約100k(<1秒)的速度相當快。 我希望您能獲得一些技巧,以期在更大的套裝上更快,更高效地進行制作。 謝謝!

找到相鄰數字之間的差異,然后查找足夠大的差異。 我們通過構造兩個列表(除第一個以外的所有數字,以及除最后一個以外的所有數字)並成對地減去它們來找到差異。 我們可以使用zip將值配對。

def find_gaps(numbers, gap_size):
    adjacent_differences = [(y - x) for (x, y) in zip(numbers[:-1], numbers[1:])]
    # If adjacent_differences[i] > gap_size, there is a gap of that size between
    # numbers[i] and numbers[i+1]. We return all such indexes in a list - so if
    # the result is [] (empty list), there are no gaps.
    return [i for (i, x) in enumerate(adjacent_differences) if x > gap_size]

(另外, 學習一些Python習慣用法。我們更喜歡直接迭代,並且我們有一個真正的布爾類型。)

您可以使用XOR並進行平移,它的運行時間大約為O(n)。

但是,實際上,建立索引(所有間隙的哈希表大於某個最小長度)可能是更好的方法。

假設您從這些整數的序列(而不是位掩碼)開始,那么只需遍歷序列即可構建索引; 每當發現間隙大於閾值時,便將該間隙大小添加到字典中(如有必要,將其實例化為空列表,然后在序列中附加偏移量。

最后,您將獲得序列中每個缺口(大於所需閾值)的列表。

關於此方法的一個好處是,在修改基本列表時,您應該能夠維護該索引。 因此,用於后續索引查詢和索引更新的O(n * log(n))初始時間由O(log(n))成本攤銷。

這是一個非常原始的函數,用於構建gap_index()

def gap_idx(s, thresh=2):
    ret = dict()
    lw = s[0]  # initial low val.
    for z,i in enumerate(s[1:]):
        if i - lw < thresh:
            lw = i
            continue
        key = i - lw
        if key not in ret:
            ret[key] = list()
        ret[key].append(z)
        lw = i
    return ret

最好同時圍繞內置的“ bisect”模塊及其insort()函數構建用於維護數據集和索引的類。

如果您追求效率,那么我會按照以下方式做一些事情(其中x是序列號列表):

for i in range(1, len(x)):
  if x[i] - x[i - 1] == length + 1:
    print list(range(x[i - 1] + 1, x[i]))

aix所做的幾乎是什么...但是僅獲得所需長度的間隙:

def findGaps(mylist, gap_length, start_idx=0):
    gap_starts = []
    for idx in range(start_idx, len(mylist) - 1):
        if mylist[idx+1] - mylist[idx] == gap_length + 1:
            gap_starts.append(mylist[idx] + 1)

    return gap_starts

編輯:調整到OP的願望。

這些提供您輸入列表的單步瀏覽。

給定長度的間隙值列表:

from itertools import tee, izip
def gapsofsize(iterable, length):
    a, b = tee(iterable)
    next(b, None)
    return ( p for x, y in izip(a, b) if y-x == length+1 for p in xrange(x+1,y) )

print list(gapsofsize([1,2,5,8,9], 2))

[3, 4, 6, 7]

所有間隙值:

def gaps(iterable):
    a, b = tee(iterable)
    next(b, None)
    return ( p for x, y in izip(a, b) if y-x > 1 for p in xrange(x+1,y) )

print list(gaps([1,2,4,5,8,9,14]))

[3, 6, 7, 10, 11, 12, 13]

空隙作為向量的列表:

def gapsizes(iterable):
    a, b = tee(iterable)
    next(b, None)
    return ( (x+1, y-x-1) for x, y in izip(a, b) if y-x > 1 )

print list(gapsizes([1,2,4,5,8,9,14]))

[(3, 1), (6, 2), (10, 4)]

請注意,這些是生成器,消耗的內存很少。 我很想知道這些如何在您的測試數據集上執行。

暫無
暫無

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

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