লজিস্টিক রিগ্রেশনঃ বাইনোমিয়াল

নামের সাথে রিগ্রেশন শব্দটি থাকলেও লজিস্টিক রিগ্রেশন আসলে একটি ক্লাসিফিকেশন অ্যালগরিদম। এর আগে আমরা যে লিনিয়ার রিগ্রেশনের সাথে পরিচিত হয়েছি, সেই লিনিয়ার ইকুয়েশন থেকেই লজিস্টিক রিগ্রেশন এর উৎপত্তি , একারনেই এর নাম লজিস্টিক রিগ্রেশন। লিনিয়ার রিগ্রেশনে আমরা নিউমেরিক্যাল ভ্যালু প্রিডিক্ট করে থাকি, কিন্তু লজিস্টিক রিগ্রেশনে আমরা বাইনোমিয়াল বা মাল্টিনোমিয়াল ক্লাস প্রেডিক্ট করে থাকি।
  • বাইনোমিয়াল - প্রেডিকশন ক্লাস যখন দুইটি থাকে তখন তাকে বাইনোমিয়াল ক্লাস বলে , যেমন এর আগে আমরা দেখছি ডায়বেটিস ডেটাসেটে দুইটি ক্লাস ছিল (ডায়বেটিস আছে, ডায়বেটিস নেই)। এধরনের ক্লাস হচ্ছে বাইনোমিয়াল ক্লাস।
  • মাল্টিনোমিয়াল - প্রেডিকশন ক্লাস যখন দুইয়ের বেশী হয় তখন তাকে মাল্টিনোমিয়াল ক্লাস বলে। এধরনের ডেটায় তিনটি ,চারটি বা এর বেশী যেকোনো সংখ্যক ক্লাস থাকতে পারে। উদাহরন হিসাবে বলা যায় আইরিস ফ্লাওয়ার ডেটাসেটে তিন ধরনের আইরিস ফ্লাওয়ারের ডেটা রয়েছে, অর্থাৎ এর ক্লাস তিন টি। সেক্ষেত্রে এটি একটি মাল্টিনোমিয়াল ক্লাস।
ছবি- লিনিয়ার রিগ্রেশন এবং লজিস্টিক রিগ্রেশন (সূত্র- ইন্টারনেট)
নিচের ছবিতে আমরা দেখতে পাচ্ছি
y=b0+b1Xy= b0+b1X
একটি লিনিয়ার ইকুয়েশন , যাকে একটি বিশেষ ফাংশনের মাধ্যমে একটি প্রবাবিলিটি ভ্যালুতে পরিনত করা হয়েছে । এই ফাংশনকে বলা হয় সিগময়েড ফাংশন।
ছবি - সিগময়েড ফাংশন ( সূত্র- ইন্টারনেট )
লজিস্টিক ফাংশন দেখতে অনেকটা ইংরেজি বর্ণ S এর মত। সিগময়েড ফাংশনের মাধ্যমে যে প্রবাবিলিটি ভ্যালু পাওয়া , সেটি ব্যাবহার করে একটি থ্রেসল্ড মানের উপর ভিত্তি করে বাইনারি ক্লাস প্রিডিক্ট করা হয়। উদাহরন হিসাবে বলা যেতে পারে টিউমার ম্যালিগন্যান্ট কিনা সেটা অনুমান করার জন্য আমরা থ্রেসল্ড ভ্যালু ০.৫ সেট করলাম। এখন সিগময়েড ফাংশনের মাধ্যমে যে প্রবাবিলিটি মান পেয়েছি সেটি যদি থ্রেসল্ড ভ্যালু ০.৫ এর চেয়ে বেশী হয় তবে টিউমারটি ম্যালিগন্যান্ট, আর ০.৫ এর চেয়ে কম হলে বিনাইন ক্লাসের।
ছবি- থ্রেসল্ড ভ্যালু (সূত্র- ইন্টারনেট)
লজিস্টিক রিগ্রেশনের কিছু বৈশিষ্ট্য
  • লজিস্টিক রিগ্রেশন সহজেই ইমপ্লিমেন্ট এবং ইন্টারপ্রেট করা যায়। একই সাথে এটি অপেক্ষাকৃত কম কম্পিউটেশনাল রিসোর্স ব্যবহার করে।
  • যেসকল ডেটা লিনিয়ারলি সেপারেট করা যায় সেসব ক্ষেত্রেই লজিস্টিক রিগ্রেশন ভালো কাজ করে, নন-লিনিয়ার ডেটার ক্ষেত্রে এটি খুব বেশী কার্যকর নয়।
  • লজিস্টিক রিগ্রেশনের ওভারফিটিং প্রবনতা সাধারনত কম, তবে ডেটাসেটের ডাইমেনশন অনেক বেশী হয়ে গেলে মডেল ওভারফিট করতে পারে, এক্ষেত্রে মডেলিং এর পূর্বেই ডাইমেনশন রিডাকশন করে নিতে হবে।
  • অবজারভেশনের সংখ্যা যদি ফিচারের চেয়ে কম হয়ে যায় সেক্ষেত্রে মডেল কার্যকর হবে না এবং ওভারফিটিং সমস্যা দেখা দিবে।
