Me gustaría trazar un histograma normalizado a partir de un vector usando matplotlib. Intenté lo siguiente:
plt.hist(myarray, normed=True)
tanto como:
plt.hist(myarray, normed=1)
pero ninguna de las opciones produce un eje y de [0, 1] tal que las alturas de las barras del histograma sumen 1. Me gustaría producir un histograma de este tipo, ¿cómo puedo hacerlo?
Respuestas:
Sería más útil si presentara un ejemplo de trabajo más completo (o en este caso no funcional).
Intenté lo 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, density=True) fig.canvas.draw() plt.show()
De hecho, esto producirá un histograma de gráfico de barras con un eje y que va desde
[0,1]
.Además, según la
hist
documentación (es decir,ax.hist?
deipython
), creo que la suma también está bien:*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))
Dando una oportunidad a esto después de los comandos anteriores:
Obtengo un valor de retorno de
1.0
lo esperado. Recuerde que esonormed=True
no significa que la suma del valor en cada barra será la unidad, sino que la integral sobre las barras es la unidad. En mi casonp.sum(n)
devolvió aprox7.2767
.fuente
Si desea que la suma de todas las barras sea igual a la unidad, pese cada contenedor por el número total de valores:
Espero que ayude, aunque el hilo es bastante antiguo ...
Nota para Python 2.x: agregue conversión a
float()
para uno de los operadores de la división, ya que de lo contrario terminaría con ceros debido a la división de enterosfuente
array_like
en lugar de una matriz numpy tendrá que fundidolen(myarray)
afloat
.Sé que esta respuesta es demasiado tarde considerando que la pregunta tiene fecha de 2010, pero me encontré con esta pregunta porque yo mismo enfrentaba un problema similar. Como ya se indicó en la respuesta, normed = True significa que el área total debajo del 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 uno con suma de alturas igual a 1.
Encontré una pista en la siguiente pregunta: Python: histograma con un área normalizada a algo diferente a 1
Pero no pude encontrar una manera de hacer que las barras imiten la característica histtype = "step" hist (). Esto me desvió a: Matplotlib - Histograma escalonado con datos ya agrupados
Si la comunidad lo considera aceptable, me gustaría proponer una solución que sintetice las ideas de los dos mensajes 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 maravillosamente para mí, aunque en algunos casos he notado que la "barra" más a la izquierda o la "barra" más a la derecha del histograma no se cierra al tocar el punto más bajo del eje Y. En tal caso, la adición de un elemento 0 al principio o al final de y logró el resultado necesario.
Solo pensé en compartir mi experiencia. Gracias.
fuente
Aquí hay otra solución simple usando el
np.histogram()
método.myarray = np.random.random(100) results, edges = np.histogram(myarray, normed=True) binWidth = edges[1] - edges[0] plt.bar(edges[:-1], results*binWidth, binWidth)
De hecho, puede verificar que el total sume hasta 1 con:
> print sum(results*binWidth) 1.0
fuente