문제

pylab 프로그램(아마 matlab 프로그램일 수도 있음)에는 거리를 나타내는 숫자 배열이 있습니다. d[t]거리 시간에 t (그리고 내 데이터의 기간은 len(d) 시간 단위).

내가 관심 있는 이벤트는 거리가 특정 임계값 미만일 때이며 이러한 이벤트의 지속 시간을 계산하고 싶습니다.부울 배열을 얻는 것은 쉽습니다. b = d<threshold, 문제는 True-only 단어의 길이 순서를 계산하는 데 있습니다. b.하지만 효율적으로 수행하는 방법을 모르겠습니다(예:numpy 프리미티브를 사용하여) 배열을 탐색하고 수동으로 변경 사항을 감지했습니다(예:값이 False에서 True로 변경되면 카운터를 초기화하고, 값이 True인 동안 카운터를 늘리고, 값이 다시 False로 변경되면 시퀀스에 카운터를 출력합니다.그러나 이것은 엄청나게 느립니다.

numpy 배열에서 이러한 종류의 시퀀스를 효율적으로 감지하는 방법은 무엇입니까?

다음은 내 문제를 설명하는 일부 Python 코드입니다.네 번째 점은 나타나는 데 매우 오랜 시간이 걸립니다(그렇지 않은 경우 배열 크기를 늘리십시오).

from pylab import *

threshold = 7

print '.'
d = 10*rand(10000000)

print '.'

b = d<threshold

print '.'

durations=[]
for i in xrange(len(b)):
    if b[i] and (i==0 or not b[i-1]):
        counter=1
    if  i>0 and b[i-1] and b[i]:
        counter+=1
    if (b[i-1] and not b[i]) or i==len(b)-1:
        durations.append(counter)

print '.'
도움이 되었습니까?

해결책

그렇지 않습니다 numpy 기초 요소, itertools 함수는 종종 매우 빠르 므로이 시도를 시도하고 (물론 이것을 포함한 다양한 솔루션에 대한 시간을 측정하십시오) :

def runs_of_ones(bits):
  for bit, group in itertools.groupby(bits):
    if bit: yield sum(group)

목록에 값이 필요한 경우 목록 (runs_of_ones (bits))를 사용할 수 있습니다. 그러나 아마도 목록 이해력이 여전히 더 빠를 수 있습니다.

def runs_of_ones_list(bits):
  return [sum(g) for b, g in itertools.groupby(bits) if b]

"Numpy-Native"가능성으로 이동하는 것은 어떻습니까 :

def runs_of_ones_array(bits):
  # make sure all runs of ones are well-bounded
  bounded = numpy.hstack(([0], bits, [0]))
  # get 1 at run starts and -1 at run ends
  difs = numpy.diff(bounded)
  run_starts, = numpy.where(difs > 0)
  run_ends, = numpy.where(difs < 0)
  return run_ends - run_starts

다시 : 현실적인 예에서 서로에 대한 솔루션을 벤치마킹해야합니다!

다른 팁

모든 배열에 대해 완전히 뾰족한 벡터 화되고 일반적인 rle (문자열, 부울 등에도 작동).

실행 길이, 시작 위치 및 값의 튜플을 출력합니다.

import numpy as np

def rle(inarray):
        """ run length encoding. Partial credit to R rle function. 
            Multi datatype arrays catered for including non Numpy
            returns: tuple (runlengths, startpositions, values) """
        ia = np.asarray(inarray)                  # force numpy
        n = len(ia)
        if n == 0: 
            return (None, None, None)
        else:
            y = np.array(ia[1:] != ia[:-1])     # pairwise unequal (string safe)
            i = np.append(np.where(y), n - 1)   # must include last element posi
            z = np.diff(np.append(-1, i))       # run lengths
            p = np.cumsum(np.append(0, z))[:-1] # positions
            return(z, p, ia[i])

꽤 빠른 (i7) :

xx = np.random.randint(0, 5, 1000000)
%timeit yy = rle(xx)
100 loops, best of 3: 18.6 ms per loop

여러 데이터 유형 :

rle([True, True, True, False, True, False, False])
Out[8]: 
(array([3, 1, 1, 2]),
 array([0, 3, 4, 5]),
 array([ True, False,  True, False], dtype=bool))

rle(np.array([5, 4, 4, 4, 4, 0, 0]))
Out[9]: (array([1, 4, 2]), array([0, 1, 5]), array([5, 4, 0]))

rle(["hello", "hello", "my", "friend", "okay", "okay", "bye"])
Out[10]: 
(array([2, 1, 1, 2, 1]),
 array([0, 2, 3, 4, 6]),
 array(['hello', 'my', 'friend', 'okay', 'bye'], 
       dtype='|S6'))

위의 Alex Martelli와 동일한 결과 :

xx = np.random.randint(0, 2, 20)

xx
Out[60]: array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1])

