جنگل تصادفی با پایتون

پیاده سازی جنگل تصادفی با پایتون

این آموزش یکی از پست‌های زیرمجموعه آموزش‌های مرتبط با پایتون می‌باشد، که به آموزش جنگل تصادفی با پایتون می‌پردازد. در صورتی که تمایل دارید کل آموزش‌های مرتبط با پایتون را مشاهده کنید، از این لینک استفاده کنید. در ضمن اگه حوصله خوندن متن ندارید، می‌تونید از ویدیو آخر این پست استفاده کنید و از متن صرف نظر کنیدهمچنین اگه با خوندن این مطلب سوالی برای شما پیش اومد، خوشحال میشم که اون را از طریق راه‌های ارتباطی که در همین وبسایت موجوده، باهام مطرح کنید.

پیشنیاز این آموزش تسلط بر پایتون و مطالعه آموزش پیاده‌سازی درخت تصمیم با پایتون هست.

جنگل تصادفی چیه؟

الگوریتم جنگل تصادفی یکی از زیرشاخه‌های یادگیری ماشین یا Machine Learning هست و در عین حال که الگوریتم ساده‌ایه ولی به شدت کاربردی و مرسوم هم است. این الگوریتم یجورایی مکمل درخت تصمیم هست.

در آموزش مربوط به درخت تصمیم در رابطه با الگوریتم درخت تصمیم و پیاده‌سازی اون با پایتون صحبت کردم، الگوریتم جنگل تصادفی همون الگوریتم درخت تصمیم هست ولی با این تفاوت که به جای یک درخت، چندین درخت کار تصمیم‌گیری را برای ما انجام میدن. فرض کنید قراره با این الگوریتم قیمت دلار فردا را پیش‌بینی کنید، در اینجا چندین درخت برای شما پیش‌بینی را انجام میدن و بعدش الگوریتم از جواب‌های این درخت‌ها میانگین می‌گیره و یک جواب آخر به شما برمی‌گردونه. اینم بد نیست که بدونید به این روش، یادگیری گروهی (Ensemble Learning) میگن. معمولا دقت پیش‌بینی جنگل تصادفی از درخت تصمیم بالاتره.

جنگل تصادفی هم برای مسائل گسسته بکار میره و هم برای پیوسته. مثال پیش‌بینی قیمت دلار را دوباره در نظر بگیرید، قیمت دلار هر عدد می‌تونه باشه، مثلا می‌تونه 58 هزار تومان باشه یا 59 یا هر عددی بین این دو عدد باشه (58 و 59 دو عدد مثالی هستند، در کل منظورم اینه که قیمت دلار هر عددی می‌تونه باشه). به این مسائل پیوسته یا Regression میگن. حالا فرض کنید قراره نتیجه بازی منچستر یونایتد و اورتون را پیش‌بینی کنید، جواب پیش‌بینی سه حالت بیشتر نداره: برد منچستر، باخت منچستر و مساوی. در نتیجه در اینجا برخلاف مثال دلار با بینهایت جواب مواجه نیستیم و جواب الگوریتم کلا سه حالت بیشتر نداره. به این نوع مسائل گسسته یا Classification میگن.

جنگل تصادفی برای حل مسائل Regression از جواب‌ درخت‌ها میانگین می‌گیره و این میانگین را به عنوان جواب آخر به شما برمی‌گردونه ولی برای حل مسائل Classification، نظر اکثریت درخت‌ها را به عنوان جواب مدل در نظر می‌گیره. در این آموزش من با یک مثال Classification جلو میرم ولی پیاده‌سازی جنگل تصادفی از نوع Regression، فرق چندانی با Classification نداره و در قسمت مربوط بهش، براتون توضیح کافی میدم.

جنگل تصادفی

