עצי ההחלטות הם אחד האלגוריתמים האינטואיטיביים והנפוצים ביותר ללמידה מכונה עבור סיווג ותוקפנות.הם עובדים על ידי פיצול נתונים לתוך סניפי מבוסס על ערכים תכונה, מחקה את הדרך שבה בני האדם מקבלים החלטות.בעוד שספריות כמו פיסול למידה לומדים לקבל החלטות בנייה עצים טריוויאליים, יישום אחד מאפס הוא דרך מצוינת למתחילים לתפוס את העבודה הפנימית של האלגוריתם.

מהו עץ החלטות?

עץ החלטות הוא מבנה דמוי זרימה שבו כל צומת פנימי מייצג מבחן על תכונה (למשל, "גיל > 30?"), כל ענף מייצג את התוצאה של הבדיקה, וכל עלה מחזיק תווית ייצוגית או ערך מתמשך.המטרה היא ליצור מודל החיזוי של שינוי מטרה על ידי לימוד כללי החלטה פשוטים שמקורם בתכונות של החלטות הן פופולריות כי הם קלים לפרש נתונים או להגביל את הקריטריונים (ללא נתונים סטנדרטיים).

העץ בנוי באופן חוזר: החל מהשורש, האלגוריתם בוחר את הנקודה הטובה ביותר ונקודת הפיצולית המפרידה את הנתונים בצורה הנקיה ביותר.תהליך זה חוזר על כל תת-קבוצה עד למצב עצירה ייפגש.

מושגים שאתם חייבים להבין

צומת, שמיכות ועוזבים

שורש node מכיל את כל נתוני האימון. nodes לבחון תכונה ופיצו את הנתונים לשני צמתים או יותר של ילד.עבלים הם הקשרים המייצגים את התוצאה של מבחן.

פיצול קריטריה

כדי לבנות עץ, אתה צריך דרך למדוד את איכות התפצלות פוטנציאלית.הקריטריונים הנפוצים ביותר הם:

  • (FLT:0Gini ImpurityFLT:1) - בשימוש במונח כדי למדוד באיזו תדירות אלמנט שנבחר באופן אקראי יהיה מסומן באופן שגוי אם הוא היה מסומן באופן אקראי על פי החלוקה של שיעורים במצע.
  • (ב) ⁇ :0) ,EntropyphFLT:1 - מודד את כמות ההפרעה או אי הוודאות בהגדרה.המטרה היא למזער את האנטרופיה לאחר הפיצול (רווחי מידע).
  • (ב) הפחתה של [[המאה ה-1]], היא חישוב ההפחתה בשחלות (או טעות מרובעת) שהושגה על ידי הפיצול.

האלגוריתם מעריך כל פיצול אפשרי על כל תכונה ומבחר את זה אשר מניב את ההפחתה הגדולה ביותר בקוצר רוח (או רווח במידע).

קבל מידע ולהשיג Ratio

רווח מידע הוא ההבדל בין חוסר הנחיתות של הצומת ההורה לבין הסכום המסולק של זיהומים בילדים.בעוד פשוט, הוא נוטה לטובת תכונות עם ערכים רבים.יחס הרווח (שימוש ב C4.5) מנרמל זאת.עבור מדריך זה אנו נצמד עם רווח מידע סטנדרטי באמצעות גסני, המהווה ברירת המחדל ב C (שלב ורידיון עץ).

בניית צעד עץ החלטה על ידי צעד

הכינו את הנתונים שלכם

אתה צריך מצגת נתונים עם תכונות ותוויות מטרה. עבור פשטות, להשתמש בנתוני סיווג בינארי עם תכונות נומריות.

  • (ב) ,0) , ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇ ⁇
  • (ב) ,0) , ⁇ (ב) ,ב"ה, או לא אישרה (לא)

לנקות את הנתונים: לטפל בערכים חסרים, להסיר לשכפלות, ולהבטיח סוגים מספריים של עצי החלטות יכול להתמודד עם סוגי נתונים מעורבים אבל אנחנו נצמד לnumeric ליישום.

Define a פיצול קריטריון

אנו ניישם את הזיהומים של גיני.אינדקס גויני עבור קבוצה של פריטים הוא:

