Course
Histogramme in Matplotlib
Einführung
Laut Wikipediaist ein Histogramm eine genaue grafische Darstellung der Verteilung von numerischen Daten. Sie ist eine Schätzung der Wahrscheinlichkeitsverteilung einer kontinuierlichen Variable (quantitative Variable) und wurde erstmals von Karl Pearson eingeführt. Es ist eine Art Balkendiagramm. Um ein Histogramm zu erstellen, musst du zunächst den Wertebereich "binden" - das heißt, den gesamten Wertebereich in eine Reihe von Intervallen unterteilen - und dann zählen, wie viele Werte in jedes Intervall fallen. Die Bins werden in der Regel als aufeinanderfolgende, sich nicht überschneidende Intervalle einer Variablen angegeben. Die Bins (Intervalle) müssen nebeneinander liegen und sind oft (aber nicht zwingend) gleich groß.
Abgesehen von numerischen Daten können Histogramme auch dazu verwendet werden, die Verteilung von Bildern zu visualisieren, denn Bilder sind nichts anderes als eine Kombination von Bildelementen (Pixeln), die von $0$ bis $255$ reichen. Die x-Achse des Histogramms gibt die Anzahl der Bins an, während die y-Achse die Häufigkeit eines bestimmten Bins darstellt. Die Anzahl der Bins ist ein Parameter, der variiert werden kann, je nachdem, wie du die Verteilung deiner Daten visualisieren möchtest.
Zum Beispiel: Angenommen, du möchtest ein Histogramm eines RGB-Bildes mit Pixelwerten zwischen $0$ und $255$ erstellen. Dieses Bild kann maximal 255$ Bins haben. Wenn du die x_Achse (Anzahl der Bins) auf $255$ festlegst, gibt die y_Achse die Häufigkeit der einzelnen Pixel in diesem Bild an.
Histogramme sind ähnlich wie bar
Diagramme. Schauen wir uns ein bildhaftes Beispiel für ein Histogramm an:
Ein Histogramm ist ein hervorragendes Instrument zur Visualisierung und zum Verständnis der Wahrscheinlichkeitsverteilung von numerischen Daten oder Bilddaten, das fast jeder intuitiv versteht. Python hat viele verschiedene Möglichkeiten, Histogramme zu erstellen und zu zeichnen. Python hat nur wenige integrierte Bibliotheken für die Erstellung von Graphen. Eine dieser Bibliotheken ist matplotlib
.
Im heutigen Lernprogramm wirst du vor allem verwenden matplotlib
verwenden, um Histogramme für verschiedene Arten von Datensätzen zu erstellen und zu visualisieren.
Also lasst uns ohne Umschweife loslegen.
Histogramme mit NumPy und Matplotlib aufzeichnen
import numpy as np
Zur Reproduzierbarkeit verwendest du die Funktion seed
von numPy, die bei jeder Ausführung die gleiche Ausgabe liefert.
Du zeichnest das Histogramm von gaussian (normal) distribution
auf, das einen Mittelwert von $0$ und eine Standardabweichung von $1$ hat.
np.random.seed(100)
np_hist = np.random.normal(loc=0, scale=1, size=1000)
np_hist[:10]
array([-1.74976547, 0.3426804 , 1.1530358 , -0.25243604, 0.98132079,
0.51421884, 0.22117967, -1.07004333, -0.18949583, 0.25500144])
Überprüfen wir den Mittelwert und die Standardabweichung der obigen Verteilung.
np_hist.mean(),np_hist.std()
(-0.016772157343909157, 1.0458427194167)
Als Nächstes verwendest du die Funktion histogram
von numPy, die hist
und bin_edges
zurückgibt.
hist,bin_edges = np.histogram(np_hist)
hist
array([ 7, 37, 111, 207, 275, 213, 105, 31, 10, 4])
bin_edges
array([-3.20995538, -2.50316588, -1.79637637, -1.08958687, -0.38279736,
0.32399215, 1.03078165, 1.73757116, 2.44436066, 3.15115017,
3.85793967])
Als Nächstes stellen wir das Histogramm mit der Funktion plt.bar
von matplotlib dar, wobei die x-Achse bin_edges
und die y-Achse hist
sein werden.
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=[10,8])
plt.bar(bin_edges[:-1], hist, width = 0.5, color='#0504aa',alpha=0.7)
plt.xlim(min(bin_edges), max(bin_edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value',fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.title('Normal Distribution Histogram',fontsize=15)
plt.show()
Runden wir die bin_edges
auf eine ganze Zahl.
bin_edges = np.round(bin_edges,0)
plt.figure(figsize=[10,8])
plt.bar(bin_edges[:-1], hist, width = 0.5, color='#0504aa',alpha=0.7)
plt.xlim(min(bin_edges), max(bin_edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value',fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.title('Normal Distribution Histogram',fontsize=15)
plt.show()
Jetzt sieht die Grafik viel besser aus, oder?
Um hist
und bin_edges
zu verstehen, schauen wir uns ein Beispiel an:
Du wirst ein Array mit beliebigen Werten definieren und Bins mit einem Bereich von $5$ festlegen.
hist, bin_edges = np.histogram([1, 1, 2, 2, 2, 2, 3],bins=range(5))
hist
array([0, 2, 4, 1])
In der obigen Ausgabe zeigt hist
an, dass sich $0$ in Feld $0$, $2$ in Feld $1$, $4$ in Feld $3$ und $1$ in Feld $4$ befinden.
bin_edges
array([0, 1, 2, 3, 4])
Ähnlich bedeutet die obige Ausgabe von bin_edges
, dass Bin $0$ im Intervall $[0,1)$, Bin $1$ im Intervall $[1,2)$, Bin $2$ im Intervall $[2,3)$ und Bin $3$ im Intervall $[3,4)$ liegt.
Ein Histogramm nur mit Matplotlib zeichnen
Die Erstellung eines Histogramms mit matplotlib
ist ein Kinderspiel. Alles, was du tun musst, ist die Funktion plt.hist()
von matplotlib zu verwenden und die Daten zusammen mit der Anzahl der Bins und einigen optionalen Parametern zu übergeben.
Wenn du in plt.hist()
bins='auto' angibst, erhältst du die "ideale" Anzahl von Bins. Es geht darum, eine Bin-Breite zu wählen, die deine Daten möglichst genau wiedergibt.
Das ist alles. Stellen wir also das Histogramm des normal_distribution
dar, das du mit numpy
erstellt hast.
plt.figure(figsize=[10,8])
n, bins, patches = plt.hist(x=np_hist, bins=8, color='#0504aa',alpha=0.7, rwidth=0.85)
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value',fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.title('Normal Distribution Histogram',fontsize=15)
plt.show()
Zwei Histogramme zusammen aufzeichnen
plt.figure(figsize=[10,8])
x = 0.3*np.random.randn(1000)
y = 0.3*np.random.randn(1000)
n, bins, patches = plt.hist([x, y])
Histogramm von Irisdaten mit Pandas aufzeichnen
Du verwendest sklearn
, um einen Datensatz namens iris
zu laden. In Sklearn gibt es eine Bibliothek namens Datasets, in der du den Iris-Datensatz findest, der sofort geladen werden kann. Lass uns also schnell den Iris-Datensatz laden.
from sklearn.datasets import load_iris
import pandas as pd
data = load_iris().data
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width']
Als Nächstes erstellst du den Datenrahmen des iris
Datensatzes.
dataset = pd.DataFrame(data,columns=names)
dataset.head()
Kelchblatt-Länge | Kelchblatt-Breite | Blütenblatt-Länge | Blütenblatt-Breite | |
---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | 1.3 | 0.2 |
3 | 4.6 | 3.1 | 1.5 | 0.2 |
4 | 5.0 | 3.6 | 1.4 | 0.2 |
dataset.columns[0]
'sepal-length'
Schließlich verwendest du die integrierte Funktion pandas
.hist()
, die Histogramme für alle im Datensatz vorhandenen Merkmale erstellt.
Ist das nicht wunderbar?
fig = plt.figure(figsize = (8,8))
ax = fig.gca()
dataset.hist(ax=ax)
plt.show()
Blütenblattlänge, Blütenblattbreite und Kelchblattlänge zeigen eine unimodale Verteilung, während die Kelchblattbreite eine Gaußsche Kurve widerspiegelt. All das sind nützliche Analysen, denn dann kannst du dir überlegen, ob du einen Algorithmus verwendest, der mit dieser Art der Verteilung gut funktioniert.
Histogramm mit Matplotlib aufzeichnen
plt.figure(figsize=[10,10])
f,a = plt.subplots(2,2)
a = a.ravel()
for idx,ax in enumerate(a):
ax.hist(dataset.iloc[:,idx], bins='auto', color='#0504aa',alpha=0.7, rwidth=0.85)
ax.set_title(dataset.columns[idx])
plt.tight_layout()
<Figure size 720x720 with 0 Axes>
Histogramm von binären und RGB-Bildern aufzeichnen
Im letzten Abschnitt des Tutorials visualisierst du zwei verschiedene Bilder: Binärbilder (Dokumente) und natürliche Bilder. Binäre Bilder sind Bilder, deren Pixelwerte meist $0$ oder $255$ sind, während ein Farbkanalbild einen Pixelwert zwischen $0$ und $255$ haben kann.
Die Analyse der Pixelverteilung durch Aufzeichnen eines Histogramms der Intensitätswerte eines Bildes ist der richtige Weg, um das Vorkommen jedes Pixels für ein bestimmtes Bild zu messen. Für ein 8-Bit-Graustufenbild gibt es 256 mögliche Intensitätswerte. Um den Unterschied zwischen dem Dokument und dem natürlichen Bild im Bereich der Pixelverteilung zu untersuchen, zeichnest du also jeweils zwei Histogramme für das Dokument und das natürliche Bild. Wenn man bedenkt, dass lesbare Dokumente spärlich sind, sollte die Verteilung der Pixel in diesen Dokumentenbildern meist schief sein.
Du verwendest das Modul opencv
, um die beiden Bilder zu laden, sie in Graustufen umzuwandeln, indem du beim Einlesen einen Parameter $0$ übergibst, und sie schließlich auf dieselbe Größe zu bringen.
import cv2
lena_rgb = cv2.imread('lena.png')
lena_gray = cv2.cvtColor(lena_rgb,cv2.COLOR_BGR2GRAY)
lena_gray.shape
(512, 512)
binary = cv2.imread('binary.png')
binary.shape
(1394, 2190, 3)
binary = cv2.resize(binary,(512,512),cv2.INTER_CUBIC)
binary.shape
(512, 512, 3)
binary_gray = cv2.cvtColor(binary,cv2.COLOR_BGR2GRAY)
binary_gray.shape
(512, 512)
Lass uns sowohl das natürliche als auch das Dokumentenbild visualisieren.
plt.figure(figsize=[10,10])
plt.subplot(121)
plt.imshow(lena_rgb[:,:,::-1])
plt.title("Natural Image")
plt.subplot(122)
plt.imshow(binary[:,:,::-1])
plt.title("Document Image")
plt.show()
Hinweis: Du verwendest bins
gleich $255$, da es insgesamt $255$ Pixel in einem Bild gibt und du die Häufigkeit jedes Pixelwerts des Bildes zwischen $0$ und $255$ darstellen willst.
hist, edges = np.histogram(binary_gray,bins=range(255))
plt.figure(figsize=[10,8])
plt.bar(edges[:-1], hist, width = 0.8, color='#0504aa')
plt.xlim(min(edges), max(edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value',fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.title('Document Image Histogram',fontsize=15)
plt.show()
hist, edges = np.histogram(lena_gray,bins=range(260))
plt.figure(figsize=[10,8])
plt.bar(edges[:-1], hist, width = 0.5, color='#0504aa')
plt.xlim(min(edges), max(edges))
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Pixels',fontsize=15)
plt.ylabel('Frequency of Pixels',fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.ylabel('Frequency',fontsize=15)
plt.title('Natural Image Histogram',fontsize=15)
plt.show()
Aus den obigen Abbildungen kannst du ersehen, dass natural image
über alle 256 Intensitäten verteilt ist und eine random
Verteilung aufweist, während das Dokumentenbild eine unimodal
Verteilung aufweist und hauptsächlich zwischen den Pixelwerten $0$ bis $255$ schief ist.
Fazit
Herzlichen Glückwunsch zum Abschluss des Tutorials.
Dieses Tutorial war ein guter Ausgangspunkt dafür, wie du mit Matplotlib und der Hilfe von Numpy und Pandas ein Histogramm erstellen kannst.
Du hast auch gelernt, wie du die Macht der Histogramme nutzen kannst, um zwischen zwei verschiedenen Bildbereichen zu unterscheiden, nämlich zwischen Dokumenten und natürlichen Bildern.
Wenn du mehr über Datenvisualisierungstechniken erfahren möchtest, solltest du den DataCamp-Kurs "Datenvisualisierung mit Matplotlib " besuchen.
Wenn du Fragen zu diesem Tutorial hast, kannst du sie gerne in den Kommentaren unten stellen.
Erfahre mehr über Python
Course
Biomedizinische Bildanalyse in Python
Course