W3docs

Matplotlib-Histogramme in Python — Vollständige Anleitung

Histogramme in Python mit Matplotlib erstellen und anpassen. Bins, Dichte, KDE, kumulativ, gestapelt und Speichern in Dateien.

Die hist()-Funktion von Matplotlib erleichtert die Visualisierung, wie ein Datensatz über einen numerischen Bereich verteilt ist. Dieses Kapitel behandelt alles von einem minimalen ersten Histogramm bis hin zu praktischen Techniken, die Sie in echten Projekten einsetzen werden: die richtige Anzahl von Bins wählen, Dichte statt roher Häufigkeiten darstellen, eine KDE-Kurve überlagern, mehrere Verteilungen vergleichen und das Ergebnis in einer Datei speichern.

Stellen Sie vor dem Einstieg sicher, dass Matplotlib und NumPy installiert sind:

pip install matplotlib numpy

Wenn Sie neu in der Bibliothek sind, lesen Sie zuerst die Kapitel Matplotlib-Einführung und Erste Schritte.

Was ist ein Histogramm?

Ein Histogramm unterteilt eine kontinuierliche numerische Variable in gleichmäßig beabstandete Intervalle, sogenannte Bins, und zeichnet für jeden Bin einen Balken, dessen Höhe der Anzahl der Beobachtungen in diesem Intervall entspricht. Im Gegensatz zu einem Balkendiagramm, das diskrete Kategorien vergleicht, zeigt ein Histogramm die Form einer Verteilung — ob sie symmetrisch, schief, bimodal ist oder Ausreißer aufweist.

Verwenden Sie ein Histogramm, wenn Sie Fragen wie diese beantworten möchten:

  • Wo ist der Großteil der Daten konzentriert?
  • Ist die Verteilung annähernd normalverteilt oder schief?
  • Gibt es Lücken oder mehrere Peaks (bimodale Daten)?
  • Gibt es Ausreißer weit entfernt von der Masse der Daten?

Ein einfaches Histogramm erstellen

Übergeben Sie ein eindimensionales array oder eine Liste an plt.hist(), und Matplotlib wählt automatisch eine Bin-Anzahl:

import matplotlib.pyplot as plt
import numpy as np

# Reproducible example: 1 000 values from a normal distribution
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

plt.hist(data)

plt.title('Basic Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()

plt.tight_layout() verhindert, dass Achsenbeschriftungen abgeschnitten werden — eine gute Gewohnheit, die man vor jedem show() oder savefig()-Aufruf hinzufügen sollte.

Die Anzahl der Bins wählen

Der Parameter bins ist der wichtigste Einstellknopf für ein Histogramm. Zu wenige Bins verbergen Strukturen; zu viele Bins erzeugen Rauschen.

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

fig, axes = plt.subplots(1, 3, figsize=(12, 4))

for ax, n_bins in zip(axes, [5, 30, 100]):
    ax.hist(data, bins=n_bins, color='steelblue', edgecolor='white')
    ax.set_title(f'bins={n_bins}')
    ax.set_xlabel('Value')
    ax.set_ylabel('Frequency')

plt.suptitle('Effect of Bin Count', y=1.02)
plt.tight_layout()
plt.show()

Praktische Richtlinien:

  • 5–10 Bins — nützlich für sehr kleine Datensätze (n < 50) oder schnelle Übersichten.
  • 20–50 Bins — guter Standard für die meisten Datensätze (n = 100–10 000).
  • 50–100+ Bins — geeignet für große Datensätze (n > 10 000), bei denen feine Strukturen wichtig sind.
  • Übergeben Sie eine Zeichenkettenregel statt einer Zahl: bins='auto', bins='fd' (Freedman–Diaconis) oder bins='sturges' — Matplotlib delegiert an NumPys np.histogram_bin_edges().

Sie können auch eine explizite Liste von Bin-Rändern für ungleichmäßige Abstände übergeben:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.exponential(scale=2, size=1000)

# Finer bins near 0, coarser bins in the tail
edges = [0, 0.5, 1, 1.5, 2, 3, 4, 6, 8, 12]

plt.hist(data, bins=edges, color='darkorange', edgecolor='white')
plt.title('Custom Bin Edges (Exponential Data)')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()

Aussehen anpassen

Farbe, Transparenz und Rand

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=5, scale=1.5, size=800)

