-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPart B Multi-Instance
719 lines (719 loc) · 59.1 KB
/
Part B Multi-Instance
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
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "markdown",
"source": [
"Note: For this code the only datasets needed from DeliciousMIL are: train-data.dat, test-data.dat, train-label.dat, test-label.dat.\n",
"\n"
],
"metadata": {
"id": "qjF-GnP19e0w"
}
},
{
"cell_type": "markdown",
"source": [
"# 1"
],
"metadata": {
"id": "3dM0CyVK-shM"
}
},
{
"cell_type": "code",
"source": [
"# !pip install pyclustering\n",
"# !pip install scikit-learn-extra"
],
"metadata": {
"id": "yeiIG_eZ9HJR"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Import necessary libraries"
],
"metadata": {
"id": "ze6dJrWZ-9Pc"
}
},
{
"cell_type": "code",
"source": [
"from sklearn.cluster import KMeans\n",
"from sklearn.metrics import silhouette_score, silhouette_samples\n",
"import matplotlib.pyplot as plt"
],
"metadata": {
"id": "tZfmbYGCaGEE"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"import re\n",
"import itertools\n",
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"from sklearn.cluster import KMeans\n",
"from sklearn.naive_bayes import GaussianNB\n",
"from sklearn.metrics import classification_report, f1_score\n",
"import pickle\n",
"import numpy as np\n"
],
"metadata": {
"id": "3oTJTTMHXyLS"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Load data"
],
"metadata": {
"id": "XDiKaKMG_AV8"
}
},
{
"cell_type": "code",
"source": [
"with open('train-data.dat', 'r') as f:\n",
" train_lines = f.readlines()\n",
"with open('test-data.dat', 'r') as f:\n",
" test_lines = f.readlines()"
],
"metadata": {
"id": "PGLSpf-EDy7-"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"train_data, test_data = dict(), dict()\n",
"n = 0\n",
"for line in train_lines:\n",
" train_data[n] = line.split()[2:]\n",
" n += 1\n",
"n = 0\n",
"for line in test_lines:\n",
" test_data[n] = line.split()[2:]\n",
" n += 1"
],
"metadata": {
"id": "tGzU-5KbQVma"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Preprocessing"
],
"metadata": {
"id": "wk-K8Gtx_YJ1"
}
},
{
"cell_type": "code",
"source": [
"import re\n",
"import itertools\n",
"\n",
"def split_sentences(document):\n",
" sentences = re.findall(r\"<\\d+> (.+?) <\\d+>\", document)\n",
" return sentences\n",
"\n",
"train_docs, test_docs, train_bag_len, test_bag_len, train_labels, test_labels = [], [], [], [], [], []\n",
"for train_key, train_value in train_data.items():\n",
" train_text_doc = ' '.join(train_value)\n",
" train_docs.append(split_sentences(train_text_doc))\n",
" train_bag_len.append(len(train_docs[train_key])) \n",
" train_labels.append(train_data[train_key])\n",
"for test_key, test_value in test_data.items():\n",
" test_text_doc = ' '.join(test_value)\n",
" test_docs.append(split_sentences(test_text_doc))\n",
" test_bag_len.append(len(test_docs[test_key]))\n",
" test_labels.append(test_data[test_key])\n",
"train_labels = np.array(train_labels)\n",
"train_labels = train_labels.astype(int)\n",
"test_labels = np.array(test_labels)\n",
"test_labels = test_labels.astype(int)\n",
"\n",
"# Create two lists of all sentences for the train/test set\n",
"train_sentences = list(itertools.chain.from_iterable(train_docs))\n",
"test_sentences = list(itertools.chain.from_iterable(test_docs))"
],
"metadata": {
"id": "4v1jnWfsXvMR"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"# Keep the most popular labels"
],
"metadata": {
"id": "--wG3Xxm80Jo"
}
},
{
"cell_type": "code",
"source": [
"column_sums = np.sum(train_labels, axis=0)\n",
"most_pop_column = np.argmax(column_sums)\n",
"\n",
"# Keep only the column with the highest sum\n",
"y_train = train_labels[:, most_pop_column]\n",
"y_test = test_labels[:, most_pop_column]"
],
"metadata": {
"id": "BDB__zC_X5kI"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Vectorization"
],
"metadata": {
"id": "SeG_b8gEAZVC"
}
},
{
"cell_type": "code",
"source": [
"def vectorization(trains, tests, min_df):\n",
" from sklearn.feature_extraction.text import TfidfVectorizer\n",
"\n",
" vectorizer = TfidfVectorizer(min_df=min_df)\n",
" x_train = vectorizer.fit_transform(trains)\n",
" x_train_m = x_train.toarray()\n",
" x_test = vectorizer.transform(tests)\n",
" x_test_m = x_test.toarray()\n",
"\n",
" print(x_train_m.shape)\n",
" print(x_test_m.shape)\n",
"\n",
" return x_train_m, x_test_m\n",
"\n",
"trains_vect, tests_vect = vectorization(train_sentences, test_sentences, min_df=0.02) #the smaller the df the better, later on we use 0.01"
],
"metadata": {
"id": "O-fA3eAOAbGm"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Elbow Method (we also print the most suitable value for the clusters)"
],
"metadata": {
"id": "Xx07YoW--eBn"
}
},
{
"cell_type": "code",
"source": [
"import matplotlib.pyplot as plt\n",
"distortions = []\n",
"K = range(3, 303, 30)\n",
"for k in K:\n",
" kmeans = KMeans(n_clusters=k)\n",
" kmeans.fit(trains_vect)\n",
" distortions.append(kmeans.inertia_)\n",
"\n",
"# Plot the elbow curve\n",
"plt.plot(K, distortions, 'bx-')\n",
"plt.xlabel('Number of clusters (K)')\n",
"plt.ylabel('Distortion')\n",
"plt.title('Elbow Method')\n",
"plt.show()\n",
"\n",
"# Find the suitable number of clusters based on the elbow plot\n",
"elbow_index = np.argmin(distortions)\n",
"suitable_clusters = K[elbow_index]\n",
"print(\"The suitable number of clusters (K) based on the elbow method:\", suitable_clusters)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 856
},
"id": "ogoSrJbmZ2Kj",
"outputId": "337c7b7d-51e7-4751-e567-1fc4d23f2eff"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n",
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n"
]
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {}
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"The suitable number of clusters (K) based on the elbow method: 273\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"# Perform K-means clustering\n",
"k = 273 #suitable_clusters # Specify the desired number of clusters\n",
"kmeans = KMeans(n_clusters=k)\n",
"kmeans.fit(trains_vect)\n",
"\n",
"# Get the cluster labels for test set\n",
"test_kmeans_labels = kmeans.predict(tests_vect)\n",
"\n",
"# Save the cluster labels\n",
"with open('labels.p', 'wb') as file:\n",
" pickle.dump(test_kmeans_labels, file)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "9GkBsXh9fKZf",
"outputId": "3e409811-fd23-4b0b-a362-720a62da1452"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"/usr/local/lib/python3.10/dist-packages/sklearn/cluster/_kmeans.py:870: FutureWarning: The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n",
" warnings.warn(\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"# Get features for test set based on kmeans labels\n",
"\n",
"X_test = np.zeros((len(test_docs), 273))\n",
"with open('labels.p', 'rb') as file:\n",
" test_kmeans_labels = pickle.load(file)\n",
"te_kmeans_labels_lists = [] \n",
"c = 0\n",
"for length in test_bag_len:\n",
" te_kmeans_labels_lists.append(list(test_kmeans_labels[c:c + length]))\n",
" c += length\n",
"for i in range(len(X_test)):\n",
" for j in range(len(te_kmeans_labels_lists[i])):\n",
" X_test[i, te_kmeans_labels_lists[i][j]] += 1 "
],
"metadata": {
"id": "eLIvsDewX_5p"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"train_features = trains_vect \n",
"test_features = tests_vect\n",
"\n",
"print(\"train_features shape:\", train_features.shape)\n",
"print(\"train_labels_filtered shape:\", train_labels.shape)\n",
"print(\"y_train shape:\", y_train.shape)\n",
"\n",
"label_indices = np.isin(y_train, [0, 1])\n",
"train_features_filtered = train_features[label_indices]\n",
"train_labels_filtered = train_labels[label_indices]\n",
"\n",
"print(\"train_features_filtered shape:\", train_features_filtered.shape)\n",
"print(\"train_labels_filtered shape:\", train_labels_filtered.shape)\n",
"\n",
"# Train Gaussian Naive Bayes classifier\n",
"clf = GaussianNB() #try with one first to get some insights\n",
"clf.fit(train_features_filtered, train_labels_filtered)\n",
"y_pred = clf.predict(test_features)\n",
"\n",
"# Evaluate the classifier\n",
"print('Classifier: Gaussian NB')\n",
"print('Classification Report:')\n",
"print(classification_report(test_labels, y_pred))\n",
"print('F1 Score:', f1_score(test_labels, y_pred))\n",
"\n",
"#error: remember to fix"
],
"metadata": {
"id": "xLmxMxa191zh"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"# 2"
],
"metadata": {
"id": "Cc3PhVhZ-oFt"
}
},
{
"cell_type": "code",
"source": [
"import numpy as np\n",
"from sklearn.naive_bayes import GaussianNB\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.ensemble import RandomForestClassifier\n",
"from sklearn.svm import SVC\n",
"from sklearn.model_selection import GridSearchCV\n",
"from sklearn.metrics import classification_report, f1_score\n",
"from sklearn.preprocessing import StandardScaler\n",
"from sklearn.preprocessing import MaxAbsScaler\n",
"import re\n",
"from sklearn.feature_extraction.text import CountVectorizer\n",
"import pandas as pd\n",
"import numpy as np\n",
"from sklearn.model_selection import train_test_split\n",
"import warnings\n",
"warnings.filterwarnings(\"ignore\")"
],
"metadata": {
"id": "c2qr8VqjBOnp"
},
"execution_count": 1,
"outputs": []
},
{
"cell_type": "code",
"source": [
"with open('train-data.dat', 'r') as train_file:\n",
" train_data = train_file.readlines()\n",
"\n",
"with open('test-data.dat', 'r') as test_file:\n",
" test_data = test_file.readlines()\n"
],
"metadata": {
"id": "02A6Tx2xBRRN"
},
"execution_count": 5,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Preprocessing"
],
"metadata": {
"id": "uAn6Tyz3CR4G"
}
},
{
"cell_type": "code",
"source": [
"def preprocess_document(document):\n",
" # Remove special characters and convert to lowercase (lowercase also not needed, just in case)\n",
" document = re.sub(r'[^a-zA-Z0-9\\s<>]', '', document.lower())\n",
"\n",
" # Split into sentences and words\n",
" sentences = document.split('\\n')\n",
" sentences = [sentence.strip() for sentence in sentences if sentence.strip()]\n",
"\n",
" # Remove words and numbers enclosed in < and > symbols\n",
" preprocessed_sentences = []\n",
" for sentence in sentences:\n",
" words = sentence.split()\n",
" words = [word for word in words if not (word.startswith('<') and word.endswith('>'))]\n",
" preprocessed_sentences.append(' '.join(words))\n",
"\n",
" # Wrap each line in single quotes\n",
" preprocessed_document = \"'\" + \"'\\n'\".join(preprocessed_sentences) + \"'\"\n",
"\n",
" return preprocessed_document\n",
"\n",
"preprocessed_train_data = [preprocess_document(document) for document in train_data]\n",
"preprocessed_test_data = [preprocess_document(document) for document in test_data]\n",
"\n",
"# Print the first 5 lines of preprocessed train-data\n",
"print(\"Preprocessed train-data:\")\n",
"for i in range(5):\n",
" print(preprocessed_train_data[i])\n",
" print()\n",
"\n",
"# Print the first 5 lines of preprocessed test-data\n",
"print(\"Preprocessed test-data:\")\n",
"for i in range(5):\n",
" print(preprocessed_test_data[i])\n",
" print()\n"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Xl3zo7tHBTxV",
"outputId": "3b9b6646-bfc8-43db-f732-58b44bb806a7"
},
"execution_count": 6,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Preprocessed train-data:\n",
"'6705 5997 8310 3606 674 8058 5044 4836 4312 5154 8310 4225'\n",
"\n",
"'1827 1037 8482 483 3567 6172 6172 2892 1362 787 399 777 1332 318 769 4621 3199 1480 6213 971 6890 5909 15 3445 2475 324 4138 3404 6176 65 2926 1375 7705 709 1323 1652 5735 7439 3445 2475 4396 4382 1798 1870 1845 4410 7758 4278 7775 318 769 2898 1923 8193 2930 485 5951 6123 2480 3158 2193 2438 7485 3412 5304 5644 3734 7459 1652 3174 8343 426 1968 7506 561 4051 2722 6717 6172 3432 7859 4595 2351 5951 135 7023 7215 7038 7221 560 4631 4411 1348 8185 5192 3445 2475 5696 5154 361 7953 4245 560 2351 4410 7758 2174 1120 6688 7705 2747 1296 1652 134 5909 7953 4245'\n",
"\n",
"'8482 787 2169 4077 6335 1137 1598 1055 1223 2735 3492 413 838 4457 8392 3631 3699 42 5217 4281 6309 2912 6629 1985 2781 2155 5217 8032 860 7998 1469 4077 682 5950 7654 1561 5217 137 4032 42 5217 29 365 5339 4081 4386 7654 679 5217 620 8197 679 8403 42 5217 2134 5427 980 550 316 762 5582 3148 6039 5217 7378 470 674 8197 1072 42 5217 4164 470 5208 7048 371 2602 2975 6690 1386 3303 1193 8197 6955 894 2839 42 7194 5217 135 4998 2797 470 470 3154 2651 94 1450 4176 5366 5217 1564 1657 3481 886 4462 660 2044 5217 1657 4688 4716 894 2839 1770 5339 2368 8424 674 5055 872 5217 4123 5506 3134 8151 2287 1851 8197 1357 4002 5217 163 771 4877 6954 2623 42 664 2468 1194 4013 5785 2155 5757 5217 7146 6103 7553 6610 1824 5623 2287 1566 2115 1072 1945 1366 7593 5339 5055 4021 5217 29 1386 8243 1072 6068 3988 2781 2155 5217 1386 1072 5217 1386 8243 2287 5217 4851 7654 6073 679 5217 965 2287 852 345 1085 1386 1450 1163 852 2781 4439 6 3424 3733 8115 4386 5217 5339 4049 2623 1194 3424 2287 5217 2912 2836 12 2623 1386 4312 1908 5217 2947 2623 5427 5217 1378 550 4711 6300 5604 1386 2287 6060 6901 1757 2729 8197 880 209 5793 1657'\n",
"\n",
"'3843 3843 5427 3355 3843 5154 7451 5101 681 5339 1910 1259 1921 3778 682 3375 1758 108 3681 1874'\n",
"\n",
"'5877 4688 5877 1137 343 4695 1145 125 679 5744 3481 5744 1145 125 679 674 343 2287 5744 679 574 5877 191 3492 219 4688 191 1137 5877 1054 674 6622 3930 2419 537 2419 5312 2419 406 1621 7659 3400 4621'\n",
"\n",
"Preprocessed test-data:\n",
"'5282 4641 3031 536 5366 1759 4855 1037 7752 2287 1090 1921 6213 3292 5750 6068 5648 1444 6157 1574 6955 2287 3816 5553 568 6955 5523 2793 4312 2033 4217 7593 6955 965 7553 7464 2651 8283 1426 5741 4032 740 470 2413 4767 6629 4551 7859 1007 6629 945 7553 4551 6955 568 7981 4386 6166 539 8115 6183 7440 1137 6 1137 4386 6985 470 2151 7340 1779 4691 1499 4386 4691 8032 1193 6955 4124 4386 7553 126 7553 4086 6955 8235 539 4386 965 5598 1921 2904 852 4691 1137 874 323 4691 1574 482 2651 470 5427 6157 1783 6073 679 7752 3710 561 1072 126 4386 4844 5744 4790 679 9 188 327 764 3473 7281 327 8250 291 3885 674 4344 3804 42 2287 674 1620 2054 2054 4258 6544 5388 474 130 793 2054 4267 5238 3648 7004 2287 2385 6 561 1072 6700 1193 2287 8283 1193 1891 8283 3710 5388 3486 4032 188 3482 4959 6888 4319 2287 6888 421 5875 2985 3268 5663 2287 7553 1946 5663 777 3343 6888 4258 325 2866 2287 4846 1523 4634 2155 7553 903 5073 325 1709 2733 777 7275 1576 5073 325 903 903 325 1709 2733'\n",
"\n",
"'838 4060 2673 3204 5724 8518 6629 7752 6103 4755 782 315 2731 2651 384 4123 5909 5734 7034 2731 6103 4755 3191 4598 1868 3204 6559 3112 2123 568 5994 7168 4936 6715 6290 7123 4085 3031 3031 4402 3968 247 950 413 5724 419 3127 318 2651 950 1869 1770 3083 7439 1499 541 7959 6746 40 5655 482 2651 5313 1375 62 6623 1965 3968 5411 5302 439 7524 165 7752 4176 5486 135 1330 5924 6251 7828 2993 3199 1295 1281 4079 4731 3548 5080 814 1730 1542 1690 1564 6954 3518 3158 814 2222 4571 7746 6468 782 6735 1564 4193 6400 3195 965 674 2897 4851 989 3822 614 2244 1368 6473 3009 7469 4098 3495 6188 2248 5354 5919 6901 4974 1983 7294 920 1733 1332 3707 5277 3191 1426 6365 1194 3707 7118 4833 1223 4745 2623 3492 6365 434 256 5055 3375 3004 5209 1710 5238 7719 2988 3864 3979 7469 3558 2442 6193 7013 3864 8467 4178 3997 3415 3994 594 8377 5118 470 1316 3683 2721 2988 5303 4974 291 2718 209 5388 470 6068 950 4952 3090 6107 270 3127 5842 2711 740 2044 4851 135 2044 674 1904 2711 6403 2537 72 134 3772 4767 3772 2731 7123 6183 3648 6400 614 4855 594 672 5282 1319 1319 5282'\n",
"\n",
"'3664 3664 1254 5970 126 2401 2401 1696 1254 5970 3664 3664 381 594 1426 125 2401 1145 6890 1254 5970 1781 3664 7039 2998 682 3664 7439 4852 752 628 2731 6842 1704 7962 4852 752 4015 139 3664 7266 592 3326 6032 2044 1072 3664 6103 6709 3664 2401 5744 2441 2419 126 5745 8174 3203 3400 6171 2287 1293 209 5452 991 539 3582 3099 1444 7004 4983 8508 2401 2054 3664 3994 6629 209 2044 1375 700 4484 4621 4851 5909 8107 2401 73 2401 7959 777 6629 4952 5724 5436 7488 73 1905 8174 4851 8174 700 4484 768 546 6955 1783 7439 3664 5970 700 4484 7752 5909 6888 8508 4698 777 2401 2568 1709 4698 2001 3982 6890 7041 8508 4078 7962 6888 8174 8508 7693 8508 6888 2683 1564 1946 1704 614 4459 700 4484 5924 6279 2401 4653 8508 768 7693 5169 674 7960 777 502 3780 8508 4653 3099 7038 6060 1316 5909 2374 2610 5388 7034 4981 1472 188 3994 3422 5044 2401 6955 997 7572 5106 2401 7146 126 94 5486 8283 5044 2401 4887 126 5116 766 4466 2090 5817 7464 219 4974 2401 126 5909 993 6888 4621 470 3952 3112 7962 8508 5000 6888'\n",
"\n",
"'4688 3981 6858 4338 4282 2229 1394 568 5680 4282 190 6154 5523 2064 4086 2011 4688 2623 7139 4197 4086 4338 4688 7034 653 561 894 2839 4959 1704 1496 343 5282 5265 1145 125 2881 5101 3544 3775 3492 5101 4616 2468 3341 1564 4015 793 5101 4312 2897 2336 2287 5388 2166 2287 4880 7289 556 3191 2860 7266 5741 3653 126 5523 5154 470 9 3191 384 34 2054 371 4691 4032 6119 4314 5154 2054 8343 2731 3418 384 4314 1145 2568 216 645 3820 2651 4691 5101 5307 6669 3492 5101 4616 2468 3341 1564 4015 793 5101 4312 2897 5101 3147 6322 3492 5101 4616 2468 3341 1564 4015 793 5101 4312 2897'\n",
"\n",
"'777 5978 3631 1505 2287 4461 46 2401 7335 47 2839 5945 3816 1314 6356 2287 8082 2514 3602 3669 4466 483 3405 4466 4081 4621 474 5970 1259 4722 2437'\n",
"\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"# Load training and test labels\n",
"y_train = pd.read_csv('/content/train-label.dat', sep='\\t', header=None)[0].values\n",
"y_test = pd.read_csv('/content/test-label.dat', sep='\\t', header=None)[0].values\n",
"\n",
"# Convert the label strings into binary matrix representation\n",
"y_train_bin = np.array([list(map(int, label.split())) for label in y_train])\n",
"y_test_bin = np.array([list(map(int, label.split())) for label in y_test])"
],
"metadata": {
"id": "AS1DSxPQCWrB"
},
"execution_count": 7,
"outputs": []
},
{
"cell_type": "code",
"source": [
"popular_label = np.argmax(np.sum(y_train_bin, axis=0))\n",
"\n",
"# Keep only the column with the highest sum\n",
"y_train_bin = y_train_bin[:, popular_label]\n",
"y_test_bin = y_test_bin[:, popular_label]"
],
"metadata": {
"id": "cL2VUMpuCYqx"
},
"execution_count": 8,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Vectorization"
],
"metadata": {
"id": "mnr9LiihCafg"
}
},
{
"cell_type": "code",
"source": [
"vectorizer = CountVectorizer(min_df=0.05)\n",
"train_vectors = vectorizer.fit_transform(preprocessed_train_data)\n",
"test_vectors = vectorizer.transform(preprocessed_test_data)\n",
"print(train_vectors.shape)\n",
"print(test_vectors.shape)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "EQednz7cCddW",
"outputId": "6887fb37-5d48-4ef8-edb8-fbf9496b5265"
},
"execution_count": 9,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"(8251, 403)\n",
"(3983, 403)\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"## Train and Evaluate models"
],
"metadata": {
"id": "LHD1Ug7ACfPH"
}
},
{
"cell_type": "code",
"source": [
"# standarize to zero mean and unit variance\n",
"scaler = MaxAbsScaler()\n",
"scaler.fit(train_vectors)\n",
"X_train = scaler.transform(train_vectors)\n",
"X_test = scaler.transform(test_vectors)\n",
"\n",
"classifiers = [LogisticRegression(random_state=0),\n",
" RandomForestClassifier(random_state=0)]\n",
"names = ['Logistic Regression', 'Random Forest']\n",
"\n",
"for name, clf in zip(names, classifiers):\n",
" print('classifier:', name)\n",
" if name == 'Logistic Regression':\n",
" parameters = {'C':[0.001, 0.01, 0.1, 1.0], 'solver': ['newton-cg', 'lbfgs']}\n",
" else:\n",
" parameters = {'n_estimators':[100,200,300]}\n",
" grid = GridSearchCV(clf,param_grid=parameters,cv=5,scoring='f1')\n",
" model_grid = grid.fit(X_train, y_train_bin)\n",
" y_pred = model_grid.predict(X_test)\n",
" print('classification report')\n",
" print(classification_report(y_test_bin, y_pred))\n",
" print('f1 score')\n",
" print(f1_score(y_test_bin, y_pred))\n"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "ytT5xL3FCiUz",
"outputId": "8f862e8b-df98-4fb9-fb51-b0588744f8a2"
},
"execution_count": 10,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"classifier: Logistic Regression\n",
"classification report\n",
" precision recall f1-score support\n",
"\n",
" 0 0.66 0.89 0.76 2425\n",
" 1 0.62 0.28 0.39 1558\n",
"\n",
" accuracy 0.65 3983\n",
" macro avg 0.64 0.59 0.57 3983\n",
"weighted avg 0.65 0.65 0.61 3983\n",
"\n",
"f1 score\n",
"0.3865248226950354\n",
"classifier: Random Forest\n",
"classification report\n",
" precision recall f1-score support\n",
"\n",
" 0 0.67 0.88 0.76 2425\n",
" 1 0.63 0.31 0.41 1558\n",
"\n",
" accuracy 0.66 3983\n",
" macro avg 0.65 0.60 0.59 3983\n",
"weighted avg 0.65 0.66 0.62 3983\n",
"\n",
"f1 score\n",
"0.413585554600172\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"## Conclusions"
],
"metadata": {
"id": "CS6U4z3UCk67"
}
},
{
"cell_type": "markdown",
"source": [
"Based on these metrics, we can see that the Random Forest classifier outperforms the Logistic Regression model in terms of both precision and recall for both labels. It achieves a higher F1-score for label 1 (positive class), indicating better performance in capturing the positive instances. Additionally, the Random Forest model has a slightly higher accuracy.\n",
"\n",
"Therefore, considering the overall performance and the F1-score as the evaluation metric, the Random Forest classifier can be considered the better model among the two."
],
"metadata": {
"id": "MB5V_GZMCpu6"
}
}
]
}