اینم خوبه که بدونید که جنگل تصادفی چطور درخت‌های داخل خودش را ایجاد می‌کنه؟ الگوریتم جنگل تصادفی اینطوریه که میاد دیتا را تکه تکه می‌کنه ولی با هر کدوم از این تکه‌ها یک درخت تصمیم ایجاد می‌کنه! کار قشنگی که می‌کنه اینه که تکه‌ها با جایگذاری انتخاب می‌کنه، یعنی ممکنه دیتای چند تا درخت در قسمتی مشترک باشند.

جنگل تصادفی با پایتون

خب بریم سراغ پیاده‌سازی یک جنگل تصادفی با پایتون:

مرحله اول: دیتا

دیتا مهم‌ترین بخش از پیاده‌سازی یک مدل هوش مصنوعی هست، دیتایی که قراره باهاش یک مدل ایجاد کنید باید مرتبط با مسئله باشه، کافی باشه و تمیز باشه. هر کدوم از این سه عامل اگه درست رعایت نشده باشه، دقت مدل کمتر میشه. در این آموزش من قصد ندارم وارد بحث نحوه جمع‌آوری دیتا و تمیز کردن اون بشم ولی مقاله تمیز کردن دیتا در اکسل می‌تونه دید خوبی در رابطه با دیتای تمیز به شما بده، همچنین مقاله وب اسکرپینگ هم یکی از راه‌های جمع‌آوری دیتا را به شما آموزش میده.

بجز دیتا، انتخاب نوع الگوریتم هم مهمه، منظورم اینه که شاید برای یک دیتا جنگل تصادفی خوب عمل کنه و برای دیتای دیگه‌ای نه! بعضی وقتا بعد از پیاده کردن مدل متوجه میشید که الگوریتمی که انتخاب کردید برای دیتای خودتون مناسب نیست و باید برید سراغ یک الگوریتم دیگه.

من یک دیتا دانلود کردم که برای شما هم در این لینک قرار میدم تا دانلود کنید. دیتا در رابطه با مشخصات افرادی هست که موفق شده‌اند یا موفق نشده‌اند از یک بانک خارجی وام بگیرند. تصویر زیر چند ردیف از این دیتا را نشون میده:

ستون Age سن درخواست کننده وام، Experience تعداد سال سابقه کاری اون شخص، ستون Income درآمد اون فرد و بقیه ستون‌ها بجز ستون آخر، هر کدام یک فاکتور تاثیر گذار در قبول یا رد وام توسط بانک را نشون میده. ستون آخر یعنی ستون Personal.Loan در صورتی که برابر صفر باشه، یعنی بانک با درخواست وام اون شخص موافقت نکرده و در صورتی که برابر یک باشه، یعنی بانک با درخواست وام اون شخص موافقت کرده.

حالا فرض کنید من قراره به این بانک درخواست وام بدم ولی حال و حوصله ندارم که کلی کار اداری مربوط به درخواست وام را انجام بدم ولی در آخر هم بهم بگن به شما وام نمیدیم و من بمونم و کلی وقت و هزینه تلف شده! حالا قصد دارم با استفاده از این دیتا پیش‌بینی کنم که آیا بانک به من وام میده یا نه! اگه الگوریتم به من جواب مثبت داد، اون موقع میرم و کارهای اداری وام را می‌کنم ولی در غیر اینصورت وارد پروسه وام نمیشم.

مرحله دوم: وارد کردن کتابخانه‌های مورد نیاز

من از VS Code به عنوان محیط برنامه نویسی استفاده می‌کنم، البته روی VS Code خودم پلاگین Jupyter را نصب کردم تا محیطی شبیه Jupyter Notebook بدست بیارم ولی شما می‌تونید از خود Jupyter Notebook یا هر محیط دیگه‌ای استفاده کنید. دوباره یادآوری می‌کنم که اگه حوصله خوندن متن ندارید، می‌تونید از ویدیو آخر این پست استفاده کنید و متن را صرف نظر کنید.

کتابخانه‌های زیر را وارد کد خودم می‌کنم:

				
					import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.tree import plot_tree , DecisionTreeClassifier
import matplotlib.pyplot as plt
				
			

