# মডেল পারফর্মেন্স টেস্টিং - ১

আমরা ডেটা সংগ্রহ থেকে মডেল ট্রেইনিং পর্যন্ত কাজ শেষ। এখন শুধু বাকি রইল মডেল কিরকম পার্ফর্মেন্স শো করছে। মডেল পারফর্মেন্স চ্যাপ্টারটা একটু বড় হবে তাই আমি একে দুইভাগে ভাগ করলাম।

## দুই পর্বের মডেল পারফর্মেন্স টেস্টিং চ্যাপ্টারের ওভারভিউ

### মূল আলোচ্য বিষয়

* টেস্ট ডেটার মধ্যমে মডেল এভালুয়েশন
* রেজাল্ট ইন্টারপ্রিটেশন&#x20;
* রেজাল্ট ইম্প্রুভমেন্ট / মডেল ইম্প্রুভমেন্ট / অ্যাকুরেসি ইম্প্রুভমেন্ট

### এছাড়াও

* কনফিউশন ম্যাট্রিক্স
  * Recall
  * Precision
  * AUC
  * ROC
* ওভারফিটিং
* মডেল হাইপারপ্যারামিটার
* ওভারফিটিং কমানো
  * K-Fold Cross Validation বা N-Fold Cross Validation
  * Bias-Variance Trade off
  * ভাল পারফর্মেন্সের জন্য কিছুটা পারফেকশন ছাড় দেওয়া

হাটি হাটি পা পা করতে করতে অবশেষে আমরা চলে এলাম শেষের ধাপে,

