نفاذ کی طرف سے سمجھنا: فیصلہ درخت

نفاذ کی طرف سے سمجھنا: فیصلہ درخت

ماخذ نوڈ: 1936824

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

بہت سے جدید مشین لرننگ ماڈلز جیسے بے ترتیب جنگلات یا گریڈینٹ بوسٹنگ الگورتھم جیسے XGBoost، CatBoost، یا LightGBM (اور یہاں تک کہ آٹو انکوڈرز!) ایک اہم عام جزو پر بھروسہ کریں: فیصلہ درخت!

فیصلے کے درختوں کو سمجھے بغیر، مذکورہ بالا ایڈوانس بیگنگ یا گریڈینٹ بڑھانے والے الگورتھم میں سے کسی کو بھی سمجھنا ناممکن ہے، جو کسی بھی ڈیٹا سائنسدان کے لیے باعثِ شرم ہے! تو آئیے ہم ازگر میں ایک کو لاگو کرکے فیصلہ سازی کے درخت کے اندرونی کاموں کو بے نقاب کرتے ہیں۔

اس مضمون میں ، آپ سیکھیں گے۔

  • فیصلہ درخت ڈیٹا کو کیوں اور کیسے تقسیم کرتا ہے،
  • معلومات کا حصول، اور
  • NumPy کا استعمال کرتے ہوئے ازگر میں فیصلے کے درختوں کو کیسے نافذ کیا جائے۔

آپ کوڈ پر تلاش کر سکتے ہیں۔ میرا گیتوب.

پیشن گوئی کرنے کے لئے، فیصلہ درختوں پر انحصار کرتے ہیں تقسیم ڈیٹاسیٹ کو بار بار چلنے والے انداز میں چھوٹے حصوں میں۔

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

اوپر کی تصویر میں، آپ تقسیم کی ایک مثال دیکھ سکتے ہیں — اصل ڈیٹاسیٹ دو حصوں میں الگ ہو جاتا ہے۔ اگلے مرحلے میں، یہ دونوں حصے دوبارہ تقسیم ہو جاتے ہیں، وغیرہ۔ یہ اس وقت تک جاری رہتا ہے جب تک کہ کسی قسم کے روکنے کا معیار پورا نہ ہو جائے، مثال کے طور پر،

  • اگر تقسیم کے نتیجے میں کوئی حصہ خالی ہوجاتا ہے۔
  • اگر ایک خاص تکرار کی گہرائی تک پہنچ گئی تھی۔
  • اگر (پچھلی تقسیم کے بعد) ڈیٹاسیٹ صرف چند عناصر پر مشتمل ہوتا ہے، مزید تقسیم کو غیر ضروری بناتا ہے۔

ہم ان تقسیموں کو کیسے تلاش کرتے ہیں؟ اور ہم کیوں پرواہ کرتے ہیں؟ آئیے معلوم کرتے ہیں۔

پریرتا

آئیے فرض کریں کہ ہم حل کرنا چاہتے ہیں۔ بائنری درجہ بندی کا مسئلہ کہ ہم خود کو اب تخلیق کرتے ہیں:

import numpy as np
np.random.seed(0) X = np.random.randn(100, 2) # features
y = ((X[:, 0] > 0) * (X[:, 1] < 0)) # labels (0 and 1)

دو جہتی ڈیٹا اس طرح لگتا ہے:

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

ہم دیکھ سکتے ہیں کہ دو مختلف طبقے ہیں - تقریباً 75% میں ارغوانی اور تقریباً 25% معاملات میں پیلا رنگ۔ اگر آپ اس ڈیٹا کو فیصلے کے درخت کو کھلاتے ہیں۔ درجہ بندی، اس درخت کے ابتدائی طور پر درج ذیل خیالات ہیں:

"دو مختلف لیبلز ہیں، جو میرے لیے بہت گندا ہے۔ میں ڈیٹا کو دو حصوں میں تقسیم کرکے اس گندگی کو صاف کرنا چاہتا ہوں — یہ حصے پہلے کے مکمل ڈیٹا سے زیادہ صاف ہونے چاہئیں۔ - درخت جس نے شعور حاصل کیا۔

اور اسی طرح درخت کرتا ہے۔

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

درخت تقریبا ساتھ ساتھ ایک تقسیم کرنے کا فیصلہ کرتا ہے x- محور اس کا اثر یہ ہے کہ ڈیٹا کا اوپری حصہ اب بالکل ٹھیک ہے۔ صاف ، اس کا مطلب ہے کہ آپ صرف تلاش کرتے ہیں۔ ایک کلاس (اس معاملے میں جامنی) وہاں۔

