Table of Contents
Arborii de decizie sunt unul dintre cele mai intuitive și utilizate algoritmi de învățare mașină de mare scară pentru atât clasificarea și regresie. Ei lucrează prin divizarea datelor în ramuri bazate pe valori caracteristice, imitarea modul în care oamenii iau decizii. În timp ce bibliotecile, cum ar fi scikit-learn face copacii de decizie de construcție trivial, implementarea unul de la zero este o modalitate excelentă pentru începători pentru a înțelege algoritmul ți funcționează interior. Acest tutorial vă va ghida prin teorie și cod, astfel încât să puteți construi propriul arbore de decizie de la sol în sus.
Ce este un copac al deciziei?
Un arbore decizional este o structură de tip flowchart, în care fiecare nod intern reprezintă un test pe o caracteristică (de exemplu,
Copacul este construit recursiv: pornind de la rădăcină, algoritmul selectează cea mai bună caracteristică și punct de divizare care separă datele cel mai curat. Acest proces este repetat pe fiecare subset până când este îndeplinită o condiție de oprire. Pentru mai mult fundal, Wikipedia
Concepte fundamentale trebuie să înțelegeți
Noduri, ramuri şi frunze
Nodul rădăcină conține întregul set de date de formare. Nodurile interne testa o caracteristică și împărțite datele în două sau mai multe noduri pentru copii. Ramurile sunt conexiunile care reprezintă rezultatul unui test. Noduri de frunze (noduri terminale) ieșire predicție finală
Criterii de divizare
Pentru a construi un copac, aveți nevoie de o modalitate de a măsura calitatea unei potențiale împărțiri. Cele mai comune criterii sunt:
- Gini impurity[
- Entropia
- Reducere a variabilității
Algoritmul evaluează fiecare fragment posibil al fiecărei caracteristici și îl alege pe cel care produce cea mai mare reducere a impurităţii (sau câștigul în informații).
Rata de câștig și câștig a informațiilor
Câștigarea informațiilor este diferența dintre impuritatea nodului părinte și suma ponderată a impurităților copilului. Deși simplă, ea tinde să favorizeze caracteristicile cu multe valori. Raportul câștig (utilizat în C4.5) normalizează acest lucru. Pentru acest tutorial vom rămâne cu câștigul standard de informații folosind impuritate Gini, care este implicit în CART (Clasificare și Revenire Trees).
Construirea unui copac de decizie pas cu pas
1. Pregătiți datele
Aveți nevoie de un set de date cu caracteristici și etichete țintă. Pentru simplitate, utilizați un set de date binar de clasificare cu caracteristici numerice. De exemplu:
- Caracteristici: Vârsta, venitul
- Ţinta: Aprobat (1) sau neaprobat (0)
Curățați datele: mânuiți valorile lipsă, eliminați duplicatele și asigurați-vă că tipurile numerice. Arborii decizionali pot gestiona tipurile de date mixte, dar vom rămâne la numeric pentru implementare.
2. Definirea unei funcții de criteriu de divizare
Vom implementa impuritatea Gini. Indexul Gini pentru un set de elemente este:
unde p i este proporția de elemente din clasa i. Pentru o divizare binară, Gini este media ponderată a nodurilor pentru copii.
3. Punerea în aplicare a evaluării de divizare
Pentru fiecare caracteristică, sortați valorile unice. Testați fiecare prag posibil (mijlocul dintre valorile consecutive sortate). Pentru fiecare prag candidat, împărțiți datele în grupuri stânga și dreapta, calculați Gini și urmăriți cea mai bună împărțire.
4. Construi copacul recursiv
Creați o funcție care ia un subset de date și o adâncime curentă. Ea verifică condițiile de oprire (de exemplu, adâncimea maximă atinsă, eșantioane minime per nod sau niciun câștig de informații). Dacă o condiție este îndeplinită, creați un nod de frunze cu clasa majoritară. Altfel, găsiți cel mai bun despărțit și creați un nod intern, apoi apelați recursiv funcția pe partea stângă și dreapta se divide.
5. Face predicții
Odată ce copacul este construit, predicția este simplă: începeți de la rădăcină, urmați ramurile prin evaluarea testelor de caracteristici pe noua mostră, și returnați valoarea frunzei pe care aterizați.
Implementare completă în Python
Mai jos este o implementare completă, minimă a unui arbore decizional pentru clasificarea folosind impuritate Gini. Acest cod este destinat pentru învățare
import numpy as np
from collections import Counter
class DecisionTree:
def __init__(self, max_depth=None, min_samples_split=2):
self.max_depth = max_depth
self.min_samples_split = min_samples_split
self.tree = None
def fit(self, X, y):
dataset = np.column_stack((X, y))
self.tree = self._grow_tree(dataset)
def _grow_tree(self, dataset, depth=0):
X, y = dataset[:, :-1], dataset[:, -1]
n_samples, n_features = X.shape
n_labels = len(np.unique(y))
# Stopping conditions
if (n_labels == 1 or depth == self.max_depth or n_samples < self.min_samples_split):
leaf_value = Counter(y).most_common(1)[0][0]
return {'leaf': True, 'value': leaf_value}
best_feature, best_threshold = self._best_split(dataset, n_features)
if best_feature is None:
leaf_value = Counter(y).most_common(1)[0][0]
return {'leaf': True, 'value': leaf_value}
left_idx, right_idx = self._split(dataset[:, best_feature], best_threshold)
left_subtree = self._grow_tree(dataset[left_idx], depth+1)
right_subtree = self._grow_tree(dataset[right_idx], depth+1)
return {'leaf': False,
'feature': best_feature,
'threshold': best_threshold,
'left': left_subtree,
'right': right_subtree}
def _best_split(self, dataset, n_features):
best_gini = float('inf')
best_feature, best_threshold = None, None
for feature in range(n_features):
thresholds = np.unique(dataset[:, feature])
for i in range(len(thresholds)-1):
thresh = (thresholds[i] + thresholds[i+1]) / 2
left_idx, right_idx = self._split(dataset[:, feature], thresh)
if len(left_idx) == 0 or len(right_idx) == 0:
continue
gini = self._gini_gain(dataset, left_idx, right_idx)
if gini < best_gini:
best_gini = gini
best_feature = feature
best_threshold = thresh
return best_feature, best_threshold
def _split(self, values, threshold):
left_idx = np.where(values <= threshold)[0]
right_idx = np.where(values > threshold)[0]
return left_idx, right_idx
def _gini_gain(self, dataset, left_idx, right_idx):
total = len(left_idx) + len(right_idx)
gini_left = self._gini(dataset[left_idx, -1])
gini_right = self._gini(dataset[right_idx, -1])
return (len(left_idx)/total) * gini_left + (len(right_idx)/total) * gini_right
def _gini(self, labels):
_, counts = np.unique(labels, return_counts=True)
p = counts / np.sum(counts)
return 1 - np.sum(p**2)
def predict(self, X):
return np.array([self._predict_row(x, self.tree) for x in X])
def _predict_row(self, x, node):
if node['leaf']:
return node['value']
if x[node['feature']] <= node['threshold']:
return self._predict_row(x, node['left'])
else:
return self._predict_row(x, node['right'])
Testarea copacului
Utilizați un set de date simplu, cum ar fi setul clasic de iris (două caracteristici pentru clasificarea binară). scikit-learn Iris Set ] funcționează bine. Comparați precizia copacului dumneavoastră ți-s cu scikit-learn . pentru a verifica corectitudinea.
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
data = load_iris()
X = data.data[:100] # take only first two classes (binary)
y = data.target[:100]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
tree = DecisionTree(max_depth=3)
tree.fit(X_train, y_train)
preds = tree.predict(X_test)
accuracy = np.mean(preds == y_test)
print(f'Accuracy: {accuracy:.2f}')
Tehnici avansate pentru a vă îmbunătăţi arborele
Prăjirea pentru a evita supraadaptarea
Un copac matur poate memora zgomotul în datele de formare. Prunning elimină ramurile care au putere predictivă mică. Metodele comune sunt pre-prunting (oprește creșterea timpurie prin sau ) și post-prunting (creștind arborele complet apoi eliminarea ramurilor folosind un set de validare sau de calcul al complexității costurilor). Implementarea noastră sprijină deja pre-prunting.
Manipularea caracteristicilor continue și categorii
Pentru caracteristici continue, am folosit punctele de mijloc între valorile sortate ca praguri. Pentru caracteristicile categorice (de exemplu,
Să ne ocupăm de valorile lipsă
Datele din lumea reală au adesea valori lipsă. O abordare simplă este de a atribui valorile lipsă celei mai frecvente ramuri dintre probele de formare care au caracteristica. C4.5 utilizează o metodă probabilistică. Deoarece acesta este un tutorial începător, presupunem că datele sunt complete.
Compararea cu bibliotecile şi citirea ulterioară
În timp ce construirea de la zero este educaţională, sistemele de producţie folosesc biblioteci cum ar fi scitit-learn care oferă implementări optimizate C. Puteţi afla mai multe de la oficial scikit-learn decizie copaci documentaţie. Pentru teoria mai profundă, cartea
Concluzie
Construirea unui copac de decizie de la zero demistifiază unul dintre algoritmii cei mai fundamentali în învățarea mașinii. Ați învățat cum o procedură simplă de divizare recursivă poate produce un model puternic. Prin scrierea codului singur, veți obține o înțelegere mai profundă a măsurilor de impuritate, selecție împărțită, și compromisurile între prejudecată și varianță. Ca un pas următor, încercați adăugarea suport de regresie, tăiere, sau manipularea caracteristicilor categorice. Abilitățile pe care le dezvoltați aici vă va servi bine și vă mutați la metode mai complexe ansamblu, cum ar fi pădurile aleatoare și creșterea gradientului.