Machine Learning Academy · Les

Gini-onzuiverheid en informatiewinst

U berekent de Gini-onzuiverheid en entropie voor voorbeeldsplitsingen en begrijpt waarom de boom de splitsing kiest die de informatiewinst maximaliseert.

Les 2 van 413 stappen

Gini-onzuiverheid en informatiewinst is een gratis Machine Learning Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Machine Learning Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Machine Learning Academy bevat in totaal 4 lessen.

Het splitsingsprobleem: over welk kenmerk stel je een vraag?

Bij het opbouwen van een beslisboom moeten we bij elk knooppunt kiezen welk kenmerk en welke drempelwaarde de nuttigste splitsing opleveren. Het doel is kindknooppunten te maken waarin de voorbeelden zo zuiver mogelijk zijn — idealiter bevat elk kind slechts één klasse. We hebben een wiskundige maat voor onzuiverheid nodig die aangeeft hoe gemengd de klassen in een knooppunt zijn. Een lagere onzuiverheid is beter: een knooppunt waarvan alle voorbeelden tot dezelfde klasse behoren, heeft een onzuiverheid van nul (perfecte zuiverheid). Twee veelgebruikte maten voor onzuiverheid zijn Gini-onzuiverheid en entropie.

# Impurity measures how mixed the classes are in a node
# Perfect purity: all samples belong to one class -> impurity = 0
# Maximum impurity: classes are equally distributed

import numpy as np

# Node A: all class 0 -> pure
node_a = [0, 0, 0, 0]  # impurity = 0

# Node B: 50/50 mix -> maximally impure
node_b = [0, 0, 1, 1]  # impurity = maximum

# Node C: mostly one class
node_c = [0, 0, 0, 1]  # impurity = low

for name, node in [('A', node_a), ('B', node_b), ('C', node_c)]:
    print(f'Node {name}: classes = {node}')

Gini-onzuiverheid: het standaardcriterium

Gini-onzuiverheid meet de kans dat een willekeurig gekozen voorbeeld uit een knooppunt verkeerd zou worden gelabeld als het willekeurig wordt gelabeld volgens de klasseverdeling in dat knooppunt. De formule is: Gini = 1 - sum(p_i^2), waarbij p_i het aandeel van klasse i is. Gini loopt van 0 (zuiver) tot 0,5 (gelijke verdeling over twee klassen). Voor K klassen is het maximum 1 - 1/K. Gini-onzuiverheid is het standaardcriterium in de DecisionTreeClassifier van scikit-learn omdat het computationeel efficiënt is (er zijn geen logaritmen nodig).

import numpy as np

def gini_impurity(y):
    classes, counts = np.unique(y, return_counts=True)
    probabilities = counts / len(y)
    return 1 - np.sum(probabilities ** 2)

# Pure node
print('Pure [0,0,0,0]:', gini_impurity([0,0,0,0]))       # 0.0

# 50/50 split
print('50/50 [0,0,1,1]:', gini_impurity([0,0,1,1]))      # 0.5

# 75/25 split
print('75/25 [0,0,0,1]:', gini_impurity([0,0,0,1]))      # 0.375

# Three classes equal
print('3-class equal:', gini_impurity([0,1,2,0,1,2]))    # ~0.667

Entropie en informatietheorie

Entropie komt uit de informatietheorie: het meet de onzekerheid of informatiewaarde van een verdeling. Formule: H = -sum(p_i * log2(p_i)). Een zuiver knooppunt heeft entropie 0 (geen onzekerheid). Een verdeling van 50/50 heeft entropie 1 (één bit onzekerheid — je hebt één vraag nodig om de klasse te bepalen). Entropie en Gini leveren in de praktijk zeer vergelijkbare bomen op. Entropie is iets trager te berekenen (er is een logaritme nodig), maar kan betere splitsingen opleveren wanneer klasseverdelingen scheef zijn. Gebruik criterion='entropy' in scikit-learn om over te schakelen.

import numpy as np

def entropy(y):
    classes, counts = np.unique(y, return_counts=True)
    probabilities = counts / len(y)
    # Avoid log(0) by filtering zero probabilities
    probs = probabilities[probabilities > 0]
    return -np.sum(probs * np.log2(probs))

