Ga naar hoofdinhoud

Histogrammen in Matplotlib

Leer over histogrammen en hoe je ze kunt gebruiken om met behulp van matplotlib inzichten uit data te halen.
· 8 min lezen

Verken met AI

Introductie

Volgens Wikipedia is een histogram een nauwkeurige grafische weergave van de verdeling van numerieke data. Het is een schatting van de waarschijnlijkheidsverdeling van een continue variabele (kwantitatieve variabele) en werd voor het eerst geïntroduceerd door Karl Pearson. Het is een soort staafdiagram. Om een histogram te construeren, is de eerste stap om het bereik van waarden te “binnnen” — dat wil zeggen, het volledige bereik van waarden verdelen in een reeks intervallen — en vervolgens tellen hoeveel waarden in elk interval vallen. De bins worden meestal opgegeven als opeenvolgende, niet-overlappende intervallen van een variabele. De bins (intervallen) moeten aaneengesloten zijn en zijn vaak (maar niet noodzakelijk) even groot.

Afgezien van numerieke data kun je histogrammen ook gebruiken om de verdeling van afbeeldingen te visualiseren, aangezien afbeeldingen niets anders zijn dan een combinatie van beeldpunten (pixels) met waarden van $0$ tot $255$. De x-as van het histogram geeft het aantal bins aan, terwijl de y-as de frequentie van een bepaalde bin weergeeft. Het aantal bins is een parameter die je kunt variëren, afhankelijk van hoe je de verdeling van je data wilt visualiseren.

Voorbeeld: Stel, je wilt een histogram plotten van een RGB-afbeelding met pixelwaarden van $0$ tot $255$. Het maximale aantal bins dat deze afbeelding kan hebben is $255$. Als je de x-as (het aantal bins) op $255$ zet, dan geeft de y-as de frequentie van elke pixel in die afbeelding weer.

Histogrammen lijken qua idee op bar-grafieken; laten we naar een visueel voorbeeld van een histogram kijken:

Een histogram is een uitstekend hulpmiddel om de probabilistische verdeling van numerieke data of beelddata te visualiseren en te begrijpen, en wordt door bijna iedereen intuïtief begrepen. Python heeft veel verschillende opties voor het bouwen en plotten van histogrammen. Python heeft een paar ingebouwde libraries voor het maken van grafieken, en een daarvan is matplotlib.

In de tutorial van vandaag gebruik je vooral matplotlib om histogrammen te maken en te visualiseren voor verschillende soorten datasets.

Dus zonder verder oponthoud, aan de slag.

Histogram plotten met NumPy en Matplotlib

import numpy as np

Voor reproduceerbaarheid gebruik je de seed-functie van numPy, zodat je telkens dezelfde output krijgt wanneer je de code uitvoert.

Je plot het histogram van een gaussiaanse (normale) verdeling met een gemiddelde van $0$ en een standaardafwijking van $1$.

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

Laten we het gemiddelde en de standaardafwijking van bovenstaande verdeling verifiëren.

np_hist.mean(),np_hist.std()
(-0.016772157343909157, 1.0458427194167)

Vervolgens gebruik je numPy's histogram-functie, die hist en bin_edges retourneert.

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

Laten we nu het histogram plotten met matplotlib's plt.bar-functie, waarbij je x-as en y-as respectievelijk bin_edges en hist zijn.

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

Laten we de bin_edges afronden op een geheel getal.

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

Nu ziet de grafiek er veel beter uit, toch?

Om hist en bin_edges te begrijpen, bekijken we een voorbeeld:

Je definieert een array met willekeurige waarden en definieert bins met een bereik van $5$.

hist, bin_edges = np.histogram([1, 1, 2, 2, 2, 2, 3],bins=range(5))
hist
array([0, 2, 4, 1])

In de bovenstaande output geeft hist aan dat er $0$ items in bin $0$ zitten, $2$ in bin $1$, $4$ in bin $3$, $1$ in bin $4$.

bin_edges
array([0, 1, 2, 3, 4])

Op dezelfde manier betekent de bovenstaande output van bin_edges dat bin $0$ in het interval $[0,1)$ ligt, bin $1$ in het interval $[1,2)$, bin $2$ in het interval $[2,3)$ en bin $3$ in het interval $[3,4)$.

Histogram plotten met alleen Matplotlib

