2010-02-16 17 views
13

Chcę uzyskać listę danych zawartych w pojemniku histogramu. Używam numpy i Matplotlib. Wiem, jak przejść przez dane i sprawdzić krawędzie pojemnika. Jednak chcę to zrobić dla histogramu 2D i kod do tego jest raczej brzydki. Czy numpy ma jakieś konstrukcje, aby to ułatwić?Jak uzyskać dane w bin histogramie

W przypadku przypadku 1D można użyć funkcji searchsorted(). Ale logika nie jest o wiele lepsza i nie chcę robić wyszukiwania binarnego w każdym punkcie danych, kiedy nie muszę.

Większość nieprzyjemnej logiki wynika z regionów granic bin. Wszystkie regiony mają takie granice: [lewa krawędź, prawa krawędź]. Z wyjątkiem ostatniego pojemnika, który ma taki region: [lewa krawędź, prawa krawędź].

Oto przykładowy kod dla przypadku 1D:

import numpy as np 

data = [0, 0.5, 1.5, 1.5, 1.5, 2.5, 2.5, 2.5, 3] 

hist, edges = np.histogram(data, bins=3) 

print 'data =', data 
print 'histogram =', hist 
print 'edges =', edges 

getbin = 2 #0, 1, or 2 

print '---' 
print 'alg 1:' 

#for i in range(len(data)): 
for d in data: 
    if d >= edges[getbin]: 
     if (getbin == len(edges)-2) or d < edges[getbin+1]: 
      print 'found:', d 
     #end if 
    #end if 
#end for 

print '---' 
print 'alg 2:' 

for d in data: 
    val = np.searchsorted(edges, d, side='right')-1 
    if val == getbin or val == len(edges)-1: 
     print 'found:', d 
    #end if 
#end for 

Oto przykładowy kod dla przypadku 2D:

import numpy as np 

xdata = [0, 1.5, 1.5, 2.5, 2.5, 2.5, \ 
     0.5, 0.5, 0.5, 0.5, 1.5, 1.5, 1.5, 1.5, 1.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, \ 
     0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3] 
ydata = [0, 5,5, 5, 5, 5, \ 
     15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, \ 
     25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 30] 

xbins = 3 
ybins = 3 
hist2d, xedges, yedges = np.histogram2d(xdata, ydata, bins=(xbins, ybins)) 

print 'data2d =', zip(xdata, ydata) 
print 'hist2d =' 
print hist2d 
print 'xedges =', xedges 
print 'yedges =', yedges 

getbin2d = 5 #0 through 8 

print 'find data in bin #', getbin2d 

xedge_i = getbin2d % xbins 
yedge_i = int(getbin2d/xbins) #IMPORTANT: this is xbins 

for x, y in zip(xdata, ydata): 
    # x and y left edges 
    if x >= xedges[xedge_i] and y >= yedges[yedge_i]: 
     #x right edge 
     if xedge_i == xbins-1 or x < xedges[xedge_i + 1]: 
      #y right edge 
      if yedge_i == ybins-1 or y < yedges[yedge_i + 1]: 
       print 'found:', x, y 
      #end if 
     #end if 
    #end if 
#end for 

Czy jest czystszy/bardziej efektywny sposób to zrobić? Wygląda na to, że numpy ma coś do tego.

+3

Tak z ciekawości; dlaczego używasz komentarzy takich jak #end, jeśli masz kod? "Każdy piksel się liczy" Robiąc to, ignorujesz cel wcięcia. –

+3

2 powody. Najpierw jestem programistą C++, a drugi program python. Brak aparatów Pythona irytuje mnie bez końca. Kiedy mam skomplikowane bloki kodu z wieloma różnymi wcięciami, nie chcę odliczać białych znaków. I robię większość mojego rozwoju w Emacs. Poprzez umieszczanie komentarzy zamykających na blokach kodu, pozwala mi on naciskać klawisz TAB na każdej linii, a Emacs nie będzie próbował niczego błędnie wciskać. – Ben

Odpowiedz

21

digitize, od rdzenia NumPy, daje indeks z kosza, do którego każda wartość w histogramie należy :

import numpy as NP 
A = NP.random.randint(0, 10, 100) 

bins = NP.array([0., 20., 40., 60., 80., 100.]) 

# d is an index array holding the bin id for each point in A 
d = NP.digitize(A, bins)  
+0

To prawie idealne! Jeśli są tutaj jakieś numpy-devi, ta funkcja powinna naprawdę przejść w części "zobacz także" dokumentacji histogramu. Szkoda, że ​​logika binariów() nie pasuje dokładnie do logiki bin histogramu(). Prowadzi to do równie niezręcznego kodu, jak pozostałe powyższe przykłady. – Ben

+1

czy to nie jest dokładnie to samo co 'bins.searchsorted (A, 'right')'? –

4

jak o czymś takim:

In [1]: data = numpy.array([0, 0.5, 1.5, 1.5, 1.5, 2.5, 2.5, 2.5, 3]) 
In [2]: hist, edges = numpy.histogram(data, bins=3) 
In [3]: for l, r in zip(edges[:-1], edges[1:]): 
    print(data[(data > l) & (data < r)]) 
    ....:  
    ....:  
[ 0.5] 
[ 1.5 1.5 1.5] 
[ 2.5 2.5 2.5] 
In [4]: 

z odrobiną kodu do obsługi przypadki krawędzi.

0

pyplot.hist w matplotlib tworzy histogram (ale także rysuje go na ekranie, czego możesz nie chcieć). W przypadku tylko pojemników można użyć numpy.histogram, jak opisano w innej odpowiedzi.

Here to przykład porównujący pyploy.hist i numpy.histogram.