2010-10-05 9 views
56

Me gustaría trazar un histograma normalizado a partir de un vector utilizando matplotlib. Probé el siguiente:trazado de histogramas cuyas alturas de barras suman 1 en matplotlib

plt.hist(myarray, normed=True) 

así como:

plt.hist(myarray, normed=1) 

pero ni opción produce un eje Y a partir de [0, 1] de tal manera que las alturas de las barras de la suma de histograma a 1. I Me gustaría producir un histograma de este tipo: ¿cómo puedo hacerlo?

gracias!

+1

Sé que esto es viejo, pero para futuras referencias y cualquier persona que visita esta página, este tipo de eje de propagación se llama un eje de "densidad de probabilidad"! – ChristineB

+0

OP, si todavía estás cerca, quizás quieras cambiar la respuesta aceptada. –

Respuesta

39

Sería más útil si presentara un ejemplo de trabajo más completo (o en este caso no funcional).

I intentado el siguiente:

import numpy as np 
import matplotlib.pyplot as plt 

x = np.random.randn(1000) 

fig = plt.figure() 
ax = fig.add_subplot(111) 
n, bins, rectangles = ax.hist(x, 50, normed=True) 
fig.canvas.draw() 
plt.show() 

Esto en efecto producir un histograma gráfico de barras con un eje y que va desde [0,1].

Además, según la documentación hist (es decir ax.hist? de ipython), creo que la suma está muy bien también:

*normed*: 
If *True*, the first element of the return tuple will 
be the counts normalized to form a probability density, i.e., 
``n/(len(x)*dbin)``. In a probability density, the integral of 
the histogram should be 1; you can verify that with a 
trapezoidal integration of the probability density function:: 

    pdf, bins, patches = ax.hist(...) 
    print np.sum(pdf * np.diff(bins)) 

Dar a este un intento después de que los comandos anteriores:

np.sum(n * np.diff(bins)) 

I Obtenga un valor de retorno de 1.0 como se esperaba. Recuerde que normed=True no significa que la suma del valor en cada barra será la unidad, pero en lugar de la integral sobre las barras es la unidad. En mi caso, np.sum(n) devolvió aproximadamente 7.2767.

13

Sé que esta respuesta es demasiado tarde teniendo en cuenta que la fecha está fechada en 2010, pero me encontré con esta pregunta, ya que yo mismo estaba enfrentando un problema similar. Como ya se indicó en la respuesta, normed = Verdadero significa que el área total bajo el histograma es igual a 1 pero la suma de las alturas no es igual a 1. Sin embargo, quería, por conveniencia de la interpretación física de un histograma, hacer una con la suma de alturas iguales a 1.

he encontrado una pista en la siguiente pregunta - Python: Histogram with area normalized to something other than 1

Pero yo no era capaz de encontrar una manera de hacer barras imitan la histtype = "paso" hist función(). Esto me desvió a: Matplotlib - Stepped histogram with already binned data

Si la comunidad lo considera aceptable, me gustaría presentar una solución que sintetice ideas de las dos publicaciones anteriores.

import matplotlib.pyplot as plt 

# Let X be the array whose histogram needs to be plotted. 
nx, xbins, ptchs = plt.hist(X, bins=20) 
plt.clf() # Get rid of this histogram since not the one we want. 

nx_frac = nx/float(len(nx)) # Each bin divided by total number of objects. 
width = xbins[1] - xbins[0] # Width of each bin. 
x = np.ravel(zip(xbins[:-1], xbins[:-1]+width)) 
y = np.ravel(zip(nx_frac,nx_frac)) 

plt.plot(x,y,linestyle="dashed",label="MyLabel") 
#... Further formatting. 

esto ha funcionado de maravilla para mí, aunque en algunos casos he notado que la mayoría de los "barra" hacia la izquierda o la derecha más "barra" del histograma no se cierra al tocar el punto más bajo de la Y- eje. En tal caso, agregar un elemento 0 al inicio o al final de y logra el resultado necesario.

Pensé que compartiría mi experiencia. Gracias.

+0

Creo que necesita norma = Verdadero también en plt.hist. También en Python 3 debes usar list (zip (...)). –

146

Si desea que la suma de todos los bares a ser igual a la unidad, el peso de cada contenedor por el número total de valores:

weights = np.ones_like(myarray)/float(len(myarray)) 
plt.hist(myarray, weights=weights) 

Espero que ayude, aunque el hilo es bastante viejo ...

+8

Gran respuesta. Tenga en cuenta que si myarray es una python 'array_like' en lugar de una matriz numpy, tendrá que convertir' len (myarray) 'en' float'. – cmh

+0

Además, si myarray es multidimensional y solo está usando una dimensión, como myarray [0 ,:], puede cambiar len (myarray) con np.size (myarray [0 ,:]) y eso funcionará de la misma manera. (De lo contrario, dice que el objeto no se puede llamar). – ChristineB

8

Aquí hay otra solución simple que usa el método np.histogram().

myarray = np.random.random(100) 
results, edges = np.histogram(myarray, normed=True) 
binWidth = edges[1] - edges[0] 
plt.bar(edges[:-1], results*binWidth, binWidth) 

Efectivamente, puedes comprobar que las sumas totales de hasta 1 con:

> print sum(results*binWidth) 
1.0 
Cuestiones relacionadas