ক্যান্সার সারভাইভ্যাল প্রেডিকশন
ক্যান্সার সারভাইভ্যাল প্রেডিকশনের জন্য আমরা Haberman’s ডেটাসেট ব্যাবহার করবো। University of Chicago’র Billings Hospital এ ১৯৫৮ সাল থেকে ১৯৭০ সাল পর্যন্ত ব্রেস্ট ক্যান্সার আক্রান্ত ৩০৬ জন নারীর উপর গবেষণা লব্ধ ডেটা থেকে এই ডেটাসেট তৈরি করা হয়। এই ডেটাসেটটি Haberman’s ডেটাসেট নামে পরিচিত। এই ডেটাসেটের বিভিন্ন এট্রিবিউটস এর পরিচয়,
  • Lymph Node: টিউমারের আশেপাশের লিম্ফ নোড বা লসিকা গ্রন্থির সংখ্যা
  • Age: রোগীর বয়স
  • Operation year: যেই সালে সার্জারি হয়েছিল
  • Survival Status: সার্জারির পর যারা ৫ বছরের বেশী সময় বেঁচে ছিল তাদের স্ট্যাটাস 1 এবং যারা ৫ বছরের আগেই মারা গিয়েছিল তাদের স্ট্যাটাস 2 দেয়া রয়েছে।
