2010-02-16 8 views
13

Deseo obtener una lista de los datos contenidos en un contenedor de histogramas. Estoy usando numpy y Matplotlib. Sé cómo recorrer los datos y verificar los bordes de los contenedores. Sin embargo, quiero hacer esto para un histograma 2D y el código para hacer esto es bastante feo. ¿Numpy tiene construcciones para hacer esto más fácil?Cómo obtener datos en un contenedor de histogramas

Para el caso 1D, puedo usar searchsorted(). Pero la lógica no es mucho mejor, y realmente no quiero hacer una búsqueda binaria en cada punto de datos cuando no es necesario.

La mayor parte de la desagradable lógica se debe a las regiones de límite de la bandeja. Todas las regiones tienen límites como este: [borde izquierdo, borde derecho]. Excepto el último contenedor, que tiene una región como esta: [borde izquierdo, borde derecho].

Aquí hay un código de ejemplo para el caso 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 

Aquí hay un código de ejemplo para el caso 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 

¿Existe un/forma más eficiente limpiador para hacer esto? Parece que Numpy tendría algo para esto.

+3

Sólo por curiosidad; ¿Por qué usas comentarios como #end si está en tu código? "Cada píxel cuenta" Al hacer eso, estás ignorando el propósito de la sangría. –

+3

2 razones. Primero soy desarrollador de C++ y desarrollador de python en segundo lugar. La falta de llaves de Python me irrita sin fin. Cuando tengo bloques de código complicados con muchas indentaciones variables, no quiero contar espacios en blanco. Y hago la mayor parte de mi desarrollo en Emacs. Al poner comentarios de cierre en bloques de código, me permite presionar TAB en cada línea y Emacs no intentará indebidamente algo. – Ben

Respuesta

21

digitize, desde el núcleo NumPy, le dará el índice de la papelera a la que cada valor en su histograma pertenece :

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

¡Esto es casi perfecto! Si hay algún numpy devs aquí, esta función realmente debería ir en la parte "ver también" de los documentos del histograma. Es una pena que la lógica de digitalizar() bin no coincida exactamente con la lógica de histograma() bin. Esto conduce a un código tan incómodo como el resto de mis ejemplos anteriores. – Ben

+1

¿no es exactamente lo mismo que 'bins.searchsorted (A, 'right')'? –

4

¿qué tal algo como:

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]: 

con un poco de código para manejar los casos extremos.

0

pyplot.hist en matplotlib crea un histograma (pero también lo dibuja en la pantalla, que puede que no desee). Solo para los contenedores, puede usar numpy.histogram, como se describe en otra respuesta.

Here es un ejemplo que compara pyploy.hist y numpy.histogram.

Cuestiones relacionadas