File size: 42,588 Bytes
22032c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e20a1210",
   "metadata": {},
   "source": [
    "## Step 1: Import Libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "7644ff9f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import json\n",
    "import joblib\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, log_loss, classification_report, confusion_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d9c169c",
   "metadata": {},
   "source": [
    "## Step 2: Load Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "1a6a30cd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset shape: (101371, 16)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Driver</th>\n",
       "      <th>LapNumber</th>\n",
       "      <th>Compound</th>\n",
       "      <th>Stint</th>\n",
       "      <th>TyreLife</th>\n",
       "      <th>Position</th>\n",
       "      <th>LapTime (s)</th>\n",
       "      <th>Race</th>\n",
       "      <th>Year</th>\n",
       "      <th>LapTime_Delta</th>\n",
       "      <th>Cumulative_Degradation</th>\n",
       "      <th>PitStop</th>\n",
       "      <th>PitNextLap</th>\n",
       "      <th>RaceProgress</th>\n",
       "      <th>Normalized_TyreLife</th>\n",
       "      <th>Position_Change</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>ALB</td>\n",
       "      <td>1</td>\n",
       "      <td>MEDIUM</td>\n",
       "      <td>1</td>\n",
       "      <td>2.0</td>\n",
       "      <td>17</td>\n",
       "      <td>100.625</td>\n",
       "      <td>Abu Dhabi Grand Prix</td>\n",
       "      <td>2023</td>\n",
       "      <td>0.000</td>\n",
       "      <td>0.000</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.017241</td>\n",
       "      <td>0.117647</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>ALB</td>\n",
       "      <td>2</td>\n",
       "      <td>MEDIUM</td>\n",
       "      <td>1</td>\n",
       "      <td>3.0</td>\n",
       "      <td>18</td>\n",
       "      <td>93.560</td>\n",
       "      <td>Abu Dhabi Grand Prix</td>\n",
       "      <td>2023</td>\n",
       "      <td>-7.065</td>\n",
       "      <td>-7.065</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.034483</td>\n",
       "      <td>0.176471</td>\n",
       "      <td>-1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>ALB</td>\n",
       "      <td>3</td>\n",
       "      <td>MEDIUM</td>\n",
       "      <td>1</td>\n",
       "      <td>4.0</td>\n",
       "      <td>18</td>\n",
       "      <td>91.768</td>\n",
       "      <td>Abu Dhabi Grand Prix</td>\n",
       "      <td>2023</td>\n",
       "      <td>-1.792</td>\n",
       "      <td>-8.857</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.051724</td>\n",
       "      <td>0.235294</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>ALB</td>\n",
       "      <td>4</td>\n",
       "      <td>MEDIUM</td>\n",
       "      <td>1</td>\n",
       "      <td>5.0</td>\n",
       "      <td>18</td>\n",
       "      <td>91.591</td>\n",
       "      <td>Abu Dhabi Grand Prix</td>\n",
       "      <td>2023</td>\n",
       "      <td>-0.177</td>\n",
       "      <td>-9.034</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.068966</td>\n",
       "      <td>0.294118</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>ALB</td>\n",
       "      <td>5</td>\n",
       "      <td>MEDIUM</td>\n",
       "      <td>1</td>\n",
       "      <td>6.0</td>\n",
       "      <td>18</td>\n",
       "      <td>91.422</td>\n",
       "      <td>Abu Dhabi Grand Prix</td>\n",
       "      <td>2023</td>\n",
       "      <td>-0.169</td>\n",
       "      <td>-9.203</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.086207</td>\n",
       "      <td>0.352941</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  Driver  LapNumber Compound  Stint  TyreLife  Position  LapTime (s)  \\\n",
       "0    ALB          1   MEDIUM      1       2.0        17      100.625   \n",
       "1    ALB          2   MEDIUM      1       3.0        18       93.560   \n",
       "2    ALB          3   MEDIUM      1       4.0        18       91.768   \n",
       "3    ALB          4   MEDIUM      1       5.0        18       91.591   \n",
       "4    ALB          5   MEDIUM      1       6.0        18       91.422   \n",
       "\n",
       "                   Race  Year  LapTime_Delta  Cumulative_Degradation  PitStop  \\\n",
       "0  Abu Dhabi Grand Prix  2023          0.000                   0.000        0   \n",
       "1  Abu Dhabi Grand Prix  2023         -7.065                  -7.065        0   \n",
       "2  Abu Dhabi Grand Prix  2023         -1.792                  -8.857        0   \n",
       "3  Abu Dhabi Grand Prix  2023         -0.177                  -9.034        0   \n",
       "4  Abu Dhabi Grand Prix  2023         -0.169                  -9.203        0   \n",
       "\n",
       "   PitNextLap  RaceProgress  Normalized_TyreLife  Position_Change  \n",
       "0           0      0.017241             0.117647              0.0  \n",
       "1           0      0.034483             0.176471             -1.0  \n",
       "2           0      0.051724             0.235294              0.0  \n",
       "3           0      0.068966             0.294118              0.0  \n",
       "4           0      0.086207             0.352941              0.0  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PitNextLap\n",
      "0    75542\n",
      "1    25829\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "data_path = r'd:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\dataset\\f1_strategy_dataset_v4.csv'\n",
    "df = pd.read_csv(data_path)\n",
    "\n",
    "print('Dataset shape:', df.shape)\n",
    "display(df.head())\n",
    "\n",
    "target_column = 'PitNextLap'\n",
    "print(df[target_column].value_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91763788",
   "metadata": {},
   "source": [
    "## Step 3: Prepare Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "d1e0e470",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X_train shape: (81096, 76)\n",
      "X_test shape: (20275, 76)\n",
      "Class distribution in train:\n",
      "PitNextLap\n",
      "0    0.745203\n",
      "1    0.254797\n",
      "Name: proportion, dtype: float64\n"
     ]
    }
   ],
   "source": [
    "X = df.drop(columns=[target_column])\n",
    "y = df[target_column].astype(int)\n",
    "\n",
    "X = pd.get_dummies(X, drop_first=False)\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    X,\n",
    "    y,\n",
    "    test_size=0.2,\n",
    "    random_state=21,\n",
    "    stratify=y\n",
    ")\n",
    "\n",
    "print('X_train shape:', X_train.shape)\n",
    "print('X_test shape:', X_test.shape)\n",
    "print('Class distribution in train:')\n",
    "print(y_train.value_counts(normalize=True).sort_index())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "425c5bd4",
   "metadata": {},
   "source": [
    "## Step 4: Train RandomForest Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "95540597",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model training completed\n"
     ]
    }
   ],
   "source": [
    "model = RandomForestClassifier(\n",
    "    n_estimators=150,\n",
    "    random_state=21,\n",
    "    n_jobs=-1,\n",
    "    class_weight='balanced_subsample'\n",
    ")\n",
    "\n",
    "model.fit(X_train, y_train)\n",
    "\n",
    "y_pred = model.predict(X_test)\n",
    "y_prob = model.predict_proba(X_test)[:, 1]\n",
    "\n",
    "print('Model training completed')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0b9980f",
   "metadata": {},
   "source": [
    "## Step 5: Check Model Performance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "3316a60c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.9694\n",
      "Precision: 0.9729\n",
      "Recall: 0.905\n",
      "F1 Score: 0.9377\n",
      "ROC AUC: 0.9951\n",
      "Log Loss: 0.1264\n",
      "\n",
      "Classification Report:\n",
      "\n",
      "              precision    recall  f1-score   support\n",
      "\n",
      "           0     0.9683    0.9914    0.9797     15109\n",
      "           1     0.9729    0.9050    0.9377      5166\n",
      "\n",
      "    accuracy                         0.9694     20275\n",
      "   macro avg     0.9706    0.9482    0.9587     20275\n",
      "weighted avg     0.9695    0.9694    0.9690     20275\n",
      "\n"
     ]
    }
   ],
   "source": [
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "precision = precision_score(y_test, y_pred, zero_division=0)\n",
    "recall = recall_score(y_test, y_pred, zero_division=0)\n",
    "f1 = f1_score(y_test, y_pred, zero_division=0)\n",
    "roc_auc = roc_auc_score(y_test, y_prob)\n",
    "loss = log_loss(y_test, y_prob)\n",
    "\n",
    "print('Accuracy:', round(accuracy, 4))\n",
    "print('Precision:', round(precision, 4))\n",
    "print('Recall:', round(recall, 4))\n",
    "print('F1 Score:', round(f1, 4))\n",
    "print('ROC AUC:', round(roc_auc, 4))\n",
    "print('Log Loss:', round(loss, 4))\n",
    "\n",
    "print('\\nClassification Report:\\n')\n",
    "print(classification_report(y_test, y_pred, digits=4, zero_division=0))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a99818e1",
   "metadata": {},
   "source": [
    "## Step 6: Plot Confusion Matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "89658dd3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkYAAAHqCAYAAADh64FkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAARRlJREFUeJzt3QmcTXUbwPFnxjDGMvYZlK0SJrKGKWuESBTJEsoW2XeTJaSmSPZMqjcqIookayRlJ/syESXJFmYayxjmvp/n3723uWNoRmdmnJnf9/M57733nP8999x7X3k8z//5Xy+Hw+EQAAAAiDefAQAAwN8IjAAAAJwIjAAAAJwIjAAAAJwIjAAAAJwIjAAAAJwIjAAAAJwIjAAAAJwIjAAAAJwIjIA7xKFDh6RevXqSI0cO8fLykkWLFll6/l9++cWcd+bMmZae185q1aplNgBwITAC4vj555/lxRdflHvuuUcyZ84s/v7+8sgjj8ikSZPk8uXLyfpZtW/fXvbs2SOvvfaafPzxx1KpUqU08908//zzJijTzzOhz1GDQj2u21tvvZXk8584cUJGjhwpO3futOiKAaRXPql9AcCd4uuvv5ZnnnlGfH19pV27dlK6dGm5evWq/PDDDzJw4EDZt2+fzJgxI1leW4OFjRs3ytChQ6VHjx7J8hpFihQxr5MxY0ZJDT4+PnLp0iX56quvpEWLFh7HZs+ebQLRK1eu3Na5NTAaNWqUFC1aVMqVK5fo561cufK2Xg9A2kVgBIjI0aNHpWXLliZ4WLNmjRQoUMD9uXTv3l0OHz5sAqfkcubMGXObM2fOZHsNzcZo8JFaNODU7Nunn356Q2A0Z84cadSokXz++ecpci0aoGXJkkUyZcqUIq8HwD4opQEiMnbsWImKipIPPvjAIyhyue+++6R3797ux9euXZNXX31V7r33XvMXvmYqXn75ZYmOjvZ4nu5/4oknTNapcuXKJjDRMt1HH33kHqMlIA3IlGamNIDR57lKUK77celzdFxcq1atkmrVqpngKlu2bFKiRAlzTf82x0gDwerVq0vWrFnNc5s0aSIHDhxI8PU0QNRr0nE6F+qFF14wQUZitW7dWpYtWyYXLlxw79u6dasppemx+M6dOycDBgyQMmXKmPekpbjHH39cdu3a5R6zdu1aeeihh8x9vR5XSc71PnUOkWb/tm/fLjVq1DABketziT/HSMuZ+h3Ff//169eXXLlymcwUgLSNwAgQMeUdDVgefvjhRH0enTp1khEjRkiFChVkwoQJUrNmTQkNDTVZp/g0mGjevLk89thjMn78ePMXrAYXWppTTz/9tDmHatWqlZlfNHHixCR9L3ouDcA0MBs9erR5nSeffFLWr19/y+d988035i/906dPm+CnX79+smHDBpPZ0UAqPs30/PXXX+a96n0NPrSElVj6XjVo+eKLLzyyRSVLljSfZXxHjhwxk9D1vb399tsmcNR5WPp5u4KUUqVKmfesunTpYj4/3TQIcvnzzz9NQKVlNv1sa9euneD16VyyfPnymQDp+vXrZt+7775rSm5TpkyRggULJvq9ArApB5DORUREOPSPQpMmTRI1fufOnWZ8p06dPPYPGDDA7F+zZo17X5EiRcy+devWufedPn3a4evr6+jfv79739GjR824cePGeZyzffv25hzxvfLKK2a8y4QJE8zjM2fO3PS6Xa/x4YcfuveVK1fOERAQ4Pjzzz/d+3bt2uXw9vZ2tGvX7obX69Chg8c5n3rqKUeePHlu+ppx30fWrFnN/ebNmzvq1Klj7l+/ft2RP39+x6hRoxL8DK5cuWLGxH8f+vmNHj3avW/r1q03vDeXmjVrmmNhYWEJHtMtrhUrVpjxY8aMcRw5csSRLVs2R9OmTf/1PQJIG8gYId2LjIw0n0H27NkT9VksXbrU3Gp2Ja7+/fub2/hzkYKCgkypykUzElrm0myIVVxzk7788kuJjY1N1HP++OMP08Wl2avcuXO79z/44IMmu+V6n3F17drV47G+L83GuD7DxNCSmZa/Tp48acp4eptQGU1pmdLb++//TGkGR1/LVSb88ccfE/2aeh4tsyWGLpmgnYmahdIMl5bWNGsEIH0gMEK6p/NWlJaIEuPXX381f1nrvKO48ufPbwIUPR5X4cKFbziHltPOnz9v2Wf/7LPPmvKXlvgCAwNNSe+zzz67ZZDkuk4NMuLT8tTZs2fl4sWLt3wv+j5UUt5Lw4YNTRA6b948042m84Pif5Yuev1aZixevLgJbvLmzWsCy927d0tERESiX/Ouu+5K0kRrXTJAg0UNHCdPniwBAQGJfi4AeyMwQrqngZHOHdm7d2+SPov4k59vJkOGDAnudzgct/0arvkvLn5+frJu3TozZ6ht27YmcNBg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v36mK+3HH3+UsmXLSv369eX06dN8E0AiXLx40fy50X9gALAeXWlIUZoheuihh2Tq1KnmcWxsrBQqVEh69uwpQ4YM4dsAkkAzRgsXLpSmTZvyuQEWIWOEFHP16lXZvn271K1b95//A3p7m8cbN27kmwAApDoCI6SYs2fPyvXr1yUwMNBjvz4+efIk3wQAINURGAEAADgRGCHF5M2bVzJkyCCnTp3y2K+P8+fPzzcBAEh1BEZIMZkyZZKKFSvK6tWr3ft08rU+Dg4O5psAAKQ6n9S+AKQv2qrfvn17qVSpklSuXFkmTpxo2o9feOGF1L40wBaioqLk8OHD7sdHjx6VnTt3Su7cuaVw4cKpem1AWkC7PlKctuqPGzfOTLguV66cTJ482bTxA/h3a9euldq1a9+wX//BMXPmTD5C4D8iMAIAAHBijhEAAIATgREAAIATgREAAIATgREAAIATgREAAIATgREAAIATgREAAIATgREAAIATgRGQzj3//PPStGlT9+NatWpJnz59UmVFZy8vL7lw4UKKvzYAuBAYAXdwwKKBgm76A7z33XefjB49Wq5du5asr/vFF1/Iq6++mqixBDMA0hp+RBa4gzVo0EA+/PBDiY6OlqVLl0r37t0lY8aMEhIS4jHu6tWrJniygv4YKQCkV2SMgDuYr6+v5M+fX4oUKSLdunWTunXryuLFi93lr9dee00KFiwoJUqUMON/++03adGiheTMmdMEOE2aNJFffvnFfb7r169Lv379zPE8efLIoEGDxOFweLxm/FKaBmWDBw+WQoUKmevRzNUHH3xgzuv6MdNcuXKZzJZel4qNjZXQ0FApVqyY+Pn5SdmyZWXBggUer6OB3v3332+O63niXicApBYCI8BGNIjQ7JBavXq1hIeHy6pVq2TJkiUSExMj9evXl+zZs8v3338v69evl2zZspmsk+s548ePN7/A/r///U9++OEHOXfunCxcuPCWr9muXTv59NNPZfLkyXLgwAF59913zXk1UPr888/NGL2OP/74QyZNmmQea1D00UcfSVhYmOzbt0/69u0rzz33nHz33XfuAO7pp5+Wxo0by86dO6VTp04yZMiQZP70ACARHADuSO3bt3c0adLE3I+NjXWsWrXK4evr6xgwYIA5FhgY6IiOjnaP//jjjx0lSpQwY130uJ+fn2PFihXmcYECBRxjx451H4+JiXHcfffd7tdRNWvWdPTu3dvcDw8P13SSee2EfPvtt+b4+fPn3fuuXLniyJIli2PDhg0eYzt27Oho1aqVuR8SEuIICgryOD548OAbzgUAKY05RsAdTDNBmp3RbJCWp1q3bi0jR440c43KlCnjMa9o165dcvjwYZMxiuvKlSvy888/S0REhMnqVKlSxX3Mx8dHKlWqdEM5zUWzORkyZJCaNWsm+pr1Gi5duiSPPfaYx37NWpUvX97c18xT3OtQwcHBiX4NAEguBEbAHUzn3kyfPt0EQDqXSAMZl6xZs3qMjYqKkooVK8rs2bNvOE++fPluu3SXVHod6uuvv5a77rrL45jOUQKAOxmBEXAH0+BHJzsnRoUKFWTevHkSEBAg/v7+CY4pUKCAbN68WWrUqGEea+v/9u3bzXMTolkpzVTp3CCd+B2fK2Olk7pdgoKCTAB07Nixm2aaSpUqZSaRx7Vp06ZEvU8ASE5MvgbSiDZt2kjevHlNJ5pOvj569KhZZ6hXr15y/PhxM6Z3797yxhtvyKJFi+TgwYPy0ksv3XJBxaJFi0r79u2lQ4cO5jmuc3722WfmuHbLaTealvzOnDljskVayhswYICZcD1r1ixTxvvxxx9lypQp5rHq2rWrHDp0SAYOHGgmbs+ZM8dMCgeA1EZgBKQRWbJkkXXr1knhwoVNx5dmZTp27GjmGLkySP3795e2bduaYEfn9GgQ89RTT93yvFrKa968uQmiSpYsKZ07d5aLFy+aY1oqGzVqlOkoCwwMlB49epj9ukDk8OHDTXeaXod2xmlpTdv3lV6jdrRpsKWt/Nq99vrrryf7ZwQA/8ZLZ2D/6ygAAIB0gIwRAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACAE4ERAACA/O3/eNkL5+0vWWgAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 600x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "cm = confusion_matrix(y_test, y_pred)\n",
    "\n",
    "plt.figure(figsize=(6, 5))\n",
    "sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')\n",
    "plt.xlabel('Predicted')\n",
    "plt.ylabel('Actual')\n",
    "plt.title('Confusion Matrix')\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d710186f",
   "metadata": {},
   "source": [
    "## Step 7: Save Model and Metrics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "e2060814",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Saved model: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy\\model\\model.joblib\n",
      "Saved columns: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy\\model\\feature_columns.json\n",
      "Saved labels: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy\\model\\label_classes.json\n",
      "Saved target info: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy\\model\\target_info.json\n",
      "Saved metrics: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy\\metrics\\final_metircs.csv\n",
      "Saved predictions: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy\\metrics\\prediction.csv\n"
     ]
    }
   ],
   "source": [
    "base_output = r'd:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\F1_Strategy'\n",
    "model_dir = os.path.join(base_output, 'model')\n",
    "metrics_dir = os.path.join(base_output, 'metrics')\n",
    "\n",
    "os.makedirs(model_dir, exist_ok=True)\n",
    "os.makedirs(metrics_dir, exist_ok=True)\n",
    "\n",
    "model_path = os.path.join(model_dir, 'model.joblib')\n",
    "columns_path = os.path.join(model_dir, 'feature_columns.json')\n",
    "labels_path = os.path.join(model_dir, 'label_classes.json')\n",
    "info_path = os.path.join(model_dir, 'target_info.json')\n",
    "metrics_path = os.path.join(metrics_dir, 'final_metircs.csv')\n",
    "predictions_path = os.path.join(metrics_dir, 'prediction.csv')\n",
    "\n",
    "joblib.dump(model, model_path)\n",
    "with open(columns_path, 'w', encoding='utf-8') as f:\n",
    "    json.dump(list(X.columns), f, indent=2)\n",
    "with open(labels_path, 'w', encoding='utf-8') as f:\n",
    "    json.dump([0, 1], f, indent=2)\n",
    "with open(info_path, 'w', encoding='utf-8') as f:\n",
    "    json.dump({'target_col': target_column, 'model_name': 'RandomForestClassifier'}, f, indent=2)\n",
    "\n",
    "final_metrics = pd.DataFrame([\n",
    "    {'metric': 'accuracy', 'value': accuracy},\n",
    "    {'metric': 'precision', 'value': precision},\n",
    "    {'metric': 'recall', 'value': recall},\n",
    "    {'metric': 'f1', 'value': f1},\n",
    "    {'metric': 'roc_auc', 'value': roc_auc},\n",
    "    {'metric': 'log_loss', 'value': loss}\n",
    "])\n",
    "final_metrics.to_csv(metrics_path, index=False)\n",
    "\n",
    "prediction_df = pd.DataFrame({\n",
    "    'Actual': y_test,\n",
    "    'Predicted': y_pred,\n",
    "    'Probability': y_prob\n",
    "})\n",
    "prediction_df.to_csv(predictions_path, index=False)\n",
    "\n",
    "print('Saved model:', model_path)\n",
    "print('Saved columns:', columns_path)\n",
    "print('Saved labels:', labels_path)\n",
    "print('Saved target info:', info_path)\n",
    "print('Saved metrics:', metrics_path)\n",
    "print('Saved predictions:', predictions_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25072de9",
   "metadata": {},
   "source": [
    "## Step 8: Final Summary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "ebe897d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Metric</th>\n",
       "      <th>Value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Accuracy</td>\n",
       "      <td>0.969371</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Precision</td>\n",
       "      <td>0.972945</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Recall</td>\n",
       "      <td>0.904955</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>F1 Score</td>\n",
       "      <td>0.937719</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>ROC AUC</td>\n",
       "      <td>0.995099</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Log Loss</td>\n",
       "      <td>0.126425</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      Metric     Value\n",
       "0   Accuracy  0.969371\n",
       "1  Precision  0.972945\n",
       "2     Recall  0.904955\n",
       "3   F1 Score  0.937719\n",
       "4    ROC AUC  0.995099\n",
       "5   Log Loss  0.126425"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Final model used: RandomForestClassifier\n",
      "Target column: PitNextLap\n"
     ]
    }
   ],
   "source": [
    "summary = pd.DataFrame([\n",
    "    {'Metric': 'Accuracy', 'Value': accuracy},\n",
    "    {'Metric': 'Precision', 'Value': precision},\n",
    "    {'Metric': 'Recall', 'Value': recall},\n",
    "    {'Metric': 'F1 Score', 'Value': f1},\n",
    "    {'Metric': 'ROC AUC', 'Value': roc_auc},\n",
    "    {'Metric': 'Log Loss', 'Value': loss}\n",
    "])\n",
    "\n",
    "display(summary)\n",
    "print('Final model used: RandomForestClassifier')\n",
    "print('Target column:', target_column)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}