Werkplaats / De werkplaats
In jouw eigen tempo
← Wiskunde-fundament
MODULE 01 · LES 02

Hoeveel wijzen ze dezelfde kant op?

Ontdek het inproduct en de hoek tussen vectoren. De eerste stap richting embeddings.

45 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je berekent het inproduct van even lange vectoren.
  • Je onderscheidt lengte van richting met cosinusgelijkenis.

Twee lezers kiezen boeken over techniek en geschiedenis. Ada leest er drie en vier, Bram zes en acht: Bram leest meer, maar de verhouding is gelijk. Kunnen we die overeenkomst zien zonder alleen de grootste aantallen te belonen?

We schrijven hun voorkeuren als a = (3, 4) en b = (6, 8), steeds met techniek eerst. Bram staat in het pijldiagram twee keer zo ver van de oorsprong, op dezelfde lijn. We bouwen nu een score die dat verschil tussen omvang en richting zichtbaar maakt.

1. Bijdragen per component combineren

Kijk eerst naar de oranje pijl (1, 0). Alleen de horizontale component telt mee in die richting: (3, 4) draagt drie bij, (0, 4) nul en (−3, 4) min drie. Een positieve bijdrage loopt mee met de referentie, een negatieve ertegenin.

KIJK · VERANDER · BEGRIJPEen vector in de ruimte

Verander de componenten. Wat gebeurt er met de lengte?

xy0referentie (1, 0)v = (3, 4)
Lengte 5.00Inproduct met (1, 0) 3.0Cosinus 0.60

Zet y op 4 en wissel x tussen 3, 0 en −3. De meetwaarde inproduct met (1, 0) volgt precies die horizontale bijdrage. Bij een referentie met twee niet-nulle componenten combineer je beide bijdragen.

Het inproduct (dot product) vermenigvuldigt bijbehorende componenten en telt de producten op. Voor twee componenten schrijven we:

a·b=a1b1+a2b2

De punt betekent inproduct; a en b zijn de twee vectoren. Het kleine cijfer 1 verwijst naar de eerste component, 2 naar de tweede. Naast elkaar geschreven componenten worden vermenigvuldigd; de uitkomst is één getal.

Neem a = (2, 3) en b = (4, −1). De eerste bijdrage is 2 × 4 = 8, de tweede 3 × −1 = −3; samen krijg je 5. Dezelfde berekening in Python:

a = [2, 3]
b = [4, -1]
print(a[0] * b[0] + a[1] * b[1])   # 5

Een vector kan ook drie of meer componenten hebben: je telt gewoon meer producten op. len(a) telt de componenten; range(len(a)) geeft hun Pythonposities vanaf nul. Deze lus doorloopt ze één voor één:

def som(waarden):
    totaal = 0
    for i in range(len(waarden)):
        totaal = totaal + waarden[i]
    return totaal

print(som([8, -3]))   # 5

Inspringing groepeert Pythonregels: binnen de functie spring je in, binnen de lus nogmaals. return staat ná de lus op hetzelfde inspringniveau als for; binnen de lus zou hij al na de eerste component stoppen. Voor het inproduct tel je per positie het product a[i] * b[i] op.

Maak hiermee inproduct(a, b). Controleer eerst of beide lijsten even lang zijn; zo voorkom je een schijnbaar geldige score op onvolledige gegevens. if voert de ingesprongen regel alleen uit als de voorwaarde klopt; != betekent “niet gelijk aan”.

if len(a) != len(b):
    raise ValueError("Verschillende lengtes")

raise ValueError(...) stopt met die foutmelding. Bij gelijke lengtes ga je door met de optellus en geef je het totaal terug.

01
CHECKPOINTBereken een inproduct

2. De invloed van omvang weghalen

Terug naar Ada en Bram: hun inproduct is 3 × 6 + 4 × 8 = 18 + 32 = 50. Ada's vectorlengte is 5; Brams lengte is de wortel van 36 + 64, dus 10. Hun inproduct gedeeld door beide lengtes wordt 50 / (5 × 10) = 1.

Als je dezelfde vector met een positieve factor 2 schaalt en de andere gelijk houdt, verdubbelt het inproduct én de lengte van die vector. In de verhouding vallen die twee factoren tegen elkaar weg. Zo vergelijk je richting zonder een groter leesvolume automatisch te belonen.

cos(a,b)=a·b‖a‖·‖b‖

Dit heet cosinusgelijkenis (cosine similarity). De teller boven de breukstreep is het inproduct; de noemer eronder vermenigvuldigt de twee lengtes. Je hebt hiervoor geen aparte goniometrische Pythonfunctie nodig.

a = [3, 4]
b = [6, 8]
lengte_a = (3 ** 2 + 4 ** 2) ** 0.5
lengte_b = (6 ** 2 + 8 ** 2) ** 0.5
product_lengtes = lengte_a * lengte_b
print(inproduct(a, b) / product_lengtes)
# 1.0

Voor meer componenten tel je met een lus iedere component maal zichzelf op en neem je daarna de wortel. Dezelfde richting geeft score 1, loodrecht geeft 0, tegengesteld −1. Een nulvector heeft geen richting: weiger die vóór de deling.