print('Pure [0,0,0,0]:', entropy([0,0,0,0]))         # 0.0
print('50/50 [0,0,1,1]:', entropy([0,0,1,1]))        # 1.0 (1 bit)
print('75/25 [0,0,0,1]:', entropy([0,0,0,1]).round(3))  # 0.811
print('3-class equal:', entropy([0,1,2,0,1,2]).round(3)) # 1.585

Informatiewinst: de maatstaf voor de kwaliteit van een splitsing

Informatiewinst meet hoeveel een splitsing de onzuiverheid vermindert. Deze wordt berekend als de onzuiverheid van het ouderknooppunt min de gewogen gemiddelde onzuiverheid van de kindknooppunten: IG = impurity(parent) - (N_left/N * impurity(left) + N_right/N * impurity(right)). De beste splitsing maximaliseert de informatiewinst: deze levert kinderen op die zo zuiver mogelijk zijn, gewogen naar hun omvang (zodat grotere kinderen zwaarder meetellen). De boomopbouw evalueert elk kenmerk en elke drempelwaarde en kiest vervolgens de combinatie met de hoogste winst.

import numpy as np

def gini_impurity(y):
    _, counts = np.unique(y, return_counts=True)
    p = counts / len(y)
    return 1 - np.sum(p**2)

def information_gain(y_parent, y_left, y_right):
    n = len(y_parent)
    n_l, n_r = len(y_left), len(y_right)
    parent_impurity = gini_impurity(y_parent)
    weighted_child  = (n_l/n)*gini_impurity(y_left) + (n_r/n)*gini_impurity(y_right)
    return parent_impurity - weighted_child

y_parent = [0,0,0,1,1,1]  # 50/50 parent
y_left   = [0,0,0]         # pure left
y_right  = [1,1,1]         # pure right

print('IG:', information_gain(y_parent, y_left, y_right))  # 0.5 (perfect split)

Meerdere splitsingen evalueren

Om de beste splitsing te vinden, evalueert het algoritme alle combinaties van kandidaatkenmerken en -drempelwaarden en kiest het de combinatie met de hoogste informatiewinst. Voor een gegevensset met N voorbeelden en d kenmerken evalueert de boom per kenmerk maximaal N-1 drempelwaarden (middelpunten tussen opeenvolgende unieke waarden), wat neerkomt op O(N * d) te evalueren splitsingen per knooppunt. Hier is een vereenvoudigd voorbeeld dat laat zien hoe verschillende drempelwaarden op hetzelfde kenmerk verschillende informatiewinsten opleveren.

import numpy as np

X_feature = np.array([1, 2, 3, 4, 5, 6])
y = np.array([0, 0, 0, 1, 1, 1])

best_threshold, best_ig = None, -1

for threshold in [1.5, 2.5, 3.5, 4.5, 5.5]:
    left_mask  = X_feature <= threshold
    right_mask = ~left_mask
    y_l, y_r = y[left_mask], y[right_mask]
    
    _, cnt_p = np.unique(y, return_counts=True)
    _, cnt_l = np.unique(y_l, return_counts=True) if len(y_l) else (None, [1])
    _, cnt_r = np.unique(y_r, return_counts=True) if len(y_r) else (None, [1])
    
    ig = information_gain(y, y_l, y_r)
    print(f'Threshold {threshold}: IG = {ig:.3f}')
    if ig > best_ig:
        best_ig, best_threshold = ig, threshold

print('Best threshold:', best_threshold, 'with IG:', best_ig)

Gini versus entropie: praktisch verschil

Gini-onzuiverheid en entropie leveren meestal vrijwel identieke bomen op. De belangrijkste verschillen zijn subtiel: entropie levert doorgaans meer uitgebalanceerde bomen op (door de logaritme worden onevenwichtige splitsingen zwaarder bestraft), terwijl Gini de meest voorkomende klasse doorgaans in één tak afzondert. Rekenkundig is Gini sneller omdat de berekening van de logaritme wordt vermeden. In de praktijk is de keuze tussen beide een hyperparameter die je moet afstemmen — probeer beide met kruisvalidatie en kies degene die beter presteert op jouw specifieke gegevensset.

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer

X, y = load_breast_cancer(return_X_y=True)

for criterion in ['gini', 'entropy']:
    tree = DecisionTreeClassifier(criterion=criterion, max_depth=5, random_state=42)
    score = cross_val_score(tree, X, y, cv=10).mean()
    print(f'criterion={criterion}: CV accuracy = {score:.3f}')

