Ansambli (eng. ensembles)¶

Ansambli predstavljaju jedan od najuspešnijih pristupa u mašinskom učenju. Osnovna ideja je da umesto jednog modela koristimo veći broj modela koji zajednički donose odluku. Ako pojedinačni modeli daju razumno dobre predikcije, a njihove greške nisu previše međusobno povezane, kombinovanjem njihovih izlaza često se dobija precizniji i stabilniji model.

Intuitivno, različiti modeli mogu grešiti na različitim instancama, pa se agregacijom njihovih predikcija uticaj tih grešaka ublažava. Zbog toga ansambli u praksi često daju bolje rezultate od pojedinačnih modela.

Kod tabelarnih podataka, odnosno kada su podaci predstavljeni vektorima atributa, ansambl metode zasnovane na stablima veoma često daju odlične rezultate i spadaju među najpouzdanije pristupe u praksi. To, međutim, ne znači da su uvek preciznije od neuronskih mreža, već da su često veoma konkurentne, jednostavnije za primenu i zahtevaju manje podešavanja. Sa druge strane, kod sirovih podataka kao što su slike, zvuk ili tekst, neuronske mreže su najčešće pogodniji izbor.

Dve osnovne ideje na kojima se zasnivaju ansambli jesu bagging i boosting. Bagging se zasniva na treniranju većeg broja modela nezavisno, a zatim na agregaciji njihovih predikcija. Tipičan predstavnik ove grupe je Random Forest. Boosting se zasniva na uzastopnom treniranju modela, pri čemu svaki sledeći model pokušava da popravi greške prethodnih. Tipični predstavnici ove grupe su AdaBoost i XGBoost.

Prosta agregacija (eng. bagging)¶

Prosta agregacija podrazumeva obučavanje većeg broja modela koji pojedinačno ne moraju imati visoku preciznost, ali čije greške ne smeju biti previše međusobno povezane. Prilikom predviđanja, svi modeli daju svoja predviđanja, koja se zatim agregiraju kako bi se dobilo konačno predviđanje ansambla. Ukoliko se radi o regresiji, agregacija se najčešće vrši uprosečavanjem, mada je moguće koristiti i medijanu, dok se u slučaju klasifikacije najčešće koristi glasanje.

Snaga ovakvog pristupa zasniva se na ideji da će se pri agregaciji greške različitih modela delimično poništavati. Na primer, posmatrajmo problem regresije i pretpostavimo da predikcije pojedinačnih modela možemo modelovati kao slučajne promenljive X₁, ..., Xₘ sa istim očekivanjem μ i disperzijom σ². Ako su te promenljive nezavisne, tada njihov prosek ima isto očekivanje μ i disperziju σ²/m. Dakle, agregacijom možemo smanjiti disperziju predikcije, a da pri tome ne povećamo sistematsko odstupanje. To često vodi stabilnijem i preciznijem modelu.

Slična intuicija važi i u slučaju klasifikacije: ako pojedinačni klasifikatori relativno često daju tačan odgovor, a pritom ne greše uvek na istim instancama, zajednička odluka ansambla može biti pouzdanija od odluke pojedinačnog modela.

Naravno, pretpostavka o nezavisnosti grešaka predstavlja idealizaciju i u praksi uglavnom nije u potpunosti ispunjena. Upravo zbog toga je kod konstrukcije ansambla veoma važno da modeli budu što raznovrsniji. Ako svi modeli greše na isti način, agregacija neće doneti značajno poboljšanje.

Tipično, rezultati postaju bolji kako broj modela raste, ali samo do određene granice. Sa povećanjem broja modela raste i računska zahtevnost obučavanja i predviđanja. Modeli koji učestvuju u agregaciji ne moraju biti iste reprezentacije, iako se u praksi često koristi ansambl modela istog tipa.

Slučajna šuma (eng. random forest)¶

Slučajne šume (eng. Random Forest) predstavljaju jedan od najčešće korišćenih algoritama mašinskog učenja. Spadaju u ansambl metode zasnovane na prostoj agregaciji i sastoje se od većeg broja stabala odlučivanja. Mogu se koristiti i za regresiju i za klasifikaciju.

Osnovna ideja algoritma jeste da se konstruiše veći broj različitih stabala, a zatim da se njihove predikcije agregiraju. Međutim, trening skup se ne deli na disjunktne delove, već se za svako stablo formira poseban bootstrap uzorak, odnosno uzorak dobijen slučajnim izborom instanci iz trening skupa sa ponavljanjem. Na taj način svako stablo vidi malo drugačiji skup podataka.

