Skip to content

Metode Ensemble

Metodele ensemble combină mai mulți algoritmi de învățare pentru a obține performanțe mai bune decât oricare model individual. Principiul de bază: "înțelepciunea mulțimii".

De ce funcționează?

Dacă avem mai mulți clasificatori independenți, fiecare cu acuratețe > 50%, combinarea lor prin vot majoritar crește probabilitatea de a obține răspunsul corect.

import numpy as np

# Simulare: 10 clasificatori cu acuratețe 60%
n_clasificatori = 10
acuratete_individual = 0.6
n_simulari = 10000

# Vot majoritar
corecte = 0
for _ in range(n_simulari):
    voturi = np.random.random(n_clasificatori) < acuratete_individual
    if voturi.sum() > n_clasificatori / 2:
        corecte += 1

print(f"Acuratețe individuală: {acuratete_individual:.0%}")
print(f"Acuratețe ensemble (vot): {corecte/n_simulari:.0%}")
# ~73% pentru 10 clasificatori cu 60% acuratețe

Tipuri de ensemble

Metodă Strategie Reduce
Bagging Antrenare paralelă pe subseturi Varianță
Boosting Antrenare secvențială, focus pe erori Bias
Voting Combinare modele diferite Ambele
Stacking Model care învață să combine Ambele

Bagging (Bootstrap Aggregating)

Bagging antrenează modele identice pe subseturi diferite ale datelor (sampling cu înlocuire).

Principiu

  1. Creează N subseturi prin bootstrap (sampling cu înlocuire)
  2. Antrenează câte un model pe fiecare subset
  3. Combină predicțiile prin vot (clasificare) sau medie (regresie)
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Date
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# Bagging cu arbori de decizie
bagging = BaggingClassifier(
    estimator=DecisionTreeClassifier(),
    n_estimators=100,
    max_samples=0.8,      # 80% din date pentru fiecare model
    max_features=0.8,     # 80% din features
    bootstrap=True,       # Sampling cu înlocuire
    random_state=42
)

bagging.fit(X_train, y_train)
print(f"Acuratețe Bagging: {accuracy_score(y_test, bagging.predict(X_test)):.3f}")

# Comparație cu un singur arbore
tree = DecisionTreeClassifier(random_state=42)
tree.fit(X_train, y_train)
print(f"Acuratețe Arbore singur: {accuracy_score(y_test, tree.predict(X_test)):.3f}")

Random Forest

Random Forest este bagging cu arbori de decizie + selecție aleatoare de features la fiecare split.

from sklearn.ensemble import RandomForestClassifier

# Random Forest
rf = RandomForestClassifier(
    n_estimators=100,       # Numărul de arbori
    max_depth=10,           # Adâncimea maximă
    max_features='sqrt',    # sqrt(n_features) la fiecare split
    min_samples_split=5,    # Minim samples pentru split
    min_samples_leaf=2,     # Minim samples în frunze
    bootstrap=True,
    random_state=42,
    n_jobs=-1               # Paralelizare
)

rf.fit(X_train, y_train)
print(f"Acuratețe Random Forest: {accuracy_score(y_test, rf.predict(X_test)):.3f}")

Importanța features

import matplotlib.pyplot as plt
import numpy as np

# Importanța features
importances = rf.feature_importances_
indices = np.argsort(importances)[::-1]

plt.figure(figsize=(10, 6))
plt.title("Importanța Features - Random Forest")
plt.bar(range(len(importances)), importances[indices])
plt.xticks(range(len(importances)), [f'F{i}' for i in indices], rotation=45)
plt.tight_layout()
plt.show()

Out-of-Bag (OOB) Score

Datele nefolosite în bootstrap pot fi folosite pentru validare.

rf_oob = RandomForestClassifier(
    n_estimators=100,
    oob_score=True,  # Activează OOB
    random_state=42
)
rf_oob.fit(X_train, y_train)

print(f"OOB Score: {rf_oob.oob_score_:.3f}")
print(f"Test Score: {rf_oob.score(X_test, y_test):.3f}")

Boosting

Boosting antrenează modele secvențial, fiecare nou model focalizându-se pe erorile celor anterioare.

AdaBoost (Adaptive Boosting)

Crește ponderile pentru exemplele clasificate greșit.

from sklearn.ensemble import AdaBoostClassifier

