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.
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.
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.
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)
| 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 |
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
# 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
Učitati bazu CustomerChurn.csv, izdvojiti ciljnu promenljivu Churn, a zatim podeliti podatke na trening, validacioni i test skup.
Istrenirati tri modela:
RandomForestClassifierBaggingClassifier sa baznim modelom LogisticRegressionBaggingClassifier sa baznim modelom KNeighborsClassifierZa 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.