Spaces:
Configuration error
Configuration error
File size: 146,754 Bytes
97e3689 |
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 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 |
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"objc[62740]: Class CaptureDelegate is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_videoio.3.4.16.dylib (0x111248860) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e480). One of the two will be used. Which one is undefined.\n",
"objc[62740]: Class CVWindow is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_highgui.3.4.16.dylib (0x107d00a68) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e4d0). One of the two will be used. Which one is undefined.\n",
"objc[62740]: Class CVView is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_highgui.3.4.16.dylib (0x107d00a90) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e4f8). One of the two will be used. Which one is undefined.\n",
"objc[62740]: Class CVSlider is implemented in both /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/mediapipe/.dylibs/libopencv_highgui.3.4.16.dylib (0x107d00ab8) and /Users/fuixlabsdev1/Programming/PP/graduation-thesis/env/lib/python3.8/site-packages/cv2/cv2.abi3.so (0x289c9e520). One of the two will be used. Which one is undefined.\n"
]
}
],
"source": [
"import mediapipe as mp\n",
"import cv2\n",
"import pandas as pd\n",
"import pickle\n",
"import numpy as np\n",
"import csv\n",
"import seaborn as sns\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.preprocessing import StandardScaler\n",
"from sklearn.calibration import CalibratedClassifierCV\n",
"from sklearn.linear_model import LogisticRegression, SGDClassifier\n",
"from sklearn.svm import SVC\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"from sklearn.tree import DecisionTreeClassifier\n",
"from sklearn.ensemble import RandomForestClassifier\n",
"from sklearn.naive_bayes import GaussianNB\n",
"\n",
"from sklearn.metrics import precision_score, accuracy_score, f1_score, recall_score, confusion_matrix, roc_curve, auc\n",
"\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"\n",
"# Drawing helpers\n",
"mp_drawing = mp.solutions.drawing_utils\n",
"mp_pose = mp.solutions.pose"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1. Set up important landmarks and functions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Generate Data Frame\n",
"\n",
"According to my research *the correct form* for a squat is analyzed through the position of:\n",
"- Back\n",
"- Hip\n",
"- Legs\n",
"\n",
"Therefore, there will be *9 keypoints* which will be extract from mediapipe in order to train or detect a correct form of a squat:\n",
"- \"NOSE\",\n",
"- \"LEFT_SHOULDER\",\n",
"- \"RIGHT_SHOULDER\",\n",
"- \"LEFT_HIP\",\n",
"- \"RIGHT_HIP\",\n",
"- \"LEFT_KNEE\",\n",
"- \"RIGHT_KNEE\",\n",
"- \"LEFT_ANKLE\",\n",
"- \"RIGHT_ANKLE\"\n",
"\n",
"The data frame will be saved in a .csv file.\n",
"\n",
"A data frame will contains a \"Label\" columns which represent the label of a data point.\n",
"\n",
"There are another 9 x 4 columns represent 9 features of a human pose that are important for a squat.\n",
"In that each landmark's info will be flatten\n",
"\n",
"According to the [Mediapipe documentation](https://google.github.io/mediapipe/solutions/pose#python-solution-api),\n",
"Each landmark consists of the following:\n",
"- x and y: Landmark coordinates normalized to [0.0, 1.0] by the image width and height respectively.\n",
"- z: Represents the landmark depth with the depth at the midpoint of hips being the origin, and the smaller the value the closer the landmark is to the camera. The magnitude of z uses roughly the same scale as x.\n",
"- visibility: A value in [0.0, 1.0] indicating the likelihood of the landmark being visible (present and not occluded) in the image."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Determine important landmarks for squat\n",
"IMPORTANT_LMS = [\n",
" \"NOSE\",\n",
" \"LEFT_SHOULDER\",\n",
" \"RIGHT_SHOULDER\",\n",
" \"LEFT_HIP\",\n",
" \"RIGHT_HIP\",\n",
" \"LEFT_KNEE\",\n",
" \"RIGHT_KNEE\",\n",
" \"LEFT_ANKLE\",\n",
" \"RIGHT_ANKLE\"\n",
"]\n",
"\n",
"# Generate all columns of the data frame\n",
"\n",
"landmarks = [\"label\"] # Label column\n",
"\n",
"for lm in IMPORTANT_LMS:\n",
" landmarks += [f\"{lm.lower()}_x\", f\"{lm.lower()}_y\", f\"{lm.lower()}_z\", f\"{lm.lower()}_v\"]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def rescale_frame(frame, percent=50):\n",
" '''\n",
" Rescale a frame to a certain percentage compare to its original frame\n",
" '''\n",
" width = int(frame.shape[1] * percent/ 100)\n",
" height = int(frame.shape[0] * percent/ 100)\n",
" dim = (width, height)\n",
" return cv2.resize(frame, dim, interpolation =cv2.INTER_AREA)\n",
" \n",
"\n",
"def init_csv(dataset_path: str):\n",
" '''\n",
" Create a blank csv file with just columns\n",
" '''\n",
"\n",
" # Write all the columns to a file\n",
" with open(dataset_path, mode=\"w\", newline=\"\") as f:\n",
" csv_writer = csv.writer(f, delimiter=\",\", quotechar='\"', quoting=csv.QUOTE_MINIMAL)\n",
" csv_writer.writerow(landmarks)\n",
"\n",
" \n",
"def export_landmark_to_csv(dataset_path: str, results, action: str) -> None:\n",
" '''\n",
" Export Labeled Data from detected landmark to csv\n",
" '''\n",
" landmarks = results.pose_landmarks.landmark\n",
" keypoints = []\n",
"\n",
" try:\n",
" # Extract coordinate of important landmarks\n",
" for lm in IMPORTANT_LMS:\n",
" keypoint = landmarks[mp_pose.PoseLandmark[lm].value]\n",
" keypoints.append([keypoint.x, keypoint.y, keypoint.z, keypoint.visibility])\n",
" \n",
" keypoints = list(np.array(keypoints).flatten())\n",
"\n",
" # Insert action as the label (first column)\n",
" keypoints.insert(0, action)\n",
"\n",
" # Append new row to .csv file\n",
" with open(dataset_path, mode=\"a\", newline=\"\") as f:\n",
" csv_writer = csv.writer(f, delimiter=\",\", quotechar='\"', quoting=csv.QUOTE_MINIMAL)\n",
" csv_writer.writerow(keypoints)\n",
" \n",
"\n",
" except Exception as e:\n",
" print(e)\n",
" pass\n",
"\n",
"\n",
"def concat_csv_files_with_same_headers(file_paths: list, saved_path: str):\n",
" '''\n",
" Concat different csv files\n",
" '''\n",
" all_df = []\n",
" for path in file_paths:\n",
" df = pd.read_csv(path, index_col=None, header=0)\n",
" all_df.append(df)\n",
" \n",
" results = pd.concat(all_df, axis=0, ignore_index=True)\n",
" results.to_csv(saved_path, sep=',', encoding='utf-8', index=False)\n",
"\n",
"\n",
"def describe_dataset(dataset_path: str):\n",
" ''''''\n",
"\n",
" data = pd.read_csv(dataset_path)\n",
" print(f\"Headers: {list(data.columns.values)}\")\n",
" print(f'Number of rows: {data.shape[0]} \\nNumber of columns: {data.shape[1]}\\n')\n",
" print(f\"Labels: \\n{data['label'].value_counts()}\\n\")\n",
" print(f\"Missing values: {data.isnull().values.any()}\\n\")\n",
" duplicate = data[data.duplicated()]\n",
" print(f\"Duplicate Rows : {duplicate.sum(axis=1)}\")\n",
"\n",
" return data\n",
"\n",
"\n",
"def round_up_metric_results(results) -> list:\n",
" '''Round up metrics results such as precision score, recall score, ...'''\n",
" return list(map(lambda el: round(el, 3), results))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2. Extract data for train set"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"DATASET_PATH = \"./train.csv\"\n",
"\n",
"cap = cv2.VideoCapture(\"../data/squat/squat_posture.mp4\")\n",
"up_save_count = 0\n",
"down_save_count = 0\n",
"\n",
"# init_csv(DATASET_PATH)\n",
"\n",
"with mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) as pose:\n",
" while cap.isOpened():\n",
" ret, image = cap.read()\n",
"\n",
" if not ret:\n",
" break\n",
" \n",
" # Reduce size of a frame\n",
" image = rescale_frame(image, 60)\n",
" image = cv2.flip(image, 1)\n",
"\n",
" # Recolor image from BGR to RGB for mediapipe\n",
" image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
" image.flags.writeable = False\n",
"\n",
" results = pose.process(image)\n",
"\n",
" # Recolor image from BGR to RGB for mediapipe\n",
" image.flags.writeable = True\n",
" image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n",
"\n",
" # Draw landmarks and connections\n",
" mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, mp_drawing.DrawingSpec(color=(244, 117, 66), thickness=2, circle_radius=4), mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2))\n",
"\n",
" # Display the saved count\n",
" cv2.putText(image, f\"UP saved: {up_save_count}\", (50, 150), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 255, 255), 1, cv2.LINE_AA)\n",
" cv2.putText(image, f\"DOWN saved: {down_save_count}\", (50, 200), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 255, 255), 1, cv2.LINE_AA)\n",
"\n",
" cv2.imshow(\"CV2\", image)\n",
"\n",
" # Pressed key for action\n",
" k = cv2.waitKey(1) & 0xFF\n",
"\n",
" if k == ord('d'): \n",
" export_landmark_to_csv(DATASET_PATH, results, \"down\")\n",
" down_save_count += 1\n",
" elif k == ord(\"u\"):\n",
" export_landmark_to_csv(DATASET_PATH, results, \"up\")\n",
" up_save_count += 1\n",
" # Press q to stop\n",
" elif k == ord(\"q\"):\n",
" break\n",
" else: continue\n",
"\n",
" cap.release()\n",
" cv2.destroyAllWindows()\n",
"\n",
" # (Optional)Fix bugs cannot close windows in MacOS (https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv)\n",
" for i in range (1, 5):\n",
" cv2.waitKey(1)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Headers: ['label', 'nose_x', 'nose_y', 'nose_z', 'nose_v', 'left_shoulder_x', 'left_shoulder_y', 'left_shoulder_z', 'left_shoulder_v', 'right_shoulder_x', 'right_shoulder_y', 'right_shoulder_z', 'right_shoulder_v', 'left_hip_x', 'left_hip_y', 'left_hip_z', 'left_hip_v', 'right_hip_x', 'right_hip_y', 'right_hip_z', 'right_hip_v', 'left_knee_x', 'left_knee_y', 'left_knee_z', 'left_knee_v', 'right_knee_x', 'right_knee_y', 'right_knee_z', 'right_knee_v', 'left_ankle_x', 'left_ankle_y', 'left_ankle_z', 'left_ankle_v', 'right_ankle_x', 'right_ankle_y', 'right_ankle_z', 'right_ankle_v']\n",
"Number of rows: 3739 \n",
"Number of columns: 37\n",
"\n",
"Labels: \n",
"down 1914\n",
"up 1825\n",
"Name: label, dtype: int64\n",
"\n",
"Missing values: False\n",
"\n",
"Duplicate Rows : Series([], dtype: float64)\n"
]
}
],
"source": [
"df = describe_dataset(DATASET_PATH)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3. Extract data for test set "
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"TEST_DATASET_PATH = \"./test.csv\"\n",
"\n",
"cap = cv2.VideoCapture(\"../data/squat/squat_test_4.mp4\")\n",
"up_save_count = 0\n",
"down_save_count = 0\n",
"\n",
"# init_csv(TEST_DATASET_PATH)\n",
"\n",
"with mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) as pose:\n",
" while cap.isOpened():\n",
" ret, image = cap.read()\n",
"\n",
" if not ret:\n",
" break\n",
" \n",
" # Reduce size of a frame\n",
" image = rescale_frame(image, 60)\n",
" # image = cv2.flip(image, 1)\n",
"\n",
" # Recolor image from BGR to RGB for mediapipe\n",
" image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
" image.flags.writeable = False\n",
"\n",
" results = pose.process(image)\n",
"\n",
" # Recolor image from BGR to RGB for mediapipe\n",
" image.flags.writeable = True\n",
" image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)\n",
"\n",
" # Draw landmarks and connections\n",
" mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, mp_drawing.DrawingSpec(color=(244, 117, 66), thickness=2, circle_radius=4), mp_drawing.DrawingSpec(color=(245, 66, 230), thickness=2, circle_radius=2))\n",
"\n",
" # Display the saved count\n",
" cv2.putText(image, f\"UP saved: {up_save_count}\", (50, 150), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 255, 255), 1, cv2.LINE_AA)\n",
" cv2.putText(image, f\"DOWN saved: {down_save_count}\", (50, 200), cv2.FONT_HERSHEY_COMPLEX, 2, (255, 255, 255), 1, cv2.LINE_AA)\n",
"\n",
" cv2.imshow(\"CV2\", image)\n",
"\n",
" # Pressed key for action\n",
" k = cv2.waitKey(1) & 0xFF\n",
"\n",
" if k == ord('d'): \n",
" export_landmark_to_csv(TEST_DATASET_PATH, results, \"down\")\n",
" down_save_count += 1\n",
" elif k == ord(\"u\"):\n",
" export_landmark_to_csv(TEST_DATASET_PATH, results, \"up\")\n",
" up_save_count += 1\n",
" # Press q to stop\n",
" elif k == ord(\"q\"):\n",
" break\n",
" else: continue\n",
"\n",
" cap.release()\n",
" cv2.destroyAllWindows()\n",
"\n",
" # (Optional)Fix bugs cannot close windows in MacOS (https://stackoverflow.com/questions/6116564/destroywindow-does-not-close-window-on-mac-using-python-and-opencv)\n",
" for i in range (1, 5):\n",
" cv2.waitKey(1)\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4. Train custom model using Scikit Learn"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 4.1 Read and describe data"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Headers: ['label', 'nose_x', 'nose_y', 'nose_z', 'nose_v', 'left_shoulder_x', 'left_shoulder_y', 'left_shoulder_z', 'left_shoulder_v', 'right_shoulder_x', 'right_shoulder_y', 'right_shoulder_z', 'right_shoulder_v', 'left_hip_x', 'left_hip_y', 'left_hip_z', 'left_hip_v', 'right_hip_x', 'right_hip_y', 'right_hip_z', 'right_hip_v', 'left_knee_x', 'left_knee_y', 'left_knee_z', 'left_knee_v', 'right_knee_x', 'right_knee_y', 'right_knee_z', 'right_knee_v', 'left_ankle_x', 'left_ankle_y', 'left_ankle_z', 'left_ankle_v', 'right_ankle_x', 'right_ankle_y', 'right_ankle_z', 'right_ankle_v']\n",
"Number of rows: 4160 \n",
"Number of columns: 37\n",
"\n",
"Labels: \n",
"down 2127\n",
"up 2033\n",
"Name: label, dtype: int64\n",
"\n",
"Missing values: False\n",
"\n",
"Duplicate Rows : Series([], dtype: float64)\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Brief describe of the dataset\n",
"df = describe_dataset(\"./train.csv\")\n",
"sns.countplot(x='label', data=df, palette=\"Set1\") \n",
"df.loc[df[\"label\"] == \"down\", \"label\"] = 0\n",
"df.loc[df[\"label\"] == \"up\", \"label\"] = 1"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [],
"source": [
"# Extract features and class\n",
"X = df.drop(\"label\", axis=1) # features\n",
"y = df[\"label\"].astype(\"int\")\n",
"\n",
"sc = StandardScaler()\n",
"X = pd.DataFrame(sc.fit_transform(X))"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3319 1\n",
"2621 0\n",
"3820 1\n",
"Name: label, dtype: int64"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Split train set and test set\n",
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234)\n",
"y_test.head(3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 4.2 Train Machine learning model"
]
},
{
"cell_type": "code",
"execution_count": 48,
"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>Model</th>\n",
" <th>Precision Score</th>\n",
" <th>Accuracy score</th>\n",
" <th>Recall Score</th>\n",
" <th>F1 score</th>\n",
" <th>Confusion Matrix</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>LR</td>\n",
" <td>[0.995, 1.0]</td>\n",
" <td>0.997596</td>\n",
" <td>[1.0, 0.995]</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>[[427, 0], [2, 403]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>SVC</td>\n",
" <td>[0.995, 1.0]</td>\n",
" <td>0.997596</td>\n",
" <td>[1.0, 0.995]</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>[[427, 0], [2, 403]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>KNN</td>\n",
" <td>[0.995, 1.0]</td>\n",
" <td>0.997596</td>\n",
" <td>[1.0, 0.995]</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>[[427, 0], [2, 403]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>SGDC</td>\n",
" <td>[0.995, 1.0]</td>\n",
" <td>0.997596</td>\n",
" <td>[1.0, 0.995]</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>[[427, 0], [2, 403]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>RF</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>0.997596</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>[0.998, 0.998]</td>\n",
" <td>[[426, 1], [1, 404]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>DTC</td>\n",
" <td>[0.995, 0.998]</td>\n",
" <td>0.996394</td>\n",
" <td>[0.998, 0.995]</td>\n",
" <td>[0.996, 0.996]</td>\n",
" <td>[[426, 1], [2, 403]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>NB</td>\n",
" <td>[0.986, 1.0]</td>\n",
" <td>0.992788</td>\n",
" <td>[1.0, 0.985]</td>\n",
" <td>[0.993, 0.993]</td>\n",
" <td>[[427, 0], [6, 399]]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Model Precision Score Accuracy score Recall Score F1 score \\\n",
"0 LR [0.995, 1.0] 0.997596 [1.0, 0.995] [0.998, 0.998] \n",
"1 SVC [0.995, 1.0] 0.997596 [1.0, 0.995] [0.998, 0.998] \n",
"2 KNN [0.995, 1.0] 0.997596 [1.0, 0.995] [0.998, 0.998] \n",
"3 SGDC [0.995, 1.0] 0.997596 [1.0, 0.995] [0.998, 0.998] \n",
"4 RF [0.998, 0.998] 0.997596 [0.998, 0.998] [0.998, 0.998] \n",
"5 DTC [0.995, 0.998] 0.996394 [0.998, 0.995] [0.996, 0.996] \n",
"6 NB [0.986, 1.0] 0.992788 [1.0, 0.985] [0.993, 0.993] \n",
"\n",
" Confusion Matrix \n",
"0 [[427, 0], [2, 403]] \n",
"1 [[427, 0], [2, 403]] \n",
"2 [[427, 0], [2, 403]] \n",
"3 [[427, 0], [2, 403]] \n",
"4 [[426, 1], [1, 404]] \n",
"5 [[426, 1], [2, 403]] \n",
"6 [[427, 0], [6, 399]] "
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"algorithms =[(\"LR\", LogisticRegression()),\n",
" (\"SVC\", SVC(probability=True)),\n",
" ('KNN',KNeighborsClassifier()),\n",
" (\"DTC\", DecisionTreeClassifier()),\n",
" (\"SGDC\", CalibratedClassifierCV(SGDClassifier())),\n",
" (\"NB\", GaussianNB()),\n",
" ('RF', RandomForestClassifier()),]\n",
"\n",
"models = {}\n",
"final_results = []\n",
"\n",
"for name, model in algorithms:\n",
" trained_model = model.fit(X_train, y_train)\n",
" models[name] = trained_model\n",
"\n",
" # Evaluate model\n",
" model_results = model.predict(X_test)\n",
"\n",
" p_score = precision_score(y_test, model_results, average=None, labels=[0, 1])\n",
" a_score = accuracy_score(y_test, model_results)\n",
" r_score = recall_score(y_test, model_results, average=None, labels=[0, 1])\n",
" f1_score_result = f1_score(y_test, model_results, average=None, labels=[0, 1])\n",
" cm = confusion_matrix(y_test, model_results, labels=[0, 1])\n",
" final_results.append(( name, round_up_metric_results(p_score), a_score, round_up_metric_results(r_score), round_up_metric_results(f1_score_result), cm))\n",
"\n",
"# Sort results by F1 score\n",
"final_results.sort(key=lambda k: sum(k[4]), reverse=True)\n",
"pd.DataFrame(final_results, columns=[\"Model\", \"Precision Score\", \"Accuracy score\", \"Recall Score\", \"F1 score\", \"Confusion Matrix\"])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 4.3 Test set evaluation"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Headers: ['label', 'nose_x', 'nose_y', 'nose_z', 'nose_v', 'left_shoulder_x', 'left_shoulder_y', 'left_shoulder_z', 'left_shoulder_v', 'right_shoulder_x', 'right_shoulder_y', 'right_shoulder_z', 'right_shoulder_v', 'left_hip_x', 'left_hip_y', 'left_hip_z', 'left_hip_v', 'right_hip_x', 'right_hip_y', 'right_hip_z', 'right_hip_v', 'left_knee_x', 'left_knee_y', 'left_knee_z', 'left_knee_v', 'right_knee_x', 'right_knee_y', 'right_knee_z', 'right_knee_v', 'left_ankle_x', 'left_ankle_y', 'left_ankle_z', 'left_ankle_v', 'right_ankle_x', 'right_ankle_y', 'right_ankle_z', 'right_ankle_v']\n",
"Number of rows: 853 \n",
"Number of columns: 37\n",
"\n",
"Labels: \n",
"down 430\n",
"up 423\n",
"Name: label, dtype: int64\n",
"\n",
"Missing values: False\n",
"\n",
"Duplicate Rows : Series([], dtype: float64)\n"
]
}
],
"source": [
"test_df = describe_dataset(\"./test.csv\")\n",
"test_df.loc[test_df[\"label\"] == \"down\", \"label\"] = 0\n",
"test_df.loc[test_df[\"label\"] == \"up\", \"label\"] = 1\n",
"\n",
"test_x = test_df.drop(\"label\", axis=1)\n",
"test_y = test_df[\"label\"].astype(\"int\")"
]
},
{
"cell_type": "code",
"execution_count": 58,
"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>Model</th>\n",
" <th>Precision score</th>\n",
" <th>Accuracy score</th>\n",
" <th>Recall score</th>\n",
" <th>F1 score</th>\n",
" <th>Confusion Matrix</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>LR</td>\n",
" <td>0.994141</td>\n",
" <td>0.994138</td>\n",
" <td>0.994138</td>\n",
" <td>0.994138</td>\n",
" <td>[[428, 2], [3, 420]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>SGDC</td>\n",
" <td>0.993063</td>\n",
" <td>0.992966</td>\n",
" <td>0.992966</td>\n",
" <td>0.992965</td>\n",
" <td>[[430, 0], [6, 417]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>KNN</td>\n",
" <td>0.985207</td>\n",
" <td>0.984760</td>\n",
" <td>0.984760</td>\n",
" <td>0.984754</td>\n",
" <td>[[430, 0], [13, 410]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>SVC</td>\n",
" <td>0.977595</td>\n",
" <td>0.976553</td>\n",
" <td>0.976553</td>\n",
" <td>0.976536</td>\n",
" <td>[[430, 0], [20, 403]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>DTC</td>\n",
" <td>0.254120</td>\n",
" <td>0.504103</td>\n",
" <td>0.504103</td>\n",
" <td>0.337902</td>\n",
" <td>[[430, 0], [423, 0]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>NB</td>\n",
" <td>0.254120</td>\n",
" <td>0.504103</td>\n",
" <td>0.504103</td>\n",
" <td>0.337902</td>\n",
" <td>[[430, 0], [423, 0]]</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>RF</td>\n",
" <td>0.254120</td>\n",
" <td>0.504103</td>\n",
" <td>0.504103</td>\n",
" <td>0.337902</td>\n",
" <td>[[430, 0], [423, 0]]</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Model Precision score Accuracy score Recall score F1 score \\\n",
"0 LR 0.994141 0.994138 0.994138 0.994138 \n",
"1 SGDC 0.993063 0.992966 0.992966 0.992965 \n",
"2 KNN 0.985207 0.984760 0.984760 0.984754 \n",
"3 SVC 0.977595 0.976553 0.976553 0.976536 \n",
"4 DTC 0.254120 0.504103 0.504103 0.337902 \n",
"5 NB 0.254120 0.504103 0.504103 0.337902 \n",
"6 RF 0.254120 0.504103 0.504103 0.337902 \n",
"\n",
" Confusion Matrix \n",
"0 [[428, 2], [3, 420]] \n",
"1 [[430, 0], [6, 417]] \n",
"2 [[430, 0], [13, 410]] \n",
"3 [[430, 0], [20, 403]] \n",
"4 [[430, 0], [423, 0]] \n",
"5 [[430, 0], [423, 0]] \n",
"6 [[430, 0], [423, 0]] "
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"testset_final_results = []\n",
"\n",
"for name, model in models.items():\n",
" # Evaluate model\n",
" model_results = model.predict(test_x)\n",
"\n",
" p_score = precision_score(test_y, model_results, average=\"weighted\")\n",
" a_score = accuracy_score(test_y, model_results)\n",
" r_score = recall_score(test_y, model_results, average=\"weighted\")\n",
" f1_score_result = f1_score(test_y, model_results, average=\"weighted\")\n",
" cm = confusion_matrix(test_y, model_results, labels=[0, 1])\n",
" testset_final_results.append(( name, (p_score), a_score, (r_score), (f1_score_result), cm ))\n",
"\n",
"\n",
"testset_final_results.sort(key=lambda k: k[4], reverse=True)\n",
"eval_df = pd.DataFrame(testset_final_results, columns=[\"Model\", \"Precision score\", \"Accuracy score\", \"Recall score\", \"F1 score\", \"Confusion Matrix\"])\n",
"eval_df = eval_df.sort_values(by=['F1 score'], ascending=False).reset_index(drop=True)\n",
"eval_df.to_csv(f\"evaluation.csv\", sep=',', encoding='utf-8', index=False)\n",
"eval_df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 4.3. Dumped model using pickle\n",
"\n",
"According to the evaluations, there are multiple good models at the moment, therefore, I will pick the Random Forrest model to use."
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [],
"source": [
"with open(\"./model/sklearn_models.pkl\", \"wb\") as f:\n",
" pickle.dump(models, f)"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [],
"source": [
"with open(\"./model/LR_model.pkl\", \"wb\") as f:\n",
" pickle.dump(models[\"LR\"], f)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [],
"source": [
"with open(\"./model/SGDC_model.pkl\", \"wb\") as f:\n",
" pickle.dump(models[\"SGDC\"], f)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 5. Evaluation"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(array([0.99303944, 0.99526066]),\n",
" array([0.99534884, 0.9929078 ]),\n",
" array([0.9941928 , 0.99408284]))"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"best_model = models[\"LR\"]\n",
"y_predictions = best_model.predict(test_x)\n",
"\n",
"p_score = precision_score(test_y, y_predictions, labels=[0, 1], average=None)\n",
"r_score = recall_score(test_y, y_predictions, labels=[0, 1], average=None)\n",
"f1_score_result = f1_score(test_y, y_predictions, labels=[0, 1], average=None)\n",
"\n",
"p_score, r_score, f1_score_result"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<AxesSubplot:>"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 800x600 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"KNN_cm = eval_df[ eval_df[\"Model\"] == 'LR' ][\"Confusion Matrix\"].values[0]\n",
"\n",
"cm_array_df = pd.DataFrame(KNN_cm, index=[\"down\", \"up\"], columns=[\"down\", \"up\"])\n",
"\n",
"fig, ax = plt.subplots(figsize=(8,6)) \n",
"sns.heatmap(cm_array_df, linewidths=1, annot=True, ax=ax, fmt='g', cmap=\"crest\")"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [],
"source": [
"def to_labels(y_pred, y_pred_proba, threshold):\n",
" '''Return prediction taking confidence threshold into account'''\n",
" results = []\n",
"\n",
" for index, predicted_class in enumerate(y_pred):\n",
" prediction_probabilities = y_pred_proba[index]\n",
" class_prediction_probability = round(prediction_probabilities[np.argmax(prediction_probabilities)], 2)\n",
"\n",
" results.append(predicted_class if class_prediction_probability >= threshold else -1)\n",
" \n",
" return results\n",
"\n",
"\n",
"def calculate_correlation_score_confidence(test_x, test_y):\n",
" '''Calculate correlation between Precision score/Recall score/F1 score and confidence threshold'''\n",
" y_predictions = best_model.predict(test_x)\n",
" y_predict_proba = best_model.predict_proba(test_x)\n",
"\n",
" thresholds = list(np.arange(0, 1.05, 0.01))\n",
"\n",
" f1_score_results = []\n",
"\n",
" for threshold in thresholds:\n",
" true_predictions = to_labels(y_predictions, y_predict_proba, threshold)\n",
" f1_s = list(f1_score(test_y, true_predictions, labels=[0, 1], average=None))\n",
" all_class_f1 = f1_score(test_y, true_predictions, labels=[0, 1], average=\"weighted\")\n",
" f1_s.append(all_class_f1)\n",
" f1_score_results.append(f1_s)\n",
" \n",
" return thresholds, f1_score_results\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 68,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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4GD69evH888/z8aNG9m7dy+LFy926meL+DvbqLPCIoP8QtcucvYVrVtD48bW42XLICMD68KSvfXhgMdqk8Cj8BtAMjIySEpKIikpCYA9e/aQlJRk/6frslx//fW8/PLL/PLLL+zbt4+lS5dy991307JlS1q1akV4eDgTJ07koYce4r333mP37t38/PPPzJw5E4Bhw4YRHh7OiBEj2Lx5M0uWLOGee+7h1ltvtbc8lGXYsGHEx8czZMgQVqxYwZ49e1i2bBn33nsvBw+6tz9s7NixpKWlcdNNN7Fu3Tp27tzJ+++/z44dOwB48MEHee6555g/fz47duzg4YcfJikpyaEn11nOvO8pU6bw4osv8uqrr7Jz505+++03XnvtNftr2MJxSkpKuSPpbr75ZhITE7n22mtZtWoVf/75J5999hlr1qwp8/zmzZvz/vvvs23bNn755ReGDRvmsHo8Z84cZs6cyebNm/nzzz95//33sVgsNG7cmG+++YZXX32VpKQk9u3bx3vvvUdRURHnn3++y78+Iv7ItvIL/nvRm8lUsttbfj789FPxA5r4IB6g8BtA1q1bR4cOHewXG02YMIEOHTowefLkcp9z5ZVX8vXXXzN48GBatmzJiBEjaNWqFT/++CPBwdaumccee4z777+fyZMn07p1a4YOHWrvl42IiOCHH37gxIkTdO7cmeuvv56+ffuec9ZwREQEy5cvp1GjRlx33XW0bt2a2267jezsbKKjo6voV8Q5tWrVYvHixfYJCR07duSdd96xt0qMGzeO+++/n/vvv58LL7yQ77//nq+++sph0oOznHnfI0aMYNq0abz55ptccMEFXH311ezcudP+Gi+++CILFy6kYcOG5V5YFhoayo8//kidOnUYNGgQF154Ic8++2y50yFmzZrFyZMn6dChA7feeivjxo2jTp069sdjY2N555136NGjB+3atWPRokV8/fXX1KpVi9jYWD7//HP69OlD69at+e9//8u8efO44IILXP71EfFHIUEmgszWVgd/3OXN5vSRZwsWFB9o1q94gMkwXBwk6wfS0tKIiYkhNTW1VJDKyclhz549NG3alPDwcA9VKBKY9PtPAtWFj/9Aem4BSx64nKbxvnGNiauysiAuDnJzoWFD2L8fWPosLJ0KF4+Aa171dIniZc6W1ypDK78iIiIeFh5qG3dW4OFKqk9EBHTvbj0+cKA4/GqLY/EAhV8REREPiygOv/66y5vN6VMhV61CbQ/iEQq/IiIiHmbx840ubIr3PwJs4bd4l7fUgxB4XZjiIQq/IiIiHmbb5c2fL3gD6Nq1eGtjisOvre0hLwNyUj1WlwQWhV8REREPs7U9+OuoM5uYGLjwQuvxxo2Qnhth3ewC1PogbqPwKyIi4mGWAFn5hZK+36Ii+PlnILqB9Q7N+hU3UfgVERHxMEuArPxCWRe92cKvdnkT91D4FRER8bBAueANNPFBPE/hV0RExMMCZdQZQOPGUK+e9fjnn6EgQm0P4l4KvyJlmDJlChdddJH9+5EjR3LttddW+PUuv/xy7rvvvkrXJSL+ybbJRSD0/JpMJau/GRmw6Whb6zda+RU3Ufj1IyNHjsRkMpW67dq1C4Dly5czePBg6tWrh8lk4osvvjjnaxYWFjJ16lRatWqFxWIhLi6Orl27Mnv27Gp+N9XvmWeeISgoiGeffdbTpYhIgLO3PQTAyi+c0fqw4zzrgXp+xU0Ufv3MgAEDSE5Odrg1bdoUgMzMTNq3b8/rr7/u9OtNmTKFadOm8dRTT7F161aWLFnCHXfcwcmTJ6vrLZCXl1dtr3262bNn89BDDzFr1iy3/DwRkfLY2x4CYOUXzgi/vydYD9IOW0dAiFQzhV8/ExYWRmJiosMtKMj6h+rAgQN5+umnue6665x+va+//poxY8Zwww030LRpU9q3b8/tt9/OhAkT7OcUFRXx3HPP0bx5c8LCwmjUqBH/93//Z39806ZN9OnTB4vFQq1atbjzzjvJyMiwP25rKZg6dSr16tWjZcuWABw6dIihQ4dSs2ZNatWqxZAhQ9i7d28lf4Wsli1bRnZ2Nk8++SSZmZksX7680q+5atUqevXqRUREBDVr1uTKK68s938SPvjgAzp16kRUVBSJiYnccsstHD161P74yZMnGTZsGLVr18ZisdCiRQv7anteXh5jx46lbt26hIeH06RJE6ZOnWp/bmpqKnfeeSd16tQhOjqaPn368Pvvv9sf//333+nduzdRUVFER0fTsWNH1q1bV+n3LyIVF0gXvAG0bw8REdbjVWsjABMU5kHWMY/WJYEh2NMF+IpOnSAlxf0/NzERPJlLEhMTWbx4MWPGjKF27dplnjNp0iTeeecdXn75ZS699FKSk5PZvn07AFlZWQwYMICuXbuydu1ajh49yqhRoxg7dixz5syxv8aiRYuIjo5m4cKFGIZBVlYWvXv3pmfPnixfvpzg4GCefvppBgwYwMaNGwkNDa3U+5o5cyY333wzISEh3HzzzcycOZPLLruswq+XlJRE3759ue2223j11VcJDg5myZIlFBaW/RdZXl4eTz31FOeffz5Hjx5l/PjxjBw5kgULFgDw2GOPsXXrVr777jvi4+PZtWsX2dnZALz66qt89dVXfPzxxzRq1IgDBw5w4ID1nwsNw+Cqq64iLi6OBQsWEBMTw1tvvUXfvn35448/iIuLY9iwYXTo0IHp06cTFBREUlISISEhFX7vIlJ5llDrX8eBMOoMICQELrkEliyBAwdMHCi8iIZBG6ytDzXqeLo88XdGAEpNTTUAIzU1tdRj2dnZxtatW43s7GyH++vXNwzrxuPuvdWv7/z7GjFihBEUFGRERkbab9dff32Z5wLG//73v3O+5pYtW4zWrVsbZrPZuPDCC4277rrLWLBggf3xtLQ0IywszHjnnXfKfP7bb79t1KxZ08jIyLDf9+233xpms9lISUmx152QkGDk5ubaz5k5c6Zx/vnnG0VFRfb7cnNzDYvFYvzwww/nrPtsUlNTjYiICCMpKckwDMPYsGGDERER4fDfw+OPP260b9/e/v2IESOMIUOGlPuaN998s9GjR49yH+/Vq5dx7733lvv4r7/+agBGenq6YRiGMXjwYOOf//xnmefec889Rp8+fRx+bWwWLVpkREdHGzk5OQ73n3feecZbb71lGIZhREVFGXPmzCm3Fk8q7/efiL/75vfDRuOJ3xg3/He1p0txm8ceK/m7bt6opwzj8WjD2PKlp8sSL3K2vFYZWvl1UmKib/zc3r17M336dPv3kZGRlfr5bdq0YfPmzaxfv56VK1faL5obOXIkM2bMYNu2beTm5tK3b98yn79t2zbat2/vUEePHj0oKipix44dJCRYe70uvPBCh9Xc9evXs2vXLqKiohxeLycnh927d5f5sy644AL27dsHQM+ePfnuu+/KPO/DDz+kWbNmtG/fHoCLLrqIZs2a8dFHH3HnnXc6+SvjKCkpiRtuuMHp8zds2MCUKVNISkrixIkTFBX3ue3fv582bdrwr3/9i7///e/89ttv9O/fn2uvvZbu3bsD1jaRK664gvPPP58BAwZw9dVX079/f8D665aRkUGtWrUcfl52drb9123ChAmMGjWK999/n379+nHDDTdw3nnnVeh9i0jVsIRauxADYdqDjUPf74FLuKk+mvggbqHw6yRfaYmMjIykefPmVfqaZrOZzp0707lzZ8aPH88HH3zArbfeyqOPPorFYjnrcw3DwGQylfnY6fefGdKLioro2LEjc+fOLfW88tovFixYQH5+PsBZ65o1axZbtmwhOLjkP/+ioiJmzpxZ4fB7rl+H02VmZtK/f3/69+/PBx98QO3atdm/fz9XXnml/WK/gQMHsm/fPr799lt++ukn+vbty913380LL7zAxRdfzJ49e/juu+/46aefuPHGG+nXrx+ffvopRUVF1K1bl6VLl5b6ubGxsYD1IsZbbrmFb7/9lu+++47HH3+cjz76iL/97W8Veu8iUnmWkMBqewDo2tU69swwYNWuC6ArkHrQ02VJAFD4FZe1adMGsIa4Fi1aYLFYWLRoEaNGjSrz3HfffZfMzEx7wF21ahVms9l+YVtZLr74YubPn2+/aMsZjRs3Puc5mzZtYt26dSxdupS4uDj7/adOneKyyy5j8+bNtG3b1qmfd7p27dqxaNEinnjiiXOeu337do4dO8azzz5Lw4YNAcq84Kx27dqMHDmSkSNH0rNnTx588EFeeOEFAKKjoxk6dChDhw7l+uuvZ8CAAZw4cYKLL76YlJQUgoODadKkSbk1tGzZkpYtWzJ+/HhuvvlmZs+erfAr4kGWAJrzaxMTAxdeCBs3wu97EknPrUGUwq+4gaY9BJCMjAySkpJISkoCYM+ePSQlJbF///5yn3P99dfz8ssv88svv7Bv3z6WLl3K3XffTcuWLWnVqhXh4eFMnDiRhx56iPfee4/du3fz888/M3PmTACGDRtGeHg4I0aMYPPmzSxZsoR77rmHW2+91d7yUJZhw4YRHx/PkCFDWLFiBXv27GHZsmXce++9HDxY8T8cZ86cSZcuXbjsssto27at/XbppZfSrVs3e92umjRpEmvXrmXMmDFs3LiR7du3M336dI4dK33lcqNGjQgNDeW1117jzz//5KuvvuKpp55yOGfy5Ml8+eWX7Nq1iy1btvDNN9/QunVrAF5++WU++ugjtm/fzh9//MEnn3xCYmIisbGx9OvXj27dunHttdfyww8/sHfvXlavXs2///1v1q1bR3Z2NmPHjmXp0qXs27ePVatWsXbtWvtri4hn2EadBdLKL5S0PhQVmfnlUCe1PYhbKPwGkHXr1tGhQwc6dOgAWHs/O3TowOTJk8t9zpVXXsnXX3/N4MGDadmyJSNGjKBVq1b8+OOP9raBxx57jPvvv5/JkyfTunVrhg4dah/bFRERwQ8//MCJEyfo3Lkz119/PX379j3nrOGIiAiWL19Oo0aNuO6662jdujW33XYb2dnZTq8EnykvL48PPviAv//972U+/ve//50PPvigQnOGW7ZsyY8//sjvv/9Oly5d6NatG19++aVDa4VN7dq1mTNnDp988glt2rTh2Wefta/o2oSGhjJp0iTatWvHZZddRlBQEB999BEANWrU4LnnnqNTp0507tyZvXv3smDBAsxmMyaTiQULFnDZZZdx22230bJlS2666Sb27t1LQkICQUFBHD9+nOHDh9OyZUtuvPFGBg4c6NSKtYhUn5JRZwUersS9HPp+918Cx3dBgXtmvUvgMhmGYXi6CHdLS0sjJiaG1NTUUkEqJyeHPXv20LRpU8LDwz1UoUhg0u8/CVR/pefS+f9+AuDPZwZhNpd9rYS/2bsXivdhol+LVSy8ZRBcPwvalr1IIYHlbHmtMrTyKyIi4mG2tgeA3ILA2eWscWOoV896/PPBThQUBcGv73i2KPF7Cr8iIiIeFh5SEn4DqfXBZCppfcjIDmPTX+1g/xpI3ujZwsSvKfyKiIh4WJDZRFhw8azfAL3oDWBVXvHUoF/f9kwxEhAUfkVERLxAII47gzPC77EB1oNNn0DWCc8UJH5P4bccAXgdoIjH6fedBDLbxIdAW/lt3x4iIqzHqzbUgsQLoSAHNnzg2cLEbyn8niEkJASArKwsD1ciEnhsY+aCgoLOcaaI/wnUld+QEOtubwAHDpjYVvtB6zdr34GiwPq1EPfQDm9nCAoKIjY21mFObXnb84pI1SkqKuKvv/4iIiKizPnIIv7OtvKbGUAXvNn07g2LF1uPr39sMKtubEzsqX2w80c4f6BnixO/o79hypCYmAhgD8Ai4h5ms5lGjRrpfzglINWPtbDlcBrPLNjOhfVjqR0V5umS3GbsWPjgA9ixA7ZuM3Pj15/z7aBLCPn1bYVfqXLa5OIsQ5MLCwvJz893Y2UigS00NBSzWd1YEpj2Hc/kprd/Jjk1hxZ1ajDvzq7E1wicALx7N1xyCRw/bv3+ro6zmH7VeEz3rIP4Fp4tTjyiuja5UPitwl9MERGRyth7LJOhb6/hSFouLRNqMO+OrtQKoAC8ciX07Qu2XeZf7P8IE+4rhIHPebYw8Qi/3uHtzTfftG9n2rFjR1asWHHW85ctW0bHjh0JDw+nWbNm/Pe//3VTpSIiItWnSXwkH93ZjYToMP44ksGwGb9wPCPX02W5zaWXwqxZJd8/8OPTfDH3GOSme64o8TseD7/z58/nvvvu49FHH2XDhg307NmTgQMHsn///jLP37NnD4MGDaJnz55s2LCBRx55hHHjxvHZZ5+5uXIREZGq1zQ+knl3dKVOVBjbU9IZNuMXTmTmebostxk2DKZMsR4bmBn28aus/+gnj9Yk/sXjbQ+XXHIJF198MdOnT7ff17p1a6699lqmTp1a6vyJEyfy1VdfsW3bNvt9o0eP5vfff2fNmjVO/Uy1PYiIiLfb/VcGN739M3+l59IqMYp7+7YgUK4FNQx4/uFYli6wAFC7xnHaX6TV30BTUJDO0p/bVXle8+i0h7y8PNavX8/DDz/scH///v1ZvXp1mc9Zs2YN/fv3d7jvyiuvZObMmeTn59vn9J4uNzeX3NySfzZKTU0FrCFYRETEG9UOg7dvasPtc9aydd8R7pp1xNMluZXRzIyl7sVkJ9fir4wQfloZ5+mSxO2sMbWq12k9Gn6PHTtGYWEhCQkJDvcnJCSQkpJS5nNSUlLKPL+goIBjx45Rt27dUs+ZOnUqTzzxRKn7GzZsWInqRURERKS6HT9+nJiYmCp7Pa+Y83vmTE/DMM4657Os88u632bSpElMmDDB/n1RUREnTpygVq1amifqg9LS0mjYsCEHDhxQ20qA0WcfuPTZBy599oErNTWVRo0aERdXtav+Hg2/8fHxBAUFlVrlPXr0aKnVXZvExMQyzw8ODqZWrVplPicsLIywMMdRMbGxsRUvXLxCdHS0/iAMUPrsA5c++8Clzz5wVfX8d49OewgNDaVjx44sXLjQ4f6FCxfSvXv3Mp/TrVu3Uuf/+OOPdOrUqcx+XxERERERG4+POpswYQIzZsxg1qxZbNu2jfHjx7N//35Gjx4NWFsWhg8fbj9/9OjR7Nu3jwkTJrBt2zZmzZrFzJkzeeCBBzz1FkRERETER3i853fo0KEcP36cJ598kuTkZNq2bcuCBQto3LgxAMnJyQ4zf5s2bcqCBQsYP348b7zxBvXq1ePVV1/l73//u6fegrhZWFgYjz/+eKlWFvF/+uwDlz77wKXPPnBV12fv8Tm/IiIiIiLu4vG2BxERERERd1H4FREREZGAofArIiIiIgFD4VdEREREAobCr3idN998k6ZNmxIeHk7Hjh1ZsWJFued+/vnnXHHFFdSuXZvo6Gi6devGDz/84MZqpaq58vmfbtWqVQQHB3PRRRdVb4FSbVz97HNzc3n00Udp3LgxYWFhnHfeecyaNctN1UpVcvWznzt3Lu3btyciIoK6devyz3/+k+PHj7upWqkqy5cvZ/DgwdSrVw+TycQXX3xxzucsW7aMjh07Eh4eTrNmzfjvf//r8s9V+BWvMn/+fO677z4effRRNmzYQM+ePRk4cKDDuLvTLV++nCuuuIIFCxawfv16evfuzeDBg9mwYYObK5eq4Ornb5Oamsrw4cPp27evmyqVqlaRz/7GG29k0aJFzJw5kx07djBv3jxatWrlxqqlKrj62a9cuZLhw4dz++23s2XLFj755BPWrl3LqFGj3Fy5VFZmZibt27fn9ddfd+r8PXv2MGjQIHr27MmGDRt45JFHGDduHJ999plrP9gQ8SJdunQxRo8e7XBfq1atjIcfftjp12jTpo3xxBNPVHVp4gYV/fyHDh1q/Pvf/zYef/xxo3379tVYoVQXVz/77777zoiJiTGOHz/ujvKkGrn62f/nP/8xmjVr5nDfq6++ajRo0KDaapTqBxj/+9//znrOQw89ZLRq1crhvrvuusvo2rWrSz9LK7/iNfLy8li/fj39+/d3uL9///6sXr3aqdcoKioiPT2duLi46ihRqlFFP//Zs2eze/duHn/88eouUapJRT77r776ik6dOvH8889Tv359WrZsyQMPPEB2drY7SpYqUpHPvnv37hw8eJAFCxZgGAZHjhzh008/5aqrrnJHyeJBa9asKfXfypVXXsm6devIz893+nU8vsObiM2xY8coLCwkISHB4f6EhARSUlKceo0XX3yRzMxMbrzxxuooUapRRT7/nTt38vDDD7NixQqCg/XHma+qyGf/559/snLlSsLDw/nf//7HsWPHGDNmDCdOnFDfrw+pyGffvXt35s6dy9ChQ8nJyaGgoIBrrrmG1157zR0liwelpKSU+d9KQUEBx44do27duk69jlZ+xeuY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iy++oHfv3sTFxXHttdeyc+fOcl9fRKS6qOdXRMTNypqXGx8fj8ViYdasWWU+Jz4+3n48ZMgQhgwZQm5uLj///DNTp07llltuoUmTJnTr1s3pOmwhNTk5udRjhw8fdviZ5T03JSWF+vXr2+8vKCgoFZojIyN54okneOKJJzhy5Ih9FXjw4MFs377d6XpFRKqCVn5FRLzA1Vdfze7du6lVqxadOnUqdWvSpEmp54SFhdGrVy+ee+45ADZs2ODSz+zWrRsWi4UPPvjA4f6DBw+yePFi+vbtW+5zL7/8cgDmzp3rcP/HH39MQUFBuc9LSEhg5MiR3HzzzezYsYOsrCyXahYRqSyt/IqIeIH77ruPzz77jMsuu4zx48fTrl07ioqK2L9/Pz/++CP3338/l1xyCZMnT+bgwYP07duXBg0acOrUKV555RVCQkLo1auXSz8zNjaWxx57jEceeYThw4dz8803c/z4cZ544gnCw8N5/PHHy31u69at+cc//sG0adMICQmhX79+bN68mRdeeIHo6GiHcy+55BKuvvpq2rVrR82aNdm2bRvvv/8+3bp103xjEXE7hV8RES8QGRnJihUrePbZZ3n77bfZs2cPFouFRo0a0a9fP/vK7yWXXMK6deuYOHEif/31F7GxsXTq1InFixdzwQUXuPxzJ02aRJ06dXj11VeZP38+FouFyy+/nGeeeeasY84AZs6cSUJCAnPmzOHVV1/loosu4rPPPuOmm25yOK9Pnz589dVXvPzyy2RlZVG/fn2GDx/Oo48+6nK9IiKVZTIMw/B0ESIiIiIi7qCeXxEREREJGAq/IiIiIhIwFH5FREREJGAo/IqIiIhIwFD4FREREZGAofArIiIiIgFD4VdEREREAobCr4iIiIgEDIVfEREREQkYCr8iIiIiEjAUfkVEREQkYPw/j2nM1jXyG/QAAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 800x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"thresholds, f1_scores = calculate_correlation_score_confidence(test_x, test_y)\n",
"\n",
"first_class = [ el[0] for el in f1_scores ]\n",
"second_class = [ el[1] for el in f1_scores ]\n",
"all_classes = [ el[2] for el in f1_scores ]\n",
"\n",
"fig, ax = plt.subplots(figsize=(8,6))\n",
"plt.plot(thresholds, first_class, label = \"F1 Score - Correct class\")\n",
"plt.plot(thresholds, second_class, label = \"F1 Score - Incorrect class\")\n",
"plt.plot(thresholds, all_classes, label = \"F1 Score - All classes\", linewidth=2.0, color=\"blue\")\n",
"plt.legend(loc = 'lower left')\n",
"plt.ylim([0, 1])\n",
"plt.xlim([0.025, 1])\n",
"plt.xlabel(\"Thresholds\", fontsize = 12)\n",
"plt.ylabel(\"F1 Score\", fontsize = 12)\n",
"# plt.axvline(thresholds[np.argmin(abs(precision-recall))], color=\"k\", ls = \"--\")\n",
"# plt.title(label = F\"Threshold = {thresholds[np.argmin(abs(precision-recall))]:.3f}\", fontsize = 12)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Optimal Threshold: 0.5421684074365937\n"
]
},
{
"data": {
"image/png": "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slwON3fccQeff/45AP3792fo0KG0bduWqKgounbt6vYCRUSKpcxMeOMNuO022LcPatSAb74BN66JJ+KpXF44MzMzk8zMTOfCmYsWLWLdunXUrFmTgQMH4ufnly+FuosWzhSRQu/IEejdG5Yvt7ajouC99xRspFhz5fvb5XBzOQcPHqRChQruOly+ULgRkULt5Em4/nqrt8bfH6ZMgUce0aR8Uuzl66rgOUlMTOSpp56iZs2aLr922rRpVKtWjYCAACIjI1m7du1l909NTWXUqFFUqVIFf39/atSowezZs/NauohI4VKihNVrU7u2dbv3o48q2Ii4KNfh5vjx4/To0YOyZcsSERHBlClTyMzM5MUXX6R69ep8//33LoeM6OhohgwZwqhRo4iNjaVly5Z07NiRffv2XfI13bp145tvvmHWrFn89ttvLFy4kDp16rj0viIihcrhw/DHH+e3X3wRtmyBm26yrSSRoizXl6UGDRrE559/TlRUFF999RU7duygffv2nDlzhtGjR9OqVSuX37xJkyY0bNiQ6dOnO9vq1q3LPffcw/jx47Pt/9VXX/Hggw+yZ88ers3lhFWpqamkpqY6t5OTk6lUqZIuS4lI4fDdd9C9O0REwIYN1qUoEckmXy5LffHFF8yZM4cJEybw2WefYYyhVq1afPvtt3kKNmlpacTExNCuXbss7e3atWPDhg05vuazzz6jUaNGvP7661SoUIFatWoxfPhwTp8+fcn3GT9+PKGhoc5HpUqVXK5VRMTtMjJg7Fho0wYSE+HMGasHR0SuWq5nKD506BD16tUDoHr16gQEBDBgwIA8v/GRI0fIyMggPDw8S3t4eDiJiYk5vmbPnj2sW7eOgIAAli5dypEjRxg0aBB///33JS+JjRw5kmHDhjm3z/XciIjYJiEBHn4Yvv3W2u7bF95+W12+Im6S63CTmZmJr6+vc9vb25tgN/yP6LhooJwxJlvbhTU4HA7mz59PaGgoABMnTuT+++9n6tSpBAYGZnuNv78//urmFZHCYuVKK9gcPmyFmenToWdPu6sS8Si5DjfGGPr06eMMCmfOnGHgwIHZAs6SJUtydbwyZcrg7e2drZfm8OHD2XpzzilfvjwVKlRwBhuwxugYYzhw4ADXXXddbj+OiEjBM8YaLHz4MNx4IyxaBLohQsTtcj3mpnfv3oSFhTnHrjz8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xgcwZgxERsI996i3RkRExEXqubFbZia8/LJ1N1RqqtXm4wNduyrYiIiI5IHCjZ3+/BM6dIB//Qt++MEaMCwiIiJXReHGLt9+a90NtXIlBAbC7NnQo4fdVYmIiBR5CjcFLSPDGlPTpg0kJkK9erBlC/Ttq8tQIiIeqGrVqkyePNnuMooVhZuCNmwYjB1rzTzcrx9s3mwFHBERyRd9+vTB4XDgcDjw8fGhcuXKPP744xw7dszu0vJdcnIyL7zwAtdffz2BgYGULl2aW265hddff92jP7/ulipoTz8NixfDq6/Cww/bXY2ISLHQoUMH5syZQ3p6Otu3b6dfv34cP36chQsX2l1avvn777+59dZbSU5O5t///jeRkZH4+fnx+++/s2DBAhYsWMATTzxhd5n5Qj03+S093RpXc0716rB7t4KNiHiOU6cu/ThzJvf7nj595X3zyN/fn3LlylGxYkXatWtHVFQUK1ascD6fkZFB//79qVatGoGBgdSuXZu33noryzH69OnDPffcw4QJEyhfvjylS5fmiSee4OzZs859Dh8+TJcuXQgMDKRatWrMnz8/Wy379u3j7rvvpkSJEoSEhNCtWzf+/PNP5/Njxoyhfv36zJ49m8qVK1OiRAkef/xxMjIyeP311ylXrhxhYWG8/PLLl/3Mzz//PPv27eOHH36gb9++3HTTTdSpU4d//OMfLFiwgEGDBjn3dTgcLFu2LMvrS5Uqxdy5c53bBw8eJCoqimuuuYbSpUtz991388cffzifX7VqFY0bNyY4OJhSpUrRokUL9u7dC8CPP/5I69atKVmyJCEhIURGRrJly5bL1n811HOTnw4cgO7dYd06+OoraNfOavf3t7cuERF3KlHi0s916gRffHF+OywMUlJy3rdVK1i16vx21apw5EjWfYzJa5VOe/bs4auvvsLX19fZlpmZScWKFVm0aBFlypRhw4YNPProo5QvX55u3bo59/vuu+8oX7483333Hb///jtRUVHUr1+fRx55BLAC0P79+/n222/x8/Nj8ODBHD58+ILyDffccw/BwcGsXr2a9PR0Bg0aRFRUFKsu+Oy7d+/myy+/5KuvvmL37t3cf//9xMfHU6tWLVavXs2GDRvo168fd955J02bNs32GTMzM4mOjubhhx+mQoUKOZ4HhwvjPFNSUmjdujUtW7ZkzZo1+Pj48NJL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RoKDg6lUqRKDBg3i5MmTlzzOjz/+SOvWrSlZsiQhISFERkayZcsW5/MbNmzgtttuIzAwkEqVKjF48GBOnTp12docDgflypWjfPnytG7dmtGjR/Pzzz87e5amT59OjRo18PPzo3bt2nz44YdZXj9mzBgqV66Mv78/ERERDB482PnchZelqlatCkDXrl1xOBzO7QsvS3399dcEBARw/PjxLO8xePBgWrVq5bbP2ahRI4YOHcrevXv57bffnPtc7s9j1apV9O3bl6SkJGcP0JgxYwBIS0tjxIgRVKhQgeDgYJo0acKqVasuW49IcaFwI1LMeHl5MWXKFH7++Wc++OADvv32W0aMGHHJ/Xv06EHFihXZvHkzMTExPPfcc/j6+gKwbds22rdvz7333stPP/1EdHQ069at48knn3SppsDAQADOnj3L0qVLefrpp3nmmWf4+eefeeyxx+jbty/fffcdAJ9++imTJk3i3XffZdeuXSxbtowbb7wxx+Nu3rwZgDlz5pCQkODcvlCbNm0oVaoUixcvdrZlZGSwaNEievTo4bbPefz4cRYsWADgPH9w+T+P5s2bM3nyZGcPUEJCAsOHDwegb9++rF+/no8//piffvqJBx54gA4dOrBr165c1yTisfJ93XERKXC9e/c23t7eJjg42Pm4//77c9x30aJFpnTp0s7tOXPmmNDQUOd2yZIlzdy5c3N8bc+ePc2jjz6apW3t2rXGy8vLnD59OsfXXHz8/fv3m6ZNm5qKFSua1NRU07x5c/PII49kec0DDzxgOnXqZIwx5s033zS1atUyaWlpOR6/SpUqZtKkSc5twCxdujTLPqNHjzY333yzc3vw4MHmjjvucG5//fXXxs/Pz/z9999X9TkBExwcbIKCggxgAHPXXXfluP85V/rzMMaY33//3TgcDnPw4MEs7XfeeacZOXLkZY8vUhz42ButRCS/tG7dmunTpzu3g4ODAfjuu+945ZVX2L59O8nJyaSnp3PmzBlOnTrl3OdCw4YNY8CAAXz44Ye0adOGBx54gBo1agAQExPD77//zvz58537G2PIzMwkPj6eunXr5lhbUlISJUqUwBhDSkoKDRs2ZMmSJfj5+bFjx44sA4IBWrRowVtvvQXAAw88wOTJk6levTodOnSgU6dOdOnSBR+fvP911qNHD5o1a8ahQ4eIiIhg/vz5dOrUiWuuueaqPmfJkiXZunUr6enprF69mjfeeIMZM2Zk2cfVPw+ArVu3YoyhVq1aWdpTU1MLZCyRSGGncCPioYKDg6lZs2aWtr1799KpUycGDhzIv//9b6699lrWrVtH//79OXv2bI7HGTNmDN27d+eLL77gyy+/ZPTo0Xz88cd07dqVzMxMHnvssSxjXs6pXLnyJWs796Xv5eVFeHh4ti9xh8ORZdsY42yrVKkSv/32GytXruS///0vgwYN4o033mD16tVZLve4onHjxtSoUYOPP/6Yxx9/nKVLlzJnzhzn83n9nF5eXs4/gzp16pCYmEhUVBRr1qwB8vbnca4eb29vYmJi8Pb2zvJciRIlXPrsIp5I4UakGNmyZQvp6em8+eabeHlZQ+4WLVp0xdfVqlWLWrVqMXToUB566CHmzJlD165dadiwIb/88ku2EHUlF37pX6xu3bqsW7eOXr16Ods2bNiQpXckMDCQu+66i7vuuosnnniCOnXqsG3bNho2bJjteL6+vrm6C6t79+7Mnz+fihUr4uXlRefOnZ3P5fVzXmzo0KFMnDiRpUuX0rVr11z9efj5+WWrv0GDBmRkZHD48GFatmx5VTWJeCINKBYpRmrUqEF6ejpvv/02e/bs4cMPP8x2meRCp0+f5sknn2TVqlXs3buX9evXs3nzZmfQ+Oc//8nGjRt54okniIuLY9euXXz22Wc89dRTea7x2WefZe7cucyYMYNdu3YxceJElixZ4hxIO3fuXGbNmsXPP//s/AyBgYFUqVIlx+NVrVqVb775hsTERI4dO3bJ9+3Rowdbt27l5Zdf5v777ycgIMD5nLs+Z0hICAMGDGD06NEYY3L151G1alVOnjzJN998w5EjR0hJSaFWrVr06NGDXr16sWTJEuLj49m8eTOvvfYay5cvd6kmEY9k54AfEckfvXv3NnfffXeOz02cONGUL1/eBAYGmvbt25t58+YZwBw7dswYk3UAa2pqqnnwwQdNpUqVjJ+fn4mIiDBPPvlklkG0mzZtMm3btjUlSpQwwcHB5qabbjIvv/zyJWvLaYDsxaZNm2aqV69ufH19Ta1atcy8efOczy1dutQ0adLEhISEmODgYNO0aVPz3//+1/n8xQOKP/vsM1OzZk3j4+NjqlSpYozJPqD4nFtuucUA5ttvv832nLs+5969e42Pj4+Jjo42xlz5z8MYYwYOHGhKly5tADN69GhjjDFpaWnmxRdfNFWrVjW+vr6mXLlypmvXruann366ZE0ixYXDGGPsjVciIiIi7qPLUiIiIuJRFG5ERETEoyjciIiIiEdRuBERERGPonAjIiIiHkXhRkRERDyKwo2IiIh4FIUbERER8SgKNyIiIuJRFG5ERETEoyjciIiIiEf5f/Dcup3LQN1kAAAAAElFTkSuQmCC",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# calculate the fpr and tpr for all thresholds of the classification\n",
"probs = best_model.predict_proba(test_x)\n",
"preds = probs[:,1]\n",
"fpr, tpr, threshold = roc_curve(test_y, preds)\n",
"roc_auc = auc(fpr, tpr)\n",
"\n",
"optimal_idx = np.argmax(tpr - fpr)\n",
"optimal_threshold = threshold[optimal_idx]\n",
"print(f\"Optimal Threshold: {optimal_threshold}\")\n",
"\n",
"# method I: plt\n",
"plt.plot(fpr, tpr, 'b', label = 'AUC = %0.2f' % roc_auc)\n",
"plt.plot([0, 1], [0, 1],'r--', label=\"Random Guess\")\n",
"plt.legend(loc=4)\n",
"plt.ylabel('True Positive Rate')\n",
"plt.xlabel('False Positive Rate')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.8.13 (conda)",
"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.8.13"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "9260f401923fb5c4108c543a7d176de9733d378b3752e49535ad7c43c2271b65"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
|