تاہم، نیچے کا حصہ اب بھی ہے گنداایک لحاظ سے پہلے سے بھی زیادہ گڑبڑ۔ مکمل ڈیٹاسیٹ میں کلاس کا تناسب تقریباً 75:25 ہوتا تھا، لیکن اس چھوٹے حصے میں یہ تقریباً 50:50 ہے، جو اتنا ہی ملایا جاتا ہے جتنا کہ یہ حاصل کر سکتا ہے۔

 نوٹ: یہاں، اس سے کوئی فرق نہیں پڑتا ہے کہ تصویر میں جامنی اور پیلے رنگ کو اچھی طرح سے الگ کیا گیا ہے۔ بس مختلف لیبلوں کی خام مقدار دو حصوں میں شمار.

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

پھر بھی، یہ درخت کے لیے پہلے قدم کے طور پر کافی اچھا ہے، اور اس طرح یہ چلتا رہتا ہے۔ اگرچہ یہ سب سے اوپر میں ایک اور تقسیم نہیں کرے گا، صاف حصہ اب، یہ اسے صاف کرنے کے لیے نیچے والے حصے میں ایک اور تقسیم بنا سکتا ہے۔

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

اور voilà، تین الگ الگ حصوں میں سے ہر ایک مکمل طور پر صاف ہے، کیونکہ ہمیں فی حصہ صرف ایک ہی رنگ (لیبل) ملتا ہے۔

اب پیشین گوئیاں کرنا واقعی آسان ہے: اگر کوئی نیا ڈیٹا پوائنٹ آتا ہے، تو آپ صرف چیک کریں کہ کس میں سے تین حصے یہ جھوٹ بولتا ہے اور اسے متعلقہ رنگ دیتا ہے۔ یہ اب اتنا اچھا کام کرتا ہے کیونکہ ہر ایک حصہ ہے۔ صاف. آسان، ٹھیک ہے؟

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

ٹھیک ہے، ہم بات کر رہے تھے۔ صاف اور گندا ڈیٹا لیکن اب تک یہ الفاظ صرف کچھ مبہم خیال کی نمائندگی کرتے ہیں۔ کسی بھی چیز کو عملی جامہ پہنانے کے لیے، ہمیں وضاحت کرنے کا راستہ تلاش کرنا ہوگا۔ صفائی.

صفائی کے لیے اقدامات

آئیے فرض کریں کہ ہمارے پاس کچھ لیبلز ہیں، مثال کے طور پر

y_1 = [0, 0, 0, 0, 0, 0, 0, 0] y_2 = [1, 0, 0, 0, 0, 0, 1, 0]
y_3 = [1, 0, 1, 1, 0, 0, 1, 0]

بدیہی طور پر ، y₁ لیبلز کا سب سے صاف سیٹ ہے، اس کے بعد y₂ اور پھر y₃. اب تک تو بہت اچھا ہے، لیکن ہم اس رویے پر نمبر کیسے ڈال سکتے ہیں؟ شاید سب سے آسان چیز جو ذہن میں آتی ہے وہ یہ ہے:

صرف صفر کی مقدار اور ان کی مقدار کو شمار کریں۔ ان کے مطلق فرق کا حساب لگائیں۔ اسے بہتر بنانے کے لیے، صفوں کی لمبائی میں تقسیم کرکے اسے نارمل کریں۔

مثال کے طور پر، y₂ کل 8 اندراجات ہیں — 6 صفر اور 2۔ لہذا، ہماری اپنی مرضی کے مطابق وضاحت صفائی کا سکور ہوگا |6 – 2| / 8 = 0.5۔ اس کی صفائی کے اسکور کا حساب لگانا آسان ہے۔ y₁ اور y₃ بالترتیب 1.0 اور 0.0 ہیں۔ یہاں، ہم عام فارمولہ دیکھ سکتے ہیں:

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

یہاں، n₀ اور n₁ بالترتیب صفر اور ایک کے نمبر ہیں، n = n₀ + n₁ صف کی لمبائی ہے اور p₁ = n₁ / n 1 لیبلز کا حصہ ہے۔