# AdaBoost
ada = AdaBoostClassifier(
    estimator=DecisionTreeClassifier(max_depth=1),  # "Stumps"
    n_estimators=100,
    learning_rate=0.1,
    random_state=42
)

ada.fit(X_train, y_train)
print(f"Acuratețe AdaBoost: {accuracy_score(y_test, ada.predict(X_test)):.3f}")

Gradient Boosting

Antrenează modele pentru a prezice reziduurile (erorile) modelelor anterioare.

from sklearn.ensemble import GradientBoostingClassifier

# Gradient Boosting
gb = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    min_samples_split=5,
    min_samples_leaf=2,
    subsample=0.8,          # Stochastic GB
    random_state=42
)

gb.fit(X_train, y_train)
print(f"Acuratețe Gradient Boosting: {accuracy_score(y_test, gb.predict(X_test)):.3f}")

XGBoost

XGBoost (Extreme Gradient Boosting) - implementare optimizată și regularizată.

# pip install xgboost
from xgboost import XGBClassifier

xgb = XGBClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    subsample=0.8,
    colsample_bytree=0.8,
    reg_alpha=0.1,          # Regularizare L1
    reg_lambda=1.0,         # Regularizare L2
    random_state=42,
    use_label_encoder=False,
    eval_metric='logloss'
)

xgb.fit(X_train, y_train)
print(f"Acuratețe XGBoost: {accuracy_score(y_test, xgb.predict(X_test)):.3f}")

LightGBM

LightGBM - mai rapid, eficient pentru date mari.

# pip install lightgbm
from lightgbm import LGBMClassifier

lgbm = LGBMClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    num_leaves=31,
    subsample=0.8,
    colsample_bytree=0.8,
    random_state=42,
    verbose=-1
)

lgbm.fit(X_train, y_train)
print(f"Acuratețe LightGBM: {accuracy_score(y_test, lgbm.predict(X_test)):.3f}")

CatBoost

CatBoost - excelent pentru date categorice.

# pip install catboost
from catboost import CatBoostClassifier

cat = CatBoostClassifier(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3,
    random_state=42,
    verbose=0
)

cat.fit(X_train, y_train)
print(f"Acuratețe CatBoost: {accuracy_score(y_test, cat.predict(X_test)):.3f}")

Voting

Voting combină predicțiile mai multor modele diferite.

Hard Voting

Vot majoritar - alege clasa cu cele mai multe voturi.

from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier

# Definire modele
models = [
    ('lr', LogisticRegression(max_iter=1000)),
    ('svm', SVC(kernel='rbf', probability=True)),
    ('dt', DecisionTreeClassifier(max_depth=5))
]

# Hard voting
voting_hard = VotingClassifier(estimators=models, voting='hard')
voting_hard.fit(X_train, y_train)
print(f"Acuratețe Hard Voting: {accuracy_score(y_test, voting_hard.predict(X_test)):.3f}")

Soft Voting

Media probabilităților - necesită modele cu predict_proba.

# Soft voting (media probabilităților)
voting_soft = VotingClassifier(estimators=models, voting='soft')
voting_soft.fit(X_train, y_train)
print(f"Acuratețe Soft Voting: {accuracy_score(y_test, voting_soft.predict(X_test)):.3f}")

Voting cu ponderi

# Voting cu ponderi diferite
voting_weighted = VotingClassifier(
    estimators=models,
    voting='soft',
    weights=[2, 1, 1]  # LR are pondere dublă
)
voting_weighted.fit(X_train, y_train)
print(f"Acuratețe Weighted Voting: {accuracy_score(y_test, voting_weighted.predict(X_test)):.3f}")

Stacking

Stacking folosește un meta-model care învață să combine predicțiile.

from sklearn.ensemble import StackingClassifier

# Modele de bază
base_models = [
    ('rf', RandomForestClassifier(n_estimators=50, random_state=42)),
    ('gb', GradientBoostingClassifier(n_estimators=50, random_state=42)),
    ('svm', SVC(kernel='rbf', probability=True, random_state=42))
]

# Meta-model
stacking = StackingClassifier(
    estimators=base_models,
    final_estimator=LogisticRegression(),
    cv=5,                    # Cross-validation pentru predicții
    stack_method='auto',     # predict_proba dacă disponibil
    passthrough=False        # True pentru a include și features originale
)

stacking.fit(X_train, y_train)
print(f"Acuratețe Stacking: {accuracy_score(y_test, stacking.predict(X_test)):.3f}")