plt.hist(
    data,
    bins=30,
    color='steelblue',
    edgecolor='white',   # thin white line between bars
    linewidth=0.5,
    alpha=0.85,          # slight transparency
)

plt.title('Styled Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()

alpha (0 = vollständig transparent, 1 = vollständig undurchsichtig) ist besonders nützlich beim Überlagern mehrerer Histogramme, damit Balken einander nicht verdecken.

Diagrammunrat entfernen

Das Entfernen der oberen und rechten Achsenränder verleiht dem Histogramm ein saubereres Aussehen:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(data, bins=30, color='cornflowerblue', edgecolor='white')

ax.set_title('Clean Histogram')
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

plt.tight_layout()
plt.show()

Dichte-Histogramme

Standardmäßig zeigt hist() rohe Häufigkeiten auf der y-Achse. Übergeben Sie density=True, um die y-Achse zu normalisieren, sodass die Gesamtfläche aller Balken 1 ergibt. Dadurch wird das Histogramm zu einer Wahrscheinlichkeitsdichteschätzung und ermöglicht den einfachen Vergleich von Datensätzen unterschiedlicher Größen.

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

plt.hist(data, bins=30, density=True, color='mediumseagreen', edgecolor='white')

plt.title('Density Histogram')
plt.xlabel('Value')
plt.ylabel('Probability Density')
plt.tight_layout()
plt.show()

Hinweis: Die y-Achsenwerte sind Dichten, keine Wahrscheinlichkeiten. Multiplizieren Sie eine Dichte mit der Bin-Breite, um die Wahrscheinlichkeit für diesen Bin zu erhalten.

Eine KDE-Kurve überlagern

Eine Kerndichteschätzung (KDE) ist eine glatte Kurve, die die zugrundeliegende Wahrscheinlichkeitsverteilung annähert. Das Überlagern auf einem Dichte-Histogramm liefert ein anschauliches Bild der Verteilungsform. Verwenden Sie scipy.stats.gaussian_kde zur Berechnung:

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

fig, ax = plt.subplots(figsize=(8, 4))

# Density histogram
ax.hist(data, bins=30, density=True,
        color='steelblue', edgecolor='white', alpha=0.6, label='Histogram')

# KDE curve
xs = np.linspace(data.min(), data.max(), 300)
kde = gaussian_kde(data)
ax.plot(xs, kde(xs), color='navy', linewidth=2, label='KDE')

ax.set_title('Histogram with KDE Overlay')
ax.set_xlabel('Value')
ax.set_ylabel('Probability Density')
ax.legend()
plt.tight_layout()
plt.show()

Installieren Sie SciPy, falls es noch nicht verfügbar ist:

pip install scipy

Mehrere Verteilungen vergleichen

Um zwei oder mehr Verteilungen auf denselben Achsen zu vergleichen, rufen Sie hist() mehrfach auf und verwenden Sie alpha, um die Balken halbtransparent zu halten. Setzen Sie die gleichen bins für beide, damit die Balkenbreiten vergleichbar sind:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
group_a = rng.normal(loc=0,   scale=1,   size=500)
group_b = rng.normal(loc=2,   scale=1.5, size=500)

shared_bins = np.linspace(-5, 8, 40)

plt.hist(group_a, bins=shared_bins, alpha=0.6, color='steelblue',   label='Group A')
plt.hist(group_b, bins=shared_bins, alpha=0.6, color='darkorange',  label='Group B')

plt.title('Overlapping Histograms')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.legend()
plt.tight_layout()
plt.show()

Die Definition von shared_bins über np.linspace() stellt sicher, dass beide Histogramme identische Bin-Ränder verwenden und ihre Balken visuell ausgerichtet sind.

Nebeneinander (gestapelte) Histogramme

Wenn sich Überlappungen schwer lesen lassen, verwenden Sie plt.subplots(), um die Histogramme nebeneinander zu platzieren:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
group_a = rng.normal(loc=0,   scale=1,   size=500)
group_b = rng.normal(loc=2,   scale=1.5, size=500)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4), sharey=True)

ax1.hist(group_a, bins=30, color='steelblue',  edgecolor='white')
ax1.set_title('Group A')
ax1.set_xlabel('Value')
ax1.set_ylabel('Frequency')

ax2.hist(group_b, bins=30, color='darkorange', edgecolor='white')
ax2.set_title('Group B')
ax2.set_xlabel('Value')

plt.suptitle('Side-by-Side Histograms')
plt.tight_layout()
plt.show()