کتابخانه sklearn در حقیقت مهمترین کتابخانه این کد هست، چون با استفاده از این کتابخانه قراره جنگل تصادفی را پیاده کنم.

مرحله سوم: وارد کردن دیتا

در این مرحله لازمه کدی بنویسم که فایل دیتا من را بخونه:

				
					def readData():
        data = pd.read_csv('bankloan.csv')
        return data
				
			

فایل bankloan همون فایل csv حاوی دیتا من هست، این فایل را کنار فایل پایتون خودتون قرار بدید.

مرحله چهارم: بخش‌بندی کردن دیتا

تابع زیر را به کد اضافه می‌کنم:

				
					def splitData(data):
        x = data.values[:, 1:13]
        y = data.values[:, 13]
        
        xTrain, xTest, yTrain, yTest = train_test_split(x, y, test_size=0.3, random_state=100)
        
        return x, y, xTrain, xTest, yTrain, yTest
				
			

این تابع یک ورودی به نام data می‌گیره و اول اون را به دو بخش x و y تقسیم می‌کنه. x شامل ستون‌های 1 تا 12 دیتا است که در حقیقت متغیرهای مستقل را شامل میشه و y شامل ستون 13 هست که متغیر وابسته یعنی ستون Personal.Loan را شامل میشه.

در خط 5 کد، با استفاده از تابع train_test_split از sklearn متغیرهای x و y را به 4 بخش تقسیم کردم. در ایجاد مدل‌های هوش مصنوعی ما معمولا یک قسمت از دیتا را جدا می‌کنیم و با اون مدل را ایجاد می‌کنیم (اصطلاحا مدل را Train می‌کنیم) و با قسمت باقیمانده از دیتا، مدلی که ایجاد کردیم را تست می‌کنیم و دقتش را اندازه می‌گیریم. اینجا هم متغیرهای xTrain و yTrain برای ایجاد مدل قراره بکار بره و متغیرهای xTest و yTest برای ارزیابی مدل بکار میره.

پارامتر test_size مشخص می‌کنه که چقدر از دیتا را برای تست لازم داریم، من این پارامتر را روی 0.3 قرار دادم، یعنی 30 درصد دیتا را برای تست جدا کن. پارامتر random_state را برابر یک عدد دلخواه قرار میدم که هر بار که کد را اجرا می‌کنم، مقادیر متغیرهای xTest، xTrain و بقیه متغیرهای حاصل از این تابع، عوض نشه.

مرحله پنجم: ایجاد مدل

با تابع زیر مدل یا جنگل تصادفی خودم را ایجاد می‌کنم:

				
					def train(xTrain , yTrain):
        forest = RandomForestClassifier(n_estimators = 1000, criterion='gini', random_state = 100)
        forest.fit(xTrain , yTrain)
        return forest
				
			

در این تابع با استفاده از سازنده کلاس RandomForestClassifier یک متغیر به نام forest ایجاد کردم. این متغیر در حقیقت شی اولیه جنگل تصادفی من هست. در خط بعدی هم این جنگل را با استفاده از متد fit و دیتاهایی که برای آموزش مدل کنار گذاشته بودم، train کردم.

چیزی که اینجا باید بگم اینه که اگه خط دوم کد را ببینید، یک پارامتر به نام n_estimators داریم. در این پارامتر من تعداد درختان جنگلم را روی 1000 تنظیم کردم، این یعنی جنگل تصادفی من هزارتا درخت تصمیم داره. در رابطه با پارامتر criterion هم در آموزش درخت تصمیم مفصل توضیح داده‌ام و دیگه اینجا نیازی نیست دوباره توضیحش بدم.

نکته مهم اینه که اگه مسئله شما از نوع Regression بود به جای کلاس RandomForestClassifier از کلاس RandomForestRegressor استفاده کنید. البته یادتون نره قبلش اون را با دستور زیر به کد اضافه کنید:

				
					from sklearn.ensemble import RandomForestRegressor
				
			

مرحله پنجم: پیش‌بینی