Comparație metode

from sklearn.model_selection import cross_val_score
import pandas as pd

models = {
    'Decision Tree': DecisionTreeClassifier(max_depth=5, random_state=42),
    'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
    'AdaBoost': AdaBoostClassifier(n_estimators=100, random_state=42),
    'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42),
    'Voting': VotingClassifier(
        estimators=[
            ('rf', RandomForestClassifier(n_estimators=50)),
            ('gb', GradientBoostingClassifier(n_estimators=50))
        ],
        voting='soft'
    )
}

results = []
for name, model in models.items():
    scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
    results.append({
        'Model': name,
        'Mean': scores.mean(),
        'Std': scores.std()
    })

df_results = pd.DataFrame(results)
print(df_results.to_string(index=False))

Vizualizare: Bagging vs Boosting

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_moons
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier, AdaBoostClassifier

# Date
X, y = make_moons(n_samples=300, noise=0.3, random_state=42)

def plot_decision_boundary(model, X, y, ax, title):
    h = 0.02
    x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
    y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))

    Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    ax.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
    ax.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', edgecolors='black')
    ax.set_title(title)

fig, axes = plt.subplots(2, 2, figsize=(12, 10))

# Arbore simplu
tree = DecisionTreeClassifier(max_depth=3, random_state=42)
tree.fit(X, y)
plot_decision_boundary(tree, X, y, axes[0, 0], 'Decision Tree')

# Bagging
bagging = BaggingClassifier(
    estimator=DecisionTreeClassifier(max_depth=3),
    n_estimators=50, random_state=42
)
bagging.fit(X, y)
plot_decision_boundary(bagging, X, y, axes[0, 1], 'Bagging (50 arbori)')

# AdaBoost
ada = AdaBoostClassifier(
    estimator=DecisionTreeClassifier(max_depth=1),
    n_estimators=50, random_state=42
)
ada.fit(X, y)
plot_decision_boundary(ada, X, y, axes[1, 0], 'AdaBoost (50 stumps)')

# Random Forest
rf = RandomForestClassifier(n_estimators=50, max_depth=3, random_state=42)
rf.fit(X, y)
plot_decision_boundary(rf, X, y, axes[1, 1], 'Random Forest (50 arbori)')

plt.tight_layout()
plt.show()

Hiperparametri importanți

Random Forest

Parametru Descriere Valori tipice
n_estimators Numărul de arbori 100-500
max_depth Adâncimea maximă 5-20 sau None
max_features Features per split 'sqrt', 'log2'
min_samples_split Min samples pentru split 2-10
min_samples_leaf Min samples în frunză 1-5

Gradient Boosting

Parametru Descriere Valori tipice
n_estimators Numărul de etape 100-1000
learning_rate Rata de învățare 0.01-0.3
max_depth Adâncime arbori 3-10
subsample Fracțiune date per arbore 0.5-1.0

Tuning cu GridSearchCV

from sklearn.model_selection import GridSearchCV

# Random Forest
param_grid_rf = {
    'n_estimators': [50, 100, 200],
    'max_depth': [5, 10, None],
    'max_features': ['sqrt', 'log2'],
    'min_samples_split': [2, 5, 10]
}

grid_rf = GridSearchCV(
    RandomForestClassifier(random_state=42),
    param_grid_rf,
    cv=5,
    scoring='accuracy',
    n_jobs=-1
)
grid_rf.fit(X_train, y_train)

print(f"Cei mai buni parametri RF: {grid_rf.best_params_}")
print(f"Cel mai bun scor RF: {grid_rf.best_score_:.3f}")

Când să folosești fiecare metodă?

Situație Metodă recomandată
Date multe, features multe Random Forest, XGBoost
Date puține AdaBoost, Voting
Overfitting arbori Bagging
Underfitting Boosting
Modele diverse disponibile Voting, Stacking
Date categorice CatBoost
Date foarte mari LightGBM
Interpretabilitate Random Forest (feature importance)

Rezumat

  1. Bagging (Random Forest) - reduce varianța, arbori independenți
  2. Boosting (XGBoost, LightGBM) - reduce bias, arbori secvențiali
  3. Voting - combină modele diferite prin vot
  4. Stacking - meta-model care învață combinația optimă
  5. Random Forest - robust, puțin tuning necesar
  6. XGBoost/LightGBM - performanță de top, necesită tuning