sharey=True sperrt beide Teildiagramme auf die gleiche y-Achsenskala, sodass die Balkenhöhen direkt vergleichbar sind. Weitere Layout-Optionen finden Sie im Kapitel Matplotlib-Subplots.

Kumulative Histogramme

Übergeben Sie cumulative=True, um ein Histogramm zu zeichnen, bei dem jeder Balken die Gesamtanzahl der Beobachtungen bis einschließlich dieses Bins darstellt. Dies ist nützlich, um Fragen wie „Welcher Anteil der Werte liegt unterhalb von X?" zu beantworten:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

plt.hist(data, bins=30, cumulative=True, density=True,
         color='mediumpurple', edgecolor='white')

plt.title('Cumulative Density Histogram')
plt.xlabel('Value')
plt.ylabel('Cumulative Probability')
plt.tight_layout()
plt.show()

In Kombination mit density=True wird das kumulative Histogramm zu einer Stufenfunktions-Approximation der empirischen CDF (kumulativen Verteilungsfunktion). Die y-Achse reicht von 0 bis 1.

Ausrichtung des Histogramms

Übergeben Sie orientation='horizontal', um Balken zu zeichnen, die sich von der y-Achse nach links erstrecken. Dies ist selten die Standardwahl, spiegelt jedoch das Layout der Randverteilungsdiagramme eines Streudiagramms wider:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=500)

plt.hist(data, bins=20, orientation='horizontal',
         color='tomato', edgecolor='white')

plt.title('Horizontal Histogram')
plt.ylabel('Value')
plt.xlabel('Frequency')
plt.tight_layout()
plt.show()

Ein Histogramm in eine Datei speichern

Verwenden Sie plt.savefig() vor plt.show() (oder anstelle davon). Geben Sie das Format über die Dateiendung an:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)

plt.hist(data, bins=30, color='steelblue', edgecolor='white')
plt.title('Distribution of Sample Data')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()

plt.savefig('histogram.png', dpi=150)   # raster, good for web
plt.savefig('histogram.pdf')            # vector, good for print/publication
plt.show()

Gängige Formate: png, pdf, svg, eps. Verwenden Sie svg oder pdf, wenn Sie ein skalierbares Bild in Druckqualität benötigen.

hist() Wichtige Parameter — Kurzreferenz

ParameterTypBeschreibung
binsint, Liste oder stringAnzahl der Bins, explizite Ränder oder Regelname ('auto', 'fd', 'sturges')
densityboolNormalisieren, sodass Gesamtfläche = 1 (Wahrscheinlichkeitsdichte)
cumulativeboolJeder Balken zeigt die kumulative Häufigkeit/Dichte bis zu diesem Bin
orientationstring'vertical' (Standard) oder 'horizontal'
colorstringFüllfarbe des Balkens
edgecolorstringRandfarbe des Balkens; 'white' ergibt einen sauberen Trenner
alphafloat 0–1Transparenz; unter 1 setzen, wenn Histogramme überlagert werden
labelstringLegendenbeschriftung für dieses Histogramm
histtypestring'bar' (Standard), 'step', 'stepfilled'
range(min, max)Daten auf diesen Bereich vor der Binning-Einteilung begrenzen

Häufige Fallstricke

  • Zufallssamen. np.random.randn() erzeugt bei jedem Durchlauf unterschiedliche Werte. Verwenden Sie np.random.default_rng(seed) für reproduzierbare Beispiele.
  • density vs normed. Der alte Parameter normed=True wurde in Matplotlib 3.x entfernt. Verwenden Sie immer density=True.
  • Histogramme mit unterschiedlichen Stichprobengrößen vergleichen. Rohe Häufigkeitsbalken sind nicht vergleichbar, wenn die Gruppengrößen abweichen — verwenden Sie density=True, um beide zu normalisieren.
  • Diskrete ganzzahlige Daten. Bei ganzen Zahlen (z. B. Würfelwürfe, Umfragebewertungen) setzen Sie Bin-Ränder auf Halbzahlen — bins=[0.5, 1.5, 2.5, ..., 6.5] — damit jede ganze Zahl eindeutig in genau einen Bin fällt.
  • plt.show() löscht die Figur. Wenn Sie show() aufrufen und danach savefig(), erhalten Sie eine leere Datei. Rufen Sie savefig() immer vor show() auf.

Verwandte Kapitel

Was this page helpful?