簡體   English   中英

在大型numpy數組中查找常量子數組

[英]Find constant subarrays in large numpy array

我有一個像numpy浮點數組

v = np.array([1.0,1.0,2.0,2.0,2.0,2.0,...])

我需要識別數組中的所有常量段

[{value:1.0,location:0,duration:2},..]

效率是主要指標

這是一種方法 -

def island_props(v):
    # Get one-off shifted slices and then compare element-wise, to give
    # us a mask of start and start positions for each island.
    # Also, get the corresponding indices.
    mask = np.concatenate(( [True], v[1:] != v[:-1], [True] ))
    loc0 = np.flatnonzero(mask)

    # Get the start locations
    loc = loc0[:-1]

    # The values would be input array indexe by the start locations.
    # The lengths woul be the differentiation between start and stop indices.
    return v[loc], loc, np.diff(loc0)

樣品運行 -

In [143]: v
Out[143]: array([ 1.,  1.,  2.,  2.,  2.,  2.,  5.,  2.])

In [144]: value, location, lengths = island_props(v)

In [145]: value
Out[145]: array([ 1.,  2.,  5.,  2.])

In [146]: location
Out[146]: array([0, 2, 6, 7])

In [147]: lengths
Out[147]: array([2, 4, 1, 1])

運行時測試

其他方法 -

import itertools
def MSeifert(a):
    return [{'value': k, 'duration': len(list(v))} for k, v in 
             itertools.groupby(a.tolist())]

def Kasramvd(a):
    return np.split(v, np.where(np.diff(v) != 0)[0] + 1)

計時 -

In [156]: v0 = np.array([1.0,1.0,2.0,2.0,2.0,2.0,5.0,2.0])

In [157]: v = np.tile(v0,10000)

In [158]: %timeit MSeifert(v)
     ...: %timeit Kasramvd(v)
     ...: %timeit island_props(v)
     ...: 
10 loops, best of 3: 44.7 ms per loop
10 loops, best of 3: 36.1 ms per loop
10000 loops, best of 3: 140 µs per loop

您可以按如下方式對相同的項進行分組,然后通過獲取數組的大小,第一個元素和索引來完成剩下的工作:

In [2]: v = np.array([1.0,1.0,2.0,2.0,2.0,2.0,3.0, 3.0, 5.0, 6.0, 6.0])

In [4]: np.split(v, np.where(np.diff(v) != 0)[0] + 1)
Out[4]: 
[array([ 1.,  1.]),
 array([ 2.,  2.,  2.,  2.]),
 array([ 3.,  3.]),
 array([ 5.]),
 array([ 6.,  6.,  6.])]

方程式np.diff(v) != 0表示序列變化的位置(差值不為0), np.where()給出了這些位置的相應索引(來自布爾結果)。 然后你可以使用np.split()簡單地拆分數組。

最后,您可以使用列表理解來獲得期望結果:

In [7]: locations = np.where(np.diff(v) != 0)[0] + 1

In [8]: result = np.split(v, locations)

In [9]: [{'value':arr[0], 'location':loc, 'duration':arr.size} for loc, arr in zip(locations, result)]
Out[9]: 
[{'duration': 2, 'value': 1.0, 'location': 2},
 {'duration': 4, 'value': 2.0, 'location': 6},
 {'duration': 2, 'value': 3.0, 'location': 8},
 {'duration': 1, 'value': 5.0, 'location': 9}]

你可以使用itertools.groupby ,它可能會慢一點(沒有定時)但可能更容易理解:

>>> import numpy as np
>>> import itertools
>>> a = np.array([1.0,1.0,2.0,2.0,2.0,2.0])
>>> [{'value': k, 'duration': len(list(v))} for k, v in itertools.groupby(a.tolist())]
[{'duration': 2, 'value': 1.0}, {'duration': 4, 'value': 2.0}]

暫無
暫無

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

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