تشخیص سرطان سینه
روش SVM در زیر مجموعه Supervised learning قرار میگیرد. این روش مانند سایر روشهای Supervised learning نیاز به تعدادی دیتا برای آموزش دادن مدل دارد. بعد از آموزش انتظار داریم با ورود دیتای جدید، مدل بتواند نوع آن را تشخیص بدهد و متناسب با آن خروجی مناسب را تولید کند. در ادامه این نوشته دیتاست مربوط به پیش بینی سرطان سینه را بررسی میکنیم.
برای مثال در شکل زیر، دیتای آموزشی ما ممکن است، در دو دسته سبز و آبی قرار بگیرد. آنگاه خطی که این دو دسته را از هم جدا میکند، همان مدل آموزش دیدهی ما خواهد بود.

اما تعداد خطهایی که میتوانند این دو دسته را از هم تفکیک کنند، بینهایت هستند. حال این سوال پیش میآید که از کجا بفهمیم که کدام خط برای ما مناسب است؟ بهترین خط را optimal hyper plane مینامیم که برای بدست آوردن آن به دو خط به نام support vector نیاز داریم که در تصویر زیر مشاهده میشود:

مطابق با شکل بالا، خط موسوم به Support Vector از دادهای که نزدیکترین فاصله را از دسته مقابل دارد، رد میشود. این خط را برای دادههای سبز و همچنین دادههای آبی میتوان به طور مجزا ترسیم نمود. فاصله این دو خط maximized margin نام دارد و خطی که دقیقا از بین این دو خط رد میشود، optymal hyperplne نام دارد.
اما همیشه به این راحتی نمیتوان این خط را ترسیم نمود. برای مثال در شکل زیر ترسیم چنین خطی غیرممکن به نظر میرسد:

اما اگر شکل را به صورت سهبعدی فرض کنیم، یک صفحه میتواند جداکننده باشد و نواحی مد نظر مارا از هم تفکیک کند.

اگر تعداد فیچرها تنها دو مورد باشد، کار سادهتر است، اما اگر تعداد فیچرها افزایش یابد، معادلات ریاضی مرتبط با آن پیچیدهتر خواهد بود. این پیچیدگیها معمولا به زبان ریاضی ترجمه شده و راه حلی برای آن وجود دارد که کتابخانههایی مانند سایکیتلرن تمام مسائل ریاضی مرتبط با این موضوعات را حل میکند. (اطلاعات بیشتر در مورد ریاضیات در روش svm)
حل مسئله به روش SVM :
در ابتدا کتابخانههای مورد نظر را ایمپورت میکنیم:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
سپس از family موسوم به datasets از sklearn دیتاست load_breast_cancer را ایمپورت میکنیم و نام آن را cancer میگذاریم.
from sklearn.datasets import load_breast_cancer
cancer=load_breast_cancer()
cencer
با بررسی دیتای cancer مشاهده میکنیم که دیتای ما به صورت یک دیکشنری است. اساس ساخت دیکشنری key و value است که توسط علامت (,) از هم جدا شده میشوند. حال با دستور زیر keyهای دیتاست cancer را بررسی میکنیم:
cancer.keys()

مشاهده میشود که دیتاست ما دارای 7 بخش مختلف است. حال با دستور زیر بخش data را بررسی میکنیم و متوجه میشویم که بخش data خود یک list است که هر عضو آن نیز یک list است.
print(cancer['data'])
خروجی کد زیر نشان میدهد که خروجی نهایی صفر یا یک است که نشان دهنده منفی یا مثبت بودن سرطان سینه افراد است.
print(cancer['target'])

برای بررسی بیشتر دیتا میتوانیم دستورات زیر را وارد کنیم و نتیجه را مشاهده کنیم:
-->print(cancer['DESCR'])
-->print(cancer['filename'])
-->print(cancer['feature_names'])
-->print(cancer['target_names'])
--> print(cancer['frame'])
بعد از بررسی دیتای خود با دستور زیر دیتافریمی به نام df_feat تشکیل میدهیم که نام ستونهای آن مطابق با feature_names است:
df_feat=pd.DataFrame(cancer['data'],columns=cancer['feature_names'])
df_feat.head(3)

بدیهی است که اطلاعات بیشتر در مورد دیتای خود را میتوانیم با دستور زیر بدست بیاوریم:
df_feat.info()
ذستور زیر نامهای متعدد target را به ما نشان میدهد:
cancer['target_names']

دیتایی که هدف یا target ما در این مسئله است همان target از دیتای cancer است. ما در این مرحله آن را به دیتا فریمی با یک ستون تبدیل میکنیم و نام ستون آن را cancer میگذاریم.
df_target=pd.DataFrame(cancer['target'],columns=['cancer'])
حال با دستور زیر کل دیتا را در یک فریم تجمیع میکنیم و نام رایج df را بر آن میگذاریم:
df=pd.concat([df_feat,df_target],axis=1)
df.head(1)

