Wie kann ich ein Histogramm so zeichnen, dass die Höhe der Balken in matplotlib 1 ergibt?


85

Ich möchte mit matplotlib ein normalisiertes Histogramm aus einem Vektor zeichnen. Ich habe folgendes versucht:

plt.hist(myarray, normed=True)

ebenso gut wie:

plt.hist(myarray, normed=1)

Aber keine der beiden Optionen erzeugt eine y-Achse von [0, 1], sodass sich die Balkenhöhen des Histogramms zu 1 summieren. Ich möchte ein solches Histogramm erstellen - wie kann ich das tun?


5
Ich weiß, dass dies alt ist, aber als zukünftige Referenz und für jeden, der diese Seite besucht, wird diese Art der Achsenausbreitung als "Wahrscheinlichkeitsdicht" -Achse bezeichnet!
ChristineB

Antworten:


48

Es wäre hilfreicher, wenn Sie ein vollständigeres (oder in diesem Fall nicht funktionierendes) Beispiel vorlegen würden.

Ich habe folgendes versucht:

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()

Dies erzeugt in der Tat ein Balkendiagramm-Histogramm mit einer y-Achse, die von ausgeht [0,1].

Ferner denke ich gemäß der histDokumentation (dh ax.hist?von ipython), dass die Summe auch in Ordnung ist:

*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))

Probieren Sie es nach den obigen Befehlen aus:

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

Ich erhalte einen Rückgabewert von 1.0wie erwartet. Denken Sie daran, dass normed=Truedies nicht bedeutet, dass die Summe des Werts an jedem Balken Eins ist, sondern dass das Integral über den Balken Einheit ist. In meinem Fall np.sum(n)ca. zurückgekehrt 7.2767.


Ja, das ist ein Wahrscheinlichkeitsdichtediagramm. Ich denke, er möchte ein Wahrscheinlichkeitsmassendiagramm.
NoName

197

Wenn Sie möchten, dass die Summe aller Balken gleich eins ist, gewichten Sie jeden Behälter mit der Gesamtzahl der Werte:

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

Hoffe das hilft, obwohl der Thread ziemlich alt ist ...

Hinweis für Python 2.x: Fügen Sie Casting float()für einen der Operatoren der Division hinzu, da Sie sonst aufgrund der Ganzzahldivision Nullen erhalten würden


8
Gute Antwort. Beachten Sie, dass , wenn myarray eine Python ist array_likeeher als ein numpy Array , das Sie Guss benötigen len(myarray)zu float.
cmh

3
Auch wenn myarray mehrdimensional ist und Sie nur eine Dimension verwenden, wie z. B. myarray [0,:], können Sie len (myarray) gegen np.size (myarray [0 ,:]) austauschen gleicher Weg. (Andernfalls heißt es, dass das Objekt nicht aufrufbar ist.)
ChristineB

21

Ich weiß, dass diese Antwort zu spät ist, wenn man bedenkt, dass die Frage auf das Jahr 2010 datiert ist, aber ich bin auf diese Frage gestoßen, da ich selbst mit einem ähnlichen Problem konfrontiert war. Wie bereits in der Antwort angegeben, bedeutet normed = True, dass die Gesamtfläche unter dem Histogramm gleich 1 ist, die Summe der Höhen jedoch nicht gleich 1. Ich wollte jedoch zur Vereinfachung der physikalischen Interpretation eines Histogramms eine erstellen mit einer Summe von Höhen gleich 1.

Ich habe in der folgenden Frage einen Hinweis gefunden - Python: Histogramm mit einem Bereich, der auf etwas anderes als 1 normalisiert ist

Ich konnte jedoch keine Möglichkeit finden, Balken so zu gestalten, dass sie das Merkmal histtype = "step" hist () imitieren. Dies lenkte mich zu: Matplotlib - Stufen-Histogramm mit bereits gruppierten Daten

Wenn die Community dies für akzeptabel hält, möchte ich eine Lösung vorschlagen, die Ideen aus den beiden oben genannten Beiträgen zusammenfasst.

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.

Dies hat bei mir wunderbar funktioniert, obwohl ich in einigen Fällen festgestellt habe, dass der am weitesten links liegende "Balken" oder der am weitesten rechts stehende "Balken" des Histogramms nicht durch Berühren des tiefsten Punkts der Y-Achse geschlossen wird. In einem solchen Fall wurde durch Hinzufügen eines Elements 0 am Betteln oder am Ende von y das erforderliche Ergebnis erzielt.

Ich dachte nur, ich würde meine Erfahrungen teilen. Danke dir.


Ich denke, Sie brauchen normiert = True auch in plt.hist. Auch in Python 3 müssen Sie list (zip (...)) verwenden.
Sebastian Schmitz

11

Hier ist eine weitere einfache Lösung mit np.histogram()Methode.

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

Sie können in der Tat überprüfen, ob die Gesamtsumme bis zu 1 beträgt:

> print sum(results*binWidth)
1.0
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.