2016-12-31 30 views
7

Moje dane wygląda mniej więcej tak:Policz liczbę klastrów niezerowych wartości w Pythonie?

a=[0,0,0,0,0,0,10,15,16,12,11,9,10,0,0,0,0,0,6,9,3,7,5,4,0,0,0,0,0,0,4,3,9,7,1] 

Zasadniczo istnieje grono zer przed numerami niezerowych i szukam policzyć liczbę grup numerów niezerowych oddzielonych zerami. Na przykład dane powyżej, istnieją 3 grupy danych niezerowych więc kod powinien powrócić 3.

  • liczbę zer między grupami spoza zer jest zmienne

Wszelkie dobre sposoby turystyczne to w python? (Także z użyciem Pandy i Numpy w celu analizowania danych)

+0

jeśli miał w serii (lub dataframe), cou ld do: '((ser! = 0) & (ser.shift() == 0) .sum()' – JohnE

+0

Powiązane: [Wyodrębnij niezerowe bloki z tablicy] (http://stackoverflow.com/ pytania/31544129/extract-separate-non-zero-blocks-from-array) i [Jak wycinać listę w ciągłe grupy niezerowych liczb całkowitych w Pythonie] (http://stackoverflow.com/questions/6760871/how- to-slice-list-do-sąsiadujących-grup-niezerowych-liczb całkowitych-w-pythonach) – user2314737

Odpowiedz

5

z a jak układ wejściowy, mogliśmy zwektoryzowany rozwiązanie -

m = a!=0 
out = (m[1:] > m[:-1]).sum() + m[0] 

Alternatywnie do wykonania może używamy np.count_nonzero co jest bardzo efektywne liczyć bools jak ma to miejsce tutaj, podobnie jak -

out = np.count_nonzero(m[1:] > m[:-1]) + m[0] 

Zasadniczo mamy maskę non-zeros i liczy narastające zbocza. Aby uwzględnić pierwszy element, który również może być różny od zera i nie ma wzrostu, musimy go sprawdzić i dodać do całkowitej kwoty.

Należy również pamiętać, że jeśli wpis a jest listą, musimy zamiast tego użyć m = np.asarray(a)!=0.

próbki trwa trzech przypadkach -

In [92]: a # Case1 :Given sample 
Out[92]: 
array([ 0, 0, 0, 0, 0, 0, 10, 15, 16, 12, 11, 9, 10, 0, 0, 0, 0, 
     0, 6, 9, 3, 7, 5, 4, 0, 0, 0, 0, 0, 0, 4, 3, 9, 7, 
     1]) 

In [93]: m = a!=0 

In [94]: (m[1:] > m[:-1]).sum() + m[0] 
Out[94]: 3 

In [95]: a[0] = 7 # Case2 :Add a non-zero elem/group at the start 

In [96]: m = a!=0 

In [97]: (m[1:] > m[:-1]).sum() + m[0] 
Out[97]: 4 

In [99]: a[-2:] = [0,4] # Case3 :Add a non-zero group at the end 

In [100]: m = a!=0 

In [101]: (m[1:] > m[:-1]).sum() + m[0] 
Out[101]: 5 
2

proste rozwiązanie Pythona, po prostu liczyć zmian od 0 do niezerowa, poprzez śledzenie poprzedniej wartości (zbocze wykrywanie krawędzi):

a=[0,0,0,0,0,0,10,15,16,12,11,9,10,0,0,0,0,0,6,9,3,7,5,4,0,0,0,0,0,0,4,3,9,7,1] 

previous = 0 
count = 0 
for c in a: 
    if previous==0 and c!=0: 
     count+=1 
    previous = c 

print(count) # 3 
4

można to osiągnąć poprzez używając itertools.groupby() z listowych wypowiedzi:

>>> from itertools import groupby 

>>> len([is_true for is_true, _ in groupby(a, lambda x: x!=0) if is_true]) 
3 
+0

Jest to dobre, jeśli używasz iteracji, której nie można łatwo przekonwertować na tablicę Numpy. –

+0

Nie, myślę, że OP nie będzie mieć takiego warunku. – Divakar

+0

Och, chodzi mi o ogólne podejście "groupby" - właściwie nawet nie zauważyłem twojego błędu. W każdym razie chodzi mi o to, że skoro pytanie dotyczy sytuacji, w której Numpy jest dostępna, wektoryzowane rozwiązanie jest lepsze, ale dobrze jest o tym wiedzieć w innych sytuacjach. –

1
sum ([1 for n in range (len (a) - 1) if not a[n] and a[n + 1]]) 
+0

Co jeśli pierwszy element jest niezerowy? – Divakar

+0

@Divakar 'Zasadniczo istnieje kilka zer przed liczbami niezerowymi." Tak powiedział OP. – user7342539

+0

Ah moje złe, dobrze to zauważyć! – Divakar

2
  • pad tablica z zerem po obu stronach np.concatenate
  • znaleźć gdzie zera a == 0
  • Granice znalezienia z granicami np.diff
  • Podsumowując znaleziono ze sum
  • podzielić przez dwa, ponieważ my znajdzie dwa razy więcej niż chcemy

def nonzero_clusters(a): 
    return int(np.diff(np.concatenate([[0], a, [0]]) == 0).sum()/2) 

demonstracja

nonzero_clusters(
    [0,0,0,0,0,0,10,15,16,12,11,9,10,0,0,0,0,0,6,9,3,7,5,4,0,0,0,0,0,0,4,3,9,7,1] 
) 

3 

nonzero_clusters([0, 1, 2, 0, 1, 2]) 

2 

nonzero_clusters([0, 1, 2, 0, 1, 2, 0]) 

2 

nonzero_clusters([1, 2, 0, 1, 2, 0, 1, 2]) 

3 

rozrządu
a = np.random.choice((0, 1), 100000)
kod

from itertools import groupby 

def div(a): 
    m = a != 0 
    return (m[1:] > m[:-1]).sum() + m[0] 

def pir(a): 
    return int(np.diff(np.concatenate([[0], a, [0]]) == 0).sum()/2) 

def jean(a): 
    previous = 0 
    count = 0 
    for c in a: 
     if previous==0 and c!=0: 
      count+=1 
     previous = c 
    return count 

def moin(a): 
    return len([is_true for is_true, _ in groupby(a, lambda x: x!=0) if is_true]) 

def user(a): 
    return sum([1 for n in range (len (a) - 1) if not a[n] and a[n + 1]]) 

enter image description here

+0

Dla wydajności, jean2 = numba.jit (jean) działa w 65 μs. –

Powiązane problemy