Wie zeichne ich mit Matplotlib in Python ein Histogramm mit einer Datenliste?

96

Ich versuche, mit der matplotlib.hist()Funktion ein Histogramm zu zeichnen , bin mir aber nicht sicher, wie ich das machen soll.

Ich habe eine Liste

probability = [0.3602150537634409, 0.42028985507246375, 
  0.373117033603708, 0.36813186813186816, 0.32517482517482516, 
  0.4175257731958763, 0.41025641025641024, 0.39408866995073893, 
  0.4143222506393862, 0.34, 0.391025641025641, 0.3130841121495327, 
  0.35398230088495575]

und eine Liste von Namen (Strings).

Wie mache ich die Wahrscheinlichkeit als meinen y-Wert für jeden Balken und Namen als x-Werte?

DataVizGuys
quelle

Antworten:

166

Wenn Sie ein Histogramm wünschen, müssen Sie x-Werten keine 'Namen' hinzufügen, da Sie auf der x-Achse Datenfächer haben würden:

import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
np.random.seed(42)
x = np.random.normal(size=1000)
plt.hist(x, density=True, bins=30)  # `density=False` would make counts
plt.ylabel('Probability')
plt.xlabel('Data');

Geben Sie hier die Bildbeschreibung ein

Sie können Ihr Histogramm mit PDFLinien, Titeln und Legenden etwas schicker gestalten :

import scipy.stats as st
plt.hist(x, density=True, bins=30, label="Data")
mn, mx = plt.xlim()
plt.xlim(mn, mx)
kde_xs = np.linspace(mn, mx, 301)
kde = st.gaussian_kde(x)
plt.plot(kde_xs, kde.pdf(kde_xs), label="PDF")
plt.legend(loc="upper left")
plt.ylabel('Probability')
plt.xlabel('Data')
plt.title("Histogram");

Geben Sie hier die Bildbeschreibung ein

Wenn Sie jedoch eine begrenzte Anzahl von Datenpunkten haben, wie in OP, ist ein Balkendiagramm sinnvoller, um Ihre Daten darzustellen (dann können Sie Beschriftungen an die x-Achse anhängen):

x = np.arange(3)
plt.bar(x, height=[1,2,3])
plt.xticks(x, ['a','b','c'])

Geben Sie hier die Bildbeschreibung ein

Sergey Bushmanov
quelle
4
Denken Sie daran, keine Semikolons am Ende der Zeilen in Python!
Toad22222
10
@ Toad22222 Dies ist ein Auszug aus der Ipython-Notizbuchzelle. Versuchen Sie es ohne Semikolon auszuführen und sehen Sie den Unterschied. Alle Code-Schnipsel, die ich auf SO poste, laufen perfekt auf meinem Computer.
Sergey Bushmanov
2
Wenn Sie sich über das von Sergey verwendete Semikolon wundern, lesen Sie hier und Nr. 16 hier, wie das Semikolon in Jupyter-Notizbuchzellen (ehemals IPython-Notizbücher) beim Plotten verwendet wird, um den Text über das Plotobjekt zu unterdrücken.
Wayne
19

Wenn Sie matplotlib noch nicht installiert haben, versuchen Sie einfach den Befehl.

> pip install matplotlib

Bibliotheksimport

import matplotlib.pyplot as plot

Die Histogrammdaten:

plot.hist(weightList,density=1, bins=20) 
plot.axis([50, 110, 0, 0.06]) 
#axis([xmin,xmax,ymin,ymax])
plot.xlabel('Weight')
plot.ylabel('Probability')

Histogramm anzeigen

plot.show()

Und die Ausgabe ist wie folgt:

Geben Sie hier die Bildbeschreibung ein

Niraj
quelle
2
Die Linie plot.axis ([50, 110, 0, 0.06]) 'ist für das Beispiel unbrauchbar. Außerdem können Sie verwirrt sein, warum Ihre Daten nicht korrekt angezeigt werden, da es schwierig ist, den anzuzeigenden Bereich des Diagramms zu codieren.
Typhon04
8

