Werkplaats / Notebook
In jouw eigen tempo
← Alle bouwprojecten
Klassieke machine learning · PYTHON NOTEBOOK

Onderzoek een puntenwolk met PCA en k-means

Maak driedimensionale data, leer een projectie, train echte clusters en vergelijk hun scheiding.

110 min4 cellen
De opdracht, leerdoelen en voorkennis
  • Je combineert standaardisatie, PCA en k-means in een uitvoerbaar notebook.
  • Je vergelijkt aantallen clusters met een intrinsieke maat en benoemt wat die maat niet bewijst.
  • Je tekent de daadwerkelijk berekende projectie en centra.

Lees eerst: Laat ieder voorbeeld een keer onbekend zijn · Zoek groepen zonder antwoordlabels · Bewaar de richting met de meeste variatie.

Je hebt een puntenwolk met drie features en wilt weten of er zichtbare groepen in zitten. Kun je die in twee dimensies bekijken zonder de groepering meteen voor waarheid aan te nemen? In dit notebook combineer je standaardisatie, PCA en k-means en controleer je wat de grafiek en interne scores werkelijk laten zien.

We maken bewust drie compacte wolken. Dat geeft een controleerbare proef, geen bewijs dat echte planten of klanten ook drie nette groepen vormen. De algoritmen krijgen geen antwoordlabels mee.

1. Maak een herhaalbare wolk met echte variatie

Een centrum bepaalt waar een groep ongeveer ligt; normale afwijkingen geven ieder punt een eigen positie. Gebruik drie centra: [−3,0,1], [3,1,−1] en [0,4,2]. Per centrum trek je twintig punten met standaardafwijking 0.3 in iedere feature.

import numpy as np
rng = np.random.default_rng(42)
delen = []
centra = [(-3, 0, 1), (3, 1, -1),
          (0, 4, 2)]
for centrum in centra:
    groep = rng.normal(
        loc=centrum, scale=.3,
        size=(20, 3))
    delen.append(groep)
x = np.vstack(delen)
print(x.shape)  # (60, 3)

default_rng maakt een lokale generator; loc, scale en size bepalen centrum, standaardafwijking en vorm. vstack stapelt de matrices onder elkaar. Maak maak_wolk() met die generator en bewaar de uitkomst als x.

De rijvolgorde verraadt in deze simulatie de constructie, maar wordt geen extra feature. Twintig kopieën van elk centrum zouden geen willekeurige wolk zijn. Controleer daarom zowel de vorm als de variatie.

01
CHECKPOINTMaak herhaalbare driedimensionale punten

2. Leer één vast assenstelsel

De drie features hebben verschillende spreiding. Hier kiezen we bewust voor standaardisatie, gevolgd door PCA met twee componenten. Je kent beide stappen afzonderlijk; nu bewaren we de bibliotheekobjecten om latere punten exact hetzelfde te verwerken.

from sklearn.preprocessing import (
    StandardScaler)
from sklearn.decomposition import PCA
scaler = StandardScaler()
scaled = scaler.fit_transform(x)
pca = PCA(
    n_components=2, svd_solver="full")
z = pca.fit_transform(scaled)
print(z.shape)  # (60, 2)

svd_solver="full" kiest een volledige matrixontbinding; de bibliotheek gebruikt daarvoor SVD in plaats van jouw eigen covariantie-eigenvectorroute. explained_variance_ratio_ bevat het aandeel variantie per behouden component. Optellen vertelt hoeveel van de geschaalde variatie deze twee assen bewaren.

Maak leer_projectie(x) als (state,z), met scaler en pca in state. Voor nieuwe punten roep je alleen transform aan:

nieuw = np.array([[0., 1., 1.]])
nieuw_scaled = scaler.transform(nieuw)
nieuw_z = pca.transform(nieuw_scaled)
print(nieuw_z.shape)  # (1, 2)

Opnieuw fitten zou centrum, schaal en assenstelsel verplaatsen. Veel behouden variantie bewijst bovendien nog geen goede clusters. Bekijk straks de punten en de score naast elkaar.

02
CHECKPOINTLeer een kleinere representatie