Pretpostavimo da imamo p prediktora. Prilikom izgradnje svakog stabla, u svakom čvoru se ne razmatra svih p prediktora, već samo slučajno izabran podskup prediktora. Kod klasifikacije se često bira približno √p prediktora, dok se kod regresije često bira oko p/3 prediktora, mada su i ove vrednosti hiperparametri koji se mogu podešavati.

Ako se bavimo regresijom, konačna predikcija slučajne šume dobija se kao prosečna vrednost predikcija svih stabala. Ako se bavimo klasifikacijom, konačna odluka dobija se glasanjem, odnosno bira se kategorija koju je predvideo najveći broj stabala.

In [ ]:
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, roc_auc_score

# Učitavanje baze
df = pd.read_csv("diabetes.csv")

print("Dimenzije skupa podataka:", df.shape)
df.head(5)
Dimenzije skupa podataka: (768, 9)
Out[ ]:
Pregnancies Glucose BloodPressure SkinThickness Insulin BMI DiabetesPedigreeFunction Age Outcome
0 6 148 72 35 0 33.6 0.627 50 1
1 1 85 66 29 0 26.6 0.351 31 0
2 8 183 64 0 0 23.3 0.672 32 1
3 1 89 66 23 94 28.1 0.167 21 0
4 0 137 40 35 168 43.1 2.288 33 1
In [ ]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 768 entries, 0 to 767
Data columns (total 9 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   Pregnancies               768 non-null    int64  
 1   Glucose                   768 non-null    int64  
 2   BloodPressure             768 non-null    int64  
 3   SkinThickness             768 non-null    int64  
 4   Insulin                   768 non-null    int64  
 5   BMI                       768 non-null    float64
 6   DiabetesPedigreeFunction  768 non-null    float64
 7   Age                       768 non-null    int64  
 8   Outcome                   768 non-null    int64  
dtypes: float64(2), int64(7)
memory usage: 54.1 KB
In [ ]:
# Ciljna promenljiva
y = df["Outcome"]

# Prediktori
X = df.drop(columns=["Outcome"])

# Podela na trening i test skup
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# Važno je napomenuti da postoje i opštije ansambl metode zasnovane na prostoj agregaciji
# kod kojih se može birati bazni model pomoću odgovarajućeg parametra, ali se kod slučajnih šuma
# bazni modeli unapred uzimaju kao stabla odlučivanja.

# Formiranje Random Forest modela
model = RandomForestClassifier(
    n_estimators=200,      # broj stabala
    max_depth=None,        # maksimalna dubina stabala
    max_features="sqrt",   # broj atributa koji se razmatra pri svakoj podeli
    bootstrap=True,        # za svako stablo koristi se bootstrap uzorak
    random_state=42,
    n_jobs=-1              # hocemo da koristimo sva jezgra procesora
)

# Obučavanje modela
model.fit(X_train, y_train)

# Predikcija na test skupu
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]

# Evaluacija modela

print("Confusion matrix:")
print(confusion_matrix(y_test, y_pred))

acc = accuracy_score(y_test, y_pred)
auc = roc_auc_score(y_test, y_prob)
print(f"Accuracy = {acc:.4f}")
print(f"ROC AUC  = {auc:.4f}")


# Važnost atributa
importances = pd.Series(model.feature_importances_, index=X.columns).sort_values(ascending=False)

print("\nFeature importance:")
for naziv, vrednost in importances.items():
    print(f"{naziv:25s} {vrednost:.6f}")

plt.barh(list(X.columns), model.feature_importances_)
plt.show()
Confusion matrix:
[[83 17]
 [22 32]]
Accuracy = 0.7468
ROC AUC  = 0.8133

Feature importance:
Glucose                   0.266073
BMI                       0.161420
Age                       0.130861
DiabetesPedigreeFunction  0.127089
BloodPressure             0.086335
Pregnancies               0.084277
Insulin                   0.073752
SkinThickness             0.070194

Zadatak za rad na času¶

Učitati bazu CustomerChurn.csv, izdvojiti ciljnu promenljivu Churn, a zatim podeliti podatke na trening, validacioni i test skup.

Istrenirati tri modela:

  • RandomForestClassifier
  • BaggingClassifier sa baznim modelom LogisticRegression
  • BaggingClassifier sa baznim modelom KNeighborsClassifier

Za svaki od ova tri modela pronaći što bolju kombinaciju hiperparametara. Nakon toga uporediti dobijene modele na test skupu.

Na kraju, spojiti ta tri najbolja modela pomoću klase VotingClassifier, istrenirati taj završni ansambl i proveriti da li kombinovani model daje bolje rezultate od pojedinačnih modela.

Klase BaggingClassifier, RandomForestClassifier i VotingClassifier nalaze se u paketu sklearn.ensemble.