EDA به معنای exploratory data analysis
در ادامه با استفاده از توابع گرافیکی، مقدار بیشتری با دیتای خود آشنا میشویم:
-->sns.scatterplot(x='mean concavity',y='mean texture',hue='cancer',data=df)
--> sns.scatterplot(x='worst texture',y='mean texture',hue='cancer',data=df)

sns.scatterplot(x='mean radius',y='mean perimeter',hue='cancer',data=df)

حال به سراغ ماشین لرنینگ میرویم:
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=( train_test_split(df_feat,np.ravel(df_target),test_size=0.3,random_state=101))
from sklearn.svm import SVC
در دستور بالا svc به معنای support vector classifier است. classifier به این دلیل است که ما قصد دستهبندی را داریم.
model=SVC()
model.fit(x_train,y_train)
بعد از فیت کردن مدل بر روی دیتای خود آن را ارزیابی میکنیم:
predictions=model.predict(x_test)
from sklearn.metrics import classification_report,confusion_matrix
print(confusion_matrix(y_test,predictions))

print(classification_report(y_test,predictions))

تا اینجای کار را در مسئلههای قبلی نیز مشاهده کرده بودیم. حال برای اولین بار میخواهیم ببینیم چطور میشود نتایج بدست آمده را بهبود بخشید. یکی از روشهای بهبود نتایج ، تغییر دادن مقادیر defaul است. برای مثال نتایج حاصل از مدل model=SVC() بر اساس مقادیر default بدست آمده است. اما ما میخواهیم این مقادیر را تغییر دهیم. با نوشتن عبارت model( ) فشردن همزمان کلیدهای shift و tab مقادیر پیشفرض تابع نمایش داده میشود. برای مثال دیده میشود که مقدار پیشفرض برای پارامتر c برابر با یک است. ما میخواهیم پارامتر C و همچنین gamma را تغییر دهیم و برای این کار 5 مقدار برای هر پارامتر در نظر میگیریم و بر اساس حالات مختلف ممکن (25 حالت)، مدل خود را آموزش میدهیم.
این روش که به آن گرید سرچ (grid search) میگویند، تنها مختص روش SVM نیست و برای مدلهای دیگر نیز قابل اجرا میباشد. برای اجرای این روش ابتدا یک دیکشنری از مقادیر پارمترها میسازیم که key را همان پارامترها و value را مقادیر ممکن آن پارامتر قرار میدهیم. مقادیر به صورت رندوم انتخاب میشوند:
param_grid={'C':[0.1,1,10,100,1000],'gamma':[1,0.1,0.01,0.001,0.0001],'kernel':['rbf']}
از دسته Model_selection زیرمجموعه GridSearchCV را انتخاب میکنیم:
from sklearn.model_selection import GridSearchCV
نام grid را برای کتابخانه خود انتخاب میکنیم. خود GridSearchCV نیاز به تعیین پارامترهایی دارد که درون پرانتز آنها را تعیین میکنیم:
1- اولین مورد svc است که که نشان دهنده روشی است که میخواهیم گریدسرچ را روی آن پیاده کنیم.
2- پارامتر دوم همان دیکشنری است که در مرحله قبلی از مقادیر متعدد تشکیل دادیم.
3- پارامتر سوم refit است که با True قرار دادن آن میخواهیم که با هر بار تغییر پارامترها مدل را refit شود.
4- پارامتر چهارم verbose است که هر چه عدد بزرگتری باشد، جزییات بیشتری را خواهیم داشت. کمترین مقدار آن صفر است. در تعیین این پارامتر باید محدودیت زمانی را در نظر بگیریم. برای مثال در دیتابیسهای بزرگ ممکن است زمان زیادی برای محاسبات نیاز باشد. بنابراین در تعیین verbose باید محدودیت زمانی را در نظر بگیریم.
grid=GridSearchCV(SVC(),param_grid,refit=True,verbose=3)
در خط بعدی grid را روی مدل خود fit میکنیم. این مرحله ممکن است مقداری زمانبر باشد.
grid.fit(x_train,y_train)
مطابق روشهای قبلی به ارزیابی مدل خود میپردازیم:
grid_predictions=grid.predict(x_test)
print(confusion_matrix(y_test,grid_predictions))

قبل از اجرای گریدسرچ ماتریس confusion ما به شرح زیر بود. به وضوح مشخص است که تعداد TP افزایش و FP کاهش یافته است.

همچنین میتوانیم گزارش confusion report قبل و بعد را نیز با هم مقایسه کنیم. مقادیر f_1 score و accuracy بعد از اجرای گرید سرچ افزایش یافته است:

print(classification_report(y_test,grid_predictions))

در پایان برای بدست آوردن بهترین پارامترها میتوان از دستور زیر استفاده کرد:
grid.best_params_
منابع:
1- جلسه 12 منتورینگ دیتا ساینس –مونا حاتمی–
2- گیت هاب – مونا حاتمی
3- گیت هاب خودم 1 و 2