درخت تصمیم یا Decision tree یکی از روشهای Supervised Learning است. برای توضیح این روش در ادامه از مثال شرایط لازم برای موج سواری استفاده میکنیم.
فرض کنیم شرط لازم برای موج سواری کردن، برقراری هر دو شرط آفتابی و وزش باد با سرعت بیشتر از یک مقدار معین باشد.

همانگونه که در الگوریتم بالا (درخت تصمیم)مشخص است، اگر هوا بادی نباشد، نمیتوان موج سواری کرد و اگر بادی باشد، باید شرط دوم را نیز که مربوط به آفتابی بودن است را بررسی کنیم. الگوریتم بالا میتواند شرطهای بیشتری نیز داشته باشد. به هرکدام از شرطها، یک گره یا Node و به هرکدام از نتایج، برگ یا leaf میگویند. از میان گرهها آن گره که از همه موارد پایینتر است را گره ریشه یا root node گویند.
باید سعی کنیم گرهای را بعنوان گره ریشه انتخاب کنیم که نسبت به سایر گرهها ما را زودتر به جواب برساند.(صرفه جویی زمانی). برای این منظور دو پارامتر وجود دارد که در انتخاب گره ریشه ما را راهنمایی میکند:
1- Entropy
2-Information Gain

محاسبه این دو پارامتر به صورت درونی توسط کتابخانه scikitlearn انجام میشود.
مزایای روش درخت تصمیمگیری:
1- فهم آسان
2- عدم نیاز به نرمالایز کردن دادهها
معایب:
بیش از حد مناسب بودن (Overfitting)

برای از بین بردن این عیب یعنی Overfitting از روش Random forest استفاده میشود.
تفاوت Random Forest با Decision Tree :
در درخت تصمیم کل دیتا را به یک درخت تبدیل میکنیم. اما در رندوم فورست کل دیتا را به چند زیر مجموعه یا Subset تبدیل میکنیم و سپس هر کدام را به یک درخت تبدیل میکنیم. کلمه رندوم هم به این دلیل استفاده شده است که ما به صورت رندوم از کل دیتا، نمونههایی را برمیداریم و آنها را تبدیل به درخت میکنیم.

بعد از این مقدمه به سراغ پایتون میرویم. مطابق معمول ابتدا کتابخانههای مورد نیاز خود را ایمپورت میکنیم:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
و با دستور زیر دیتاست خود که یک دیتا ست fake هست را میخوانیم:
df = pd.read_csv('kyphosis.csv')

همچنین میتوانیم از دستور info و describe اطلاعات بیشتری را بدست بیاوریم.

خروجی دستورhead و describe نشان میدهد که دیتاست ما 4 ستون به نامهای kyphosis و Age و Number و Start دارد که در هر ستون تعداد 81 داده وجود دارد. برای مثال میانگین ستون سن 83 و بیشترین مقدار آن 206 است.
با دستور زیر هیستوگرامAge را ترسیم میکنیم:
sns.displot(x=df['Age'],hue=df['Kyphosis'])

در دستور بالا به دلیل ترکیب شدن رنگهای نارنجی و آبی، رنگ توسی نمایش داده شده است. اگر بخواهیم این نمودارها را به صورت مجزا ببینیم از دستورات زیر استفاده میکنیم. برای مثال دستور زیر نموداری است که مقدار عددی هر سن را به ما نشان میدهد:
sns.displot(x=df['Age'])

و یا در دستور زیر ابتدا دیتافریمی به نام present_df تعریف شده و در آن مقادیری از دیتافریم فعلی که ستون kyphosis آن مقدار present دارد را در present_df ریخته است. و سپس ستون Age دیتا فریم جدید را ترسیم کرده است:
present_df =df[df['Kyphosis']=='present']
sns.displot(present_df['Age'],color='DarkSlateGrey')
و همچننی دیتافریمی موسوم به absent تعریف شده که مقادیر آن همان مقادیر دیتافریم df باشد با شرط اینکه مقادیر ستون kyohosis برابر با absent باشد و به طور مشابه دستورات قبلی ، ستونAge از دیتا فریم ساخته شده، ترسیم شده است:
absent=df[df['Kyphosis']=='absent']
sns.displot(absent['Age'],bins=7,color='red')
با دستورات زیر ابتدا ستون kyohosis از دیتافریم اصلی مد نظر قرار گرفته است (که دو نوع متغیر دارد(present و absent))و هیستوگرام ستون Age بر روی این دو فریم تریسم شده است.
g = sns.FacetGrid(data=df,col='Kyphosis')
g.map(plt.hist,'Age')