3. Fit clusters met meerdere starts

Gebruik KMeans met n_init=10 en random_state=7. De tien initialisaties verminderen het risico van een ongunstige start; ze garanderen geen wereldwijd optimum. fit_predict leert de centra en geeft één clusterindex per punt.

from sklearn.cluster import KMeans
model = KMeans(
    n_clusters=3, n_init=10,
    random_state=7)
labels = model.fit_predict(z)
print(model.cluster_centers_.shape)
# (3, 2)
print(labels.shape)  # (60,)

Maak cluster_fit(z,k) als (model,labels) en train k = 3 op de opgeslagen z. Clusterindices zijn namen: een verwisseling van 0 en 1 verandert de groepering niet. Voor nieuwe punten gebruik je dezelfde projectie en daarna model.predict(nieuw_z).

03
CHECKPOINTFit k-means met meerdere starts

4. Begrijp silhouette vóór je de ranglijst leest

De silhouette-score vergelijkt voor ieder punt de eigen groep met de dichtstbijzijnde andere groep. a is de gemiddelde afstand tot de overige punten van het eigen cluster, dus zonder het punt zelf. b is het kleinste gemiddelde van de afstanden tot alle punten van een ander cluster.

s=b−amax(a,b)

Neem los van het notebook vier punten op een lijn: 0 en 2 vormen één groep, 10 en 12 de andere. Voor punt 0 is a = 2 en b = (10+12)/2 = 11, dus s = 9/11. Voor punt 2 is b = 9 en s = 7/9; de andere twee punten geven gespiegeld dezelfde scores.

Het gemiddelde is 79/99, ongeveer 0.79798. Veelgemaakte fout: b vervangen door de afstand tot het andere centrum; dat is niet de definitie. Deze losse speelgoedproef overschrijft de notebooklabels niet.

from sklearn.metrics import (
    silhouette_score)
toy = np.array([[0., 0.], [2., 0.],
                [10., 0.], [12., 0.]])
toy_labels = [0, 0, 1, 1]
score = silhouette_score(toy, toy_labels)
print(score)
# ongeveer 0.79798

Een hoge score wijst op compacte, gescheiden groepen; rond nul liggen punten dichter bij een grens en een negatieve score kan een ongunstige toewijzing signaleren. Bij een cluster met één punt gebruikt de bibliotheek de conventie nul voor dat punt. De score vereist minstens twee clusters en minder clusters dan punten.

5. Bereken de vergelijking en teken dezelfde arrays

Maak cluster_audit(z,model,labels). Fit kandidaten k = 2,3,4 op dezelfde z en bereken hun silhouette; geef punten, clusters, silhouette en vergelijking terug. De eerste silhouette hoort bij de meegegeven labels, de vergelijking bij de drie opnieuw gefitte kandidaten.

import matplotlib.pyplot as plt
plt.figure(figsize=(6, 4))
for label in sorted(set(labels)):
    groep = z[labels == label]
    px, py = groep[:, 0], groep[:, 1]
    naam = "cluster " + str(label)
    plt.scatter(px, py, label=naam)
c = model.cluster_centers_
plt.scatter(c[:, 0], c[:, 1],
            marker="x", color="black",
            s=90, label="centra")
plt.xlabel("Hoofdcomponent 1")
plt.ylabel("Hoofdcomponent 2")
plt.title("Groepen in de projectie")
plt.legend()
plt.tight_layout()

De booleaanse selectie z[labels==label] kiest de punten van één cluster. Teken hun echte coördinaten en de centra uit hetzelfde model. Vergelijk daarna de tabel met de grafiek: wint k = 3, en zie je ook waarom?

Dit is verkennende beoordeling op dezelfde data, geen onafhankelijke test. Een hoge interne score bewijst geen bruikbare betekenis, en een andere projectie of schaling kan een andere ranglijst geven. Bewaar x, z, state, model en labels intact tijdens de audit.

04
CHECKPOINTVergelijk interne scheiding en bekijk de punten