প্রথমেই লাইব্রেরী ইমপোর্ট এবং ডেটাসেট লোড করে নিচ্ছি,
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import seaborn as sns
import io
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix,accuracy_score
from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve
url='https://raw.githubusercontent.com/FazlyRabbiBD/Data-Science-Book/master/data-heberman.csv'
df = pd.read_csv(url)
আমাদের ডেটাসেটটি দেখতে অনেকটা এরকম
df.head(5)
আমরা রোগীর বয়স, লিম্ফ নোডের সংখ্যা এবং সার্জারির সালকে ফিচার হিসাবে ব্যাবহার করবো এবং স্ট্যাটাসকে টার্গেট ভ্যারিয়েবল হিসাবে ব্যবহার করবো। ডেটাসেটে যেসকল রোগী ৫ বছরের বেশী সময় বেঁচে ছিল তাদের স্ট্যাটাস 1 এবং যারা ৫ বছরের আগেই মারা গিয়েছিল তাদের স্ট্যাটাস 2 দেয়া রয়েছে, এক্ষেত্রে আমরা 1 এবং 2 কে 0 এবং 1 হিসাবে ম্যাপ করে নেব।
features=['age','operation_year','axil_nodes']
x=df[features]
df['status']=df['status'].map({1:0, 2:1})
y=df.status
এবার টেস্ট এর জন্য ২৫% ডেটা রেখে বাকি ডেটা দিয়ে মডেল ট্রেইন করবো। আমরা এই মডেলের নাম দিয়েছি logreg , আপনি চাইলে যেকোনো নাম দিতে পারেন।
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, random_state=5)
logreg = LogisticRegression()
logreg.fit(x_train, y_train)
আমাদের মডেল এখন তৈরি। এবার অ্যাকুরেসি চেক করার পালা।
print('Coefficients:', logreg.coef_)
print('Intercept:', logreg.intercept_)
predictions = logreg.predict(x_test)
print('Classification Report:\n',classification_report(y_test, predictions))
print('Confusion Matrix:\n',confusion_matrix(y_test, predictions))
print('Accuracy Score:',accuracy_score(y_test, predictions))
print("Precision:",metrics.precision_score(y_test, predictions))
print("Recall:",metrics.recall_score(y_test,predictions ))
কনফিউশন ম্যাট্রিক্স থেকে কিভাবে অ্যাকুরেসি চেক করতে হয় সেটি নেইভ বেইজ অধ্যায়ে বিস্তারিত আলোচনা হয়েছে। আমরা ক্লাসিফিকেশন রিপোর্ট থেকে দেখতে পাচ্ছি আমাদের মডেল প্রায় ৮১.৮১% নির্ভুল ভাবে প্রিডিকশন করতে পেরেছে।
কনফিউশন ম্যাট্রিক্সকে আরও একটু সুন্দর ভাবে ভিজুয়ালাইজ করতে চাইলে নিচের কোডটুক রান করতে হবে,
class_names=[0,1] # name of classes
fig, ax = plt.subplots()
tick_marks = np.arange(len(class_names))
plt.xticks(tick_marks, class_names)
plt.yticks(tick_marks, class_names)
###create heatmap
sns.heatmap(pd.DataFrame(confusion_matrix(y_test, predictions)), annot=True, cmap="YlGnBu" ,fmt='g')
ax.xaxis.set_label_position("top")
plt.tight_layout()
plt.title('Confusion matrix', y=1.1)
plt.ylabel('Actual label')
plt.xlabel('Predicted label')
plt.show()
বিভিন্ন ক্লাসিফিকেশন মডেলের পারফরম্যান্স কতখানি ভালো সেটা নির্ণয়ের আরেকটি পদ্ধতী হচ্ছে ROC-AUC কার্ভ। ROC অর্থ Receiver Operating Curve এবং AUC অর্থ Area Under Curve । নিচের ছবির যে নীল রঙের লাইনটি দেখা যাচ্ছে সেটি হচ্ছে ROC, আর এই ROC এর নিচে যতটুক জায়গা রয়েছে সেটি হচ্ছে AUC । ROC এর মান যত বেশী হবে অর্থাৎ নীল লাইনটি যতই উপরের দিকে (1 ) এর কাছাকাছি যাবে , আমাদের মডেলটি ততই ভালো।
logit_roc_auc = roc_auc_score(y_test, logreg.predict(x_test))
fpr, tpr, thresholds = roc_curve(y_test, logreg.predict_proba(x_test)[:,1])
plt.figure()
plt.plot(fpr, tpr, label='Logistic Regression (area = %0.2f)' % logit_roc_auc)
plt.plot([0, 1], [0, 1],'r--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic (ROC)')
plt.legend(loc="lower right")
plt.savefig('Log_ROC')
plt.show()
এবার প্রিডিকশনের পালা , মনে করুন একজন রোগীর বয়স ৩৫, তার ক্যান্সার সেলের পাশে ১৫ টি লিম্ফ নোড ছিল এবং তার সার্জারি হয়েছিল ১৯৬৪ সালে , এখন আপনার মডেলকে প্রেডিক্ট করতে হবে সে কি ৫ বছর বেচেছিল নাকি তার আগেই মারা গিয়েছিল ?
new_observation = [[35,64, 15]]
logreg.predict(new_observation)
array([0]) মানে হচ্ছে সে ৫ বছরের বেশী বেচেছিল । আমরা যদি দুটি ক্লাসের প্রবাবিলিটির মান বের করতে চাই তাহলে দেখতে পাই এই রোগীর ৫ বছরের বেশী বেঁচে থাকার সম্ভাবনা ৬২.৩৬% এবং ৫ বছরের আগেই মারা যাবার সম্ভাবনা ৩৭.৬৩%
logreg.predict_proba(new_observation)
array([[0.62361094, 0.37638906]])