نمودار قبلی را با ستون Number یا start نیز قابل ترسیم است:

حال به سراغ آموزش دادن مدل خود میرویم. ابتدا دیتای موجود را با نسبت 0.3 به 0.7 به تست و آموزش اختصاص میدهیم. در خط اول از سایکیتلرن میخواهیم از family مربوط به model_selection ، کتابخانه train_test_split را ایمپورت کند. در خط دوم تمام دیتا به جز ستون kyphosis را به xهای خود نسبت میدهیم و در خط سوم ستون دراپ شده در خط دوم را بهY اختصاص میدهیم.
from sklearn.model_selection import train_test_split
X = df.drop('Kyphosis',axis=1)
y = df['Kyphosis']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30)
حال با دستورات زیر کتابخانه مرتبط با درخت تصمیم را از tree family ایمپورت میکنیم و سپس روی دیتای خود فیت میکنیم:
from sklearn.tree import DecisionTreeClassifier
dtree = DecisionTreeClassifier()
dtree.fit(X_train,y_train)
در کد بالا به جای DecisionTreeClassifier گزینه DecisionTreeRegressor نیز قابل انتخاب است که ما فعلا همان DecisionTreeClassifier را انتخاب میکنیم چون Y ما دستهبندی شده است. در مرحله بعد با کمک توابع درونی scikit_learn به ارزیابی مدل خود میپردازیم:
predictions = dtree.predict(X_test)
from sklearn.metrics import classification_report,confusion_matrix
print(classification_report(y_test,predictions))

دستور اول زیر نشان میدهد که تعداد y تست ما 25 مورد بوده است. در دو خط بعدی متوجه میشویم که از این 25 مورد، 20 مورد آن absent و 5 مورد آن present بوده است. این اعداد در ستون support نیز قابل مشاهده است.

نکته:
اتفاق مثبت در این مسئله خروجی absent است. در ماتریس زیر نیز مشاهده میشود که در مجموع 25 مورد پیشبینی داشتهایم که 16 مورد آن از نوع true positive یعنی (absent)و 3 مورد آن از نوع true nagative و… بوده است. یعنی از 20 مورد ، 16 مورد و از 5 مورد ، سه مورد را درست تشخیص داده است. و همه این موارد در ماتریس confusion قابل مشاهده است.
نکته: جمع سطر اول برابر با 20 و جمع سطر دوم برابر یا 5 است.
print(confusion_matrix(y_test,predictions))


یادآوری:
در دروس گذشته بیان کردیم که برای بدست آوردن precision از فرمولهای زیر استفاده میشود:

حال به سراغ random forest میرویم. ابتدا از family به نام ensemble کتابخانه RandomForestClassifier را ایمپورت میکنیم. و یک نام کوچک (rfc) برای آن میگذاریم و روی x و y خود فیت میکنیم. در خط دوم مقدار n_estimator که تعداد درخت میباشد، را برابر با 100 در نظر میگیریم. تعیین این عدد تا حدی به صورت تجربی مشخص میشود.
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(n_estimators=100)
rfc.fit(X_train, y_train)
با دستور زیر پیشبینیهای خود را در متغیری ذخیره کرده و سپس آن را ارزیابی میکنیم. متناسب با اینکه چه تعداد از مقادیرfalse positive و false negative برای ما مطلوبیت بیشتری داشته باشد، یکی از مدلها(رندوم فورست یا decision tree) را انتخاب میکنیم. همچنین سایر فاکتورها نظیر precision وrecall نیز ممکن است در انتخاب ما تاثیرگذار باشند.
rfc_pred = rfc.predict(X_test)
print(confusion_matrix(y_test,rfc_pred))

print(classification_report(y_test,rfc_pred))

این مسئله به روش لاجستیک نیز قابل حل است.
from sklearn.linear_model import LogisticRegression
logmodel = LogisticRegression()
logmodel.fit(X_train,y_train)
predictions = logmodel.predict(X_test)
confusion_matrix(y_test,predictions)

print(classification_report(y_test,predictions))

نتیجهگیری:
ما برای حل این مسئله، از سه روش استفاده کردیم. برای انتخاب مدل نهایی باید به نیازهای متناسب با مسئله خود و همچنین میزان دقت مدلهای استفاده شده، توجه کنیم.
منابع:
1-کانال ویدئویی- خانوم مونا حاتمی لینک ویدئو