الان کافیه یک تابع بنویسم که یک مقدار به همراه جنگل تصادفی از من بگیره و مقدار پیش‌بینی را بهم برگردونه. توجه کنید که شی forest یک متد به نام predict داره که اون برای من پیش‌بینی را انجام میده:

				
					def prediction(xTest, forest):
        yPred = forest.predict(xTest)
        return yPred
				
			

مرحله ششم: سنجش دقت جنگل

تابع زیر دقت مدل را با استفاده از متد accuracy_score که از متدهای sklearn هست اندازه می‌گیره:

				
					def calAccuracy(yTest, yPred):
        accuracy = accuracy_score(yTest, yPred) * 100
        return accuracy
				
			

چیزی که شاید لازم باشه بگم اینه که من باید به عنوان پارامتر yTest و yPred را به تابع calAccuracy بدم، حالا yPred چیه؟ این متغیر، حامل مقادیر پیش‌بینی شده حاصل از پیش‌بینی xTest با تابع prediction هست که جلوتر بهش می‌رسیم. به زبان ساده ما مقادیر واقعی و مقادیر پیش‌بینی شده را به این تابع میدیم تا دقت جنگل را برامون حساب کنه. دقیقا برای همین بود که اون اول کار، دیتا خودم را به چند بخش تقسیم کردم.

مرحله ششم: اجرای مدل

تا اینجا فقط یک مشت متد نوشتم، در کد زیر اون‌ها را به کار می‌گیرم:

				
					data = readData()
x, y, xTrain, xTest, yTrain, yTest = splitData(data)

forest = train(xTrain, yTrain)
pred = prediction([[20, 0 , 130 , 92222 , 1 , 1.6 , 6 , 0, 1, 0, 0 ,0]] , forest)
print(pred)
				
			

در خط چهارم کد، لازمه یک دیتا به تابع prediction بدهم تا برام پیش‌بینی را انجام بده. فرض کنید من 20 سالمه، هیچ سابقه کاری ندارم ولی درآمدم 130 هست (فرض کنید 130 هزار دلار یا 130 هزار تومان، واحد پولی اینجا مهم نیست)، کدپستی محل زندگی من 92222، تعداد افراد خانواده من 1 نفره، یعنی تنها زندگی می‌کنم و…، خلاصه تمام اطلاعات خودم را در قالب یک لیست به این تابع میدم و در پارامتر بعدی هم شی جنگل تصادفی را بهش میدم. خروجی این تابع در متغیری به نام pred ذخیره میشه و با دستور print از پایتون درخواست می‌کنم که این متغیر را بهم نشون بده:

				
					[1.]
				
			

مدل بهم عدد یک را نشون میده، این یعنی جنگل تصادفی پیش‌بینی کرده که به من وام تعلق می‌گیره. خب الان می‌تونم با دلگرمی بیشتری برم بانک و تقاضا وام کنم ولی قبلش یکم صبر می‌کنم! دقت پیش‌بینی انجام شده چند درصده؟

کد زیر را هم به کدهای خودم اضافه می‌کنم تا دقت مدل را بدست بیارم:

				
					yPred = prediction(xTest , forest)
print('Accuracy of Forest:' , calAccuracy(yTest , yPred))
				
			

در کد بالا، xTest که دیتا مربوط به تست مدل بود را به تابع prediction دادم تا برام مقادیر پیش‌بینی شده را بدست بیاره و بریزه داخل یک متغیر به نام yPred. بعدش مقادیر واقعی خودم یعنی yTest و مقادیر پیش‌بینی را به تابع calAccuracy دادم تا دقت جنگل تصادفی را بدست بیاره. دقتی که بهم نشون میده به شکل زیره:

				
					Accuracy of Forest: 98.26666666666667
				
			

الان می‌دونم که دقت جوابی که مدل بهم داده حدود 98.3 درصد هست پس دیگه وقتشه برم بانک و اقدام به درخواست وام کنم.

در ضمن همونطور که دیدید، دقت جنگل تصادفی از دقت درخت تصمیمی که با همین دیتا ایجاد کردیم، یکمی بالاتره.