Een histogram plotten met matplotlib is kinderspel. Alles wat je hoeft te doen is de functie plt.hist() van matplotlib gebruiken en de data doorgeven, samen met het aantal bins en een paar optionele parameters.

In plt.hist() geeft bins='auto' je het “ideale” aantal bins. Het idee is om een binbreedte te kiezen die de meest getrouwe weergave van je data oplevert.

Dat is alles. Laten we dus het histogram plotten van de normal_distribution die je met numpy hebt opgebouwd.

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

Twee histogrammen samen plotten

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

Histogram van Iris-data plotten met Pandas

Je gebruikt sklearn om een dataset te laden genaamd iris. In sklearn heb je een library genaamd datasets waarin de Iris-dataset zit die je direct kunt laden. Laten we dus snel de iris-dataset laden.

from sklearn.datasets import load_iris
import pandas as pd
data = load_iris().data
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width']

Vervolgens maak je de dataframe van de iris-dataset.

dataset = pd.DataFrame(data,columns=names)
dataset.head()
 sepal-lengthsepal-widthpetal-lengthpetal-width
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2
dataset.columns[0]
'sepal-length'

Tot slot gebruik je de ingebouwde pandas-functie .hist(), die histogrammen zal plotten voor alle features die in de dataset aanwezig zijn.

Geweldig toch?

fig = plt.figure(figsize = (8,8))
ax = fig.gca()
dataset.hist(ax=ax)
plt.show()

De petal-length, petal-width en sepal-length vertonen een unimodale verdeling, terwijl sepal-width een Gauss-curve weerspiegelt. Dit zijn allemaal nuttige analyses, omdat je dan kunt nadenken over het gebruik van een algoritme dat goed werkt bij dit soort verdelingen.

Histogram plotten met Matplotlib

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>

Histogram van binaire en RGB-afbeeldingen plotten

In het laatste deel van de tutorial visualiseer je twee verschillende domeinafbeeldingen: binaire (document) en natuurlijke afbeeldingen. Binaire afbeeldingen zijn die waarvan de pixelwaarden meestal $0$ of $255$ zijn, terwijl een kleurkanaalafbeelding een pixelwaarde kan hebben overal tussen $0$ en $255$.

Het analyseren van de pixelverdeling door een histogram van intensiteitswaarden van een afbeelding te plotten, is de juiste manier om het voorkomen van elke pixel voor een gegeven afbeelding te meten. Voor een 8-bit grijswaardeafbeelding zijn er 256 mogelijke intensiteitswaarden. Om dus het verschil tussen de document- en natuurlijke afbeeldingen in het pixeldistributiedomein te bestuderen, plot je twee histogrammen, elk respectievelijk voor document- en natuurlijke afbeelding. Aangezien leesbare documenten spaarzaam zijn, zou de verdeling van pixels in deze documentafbeeldingen grotendeels scheef moeten zijn.

Je gebruikt de opencv-module om de twee afbeeldingen te laden, ze naar grijswaarden te converteren door bij het inlezen parameter $0$ door te geven, en ze tot slot naar dezelfde grootte te schalen.

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)

Laten we zowel de natuurlijke als de documentafbeelding visualiseren.

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

Let op: Je gebruikt bins gelijk aan $255$, omdat er in totaal $255$ pixels in een afbeelding zijn en je de frequentie wilt visualiseren van elke pixelwaarde van de afbeelding van $0$ tot $255$.

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

Uit de bovenstaande figuren kun je afleiden dat de natuurlijke afbeelding zich uitstrekt over alle 256 intensiteiten met een willekeurige verdeling, terwijl de documentafbeelding een unimodale verdeling laat zien en grotendeels scheef is tussen pixelwaarden $0$ tot $255$.

Conclusie

Gefeliciteerd met het afronden van de tutorial.

Deze tutorial was een goed startpunt om te zien hoe je met behulp van numpy en pandas een histogram kunt maken met matplotlib.

Je leerde ook hoe je de kracht van histogrammen kunt benutten om onderscheid te maken tussen twee verschillende afbeeldingsdomeinen, namelijk document- en natuurlijke afbeelding.

Wil je meer leren over datavisualisatietechnieken? Overweeg dan DataCamp's cursus Data Visualization with Matplotlib.

Voel je vrij om vragen over deze tutorial te stellen in de reacties hieronder.

Onderwerpen

Gerelateerd