# Usually within 0.5% of each other -- not the critical choice

Gewogen Gini voor problemen met meerdere klassen

Gini-onzuiverheid wordt zonder aanpassingen op natuurlijke wijze uitgebreid naar problemen met meerdere klassen: Gini = 1 - sum(p_i^2) werkt voor elk aantal klassen. Ook de berekening van de informatiewinst blijft ongewijzigd — de gewogen onzuiverheid van de kinderen min de onzuiverheid van de ouder. Bij een probleem met 3 klassen heeft een volkomen zuiver blad (bijvoorbeeld met uitsluitend klasse 2) Gini-waarde 0. Een knooppunt met gelijke aandelen van 3 klassen heeft een maximale Gini-waarde van 2/3. Beslisbomen zijn een van de weinige algoritmen die problemen met meerdere klassen zonder aanpassingen rechtstreeks verwerken — in tegenstelling tot logistische regressie, waarvoor one-vs-rest- of softmax-uitbreidingen nodig zijn.

import numpy as np

def gini_multiclass(y):
    _, counts = np.unique(y, return_counts=True)
    p = counts / len(y)
    return 1 - np.sum(p**2)

# 3-class examples
print('Pure [0,0,0]:', gini_multiclass([0,0,0]))               # 0.0
print('Equal [0,1,2]:', gini_multiclass([0,1,2]).round(3))    # 0.667
print('2 dominant [0,0,1,2]:', gini_multiclass([0,0,1,2]).round(3))  # 0.625

# Max Gini for K classes = 1 - 1/K
for K in [2, 3, 4, 5]:
    print(f'Max Gini for {K} classes: {1 - 1/K:.3f}')

Onzuiverheidsreductie binnen scikit-learn

Binnen scikit-learn slaat de boom bij elk knooppunt de onzuiverheid vóór de splitsing en de onzuiverheid van elk kind op. Het verschil, gewogen naar het aantal voorbeelden, is de onzuiverheidsreductie (informatiewinst). Deze waarde wordt per kenmerk over alle knooppunten opgeteld en genormaliseerd om feature_importances_ te berekenen — de totale onzuiverheidsreductie die aan elk kenmerk wordt toegeschreven. Kenmerken die dicht bij de wortel voorkomen en veel voorbeelden verwerken hebben doorgaans het grootste belang, omdat elke splitsing invloed heeft op een groot deel van de gegevens.

from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
import numpy as np

X, y = load_iris(return_X_y=True)
tree = DecisionTreeClassifier(criterion='gini', max_depth=3, random_state=42)
tree.fit(X, y)

# Impurity at root and children
print('Root impurity (Gini):', tree.tree_.impurity[0].round(4))
print('Left child impurity:', tree.tree_.impurity[1].round(4))
print('Right child impurity:', tree.tree_.impurity[2].round(4))

# Feature importances = total weighted impurity reduction per feature
print('Feature importances:', tree.feature_importances_.round(3))

De rol van min_impurity_decrease

Standaard splitst de boom knopen zolang er enige afname van impuriteit is en de knoop voldoende voorbeelden bevat. De parameter min_impurity_decrease voegt een minimumdrempel toe: er wordt alleen een splitsing gemaakt als die de impuriteit met minstens deze hoeveelheid vermindert. Zo voorkom je dat de boom triviaal kleine splitsingen maakt die ruis uit het hoofd leert. Als je min_impurity_decrease=0.01 instelt, splitst de boom alleen wanneer de informatiewinst groter is dan 0.01. Dit is een nuttig alternatief voor regularisatie door de diepte rechtstreeks te beperken.

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer

X, y = load_breast_cancer(return_X_y=True)

for min_ig in [0.0, 0.001, 0.005, 0.01, 0.05]:
    tree = DecisionTreeClassifier(
        min_impurity_decrease=min_ig,
        random_state=42
    )
    score = cross_val_score(tree, X, y, cv=5).mean()
    depth = tree.fit(X, y).get_depth()
    print(f'min_impurity_decrease={min_ig}: depth={depth}, CV acc={score:.3f}')

Splitsingen tussen kenmerken vergelijken