Obwohl die Frage zu fordern scheint, ein Histogramm mit zu zeichnen matplotlib.hist() Funktion , kann dies wohl nicht unter Verwendung des gleichen Teils der Frage durchgeführt werden, der verlangt, die gegebenen Wahrscheinlichkeiten als y-Werte von Balken und gegebenen Namen (Zeichenketten) als zu verwenden x-Werte.

Ich gehe von einer Beispielliste mit Namen aus, die den angegebenen Wahrscheinlichkeiten für das Zeichnen des Diagramms entsprechen. Ein einfaches Balkendiagramm dient hier dem Zweck für das gegebene Problem. Der folgende Code kann verwendet werden:

import matplotlib.pyplot as plt
probability = [0.3602150537634409, 0.42028985507246375, 
  0.373117033603708, 0.36813186813186816, 0.32517482517482516, 
  0.4175257731958763, 0.41025641025641024, 0.39408866995073893, 
  0.4143222506393862, 0.34, 0.391025641025641, 0.3130841121495327, 
  0.35398230088495575]
names = ['name1', 'name2', 'name3', 'name4', 'name5', 'name6', 'name7', 'name8', 'name9',
'name10', 'name11', 'name12', 'name13'] #sample names
plt.bar(names, probability)
plt.xticks(names)
plt.yticks(probability) #This may be included or excluded as per need
plt.xlabel('Names')
plt.ylabel('Probability')
Shayan Shafiq
quelle
4

Dies ist eine sehr runde Methode. Wenn Sie jedoch ein Histogramm erstellen möchten, in dem Sie die Bin-Werte bereits kennen, aber nicht über die Quelldaten verfügen, können Sie mit dieser np.random.randintFunktion die richtige Anzahl von Werten innerhalb des jeweiligen Bereichs generieren bin, damit die Hist-Funktion grafisch dargestellt wird, zum Beispiel:

import numpy as np
import matplotlib.pyplot as plt

data = [np.random.randint(0, 9, *desired y value*), np.random.randint(10, 19, *desired y value*), etc..]
plt.hist(data, histtype='stepfilled', bins=[0, 10, etc..])

Bei Beschriftungen können Sie x Ticks mit Bins ausrichten, um Folgendes zu erhalten:

#The following will align labels to the center of each bar with bin intervals of 10
plt.xticks([5, 15, etc.. ], ['Label 1', 'Label 2', etc.. ])
Connor Wilmers
quelle
2

Dies ist eine alte Frage, aber keine der vorherigen Antworten hat das eigentliche Problem angesprochen, dh die Tatsache, dass das Problem bei der Frage selbst liegt.

Erstens, wenn die Wahrscheinlichkeiten bereits berechnet wurden, dh die aggregierten Histogrammdaten auf normalisierte Weise verfügbar sind, sollten sich die Wahrscheinlichkeiten zu 1 addieren. Dies ist offensichtlich nicht der Fall, und das bedeutet, dass hier entweder mit der Terminologie oder mit den Daten etwas nicht stimmt oder wie die Frage gestellt wird.

Zweitens würde die Tatsache, dass die Beschriftungen bereitgestellt werden (und nicht Intervalle), normalerweise bedeuten, dass die Wahrscheinlichkeiten eine kategoriale Antwortvariable sind - und die Verwendung eines Balkendiagramms zum Zeichnen des Histogramms ist am besten (oder ein Hacking der Hist-Methode des Pyplots). Shayan Shafiqs Antwort liefert den Code.

Siehe Problem 1, diese Wahrscheinlichkeiten sind jedoch nicht korrekt und die Verwendung eines Balkendiagramms in diesem Fall als "Histogramm" wäre falsch, da es aus irgendeinem Grund nicht die Geschichte der univariaten Verteilung erzählt (möglicherweise überlappen sich die Klassen und Beobachtungen werden mehrfach gezählt mal?) und ein solches Diagramm sollte in diesem Fall nicht als Histogramm bezeichnet werden.