![modeltest](http://i.imgur.com/YglPD3U.png)

তাহলে শুরু করা যাক।

মনে রাখতে হবে,

> স্ট্যাটিস্টিক্স শুধু ডেটা নিয়ে কাজ করে, আমরা ডিফাইন করি কোনটা খারাপ আর কোনটা ভাল। এবং এই ভাল-খারাপ সম্পূর্ণ নির্ভর করে আমরা মডেল কীভাবে ব্যবহার করব।

অনেক থিওরি হল, এবার একটু ইম্প্লিমেন্টেশন দেখি।

### যে ডেটায় ট্রেইন্ড হয়েছে সেটাতে কেমন পারফর্ম করছে

আমরা কাজ শুরুর আগে ডেটাকে দুইভাগে ভাগ করেছিলাম, একটা ট্রেইনিং আরেকটা টেস্টিং। এতবার এই কথা দেখতে দেখতে মুখস্ত হয়ে যাওয়ার কথা। যাই হোক, আমরা এখন দেখব, যে ডেটায় ট্রেইন্ড হয়েছে, তাকে যদি সেই ডেটাই ফিড করানো হয়, তাহলে কিরকম প্রেডিক্ট করছে।

ব্যাপারটা অনেকটা সেই নামতার উদাহরণের মত,

**এটা যদি ট্রেইনিং ডেটা হয়:**

```
3 x 1 = 3
3 x 2 = 6
...
3 x 10 = 30
```

**তাহলে ট্রেইন্ড ডেটায় কীরকম ট্রেইন্ড হয়েছে সেটা জানার জন্য জিজ্ঞাসা করব,**

```
3 x 1 = ?
```

আপনার মডেলের উপর ট্রাই মারতে নিচের কোডটি রান করুন, (আগে বলা হয় নি যদিও, এই পর্যন্ত Jupyter Notebook এ যত কাজ করেছেন সেখান থেকে কন্টিনিউ করুন)

```python
# This returns array of predicted results
prediction_from_trained_data = nb_model.predict(X_train)
```

এখন `prediction_from_trained_data` ভ্যারিয়েবলে প্রেডিক্ট করা অ্যারেটা অ্যাসাইন হল। আমরা চাইলে এখন খাতা কলম নিয়ে বসে দেখতে পারি, ডেটাসেট এ প্রতি Observation এ রেজাল্ট কী এবং ডেটাসেট এ প্রতি Observation এ আমাদের তৈরি করা মডেলের প্রেডিক্টেড রেজাল্ট কী।

অথবা আরেকটা কাজ করা যায়, সাইকিট-লার্ন লাইব্রেরির বিল্ট ইন মডিউল দিয়ে চেক করতে পারি আমাদের মডেল কয়টা সঠিক ডায়বেটিস ধরতে পারল আর কয়টা পারল না।

খাতা কলমের বদলে জুপিটার নোটবুক ওপেন করা থাকলে সেখানে লেখা শুরু করুন,

```python
# performance metrics library
from sklearn import metrics

# get current accuracy of the model

accuracy = metrics.accuracy_score(y_train, prediction_from_trained_data)

print ("Accuracy of our naive bayes model is : {0:.4f}".format(accuracy))
```

#### যদি ভুলে গিয়ে থাকেন

আমরা ডেটাসেট স্প্লিট করে **চারটি** ভ্যারিয়েবলে রেখেছিলাম, `X_train, y_train, X_test, y_test`

যেখানে,

```
X_train = ট্রেইন করার ইনপুট ভ্যালুগুলো [no_of_preg, insulin, glucose ... etc] (পুরো ডেটাসেট এর ৭০%)
y_train = X_train এর করেসপন্ডিং আউটপুট [diabetes -> yes/no] (যেহেতু y_train এর করেসপন্ডিং ভ্যালু, বোঝাই যাচ্ছে এটাও ৭০%)

X_test = টেস্ট করার ইনপুট ভ্যালুগুলো [পুরো ডেটাসেট এর ৩০% ছিল এবং এই ৩০% ট্রেইনিং ডেটার অস্তিত্ব নাই]
y_test = টেস্ট করার ইনপুটের করেসপন্ডিং আউটপুট
```

আমরা যেহেতু দেখছি **ট্রেইন্ড ডেটায় অ্যাকুরেসি কীরকম**, তাই এটা হওয়াই স্বাভাবিক না যে `metrics.accuracy_score` ফাংশনে আমরা `X_train` এ মডেলের আউটপুট `(prediction_from_trained_data)` এবং `X_train` এর আসল আউটপুট `(y_train)`।

### আগের কোড স্নিপেটের আউটপুট

আগের কোড স্নিপেটের আউটপুট হল এটা,

```
Accuracy of our naive bayes model is : 0.7542
```

আমাদের সল্যুশন স্টেটমেন্টে টার্গেট ছিল ৭০ বা তার বেশি অ্যাকুরেসি তে প্রেডিক্ট করা। কিন্তু এখানে আমরা দেখতে পাচ্ছি অ্যাকুরেসি প্রায় `75%`।

থামেন, আগেই সেলিব্রেট করার মত কিছু হয় নাই। এই অ্যাকুরেসি স্কোর কিন্তু ট্রেইন্ড ডেটার উপর, মানে এই ডেটা দিয়েই তাকে ট্রেইন্ড করে আবার সেই ডেটায় প্রেডিকশন টেস্ট করছি। অর্থাৎ সিলেবাসের জিনিসপত্রই জিজ্ঞেস করা হল।

## টেস্টিং ডেটায় পার্ফর্মেন্স

এবার আপনাকে যদি বলি টেস্টিং ডেটায় পারফর্মেন্স কী হবে সেটার কোড লেখেন, তাহলে আপনি যা করতেন তার সাথে নিচের কোডের মিল আছে কিনা লক্ষ করুন,

```python
# this returns array of predicted results from test_data
prediction_from_test_data = nb_model.predict(X_test)

accuracy = metrics.accuracy_score(y_test, prediction_from_test_data)

print ("Accuracy of our naive bayes model is: {0:0.4f}".format(accuracy))
```

### আউটপুট

```
Accuracy of our naive bayes model is: 0.7000
```

![p\_t](http://i.imgur.com/7hPm7Cz.gif)

তার মানে হল সিলেবাসের বাইরে থেকে প্রশ্ন জিজ্ঞাসা করলেও সে ৭০% অ্যাকুরেসির সাথে উত্তর দিতে পারছে, তারমানে তার দেওয়া উত্তরের ৭০% সঠিক এবং বাকিটা ভুল।

আমরা এটাই চেয়েছিলাম, অর্থাৎ আমরা যদি এই ট্রেইন্ড মডেলে এবার নতুন পরীক্ষিত কোন ব্যক্তির ডেটা ইনপুট দেই তাহলে তার উত্তর সঠিক হওয়ার সম্ভাবনা ৭৩%। যদি মডেল বলে নতুন ব্যক্তির ডায়বেটিস হতে পারে, তার likelihood হল ৭০%।

## কিন্তু

হ্যাঁ ঠিক ধরেছেন, এখনো সেলিব্রেশনের সময় আসে নি। ডেটা কালেকশনের পরবর্তী পেইনফুল কাজ হল পারফর্মেন্স টেস্টিং এবং প্রয়োজনীয় পরিবর্তন করা।

## ক্লাসিফিকেশন টাইপ প্রবলেমের পারফর্মেন্স টেস্টিং : কনফিউশন ম্যাট্রিক্স

আমাদের সমস্যাটি ক্লাসিফিকেশন টাইপের আর এর জন্য আলাদা কিছু `measurement` আছে পারফর্মেন্স টেস্ট করার জন্য। যেটার কথা না বললেই নয় সেটা হল `Confusion Matrix`। নাম শুনে কনফিউজ হওয়ার কিছু নেই। কোড লেখার পাশাপাশি আমরা এ বিষয়ে বিস্তারিত জেনে নেব।

আপাতত জেনে রাখুন কনফিউশন ম্যাট্রিক্স দিয়ে আমরা জানতে পারব আমাদের মডেলের পার্ফর্মেন্স কীরকম। তাহলে নিচের কোডটি লিখুন,

```python
print ("Confusion Matrix")

# labels for set 1=True to upper left and 0 = False to lower right
print ("{0}".format(metrics.confusion_matrix(y_test, prediction_from_test_data, labels=[1, 0])))
```

![performance2](http://i.imgur.com/z609uE0.gif)

### কনফিউশন ম্যাট্রিক্স

|                            | Predicted True (col 0) | Predicted False (col 1) |
| -------------------------- | ---------------------- | ----------------------- |
| **Actual True**   row -> 0 | 52 (TP)                | 28 (FP)                 |
| **Actual False**  row -> 1 | 33 (FN)                | 118 (TN)                |

আমরা টেবিলের নাম্বারগুলোকে TP, FP, FN ও TN দ্বারা প্রকাশ করতে পারি। যেখানে,

```
TP = আসল আউটপুট হল ১ বা ডায়বেটিস হওয়ার সম্ভাবনা আছে **এবং** আমাদের তৈরি করা মডেলও প্রেডিক্ট করেছে ১
FP = আসল আউটপুট হল ০ বা ডায়বেটিস হওয়ার সম্ভাবনা নাই **কিন্তু** আমাদের তৈরি করা মডেল প্রেডিক্ট করছে ১
FN = আসল আউটপুট হল ১ বা ডায়বেটিস হওয়ার সম্ভাবনা আছে **কিন্তু** আমাদের তৈরি করা মডেল প্রেডিক্ট করছে ০
TN = আসল আউটপুট হল ০ এবং আমাদের মডেলও প্রেডিক্ট করছে ০
```

কনফিউশন ম্যাট্রিক্স একটু কনফিউজিং মনে হলে, ভালভাবে আরেকবার চিন্তা করুন এবং আপনার চিন্তার সাথে সাথে টেবিলটি বুঝতে চেষ্টা করুন।

**শর্টকাটে,**

* TP = কতগুলা ঘটনা ঘটেছে এবং  ঘটেছে হিসেবে ডিটেক্ট করেছে
* FP = কতগুলা ঘটনা ঘটে নাই কিন্তু ঘটেছে হিসেবে ডিটেক্ট করেছে
* FN = কতগুলা ঘটনা ঘটেছে কিন্তু ঘটে নাই হিসেবে ডিটেক্ট করেছে
* TN = কতগুলা ঘটনা ঘটে নাই এবং ডিটেক্ট ও করে নাই

**আরেকবার দেখা যাক, তাহলে উপরের স্ট্যাটিস্টিক্স অনুযায়ী,**

* 52 টা ঘটনা ডায়বেটিস হিসেবে ডিটেক্ট করেছে এবং 52 জন আসলেই ডায়বেটিসে আক্রান্ত <- TP
* 28 টা ঘটনা ডায়বেটিস হিসেবে ডিটেক্ট করেছে কিন্তু ঔ 28 জন আসলে ডায়বেটিসে আক্রান্ত নয় <- FP
* 33 টা ঘটনা ডায়বেটিস হিসেবে ডিটেক্ট করে নাই কিন্তু ঔ 33 জন আসলে ডায়বেটিসে আক্রান্ত <- FN
* 118 টা ঘটনা ডায়বেটিস হিসেবে ডিটেক্ট করে নাই এবং ঔ 118 জন ডায়বেটিসে আক্রান্ত নয় <- TN

## যদি আমাদের মডেল ১০০% অ্যাকুরেট হত তাহলে কীরকম হত তার কনফিউশন ম্যাট্রিক্স?

সহজেই বোঝা যাচ্ছে, 100% Accurate Model এর ক্ষেত্রে FP = 0 এবং FN = 0 হবে। তাহলে কনফিউশন ম্যাট্রিক্স হবে এইরকম,

|                  | Predicted True | Predicted False |
| ---------------- | -------------- | --------------- |
| **Actual True**  | 80 (TP)        | 0 (FP)          |
| **Actual False** | 0 (FN)         | 151 (TN)        |

## কনফিউশন ম্যাট্রিক্স পর্যালোচনা : ক্লাসিফিকেশন রিপোর্ট

কনফিউশন ম্যাট্রিক্স এর মাধ্যমে মডেল অ্যাকুরেসি বের করার জন্য আমরা আরও কিছু স্ট্যাটিস্টিক্স রিপোর্ট দেখতে পারি। সূত্র দেখার পাশাপাশি সাইকিট এর বিল্ট ইন ফাংশন দিয়ে কীভাবে বের করা যায় আমরা সেটাও দেখব।

ক্লাসিফিকেশন রিপোর্ট জেনারেট হয় আসলে কনফিউশন ম্যাট্রিক্সের ডেটার উপরে। ক্লাসিফিকেশন রিপোর্ট দেখার জন্য নিচের স্টেটমেন্ট রান করুন,

```python
print ("Classification Report")

# labels for set 1=True to upper left and 0 = False to lower right
print ("{0}".format(metrics.classification_report(y_test, prediction_from_test_data, labels=[1, 0])))
```

### রিপোর্ট আউটপুট

```
Classification Report
             precision    recall  f1-score   support

          1       0.61      0.65      0.63        80
          0       0.81      0.78      0.79       151

avg / total       0.74      0.74      0.74       231
```

![classification\_report](http://i.imgur.com/sdNGDe6.gif)

এখানে দুইটা টপিক নিয়ে আমরা একটু আলোচনা করব, একটি হল `Precision` এবং আরেকটি হল `Recall`।

**Precision বের করার সূত্র**

&#x20;$$ Precision = \frac{TP}{TP + FP} $$

অর্থাৎ, পার্ফেক্ট প্রিসিশনের জন্য আমরা জানি, FP = 0, সুতরাং 100% Accurate Model এর

&#x20;$$ Precision = \frac{TP}{TP + 0} = \frac{TP}{TP} = 1 $$ এর অর্থ হচ্ছে Precision এর মান যত বড় ততই ভাল। আমাদের টার্গেট থাকবে Precision এর মান যতটা বড় করা যায়। ##### \`Recall\` বের করার সূত্র $$ Recall = \frac{TP}{TP + FN} $$

একই ভাবে, 100% Accurate Model এর ক্ষেত্রে

&#x20;$$ Recall = \frac{TP}{TP + 0} = \frac{TP}{TP} = 1 $$

আবারও, আমাদের লক্ষ থাকবে Recall এর মান যতটা বাড়ানো যায়।

`Precision - 0.61 & Recall - 0.65` খারাপ না, কিন্তু এর মান আরও বাড়ানো যেতে পারে। সেই চেষ্টাই আমরা করে যাব।

## পারফর্মেন্স ইম্প্রুভ করার উপায় কী কী?

আমরা নিচের পদ্ধতিগুলোর মাধ্যমে মডেলের পার্ফর্মেন্স বের বাড়াতে পারি

* যে অ্যালগরিদমে আছি সেটা অ্যাডজাস্ট বা মডিফাই করা
* আরও ডেটা জোগাড় করা বা ডেটাফ্রেমের ইম্প্রুভ করা&#x20;
* ট্রেইনিং ইম্প্রুভ করার চেষ্টা করা
* অ্যালগরিদম চেঞ্জ করা

## চলুন আমরা বরং অ্যালগরিদম চেঞ্জ করে দেখি : Random Forest

Random Forest দিয়ে কেন দেখব? কারণ,

* এটা Ensemble Algorithm (সহজ কথায় Advanced এবং Complex)
* ডেটার সাবসেটে অনেকগুলো ট্রি থাকতে পারে
* ট্রি এর রেজাল্ট এভারেজ করে যাতে ওভারফিটিং কন্ট্রোলে থাকে এবং পার্ফর্মেন্স ভাল হয়

আমাদের ডেটা নিয়ে কিছুই করা লাগবে না, যেহেতু আমরা প্রিপ্রসেসিংয়ের কাজ আগেই করে রেখেছি। শুধু নতুন মডেল তৈরি করে ডেটা দিয়ে ট্রেইন করব এবং টেস্ট ডেটা দিয়ে পার্ফর্মেন্স টেস্ট করব।

নিচের কোডটি লিখে ফেলুন,

```python
from sklearn.ensemble import RandomForestClassifier

# Create a RandomForestClassifier object
rf_model = RandomForestClassifier(random_state=42)

rf_model.fit(X_train, y_train.ravel())
```

এটা লিখে এন্টার মারলে নিচের মত কোন আউটপুট আসলে বুঝবেন ট্রেইনিং খতম, এবার পার্ফর্মেন্স টেস্ট করার পালা

### আউটপুট:

```
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=42, verbose=0, warm_start=False)
```

## Random Forest Performance Testing : Predict Training Data

আগের মতই কোড,

```python
rf_predict_train = rf_model.predict(X_train)

#get accuracy
rf_accuracy = metrics.accuracy_score(y_train, rf_predict_train)

#print accuracy
print ("Accuracy: {0:.4f}".format(rf_accuracy))
```

#### আউটপুট:

```
Accuracy: 0.9870
```

অস্থির! তাই না? ডেটাসেট সে ভালই মুখস্ত করেছে। এবার দেখা যাক টেস্টিং ডেটায় পার্ফর্মেন্স কেমন!

## Random Forest Performance Testing : Predict Testing Data

```python
rf_predict_test = rf_model.predict(X_test)

#get accuracy
rf_accuracy_testdata = metrics.accuracy_score(y_test, rf_predict_test)

#print accuracy
print ("Accuracy: {0:.4f}".format(rf_accuracy_testdata))
```

#### আউটপুট:

```
Accuracy: 0.7000
```

টেস্টিং ডেটার ক্ষেত্রে অ্যাকুরেসি ৭০% আর ট্রেইনিং ডেটায় ৯৮%। অর্থাৎ সিলেবাসের প্রশ্নে উত্তর ভালই দিতে পারছে কিন্তু এর বাইরে থেকে প্রশ্ন করলে উত্তর বেশ খারাপই আসছে। এর মানে সে রিয়েল ওয়ার্ল্ড ডেটায় ভাল প্রেডিক্ট করতে পারছে না, কিন্তু যে ডেটাসেট এর মাধ্যমে যেটা শিখেছে, সেখান থেকে ভাল প্রেডিক্ট করতে পারছে।

এর চেয়ে তো আমাদের Naive Bayes মডেল ভাল কাজ করছিল! আমাদের টেস্টিং ডেটায় ভাল অ্যাকুরেসি দরকার।

এবার দেখা যাক Random Forest মডেলের ক্লাসিফিকেশন রিপোর্ট কেমন! আমরা উপর থেকে ধার করা কোড কিছুটা পরিবর্তন করেই বসিয়ে দিতে পারি!

```python
print ("Confusion Matrix for Random Forest")

# labels for set 1=True to upper left and 0 = False to lower right
print ("{0}".format(metrics.confusion_matrix(y_test, rf_predict_test, labels=[1, 0])))

print ("")

print ("Classification Report\n")

# labels for set 1=True to upper left and 0 = False to lower right
print ("{0}".format(metrics.classification_report(y_test, rf_predict_test, labels=[1, 0])))
```

#### আউটপুট:

```
Confusion Matrix for Random Forest
[[ 43  37]
 [ 30 121]]

Classification Report

             precision    recall  f1-score   support

          1       0.59      0.54      0.56        80
          0       0.77      0.80      0.78       151

avg / total       0.70      0.71      0.71       231
```

এখানে দেখুন, precision ও recall এর মানও আমাদের আগের Naive Bayes এর চেয়ে খারাপ।

## গুরুত্বপূর্ণ : Overfitting

যখন দেখবেন Training Data ও Testing Data এর Accuracy Score এ মোটামুটি ভালই তফাৎ, তখনই বুঝবেন আপনার মডেলটি মেশিন লার্নিংয়ের সবচেয়ে ক্লাসিক সমস্যার কবলে পড়েছে। সেটা হল Overfitting, আমাদের Random Forest মডেলটি Overfitting এর ভুক্তভোগী। আমরা পরবর্তী পর্বে Overfitting নামক **লার্নিংয়ের দুষ্টচক্র** থেকে বের হওয়ার বেশ কিছু পদ্ধতি দেখব।

## আপডেটেড নোটবুক ডাউনলোড করুন

এই পর্যন্ত যত কাজ করা হয়েছে আপনি নিজে না করে থাকলেও আমার করা নোটবুকটি ডাউনলোড করে রান করে দেখতে পারেন। [ডাউনলোড করুন এখান থেকে।](https://github.com/howtocode-com-bd/ml.howtocode.com.bd/blob/master/model_performance/performance.ipynb)