رسم یکی از درختان

پیاده کردن الگوریتم تمام شد! دوتا بلاک کدی که از اینجا به بعد براتون نوشتم، دلخواه هست و می‌تونید ازشون صرف نظر کنید.

با کد زیر می‌تونم یکی از درخت‌های تصمیم داخل جنگل را در قالب یک تصویر خروجی بگیرم:

				
					def plotDecisionTree(forest, treeNumber, att, target):
        fig, axes = plt.subplots(nrows = 1,ncols = 1,figsize = (4,4), dpi=800)
        plot_tree(forest.estimators_[treeNumber - 1],feature_names = att, class_names=target, filled = True);
        fig.savefig(f'tree_{treeNumber}.png')
        
plotDecisionTree(forest, 5, ['Age', 'Experience' , 'Income' , 'ZIPCode' , 'Family' , 'CCAvg' , 'Education', 'Mortgage' , 'SecuritiesAccount' , 'CDAccount' , 'Online' , 'CreditCard'] , ['Not Ok' , 'OK'])
				
			

تابع plotDecisionTree شی جنگل را به همراه شماره درختی که قصد داریم ازش خروجی بگیریم (treeNumber) و دو تا پارامتر  att و target که به ترتیب برچسب‌های مربوط به متغیرهای مستقل و متغیر وابسته مدل من هستند را ازم می‌گیره. وقتی این تابع را در خط ششم کد بالا برای گرفتن خروجی از درخت شماره شش (شمارش درخت‌ها از صفر شروع میشه، برای همین درخت ششم را باید با عدد 5 مشخص کنم) اجرا می‌کنم، تصویر زیر را به عنوان خروجی بهم نشون میده:

به عظمت درخت دقت کنید و به این هم فکر کنید که 999 تا درخت دیگه در این الگوریتم وجود داره. 

اهمیت متغیرهای موجود در مدل

اگه کد زیر را اجرا کنید و ازش خروجی بگیرید، اهمیت هر متغیر در پیش‌بینی مقدار جدید توسط مدل را به شما میده:

				
					colList = ['Age', 'Experience' , 'Income' , 'ZIPCode' , 'Family' , 'CCAvg' , 'Education', 'Mortgage' , 'SecuritiesAccount' , 'CDAccount' , 'Online' , 'CreditCard']
importances = list(forest.feature_importances_)
i = 0
for col in colList:
    print(f'Variable: {colList[i]} : Importance: {round(importances[i] * 100 , 2)}%')
    i = i + 1
				
			

خروجی کد:

				
					Variable: Age : Importance: 3.5%
Variable: Experience : Importance: 3.44%
Variable: Income : Importance: 33.7%
Variable: ZIPCode : Importance: 3.64%
Variable: Family : Importance: 9.99%
Variable: CCAvg : Importance: 16.41%
Variable: Education : Importance: 19.38%
Variable: Mortgage : Importance: 3.06%
Variable: SecuritiesAccount : Importance: 0.42%
Variable: CDAccount : Importance: 4.71%
Variable: Online : Importance: 0.81%
Variable: CreditCard : Importance: 0.93%
				
			

همونطور که مشخصه متغیر Income یا میزان درآمد فرد، در گرفتن وام در اون بانک حدود 34 درصد تاثیر گذاره. حالا این کد به چه دردی می‌خوره؟ این کد را بنویسید و اجرا کنید تا اون متغیرهایی که تاثیری در مدل شما ندارند را مشخص کنید و حذفشون کنید. اینجوری لازم نیس دیتا الکی جمع کنید.

ویدیو آموزش پیاده‌سازی جنگل تصادفی با پایتون

قبل اینکه ویدیو را ببینید، بگم که من ویدیو‌ها را در چنل یوتوب خودم هم آپلود می‌کنم، خیلی خوشحال میشم که اونجا هم من را دنبال کنید.

نمایش ویدیو درباره جنگل تصادفی با پایتون