Table of Contents
निर्णय पेड़ वर्गीकरण और प्रतिगमन दोनों के लिए सबसे सहज और व्यापक रूप से इस्तेमाल की जाने वाली मशीन लर्निंग एल्गोरिदम में से एक हैं। वे फीचर मूल्यों के आधार पर शाखाओं में डेटा को विभाजित करके काम करते हैं, जिस तरह से मनुष्य निर्णय लेते हैं। जबकि स्किट-लर्न जैसे पुस्तकालयों ने इमारत निर्णय पेड़ों को आदिवासी बना दिया है, जो स्क्रैच से एक को लागू करने के लिए शुरुआती लोगों के लिए एल्गोरिथ्म के आंतरिक कार्यों को समझने का एक शानदार तरीका है। यह ट्यूटोरियल आपको सिद्धांत और कोड के माध्यम से मार्गदर्शन करेगा, ताकि आप जमीन से अपना खुद का निर्णय पेड़ बना सकें।
क्या एक निर्णय वृक्ष है?
एक निर्णय पेड़ एक फ्लोचार्ट जैसी संरचना है जहां प्रत्येक आंतरिक नोड एक विशेषता पर एक परीक्षण का प्रतिनिधित्व करता है (जैसे, "Is age > 30?"), प्रत्येक शाखा उस परीक्षण के परिणाम का प्रतिनिधित्व करती है, और प्रत्येक पत्ती नोड में एक वर्ग लेबल या निरंतर मूल्य होता है। लक्ष्य एक मॉडल बनाना है जो डेटा सुविधाओं से प्रभावित सरल निर्णय नियमों को सीखकर एक लक्ष्य परिवर्तनीय की भविष्यवाणी करता है। निर्णय पेड़ लोकप्रिय हैं क्योंकि वे व्याख्या करना आसान हैं और कम डेटा प्रीप्रोसेसिंग (कोई स्केलिंग या सामान्यीकरण नहीं) की आवश्यकता होती है।
पेड़ को बार-बार बनाया गया है: जड़ से शुरू होने पर, एल्गोरिथ्म सबसे अच्छी विशेषता और विभाजन बिंदु का चयन करता है जो डेटा को सबसे साफ रूप से अलग करता है। इस प्रक्रिया को प्रत्येक उपसेट पर तब तक दोहराया जाता है जब तक कि एक रोक की स्थिति पूरी हो जाती है। अधिक पृष्ठभूमि के लिए, विकिपीडिया के निश्चय वृक्ष सीखने पर प्रवेश एक ठोस अवलोकन प्रदान करता है।
कोर अवधारणाओं को आप को समझना चाहिए
नोड्स, शाखाओं और पत्तियों
जड़ नोड में संपूर्ण प्रशिक्षण डेटासेट शामिल है। आंतरिक नोड्स एक विशेषता का परीक्षण करते हैं और डेटा को दो या दो से अधिक बच्चे नोड्स में विभाजित करते हैं। शाखाएँ कनेक्शन हैं जो परीक्षण के परिणाम का प्रतिनिधित्व करती हैं। लीफ नोड्स (टर्मिनल नोड्स) अंतिम भविष्यवाणी का उत्पादन करते हैं - वर्गीकरण में सबसे आम वर्ग या प्रतिगमन में औसत मूल्य।
विभाजन मानदंड
एक पेड़ बनाने के लिए, आपको संभावित विभाजन की गुणवत्ता को मापने का एक तरीका चाहिए। सबसे आम मानदंड हैं:
- Gini impurity - यह मापने के लिए वर्गीकरण में प्रयोग किया जाता है कि कितनी बार एक बेतरतीब ढंग से चुना तत्व गलत तरीके से लेबल किया जाएगा यदि यह यादृच्छिक रूप से सबसेट में कक्षाओं के वितरण के अनुसार लेबल किया गया था। लोअर गिनी बेहतर है।
- Entropy – एक सेट में विकार या अनिश्चितता की मात्रा को मापता है। लक्ष्य विभाजन (सूचना लाभ) के बाद एन्ट्रापी को कम करना है।
- Variance कमी - प्रतिगमन पेड़ों के लिए इस्तेमाल किया। यह विभाजन द्वारा हासिल की गई विविधता (या मतलब वर्ग त्रुटि) में कमी की गणना करता है।
एल्गोरिथ्म हर संभव पर विभाजित का मूल्यांकन करता है और वह चुनता है जो अशुद्धता में सबसे बड़ा कमी (या जानकारी में लाभ) पैदा करता है।
सूचना लाभ और लाभ अनुपात
सूचना लाभ माता-पिता नोड की अशुद्धता और बच्चे की अशुद्धियों के भारित योग के बीच का अंतर है। जबकि सरल, यह कई मूल्यों के साथ सुविधाओं का पक्ष लेता है। लाभ अनुपात (C4.5 में उपयोग किया जाता है) इसे सामान्य करता है। इस ट्यूटोरियल के लिए हम गिनी अशुद्धता का उपयोग करके मानक सूचना लाभ के साथ चिपके रहेंगे, जो CART (वर्गीकरण और प्रतिगमन पेड़) में डिफ़ॉल्ट है।
एक निर्णय का निर्माण करना
1. अपना डेटा तैयार करें
आपको सुविधाओं और लक्ष्य लेबल के साथ डेटासेट की आवश्यकता है। सादगी के लिए, संख्यात्मक विशेषताओं के साथ द्विआधारी वर्गीकरण डेटासेट का उपयोग करें। उदाहरण के लिए:
- Features:] Age, आय
- ]Target: स्वीकृत (1) या स्वीकृत नहीं (0)
डेटा को साफ करें: लापता मानों को संभालें, डुप्लिकेट को हटा दें और संख्यात्मक प्रकार को सुनिश्चित करें। निर्णय पेड़ मिश्रित डेटा प्रकारों को संभाल सकते हैं लेकिन हम कार्यान्वयन के लिए संख्यात्मक के लिए छड़ी करेंगे।
2. एक विभाजन मानदंड समारोह को परिभाषित करें
हम गिनी अशुद्धता को लागू करेंगे। आइटम के एक सेट के लिए गिनी सूचकांक है:
]]
जहां p i कक्षा में वस्तुओं का अनुपात है i.बाइनरी विभाजन के लिए, समग्र गिनी बच्चे नोड्स का भारित औसत है।
3. विभाजन मूल्यांकन को लागू करना
प्रत्येक सुविधा के लिए, अद्वितीय मानों को क्रमबद्ध करें। प्रत्येक संभावित सीमा ( लगातार छंटनी मानों के बीच इंगित) का परीक्षण करें। प्रत्येक उम्मीदवार सीमा के लिए, डेटा को बाएं और दाएं समूहों में विभाजित करें, गिनी को गणना करें और सर्वश्रेष्ठ विभाजन को ट्रैक करें।
4. ट्री को पुनरावर्ती रूप से बनाएं
एक ऐसा कार्य बनाएँ जो डेटा की एक उपसेट और एक वर्तमान गहराई को लेता है। यह स्थिति को रोकने की जाँच करता है (उदाहरण के लिए, अधिकतम गहराई तक पहुंच जाती है, न्यूनतम नमूने प्रति नोड, या कोई सूचना लाभ नहीं)। यदि कोई शर्त मिलती है, तो बहुमत वर्ग के साथ एक पत्ती नोड बनाएं। अन्यथा, सबसे अच्छा विभाजन ढूंढें और एक आंतरिक नोड बनायें, फिर से बाएं और दाएं विभाजन पर कार्य को कॉल करें।
5. भविष्यवाणियों को बनाना
एक बार पेड़ बनाया जाता है, भविष्यवाणी सीधा है: जड़ पर शुरू, नए नमूने पर फीचर टेस्ट का मूल्यांकन करके शाखाओं का पालन करें, और उस पर आपके द्वारा जमीन के पत्ते के मूल्य को वापस लौटा दें।
पायथन में पूर्ण कार्यान्वयन
नीचे गिनी अशुद्धता का उपयोग करके वर्गीकरण के लिए एक निर्णय पेड़ का एक पूरा, न्यूनतम कार्यान्वयन है। यह कोड सीखने के लिए है - यह बड़े डेटासेट के लिए अनुकूलित नहीं है।
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'])
पेड़ का परीक्षण
क्लासिक आइरिस डेटासेट (बाइनरी वर्गीकरण के लिए दो विशेषताएं) की तरह एक सरल डेटासेट का उपयोग करें। scikit-learn Iris dataset अच्छी तरह से काम करता है। scikit-learn's ] के साथ अपने पेड़ की सटीकता की तुलना करने के लिए सही ढंग से सत्यापित करने के लिए।
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}')
अपने पेड़ में सुधार करने के लिए उन्नत तकनीक
ओवरफिटिंग से बचने के लिए
एक पूरी तरह से विकसित पेड़ प्रशिक्षण डेटा में शोर को याद कर सकता है। प्रूनिंग उन शाखाओं को हटा देता है जिनमें कम पूर्वानुमान शक्ति होती है। आम तरीकों में पूर्व-प्रूनिंग (] या ]]]]) के माध्यम से विकास को रोकना है और पोस्ट-प्रूनिंग (पूरे पेड़ को उगाना तब वैधीकरण सेट या लागत-संयोजन छंटाई का उपयोग करके शाखाओं को हटा देना)। हमारे कार्यान्वयन पहले से ही पूर्व-प्रदूषण का समर्थन करता है।
सतत और कैटेगरिकल सुविधाओं को संभालने
निरंतर सुविधाओं के लिए, हम छंटनी मूल्यों के बीच मिडपॉइंट्स का उपयोग थ्रेसहोल्ड के रूप में करते थे। श्रेणीबद्ध विशेषताओं (जैसे, "रंग = लाल / हरे / नीले") के लिए, प्रत्येक श्रेणी एक अलग शाखा (मल्टी-वे स्प्लिट) बन सकती है या आप द्विआधारी-कोड कर सकते हैं। अधिकांश आधुनिक कार्यान्वयन (जैसे स्किकिट-लर्न) सभी उप-सेटों का मूल्यांकन करके श्रेणीबद्ध विशेषताओं के लिए भी द्विआधारी विभाजन का उपयोग करते हैं।
मिसिंग वैल्यू से निपटने
रियल-वर्ल्ड डेटा में अक्सर लापता मान होते हैं। एक सरल दृष्टिकोण प्रशिक्षण नमूनों के बीच सबसे अधिक बार लापता मानों को असाइन करना है जिसमें सुविधा होती है। C4.5 एक probabilistic विधि का उपयोग करता है। चूंकि यह एक शुरुआती ट्यूटोरियल है, इसलिए हम मानते हैं कि डेटा पूरा हो गया है।
पुस्तकालयों और आगे पढ़ने की तुलना में
खरोंच से निर्माण शैक्षिक है, उत्पादन प्रणाली में पुस्तकालयों का उपयोग किया जाता है जैसे कि स्किकिट-लर्निंग जो अनुकूलन सी कार्यान्वयन प्रदान करती है। आप आधिकारिक scikit-learn निर्णय पेड़ प्रलेखन से अधिक सीख सकते हैं। गहरे सिद्धांत के लिए, किताब "स्टैस्टीटिकल लर्निंग के तत्व" हस्टी, तिब्शीरानी द्वारा, और फ्राइडमैन एक आधिकारिक संसाधन है। एक और उत्कृष्ट संदर्भ ब्रेमैन एट अल द्वारा मूल CART पुस्तक है।
निष्कर्ष
स्क्रैच से एक निर्णय पेड़ का निर्माण मशीन लर्निंग में सबसे बुनियादी एल्गोरिदम में से एक को नष्ट कर देता है। आपने सीखा है कि एक सरल पुनरावर्ती विभाजन प्रक्रिया एक शक्तिशाली मॉडल का उत्पादन कर सकती है। कोड को स्वयं लिखते हुए, आप अशुद्धता उपायों, विभाजन चयन और पूर्वाग्रह और परिवर्तन के बीच व्यापार-बंदी की गहरी समझ प्राप्त करते हैं। अगले चरण के रूप में, पुनरावर्तन समर्थन, छंटाई, या वर्गीकरण सुविधाओं को संभालने की कोशिश करते हैं। आप यहां विकसित कौशल आपको अच्छी तरह से काम करेंगे क्योंकि आप यादृच्छिक जंगलों और ढाल बढ़ाने जैसे जटिल पहनाव विधियों पर जाते हैं।