am = runs_of_ones_array(xx)

tb = rle(xx)

am
Out[63]: array([4, 5, 2, 5])

tb[0][tb[2] == 1]
Out[64]: array([4, 5, 2, 5])

%timeit runs_of_ones_array(xx)
10000 loops, best of 3: 28.5 µs per loop

%timeit rle(xx)
10000 loops, best of 3: 38.2 µs per loop

Alex보다 약간 느리지 만 여전히 매우 빠르며 훨씬 더 유연합니다.

다음은 배열만 사용하는 솔루션입니다.일련의 bool을 포함하는 배열을 사용하고 전환 길이를 계산합니다.

>>> from numpy import array, arange
>>> b = array([0,0,0,1,1,1,0,0,0,1,1,1,1,0,0], dtype=bool)
>>> sw = (b[:-1] ^ b[1:]); print sw
[False False  True False False  True False False  True False False False
  True False]
>>> isw = arange(len(sw))[sw]; print isw
[ 2  5  8 12]
>>> lens = isw[1::2] - isw[::2]; print lens
[3 4]

sw 스위치가 있는 곳에는 true를 포함하고, isw 인덱스로 변환합니다.그런 다음 isw의 항목을 쌍으로 뺍니다. lens.

시퀀스가 1로 시작하면 0초 시퀀스의 길이를 계산합니다.이는 렌즈를 계산하기 위한 인덱싱에서 수정될 수 있습니다.또한 길이가 1인 시퀀스와 같은 특수한 경우를 테스트하지 않았습니다.


모든 시작 위치와 길이를 반환하는 전체 기능 True-하위 배열.

import numpy as np

def count_adjacent_true(arr):
    assert len(arr.shape) == 1
    assert arr.dtype == np.bool
    if arr.size == 0:
        return np.empty(0, dtype=int), np.empty(0, dtype=int)
    sw = np.insert(arr[1:] ^ arr[:-1], [0, arr.shape[0]-1], values=True)
    swi = np.arange(sw.shape[0])[sw]
    offset = 0 if arr[0] else 1
    lengths = swi[offset+1::2] - swi[offset:-1:2]
    return swi[offset:-1:2], lengths

다양한 bool 1D 배열에 대해 테스트되었습니다(빈 배열;단일/다중 요소;짝수/홀수 길이;~로 시작하다 True/False;오직 True/False 강요).

누구나 궁금한 점이있는 경우 (그리고 당신이 지나가는 Matlab을 언급 한 이후로) Matlab에서 그것을 해결하는 한 가지 방법이 있습니다.

threshold = 7;
d = 10*rand(1,100000);  % Sample data
b = diff([false (d < threshold) false]);
durations = find(b == -1)-find(b == 1);

나는 파이썬에 너무 익숙하지 않지만 아마도 이것은 당신에게 몇 가지 아이디어를 줄 수 있습니다. =))

durations = []
counter   = 0

for bool in b:
    if bool:
        counter += 1
    elif counter > 0:
        durations.append(counter)
        counter = 0

if counter > 0:
    durations.append(counter)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top