Een uitgewerkt voorbeeld dat laat zien hoe de boom het beste kenmerk en de beste drempel kiest. Gegeven twee kenmerken en voor elk één splitsingsdrempel berekent de boom de informatiewinst voor alle opties en kiest hij de beste optie. Dit laat zien waarom bomen van nature impliciete kenmerkselectie uitvoeren: kenmerken die bij geen enkele drempel een hoge informatiewinst opleveren, worden nooit als splitsingskenmerk gekozen en feitelijk genegeerd. Hierdoor zijn beslisbomen robuust voor irrelevante kenmerken, in tegenstelling tot KNN, dat daar wel nadeel van ondervindt.

import numpy as np

# Toy dataset: X[:,0]=income, X[:,1]=age; y=churn
X = np.array([[100, 25], [120, 30], [40, 22], [50, 28], [90, 35], [30, 40]])
y = np.array([0, 0, 1, 1, 0, 1])

# Try splitting on income at 75
left_y = y[X[:, 0] <= 75]   # [1,1,1]
right_y = y[X[:, 0] > 75]   # [0,0,0]
ig_income = information_gain(y, left_y, right_y)

# Try splitting on age at 30
left_y2 = y[X[:, 1] <= 30]  # [0,0,1,1]
right_y2 = y[X[:, 1] > 30]  # [0,1]
ig_age = information_gain(y, left_y2, right_y2)

print(f'IG(income<=75): {ig_income:.3f}')
print(f'IG(age<=30):    {ig_age:.3f}')
print('Best split:', 'income' if ig_income > ig_age else 'age')

Gini gebruiken in GridSearchCV

Wanneer je een beslisboom afstemt met GridSearchCV, kun je de parameter criterion (gini of entropie) opnemen in het parameterrooster, zodat kruisvalidatie de beste optie voor jouw specifieke gegevensverzameling kiest. Combineer dit in dezelfde zoekopdracht met max_depth, min_samples_split en min_samples_leaf. Zoeken over het criterium brengt nauwelijks extra rekenkosten met zich mee — per combinatie zijn er slechts twee extra configuraties — en levert soms een betekenisvolle verbetering op wanneer de klassedistributies sterk scheef zijn of de gegevensverzameling veel splitsingen van vergelijkbare kwaliteit bevat.

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_breast_cancer

X, y = load_breast_cancer(return_X_y=True)

param_grid = {
    'criterion': ['gini', 'entropy'],
    'max_depth': [3, 5, 7, None],
    'min_samples_leaf': [1, 5, 10]
}

grid = GridSearchCV(
    DecisionTreeClassifier(random_state=42),
    param_grid, cv=10, scoring='accuracy', n_jobs=-1
)
grid.fit(X, y)

print('Best criterion:', grid.best_params_['criterion'])
print('Best depth:', grid.best_params_['max_depth'])
print('Best CV accuracy:', grid.best_score_.round(4))

Korte kennistoets

Toets je begrip van de concepten uit deze les over machinaal leren met Python.

Samenvatting van de les

In deze les heb je geleerd dat Gini-impuriteit meet hoe gemengd de klassen in een knoop zijn (formule: 1 - som(p_i^2)), dat informatiewinst meet hoeveel een splitsing de impuriteit vermindert (impuriteit van de bovenliggende knoop min de gewogen impuriteit van de onderliggende knopen), en dat de boom altijd de splitsing kiest die de informatiewinst maximaliseert over alle kenmerken en drempels. Hierna bekijken we hoe je de boomdiepte beperkt om overfitting te voorkomen.

Gratis beginnen

Leer Python met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “Gini-onzuiverheid en informatiewinst” gratis?

Ja — de volledige tekst van “Gini-onzuiverheid en informatiewinst” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Machine Learning Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Machine Learning Academy bevat in totaal 4 lessen.

Wat leer ik in “Gini-onzuiverheid en informatiewinst”?

U berekent de Gini-onzuiverheid en entropie voor voorbeeldsplitsingen en begrijpt waarom de boom de splitsing kiest die de informatiewinst maximaliseert. Je oefent met Machine Learning Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Machine Learning Academy te beginnen?

Ervaring vooraf is niet nodig. Machine Learning Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Gini-onzuiverheid en informatiewinst”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Machine Learning Academy?

Ja. Elke les over Machine Learning Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Een boom bouwen: splitsingen, knopen en bladeren
  2. Gini-onzuiverheid en informatiewinst
  3. Boomdiepte beheersen om overfitting te voorkomen
  4. Beslisbomen visualiseren en interpreteren
← Terug naar Machine Learning Academy