Wat neem je mee?

  • Het vaste voorbereidingspad koppelt nieuwe punten aan dezelfde projectie en centra.
  • Silhouette vergelijkt gemiddelde afstanden tot groepen; ze gebruikt geen antwoordlabels.
  • Een berekende tabel en echte grafiek helpen interpreteren, maar bewijzen geen natuurlijke categorieën.

Hierna bouw je modellen die hun eigen tussenliggende representaties leren: neurale netwerken.

Bronnen: scikit-learn — clustering ↗ scikit-learn — principal component analysis ↗ · Gecontroleerd 2026-10-28.

Python start zodra jij code uitvoert.
[1]

Maak herhaalbare driedimensionale punten

Maak met één lokale default_rng(42) drie groepen van twintig punten, elk met drie features en standaardafwijking 0.3, rond de genoemde centra. Stapel de echte trekkingen en bewaar x; dubbele centrumkopieën zijn geen wolk.

Bekijk voorbeeld
import numpy as np


def maak_wolk():
    rng = np.random.default_rng(42)
    delen = []
    centra = [(-3, 0, 1), (3, 1, -1), (0, 4, 2)]
    for centrum in centra:
        groep = rng.normal(
            loc=centrum, scale=.3, size=(20, 3))
        delen.append(groep)
    return np.vstack(delen)


x = maak_wolk()
print("Punten en features:", x.shape)
[2]

Leer een kleinere representatie

Fit StandardScaler en daarna PCA met twee componenten en full-solver. Bewaar beide objecten in state en de projectie in z. Bekijk behouden variantie; gebruik voor nieuwe punten alleen dezelfde transform-stappen.

Bekijk voorbeeld
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA


def leer_projectie(x):
    scaler = StandardScaler()
    scaled = scaler.fit_transform(x)
    pca = PCA(n_components=2, svd_solver="full")
    z = pca.fit_transform(scaled)
    return {"scaler": scaler, "pca": pca}, z


state, z = leer_projectie(x)
aandeel = state["pca"].explained_variance_ratio_.sum()
print("Behouden variantie:", float(aandeel))
[3]

Fit k-means met meerdere starts

Fit KMeans met k clusters,n_init=10,random_state=7 en geef model/labels terug. Train de notebookprojectie met k=3; clusterindices zijn verwisselbare namen, geen antwoordlabels.

Bekijk voorbeeld
from sklearn.cluster import KMeans


def cluster_fit(z, k):
    model = KMeans(
        n_clusters=k, n_init=10, random_state=7)
    labels = model.fit_predict(z)
    return model, labels


model, labels = cluster_fit(z, 3)
print("Clustergroottes:", np.bincount(labels))
[4]

Vergelijk interne scheiding en bekijk de punten

Vergelijk silhouette voor k=2,3,4 op dezelfde projectie en teken de echte punten per label plus centra van het meegegeven model. a sluit het punt zelf uit; b is de kleinste gemiddelde afstand naar een andere groep. Bewaar alle invoer en notebookvariabelen intact.

Bekijk voorbeeld
import matplotlib.pyplot as plt
from sklearn.metrics import silhouette_score


def cluster_audit(z, model, labels):
    vergelijking = {}
    for k in [2, 3, 4]:
        kandidaat, groepen = cluster_fit(z, k)
        score = silhouette_score(z, groepen)
        vergelijking[k] = float(score)
    plt.figure(figsize=(6, 4))
    for label in sorted(set(labels)):
        groep = z[labels == label]
        naam = "cluster " + str(label)
        plt.scatter(groep[:, 0], groep[:, 1], label=naam)
    c = model.cluster_centers_
    plt.scatter(c[:, 0], c[:, 1], marker="x",
                color="black", s=90, label="centra")
    plt.xlabel("Hoofdcomponent 1")
    plt.ylabel("Hoofdcomponent 2")
    plt.title("Groepen in de projectie")
    plt.legend()
    plt.tight_layout()
    score = silhouette_score(z, labels)
    return {"punten": len(z), "clusters": len(set(labels)),
            "silhouette": float(score), "vergelijking": vergelijking}


rapport = cluster_audit(z, model, labels)
print("Verkennende audit:", rapport)