if lengte_a == 0:
    raise ValueError("Nulvector")
if lengte_b == 0:
    raise ValueError("Nulvector")

== test gelijkheid; = bewaart een waarde. Bouw nu cosinus(a, b) met lengtes, deze controles en de verhouding.

02
CHECKPOINTVergelijk richtingen

3. Kies op richting, niet op het grootste inproduct

Onze vraagvector is (1, 0). Vergelijk deze drie kandidaten met de zojuist gebouwde functies:

Drie kandidaten voor vraagvector (1, 0)
IndexKandidaatInproductLengteCosinus
0(4, 4)4wortel van 32≈ 0,707
1(2, 0)221
2(0, 3)030

Veelgemaakte fout: het grootste inproduct kiezen zou kandidaat 0 opleveren. Voor de meest gelijke richting wint juist kandidaat 1. Je kunt beide pijlen binnen het bereik van de visualisatie zetten.

Begin met kandidaat 0 als beste tot nu toe. Bereken daarna iedere volgende score en onthoud index plus score als die groter is; Python schrijft dat als >. Dit extra voorbeeld met vooraf berekende scores toont ook een gelijkspel:

scores = [0.4, 0.9, 0.9]
beste_index = 0
beste_score = scores[0]
for i in range(1, len(scores)):
    if scores[i] > beste_score:
        beste_index = i
        beste_score = scores[i]
# De tweede 0.9 vervangt de eerste niet.
print(beste_index)   # 1

range(1, ...) begint bij de tweede positie. In dichtstbij(query, kandidaten) vervang je de vooraf berekende score door cosinus(query, kandidaten[i]); kandidaten[i] kiest één hele vector. Geef de beste index terug; invoer is hier niet leeg, heeft passende lengtes en bevat geen nulvectoren.

03
CHECKPOINTVind de beste buur

Wat neem je mee?

  • Het inproduct telt bijdragen per component op en hangt ook van omvang af.
  • Cosinusgelijkenis deelt de omvang weg voor niet-nulle vectoren; zij meet richtingsovereenkomst.
  • Buurzoeken vergelijkt scores en bewaart de beste index; de eerste wint een gelijkspel.

Een score van 1 bewijst alleen dezelfde richting in deze gekozen kenmerken, geen identieke personen of gegarandeerd passende boeken. Later maak je met modellen vectoren voor tekst en beoordeel je of deze vergelijking nuttig is. Eerst leer je in de matrixmodule hoe je meerdere vectorbewerkingen georganiseerd uitvoert.

Verder lezen & bronnen

Inhoud gecontroleerd op 2026-10-26.
DE VOLGENDE STAPEen matrix doet iets met een vector
JOUW EXPERIMENT

Probeer het zelf

Python
main.py

Python start zodra jij code uitvoert.

UITVOER

Je uitvoer verschijnt hier.
Alles rekent in je eigen browser.

Jouw checkpoints0 / 3
01
Bereken een inproduct

Maak inproduct(a, b): tel de producten per positie op en weiger verschillende lengtes.

Een hint

Controleer len(a) en len(b). Begin met totaal=0, doorloop de posities met for en geef het totaal pas na de lus terug.

02
Vergelijk richtingen

Maak cosinus(a, b) voor even lange lijsten met willekeurig veel componenten. Weiger een nulvector met ValueError.

Een hint

Tel per vector alle componentkwadraten op en neem de wortel. Controleer beide lengtes met == 0 vóór je het inproduct door hun product deelt.

03
Vind de beste buur

Maak dichtstbij(query, kandidaten): geef de index van de hoogste cosinusscore terug; bij gelijkspel de eerste.

Een hint

Begin met kandidaat 0. Doorloop de overige indices en vervang beste_index én beste_score alleen bij een strikt grotere score.

Vastgelopen? Bekijk de voorbeeldoplossing
def inproduct(a, b):
    if len(a) != len(b):
        raise ValueError('Verschillende lengtes')
    totaal = 0
    for i in range(len(a)):
        totaal = totaal + a[i] * b[i]
    return totaal


def cosinus(a, b):
    kwadraten_a = 0
    for i in range(len(a)):
        kwadraten_a = kwadraten_a + a[i] * a[i]
    kwadraten_b = 0
    for i in range(len(b)):
        kwadraten_b = kwadraten_b + b[i] * b[i]
    lengte_a = kwadraten_a ** 0.5
    lengte_b = kwadraten_b ** 0.5
    if lengte_a == 0:
        raise ValueError('Nulvector heeft geen richting')
    if lengte_b == 0:
        raise ValueError('Nulvector heeft geen richting')
    return inproduct(a, b) / (lengte_a * lengte_b)


def dichtstbij(query, kandidaten):
    beste_index = 0
    beste_score = cosinus(query, kandidaten[0])
    for i in range(1, len(kandidaten)):
        score = cosinus(query, kandidaten[i])
        if score > beste_score:
            beste_index = i
            beste_score = score
    return beste_index

Voer de code uit en verklaar voor jezelf waarom elke stap werkt.