اس فارمولے کے ساتھ مسئلہ یہ ہے کہ یہ ہے۔ خاص طور پر دو کلاسوں کے معاملے کے مطابق، لیکن اکثر ہم کثیر طبقے کی درجہ بندی میں دلچسپی رکھتے ہیں۔ ایک فارمولہ جو کافی اچھی طرح سے کام کرتا ہے وہ ہے۔ جنی نجاست کی پیمائش:

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

یا عام معاملہ:

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

یہ اتنا اچھا کام کرتا ہے کہ سیکھیں۔ اسے پہلے سے طے شدہ اقدام کے طور پر اپنایا اس کے لئے DecisionTreeClassifier کلاس.

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 نوٹ: گنی کے اقدامات گندگی صفائی کے بجائے مثال: اگر ایک فہرست میں صرف ایک کلاس (=بہت صاف ڈیٹا!) شامل ہے، تو جمع میں تمام اصطلاحات صفر ہیں، اس لیے جمع صفر ہے۔ بدترین صورت یہ ہے کہ اگر تمام کلاسز صحیح تعداد میں ظاہر ہوں، اس صورت میں Gini 1–1/ ہے۔C کہاں C کلاسوں کی تعداد ہے۔

اب جب کہ ہمارے پاس صفائی/گڑبڑ کے لیے ایک پیمانہ ہے، آئیے دیکھتے ہیں کہ اسے اچھی تقسیم تلاش کرنے کے لیے کیسے استعمال کیا جا سکتا ہے۔

تقسیم تلاش کرنا

بہت ساری تقسیمیں ہیں جن میں سے ہم انتخاب کرتے ہیں، لیکن کون سا اچھا ہے؟ آئیے ہم اپنے ابتدائی ڈیٹاسیٹ کو Gini ناپاکی کی پیمائش کے ساتھ دوبارہ استعمال کریں۔

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

اب ہم پوائنٹس کو شمار نہیں کریں گے، لیکن آئیے فرض کریں کہ 75% ارغوانی اور 25% پیلے ہیں۔ Gini کی تعریف کا استعمال کرتے ہوئے، مکمل ڈیٹاسیٹ کی نجاست ہے۔

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

اگر ہم ڈیٹاسیٹ کو اس کے ساتھ تقسیم کرتے ہیں۔ xمحور، جیسا کہ پہلے کیا گیا تھا:

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

۔ اوپر والے حصے میں 0.0 کی Gini ناپاکی ہے۔ اور نیچے کا حصہ

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

 

اوسطاً، دونوں حصوں میں (0.0 + 0.5) / 2 = 0.25 کی Gini ناپاکی ہے، جو کہ پہلے سے پورے ڈیٹا سیٹ کے 0.375 سے بہتر ہے۔ ہم اس کا اظہار نام نہاد کے حوالے سے بھی کر سکتے ہیں۔ معلومات حاصل:

اس تقسیم کا معلوماتی فائدہ 0.375 - 0.25 = 0.125 ہے۔

اس کے طور پر آسان. معلومات کا حصول جتنا زیادہ ہوگا (یعنی گنی کی نجاست جتنی کم ہوگی)، اتنا ہی بہتر ہے۔

نوٹ: ایک اور اتنی ہی اچھی ابتدائی تقسیم y-axis کے ساتھ ہوگی۔

ذہن میں رکھنے کے لئے ایک اہم بات یہ ہے کہ یہ مفید ہے پرزوں کے سائز کے حساب سے پرزوں کی گنی نجاست کا وزن کریں۔. مثال کے طور پر، ہم یہ فرض کرتے ہیں

  • حصہ 1 50 ڈیٹا پوائنٹس پر مشتمل ہے اور اس میں Gini ناپاکی 0.0 اور ہے۔
  • حصہ 2 450 ڈیٹا پوائنٹس پر مشتمل ہے اور اس میں Gini ناپاکی 0.5 ہے،

پھر اوسط گنی نجاست (0.0 + 0.5) / 2 = 0.25 نہیں ہونی چاہئے بلکہ 50 / (50 + 450) * 0.0 + 450 / (50 + 450) * 0.5 = 0.45.

ٹھیک ہے، اور ہم بہترین تقسیم کیسے تلاش کرتے ہیں؟ اس کا سادہ مگر سنجیدہ جواب ہے:

بس تمام تقسیموں کو آزمائیں اور سب سے زیادہ معلومات حاصل کرنے والے کو منتخب کریں۔ یہ بنیادی طور پر ایک وحشیانہ طاقت کا طریقہ ہے۔