(ב) .

כאשר p i הוא שיעור הפריטים בכיתה i. עבור פיצול בינארי, הגיני הכולל הוא הממוצע המכובד של בלוטות הילד.

יישום ה-Flitation

לכל תכונה, למיין את הערכים הייחודיים.לבחון כל סף אפשרי (בין ערכים רצופים) עבור כל סף מועמד, לחלק את הנתונים לקבוצות ימין ושמאל, לחדד את הגיני ולעקוב אחר הפיצול הטוב ביותר.

4.לבנה את העץ מחדש

יצירת פונקציה שלוקחת תת-קבוצה של נתונים ועומק נוכחי.זה בודקת תנאים (למשל, עומק מקסימלי הגיע, דגימות מינימום עבור node, או ללא רווח מידע) אם מצב הוא נתקל, ליצור עלה עם המעמד הרוב.

5.הכנת תחזיות

ברגע שהעץ בנוי, החיזוי הוא פשוט: להתחיל בשורש, לעקוב אחר הענפים על ידי הערכת הבדיקות המאפיין על הדגימה החדשה, ולהחזיר את הערך של עלה שאתה נוחת עליו.

יישום מלא ב- Python

להלן יישום מלא, מינימלי של עץ החלטה עבור סיווג באמצעות שטף של גיני.קוד זה נועד ללמידה - זה לא מתאים עבור נתונים גדולים.

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'])

בדיקת העץ

השתמש בנתוני iris הקלאסיים (שני תכונות לסיווג בינארי) The FLT:0scikit-learne-learnis DatasetFLT:1 פועל היטב.

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}')

טכניקות מתקדמות לשיפור העץ

להימנע מעודף

עץ גדל במלואו יכול להרעיש רעש בנתונים האימונים.הפסקות מסירות סניפים שיש להם מעט כוח חיזוי.שיטות נפוצות הן לפני ריצה (לעצור את הצמיחה מוקדם באמצעות FLT:4 או FLT:5) ולאחר אימון (הגדל את העץ המלא הסרת הענפים באמצעות מערך אימות או עלות מורכבות pruning).

תכונות רציפות וקטגוריות

עבור תכונות רציפות, השתמשנו באמצע נקודות בין ערכים מדומים כפספים.לתכונות קטגוריות (למשל, "Color=אדום / ירוק / כחול"), כל קטגוריה יכולה להפוך ענף נפרד (מפולגת-דרך מפוצל) או שאתה יכול לקוד אותם.רוב המימושים המודרניים (כמו פיסול למידה) משתמשים בפיצולים אפילו עבור תכונות קטגוריות על ידי הערכת כל תת-קבוצות.

התמודדות עם ערכים חסרים

נתונים אמיתיים בעולם לעתים קרובות חסרים ערכים.גישה פשוטה היא להקצות ערכים חסרים לענפים התכופים ביותר בין דגימות הכשרה שיש להם את התכונה. C4.5 משתמשת בשיטה פרוביבילייסטית.

השוואת ספריות וקריאה נוספת

בעוד הבנייה מאפס היא חינוך, מערכות ייצור להשתמש בספריות כגון פיסול למידה המספקים יישומי C. אתה יכול ללמוד יותר מהרש"ל:0 scikit-learnance עצי תיעוד של פיסול למידה 1 [לתאוריה עמוקה יותר, הספר "האלמנטים של למידה סטטיסטית" על ידי Hastie, Tibshirani, ו- פרידמן הוא משאב סמכותי נוסף הוא ההתייחסות המקורית על ידי Ci et al.

מסקנה

בניית עץ החלטה ממחיקת שריטות מדמיינת אחד האלגוריתמים היסודיים ביותר בלמידה של מכונות.התרגלת פשוטה מפיצות ניתוק יכול לייצר מודל חזק.על ידי כתיבת הקוד בעצמך, אתה מקבל הבנה עמוקה יותר של אמצעי נחיתות, בחירה מפוצלת, ואת הניתוק המסחר בין הטיה ו- ce. כצעד הבא, נסה חיזוק תוקפנות, ריצה, או טיפול, כמו גם תכונות מורכבות יותר.