Das Histogramm ist per Definition eine grafische Darstellung der Verteilung univariater Variablen (siehe https://www.itl.nist.gov/div898/handbook/eda/section3/histogra.htm , https://en.wikipedia.org/wiki) /Histogramm) und wird durch Zeichnen von Balken mit Größen erstellt, die die Anzahl oder Häufigkeit von Beobachtungen in ausgewählten Klassen der interessierenden Variablen darstellen. Wenn die Variable auf einer kontinuierlichen Skala gemessen wird, sind diese Klassen Bins (Intervalle). Ein wichtiger Teil des Histogramm-Erstellungsverfahrens besteht darin, zu entscheiden, wie die Kategorien von Antworten für eine kategoriale Variable gruppiert (oder ohne Gruppierung beibehalten) werden sollen oder wie der Bereich möglicher Werte in Intervalle aufgeteilt werden soll (wo die Bin-Grenzen gesetzt werden sollen), um fortlaufend zu sein Typ Variable. Alle Beobachtungen sollten dargestellt werden, und jede nur einmal in der Handlung. Dies bedeutet, dass die Summe der Balkengrößen gleich der Gesamtzahl der Beobachtungen sein sollte (oder deren Flächen bei variablen Breiten, was ein weniger verbreiteter Ansatz ist). Wenn das Histogramm normalisiert ist, müssen sich alle Wahrscheinlichkeiten zu 1 addieren.

Wenn die Daten selbst eine Liste von "Wahrscheinlichkeiten" als Antwort sind, dh die Beobachtungen Wahrscheinlichkeitswerte (von etwas) für jedes Untersuchungsobjekt sind, ist die beste Antwort einfach plt.hist(probability) mit einer Binning-Option, und die Verwendung von bereits verfügbaren x-Labels ist verdächtig.

Dann sollte das Balkendiagramm nicht als Histogramm verwendet werden, sondern einfach

import matplotlib.pyplot as plt
probability = [0.3602150537634409, 0.42028985507246375, 
  0.373117033603708, 0.36813186813186816, 0.32517482517482516, 
  0.4175257731958763, 0.41025641025641024, 0.39408866995073893, 
  0.4143222506393862, 0.34, 0.391025641025641, 0.3130841121495327, 
  0.35398230088495575]
plt.hist(probability)
plt.show()

mit den Ergebnissen

Geben Sie hier die Bildbeschreibung ein

matplotlib kommt in diesem Fall standardmäßig mit den folgenden Histogrammwerten an

(array([1., 1., 1., 1., 1., 2., 0., 2., 0., 4.]),
 array([0.31308411, 0.32380469, 0.33452526, 0.34524584, 0.35596641,
        0.36668698, 0.37740756, 0.38812813, 0.39884871, 0.40956928,
        0.42028986]),
 <a list of 10 Patch objects>)

Das Ergebnis ist ein Tupel von Arrays. Das erste Array enthält Beobachtungszählungen, dh was auf der y-Achse des Diagramms angezeigt wird (sie addieren sich zu 13, Gesamtzahl der Beobachtungen), und das zweite Array sind die Intervallgrenzen für x -Achse.

Man kann überprüfen, ob sie gleich weit voneinander entfernt sind.

x = plt.hist(probability)[1]
for left, right in zip(x[:-1], x[1:]):
  print(left, right, right-left)

Geben Sie hier die Bildbeschreibung ein

Oder zum Beispiel für 3 Behälter (mein Urteil erfordert 13 Beobachtungen) würde man dieses Histogramm erhalten

plt.hist(probability, bins=3)

Geben Sie hier die Bildbeschreibung ein

mit den Plotdaten "hinter den Gittern"

Geben Sie hier die Bildbeschreibung ein

Der Autor der Frage muss klären, was die "Wahrscheinlichkeits" -Liste der Werte bedeutet - ist die "Wahrscheinlichkeit" nur ein Name der Antwortvariablen (warum gibt es dann x-Labels, die für das Histogramm bereit sind, macht es keinen Sinn ), oder sind die Listenwerte die aus den Daten berechneten Wahrscheinlichkeiten (dann macht die Tatsache, dass sie sich nicht zu 1 addieren, keinen Sinn).

predmod
quelle