زیادہ درست ہونے کے لیے، معیاری فیصلہ کرنے والے درخت استعمال کرتے ہیں۔ کوآرڈینیٹ محور کے ساتھ تقسیم ہوتا ہے۔یعنی xᵢ = c کچھ خصوصیت کے لئے i اور دہلیز c. اس کا مطلب یہ ہے کہ

  • اسپلٹ ڈیٹا کا ایک حصہ تمام ڈیٹا پوائنٹس پر مشتمل ہوتا ہے۔ ساتھ xᵢ cاور
  • تمام پوائنٹس کا دوسرا حصہ x ساتھ xᵢ ≥ c.

یہ سادہ تقسیم کرنے والے اصول عملی طور پر کافی اچھے ثابت ہوئے ہیں، لیکن آپ یقیناً اس منطق کو دوسرے اسپلٹس بنانے کے لیے بھی بڑھا سکتے ہیں (یعنی ترچھی لکیریں جیسے xᵢ + 2xⱼ = 3، مثال کے طور پر).

بہت اچھا، یہ وہ تمام اجزاء ہیں جن کی ہمیں ابھی جانے کی ضرورت ہے!

ہم فیصلہ درخت کو اب نافذ کریں گے۔ چونکہ یہ نوڈس پر مشتمل ہے، آئیے اس کی وضاحت کرتے ہیں۔ Node پہلی کلاس.

from dataclasses import dataclass @dataclass
class Node: feature: int = None # feature for the split value: float = None # split threshold OR final prediction left: np.array = None # store one part of the data right: np.array = None # store the other part of the data

ایک نوڈ اس خصوصیت کو جانتا ہے جسے وہ تقسیم کرنے کے لیے استعمال کرتا ہے (feature) نیز تقسیم کی قدر (value). value فیصلہ درخت کی حتمی پیشین گوئی کے لیے ذخیرہ کے طور پر بھی استعمال ہوتا ہے۔ چونکہ ہم ایک بائنری ٹری بنائیں گے، ہر نوڈ کو اپنے بائیں اور دائیں بچوں کو جاننے کی ضرورت ہے، جیسا کہ اس میں محفوظ ہے۔ left اور right .

اب، آئیے اصل فیصلے کے درخت پر عمل درآمد کرتے ہیں۔ میں اسے اسکیٹ لرن کے موافق بنا رہا ہوں، اس لیے میں اس سے کچھ کلاسز استعمال کرتا ہوں۔ sklearn.base . اگر آپ اس سے واقف نہیں ہیں تو میرا مضمون دیکھیں سکیٹ سیکھنے کے موافق ماڈل بنانے کا طریقہ.

آئیے لاگو کریں!

import numpy as np
from sklearn.base import BaseEstimator, ClassifierMixin class DecisionTreeClassifier(BaseEstimator, ClassifierMixin): def __init__(self): self.root = Node() @staticmethod def _gini(y): """Gini impurity.""" counts = np.bincount(y) p = counts / counts.sum() return (p * (1 - p)).sum() def _split(self, X, y): """Bruteforce search over all features and splitting points.""" best_information_gain = float("-inf") best_feature = None best_split = None for feature in range(X.shape[1]): split_candidates = np.unique(X[:, feature]) for split in split_candidates: left_mask = X[:, feature] split X_left, y_left = X[left_mask], y[left_mask] X_right, y_right = X[~left_mask], y[~left_mask] information_gain = self._gini(y) - ( len(X_left) / len(X) * self._gini(y_left) + len(X_right) / len(X) * self._gini(y_right) ) if information_gain > best_information_gain: best_information_gain = information_gain best_feature = feature best_split = split return best_feature, best_split def _build_tree(self, X, y): """The heavy lifting.""" feature, split = self._split(X, y) left_mask = X[:, feature] split X_left, y_left = X[left_mask], y[left_mask] X_right, y_right = X[~left_mask], y[~left_mask] if len(X_left) == 0 or len(X_right) == 0: return Node(value=np.argmax(np.bincount(y))) else: return Node( feature, split, self._build_tree(X_left, y_left), self._build_tree(X_right, y_right), ) def _find_path(self, x, node): """Given a data point x, walk from the root to the corresponding leaf node. Output its value.""" if node.feature == None: return node.value else: if x[node.feature] node.value: return self._find_path(x, node.left) else: return self._find_path(x, node.right) def fit(self, X, y): self.root = self._build_tree(X, y) return self def predict(self, X): return np.array([self._find_path(x, self.root) for x in X])

اور یہ بات ہے! آپ اب وہ تمام چیزیں کر سکتے ہیں جو آپ کو اسکِٹ سیکھنے کے بارے میں پسند ہیں:

dt = DecisionTreeClassifier().fit(X, y)
print(dt.score(X, y)) # accuracy # Output
# 1.0

چونکہ درخت غیر منظم ہے، یہ بہت زیادہ فٹ ہو رہا ہے، اس لیے ٹرین کا بہترین سکور ہے۔ نادیدہ ڈیٹا پر درستگی بدتر ہوگی۔ ہم یہ بھی چیک کر سکتے ہیں کہ درخت کیسا لگتا ہے۔

print(dt.root) # Output (prettified manually):
# Node(
# feature=1,
# value=-0.14963454032767076,
# left=Node(
# feature=0,
# value=0.04575851730144607,
# left=Node(
# feature=None,
# value=0,
# left=None,
# right=None
# ),
# right=Node(
# feature=None,
# value=1,
# left=None,
# right=None
# )
# ),
# right=Node(
# feature=None,
# value=0,
# left=None,
# right=None
# )
# )

تصویر کے طور پر، یہ ہو گا:

 

نفاذ کی طرف سے سمجھنا: فیصلہ درخت
مصنف کی طرف سے تصویر

اس مضمون میں، ہم نے دیکھا ہے کہ فیصلے کے درخت کس طرح کام کرتے ہیں۔ ہم نے کچھ مبہم، لیکن بدیہی خیالات کے ساتھ شروعات کی اور انہیں فارمولوں اور الگورتھم میں بدل دیا۔ آخر میں، ہم شروع سے فیصلہ سازی کے درخت کو نافذ کرنے میں کامیاب ہو گئے۔

اگرچہ احتیاط کا ایک لفظ: ہمارے فیصلے کے درخت کو ابھی تک باقاعدہ نہیں بنایا جا سکتا۔ عام طور پر، ہم جیسے پیرامیٹرز کی وضاحت کرنا چاہیں گے۔

  • زیادہ سے زیادہ گہرائی
  • پتی کا سائز
  • اور کم سے کم معلومات کا حصول

بہت سے دوسرے کے درمیان. خوش قسمتی سے، ان چیزوں کو نافذ کرنا اتنا مشکل نہیں ہے، جس کی وجہ سے یہ آپ کے لیے ایک بہترین ہوم ورک ہے۔ مثال کے طور پر، اگر آپ وضاحت کرتے ہیں۔ leaf_size=10 پیرامیٹر کے طور پر، پھر 10 سے زیادہ نمونوں پر مشتمل نوڈس کو مزید تقسیم نہیں کیا جانا چاہیے۔ اس کے علاوہ، یہ عمل درآمد ہے موثر نہیں. عام طور پر، آپ ڈیٹاسیٹس کے کچھ حصوں کو نوڈس میں ذخیرہ نہیں کرنا چاہیں گے، بلکہ اس کے بجائے صرف انڈیکس کو ذخیرہ کرنا چاہیں گے۔ لہذا آپ کا (ممکنہ طور پر بڑا) ڈیٹاسیٹ صرف ایک بار میموری میں ہے۔

اچھی بات یہ ہے کہ آپ اس فیصلے کے درخت کے سانچے کے ساتھ اب پاگل ہو سکتے ہیں۔ آپ کر سکتے ہیں:

  • ترچھی تقسیم کو نافذ کریں، یعنی xᵢ + 2xⱼ = 3 بجائے انصاف کی xᵢ = 3،
  • پتوں کے اندر ہونے والی منطق کو تبدیل کریں، یعنی آپ صرف اکثریتی ووٹ دینے کے بجائے ہر پتے کے اندر لاجسٹک ریگریشن چلا سکتے ہیں، جس سے آپ کو ایک لکیری درخت
  • تقسیم کرنے کے طریقہ کار کو تبدیل کریں، یعنی بروٹ فورس کرنے کے بجائے، کچھ بے ترتیب امتزاج آزمائیں اور بہترین کو چنیں، جو آپ کو اضافی درخت کی درجہ بندی کرنے والا
  • اور زیادہ.

 
 
ڈاکٹر رابرٹ کوبلر پبلکس میڈیا میں ڈیٹا سائنٹسٹ اور Towards Data Science میں مصنف ہیں۔

 
حقیقی. اجازت کے ساتھ دوبارہ پوسٹ کیا۔
 

ٹائم اسٹیمپ:

سے زیادہ KDnuggets