├── .gitignore ├── LICENSE ├── README.md ├── data ├── interim │ ├── labeled_data_CN7.csv │ ├── labeled_data_RG3.csv │ └── labeled_data_preprocessed.csv ├── processed │ ├── labeled_data_CN7.csv │ └── labeled_data_RG3.csv └── raw │ └── labeled_data.csv ├── env.yml ├── img ├── clf_report_cn7_AE.png ├── clf_report_cn7_MD.png ├── clf_report_cn7_ml.png ├── clf_report_rg3_AE.png ├── clf_report_rg3_MD.png ├── clf_report_rg3_ml.png ├── cn7_parameter_distribution.png ├── feature_importance_1.png ├── feature_importance_2.png ├── feature_importance_3.png ├── feature_importance_4.png ├── process_parameter_distribution.png └── rg3_parameter_distribution.png ├── notebooks ├── 0_data_preprocessing.ipynb ├── 1_exploratory_data_analysis.ipynb ├── 2-1_EDA_on_CN7.ipynb ├── 2-2_EDA_on_RG3.ipynb ├── 3-1_ML_on_CN7.ipynb ├── 3-2_ML_on_CN7_MD.ipynb ├── 3-3_ML_on_CN7_Variational_AE.ipynb ├── 4-1_ML_on_RG3.ipynb ├── 4-2_ML_on_RG3_MD.ipynb ├── 4-3_ML_on_RG3_Variational_AE.ipynb └── 5_feature_importances_CN7.ipynb └── src └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 John W.S. Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![license 2 | status](https://img.shields.io/github/license/johnwslee/injection_molding_analysis) 3 | 4 | # Classification of Defective Parts in Injection Molding Using Various Machine Learning Approaches 5 | 6 | **Author:** John W.S. Lee 7 | 8 | ## 1. Introduction 9 | 10 | In this study, efforts were made to classify defects in parts produced by injection molding processes. Three different modeling approaches, namely supervised learning models, Mahalanobis Distance model, and Variational AutoEncoder model, were implemented and their performances were compared. 11 | 12 | The dataset used in this study was downloaded from the Korea AI Manufacturing Platform, also known as [KAMP](https://www.kamp-ai.kr/aidataDetail?AI_SEARCH=&page=1&DATASET_SEQ=4&EQUIP_SEL=&GUBUN_SEL=&FILE_TYPE_SEL=&WDATE_SEL=). Although the website is written in Korean, the contents of the dataset were mostly written in English. The dataset consisted of 7,996 rows with 44 columns. One of the columns represented the target label, `PassOrFail`. 13 | 14 | The following is a summary of this study. For more detailed codes and notebooks used in this study, please refer to the [notebook folder](https://github.com/johnwslee/injection_molding_analysis/tree/main/notebooks). 15 | 16 | ## 2. Summary of Study 17 | 18 | ### 2.1. Basic Exploratory Data Analysis 19 | 20 | The dataset had 4 different injection-molded parts, namely `CN7` and `RG3`, each with Left-Hand and Right-Hand components. The figure below shows the distribution of processing parameters for the parts with 4 different combinations. As shown in the figure, the processing parameters for `CN7` and `RG3` exhibited very different distribution, whereas the difference between the Left-Hand and Right-Hand components were not big. Therefore, it was reasonable to proceed with two separate models for `CN7` and `RG3`. 21 | 22 | 23 | 24 | ### 2.2. Exploratory Data Analysis for `CN7` and `RG3` 25 | 26 | For each type of injection-molded parts, the distributions of the processing parameters were compared for passed parts(i.e. good parts) and failed parts (i.e. defective parts). In the case of `CN7`, there seemed to be some difference in the distributions of the processing parameters for passed/failed parts . However, the difference for `RG3` seems to be less obvious than that for `CN7`. 27 | 28 | #### Distribution of Processing Parameters for `CN7` 29 | 30 | 31 | 32 | #### Distribution of Processing Parameters for `RG3` 33 | 34 | 35 | 36 | ### 2.3. Classification of Defective Parts for `CN7` and `RG3` 37 | 38 | As mentioned above, 3 different machine learning approaches were implemented for the purpose of classifying the defective injection-molded parts. Detailed codes can be found in the [notebook folder](https://github.com/johnwslee/injection_molding_analysis/tree/main/notebooks). Since there was a significant class imbalances, f1-score was used as the evaluation metric. 39 | 40 | For `CN7`, the f1-scores for supervised learning models, Mahalanobis Distance model, and Variational AutoEncoder model were 0.67, 0.55, and 0.73, respectively. 41 | 42 | For `RG3`, the f1-scores for supervised learning models, Mahalanobis Distance model, and Variational AutoEncoder model were 0, 0.3, and 0.24, respectively. 43 | 44 |

45 | 46 | 47 |

48 |

49 | 50 | 51 |

52 |

53 | 54 | 55 |

56 | 57 | Clearly, the effectiveness of the models were different for `CN7` and `RG3` parts. Especially, it was surprising that the f1-score could be improved from 0 to 0.27 by switching from supervised learning models to Mahalanobis Distance model. It should be also noted that the choice of the thresholds for Mahalanobis Distance model and Variational AutoEncoder model played a significant roled in determining their performances. 58 | 59 | ### 2.4. Feature Importances 60 | 61 | Feature importances for `CN7` parts were checked on 3 models (i.e, SVC, RandomForest, and LightGBM) using the models' built-in function and `shap` library. 62 | 63 | The importance of each feature appeared to be slightly different based on the models and the methods used. It turned out that "Max Injection Speed", "Filling Time", "Mold Temperature 4", "Barrel Temperature 1", and "Plasticizing Position" were the processing parameters that models thought to be important. 64 | 65 |

66 | 67 | 68 |

69 |

70 | 71 | 72 |

73 | 74 | 75 | ## 3. Conclusion 76 | 77 | This study demonstrated how various machine learning approaches performed in the classification of defective parts in injection molding. It turned out that the performance of each approach varied based on the type of datasets, `CN7` and `RG3` for this study. For `CN7` parts, Variational AutoEncoder performed best, whereas Mahalanobis Distance model performed best for `RG3`. This suggests that it is important to try several machine learning approaches to find the best-performing approach for a given data. 78 | 79 | ## How to Run the Notebooks Locally 80 | 81 | To download the contents of this GitHub page on to your local machine, follow these steps: 82 | 83 | 1. Copy and paste the following link: `git clone https://github.com/johnwslee/injection_molding_analysis.git` to your Terminal. 84 | 85 | 2. On your terminal, type: `cd injection_molding_analysis`. 86 | 87 | 3. Create a virtualenv by typing: `conda env create -f env.yml` 88 | 89 | 4. Activate the virtualenv by typing: `conda activate inj_env` 90 | 91 | 5. Run the notebooks in notebook folder in order. -------------------------------------------------------------------------------- /env.yml: -------------------------------------------------------------------------------- 1 | # install with conda env create -f env.yml 2 | name: 'inj_env' 3 | channels: 4 | - conda-forge 5 | - defaults 6 | - pytorch 7 | dependencies: 8 | - python=3.10.8 9 | - ipykernel 10 | - pip 11 | - pandas=1.5.2 12 | - matplotlib=3.6.2 13 | - scikit-learn=1.2.0 14 | - scipy=1.9.3 15 | - seaborn=0.12.1 16 | - black=22.10.0 17 | - flake8=6.0.0 18 | - pytorch=1.12.1 19 | - torchvision=0.13.1 20 | - lightgbm=3.3.3 21 | - ipywidgets 22 | - mkl=2021.4.0 23 | - shap=0.41.0 24 | - pip: 25 | - plotly==5.11.0 26 | - kaleido==0.2.1 27 | - tslearn==0.5.2 28 | - xgboost==1.7.2 29 | - catboost==1.1.1 30 | - torch-summary==1.4.5 31 | - otter-grader 32 | 33 | -------------------------------------------------------------------------------- /img/clf_report_cn7_AE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/clf_report_cn7_AE.png -------------------------------------------------------------------------------- /img/clf_report_cn7_MD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/clf_report_cn7_MD.png -------------------------------------------------------------------------------- /img/clf_report_cn7_ml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/clf_report_cn7_ml.png -------------------------------------------------------------------------------- /img/clf_report_rg3_AE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/clf_report_rg3_AE.png -------------------------------------------------------------------------------- /img/clf_report_rg3_MD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/clf_report_rg3_MD.png -------------------------------------------------------------------------------- /img/clf_report_rg3_ml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/clf_report_rg3_ml.png -------------------------------------------------------------------------------- /img/cn7_parameter_distribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/cn7_parameter_distribution.png -------------------------------------------------------------------------------- /img/feature_importance_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/feature_importance_1.png -------------------------------------------------------------------------------- /img/feature_importance_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/feature_importance_2.png -------------------------------------------------------------------------------- /img/feature_importance_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/feature_importance_3.png -------------------------------------------------------------------------------- /img/feature_importance_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/feature_importance_4.png -------------------------------------------------------------------------------- /img/process_parameter_distribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/process_parameter_distribution.png -------------------------------------------------------------------------------- /img/rg3_parameter_distribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnwslee/injection_molding_analysis/faa04b2923d0e75eda569eda522ba1f383cbd728/img/rg3_parameter_distribution.png -------------------------------------------------------------------------------- /notebooks/0_data_preprocessing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "bfeabc3c-3ebe-4c8f-85ad-e3c058209de0", 6 | "metadata": {}, 7 | "source": [ 8 | "# 0. Imports" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "97be1e08-f742-4664-9aae-cd34068183dc", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import pandas as pd" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "id": "2ef4e5d7-3179-45ca-8d50-052c561a3e03", 24 | "metadata": {}, 25 | "source": [ 26 | "# 1. Data Read In" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "id": "cf967899-6162-455a-be84-0a4a53366a5d", 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "df = pd.read_csv(\"../data/raw/labeled_data.csv\")" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 3, 42 | "id": "d8224552-77f4-459c-93e8-b2094e2e24b1", 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "data": { 47 | "text/html": [ 48 | "
\n", 49 | "\n", 62 | "\n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | "
_idTimeStampPART_FACT_PLAN_DATEPART_FACT_SERIALPART_NAMEEQUIP_CDEQUIP_NAMEPassOrFailReasonInjection_Time...Mold_Temperature_3Mold_Temperature_4Mold_Temperature_5Mold_Temperature_6Mold_Temperature_7Mold_Temperature_8Mold_Temperature_9Mold_Temperature_10Mold_Temperature_11Mold_Temperature_12
05f8928bb9c0189cc666ef19b2020-10-16 04:57:472020-10-16 오전 12:00:0024CN7 W/S SIDE MLD'G RHS14650톤-우진2호기YNone9.59...24.79999927.50.00.00.00.00.00.00.00.0
15f8928de9c0189cc666ef20b2020-10-16 04:58:482020-10-16 오전 12:00:0024CN7 W/S SIDE MLD'G RHS14650톤-우진2호기YNone9.60...24.79999927.60.00.00.00.00.00.00.00.0
25f8928df9c0189cc666ef2132020-10-16 04:58:482020-10-16 오전 12:00:0023CN7 W/S SIDE MLD'G LHS14650톤-우진2호기YNone9.60...24.79999927.60.00.00.00.00.00.00.00.0
35f8928f39c0189cc666ef25e2020-10-16 04:59:482020-10-16 오전 12:00:0023CN7 W/S SIDE MLD'G LHS14650톤-우진2호기YNone9.59...25.00000027.60.00.00.00.00.00.00.00.0
45f8928f59c0189cc666ef2652020-10-16 04:59:482020-10-16 오전 12:00:0024CN7 W/S SIDE MLD'G RHS14650톤-우진2호기YNone9.59...25.00000027.60.00.00.00.00.00.00.00.0
\n", 212 | "

5 rows × 45 columns

\n", 213 | "
" 214 | ], 215 | "text/plain": [ 216 | " _id TimeStamp PART_FACT_PLAN_DATE \\\n", 217 | "0 5f8928bb9c0189cc666ef19b 2020-10-16 04:57:47 2020-10-16 오전 12:00:00 \n", 218 | "1 5f8928de9c0189cc666ef20b 2020-10-16 04:58:48 2020-10-16 오전 12:00:00 \n", 219 | "2 5f8928df9c0189cc666ef213 2020-10-16 04:58:48 2020-10-16 오전 12:00:00 \n", 220 | "3 5f8928f39c0189cc666ef25e 2020-10-16 04:59:48 2020-10-16 오전 12:00:00 \n", 221 | "4 5f8928f59c0189cc666ef265 2020-10-16 04:59:48 2020-10-16 오전 12:00:00 \n", 222 | "\n", 223 | " PART_FACT_SERIAL PART_NAME EQUIP_CD EQUIP_NAME PassOrFail \\\n", 224 | "0 24 CN7 W/S SIDE MLD'G RH S14 650톤-우진2호기 Y \n", 225 | "1 24 CN7 W/S SIDE MLD'G RH S14 650톤-우진2호기 Y \n", 226 | "2 23 CN7 W/S SIDE MLD'G LH S14 650톤-우진2호기 Y \n", 227 | "3 23 CN7 W/S SIDE MLD'G LH S14 650톤-우진2호기 Y \n", 228 | "4 24 CN7 W/S SIDE MLD'G RH S14 650톤-우진2호기 Y \n", 229 | "\n", 230 | " Reason Injection_Time ... Mold_Temperature_3 Mold_Temperature_4 \\\n", 231 | "0 None 9.59 ... 24.799999 27.5 \n", 232 | "1 None 9.60 ... 24.799999 27.6 \n", 233 | "2 None 9.60 ... 24.799999 27.6 \n", 234 | "3 None 9.59 ... 25.000000 27.6 \n", 235 | "4 None 9.59 ... 25.000000 27.6 \n", 236 | "\n", 237 | " Mold_Temperature_5 Mold_Temperature_6 Mold_Temperature_7 \\\n", 238 | "0 0.0 0.0 0.0 \n", 239 | "1 0.0 0.0 0.0 \n", 240 | "2 0.0 0.0 0.0 \n", 241 | "3 0.0 0.0 0.0 \n", 242 | "4 0.0 0.0 0.0 \n", 243 | "\n", 244 | " Mold_Temperature_8 Mold_Temperature_9 Mold_Temperature_10 \\\n", 245 | "0 0.0 0.0 0.0 \n", 246 | "1 0.0 0.0 0.0 \n", 247 | "2 0.0 0.0 0.0 \n", 248 | "3 0.0 0.0 0.0 \n", 249 | "4 0.0 0.0 0.0 \n", 250 | "\n", 251 | " Mold_Temperature_11 Mold_Temperature_12 \n", 252 | "0 0.0 0.0 \n", 253 | "1 0.0 0.0 \n", 254 | "2 0.0 0.0 \n", 255 | "3 0.0 0.0 \n", 256 | "4 0.0 0.0 \n", 257 | "\n", 258 | "[5 rows x 45 columns]" 259 | ] 260 | }, 261 | "execution_count": 3, 262 | "metadata": {}, 263 | "output_type": "execute_result" 264 | } 265 | ], 266 | "source": [ 267 | "df.head()" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 4, 273 | "id": "03206431-93f9-4a43-97e8-dd7d7d42099a", 274 | "metadata": {}, 275 | "outputs": [ 276 | { 277 | "name": "stdout", 278 | "output_type": "stream", 279 | "text": [ 280 | "\n", 281 | "RangeIndex: 7996 entries, 0 to 7995\n", 282 | "Data columns (total 45 columns):\n", 283 | " # Column Non-Null Count Dtype \n", 284 | "--- ------ -------------- ----- \n", 285 | " 0 _id 7996 non-null object \n", 286 | " 1 TimeStamp 7996 non-null object \n", 287 | " 2 PART_FACT_PLAN_DATE 7996 non-null object \n", 288 | " 3 PART_FACT_SERIAL 7996 non-null int64 \n", 289 | " 4 PART_NAME 7996 non-null object \n", 290 | " 5 EQUIP_CD 7996 non-null object \n", 291 | " 6 EQUIP_NAME 7996 non-null object \n", 292 | " 7 PassOrFail 7996 non-null object \n", 293 | " 8 Reason 7996 non-null object \n", 294 | " 9 Injection_Time 7996 non-null float64\n", 295 | " 10 Filling_Time 7996 non-null float64\n", 296 | " 11 Plasticizing_Time 7996 non-null float64\n", 297 | " 12 Cycle_Time 7996 non-null float64\n", 298 | " 13 Clamp_Close_Time 7996 non-null float64\n", 299 | " 14 Cushion_Position 7996 non-null float64\n", 300 | " 15 Switch_Over_Position 7996 non-null float64\n", 301 | " 16 Plasticizing_Position 7996 non-null float64\n", 302 | " 17 Clamp_Open_Position 7996 non-null float64\n", 303 | " 18 Max_Injection_Speed 7996 non-null float64\n", 304 | " 19 Max_Screw_RPM 7996 non-null float64\n", 305 | " 20 Average_Screw_RPM 7996 non-null float64\n", 306 | " 21 Max_Injection_Pressure 7996 non-null float64\n", 307 | " 22 Max_Switch_Over_Pressure 7996 non-null float64\n", 308 | " 23 Max_Back_Pressure 7996 non-null float64\n", 309 | " 24 Average_Back_Pressure 7996 non-null float64\n", 310 | " 25 Barrel_Temperature_1 7996 non-null float64\n", 311 | " 26 Barrel_Temperature_2 7996 non-null float64\n", 312 | " 27 Barrel_Temperature_3 7996 non-null float64\n", 313 | " 28 Barrel_Temperature_4 7996 non-null float64\n", 314 | " 29 Barrel_Temperature_5 7996 non-null float64\n", 315 | " 30 Barrel_Temperature_6 7996 non-null float64\n", 316 | " 31 Barrel_Temperature_7 7996 non-null float64\n", 317 | " 32 Hopper_Temperature 7996 non-null float64\n", 318 | " 33 Mold_Temperature_1 7996 non-null float64\n", 319 | " 34 Mold_Temperature_2 7996 non-null float64\n", 320 | " 35 Mold_Temperature_3 7996 non-null float64\n", 321 | " 36 Mold_Temperature_4 7996 non-null float64\n", 322 | " 37 Mold_Temperature_5 7996 non-null float64\n", 323 | " 38 Mold_Temperature_6 7996 non-null float64\n", 324 | " 39 Mold_Temperature_7 7996 non-null float64\n", 325 | " 40 Mold_Temperature_8 7996 non-null float64\n", 326 | " 41 Mold_Temperature_9 7996 non-null float64\n", 327 | " 42 Mold_Temperature_10 7996 non-null float64\n", 328 | " 43 Mold_Temperature_11 7996 non-null float64\n", 329 | " 44 Mold_Temperature_12 7996 non-null float64\n", 330 | "dtypes: float64(36), int64(1), object(8)\n", 331 | "memory usage: 2.7+ MB\n" 332 | ] 333 | } 334 | ], 335 | "source": [ 336 | "df.info()" 337 | ] 338 | }, 339 | { 340 | "cell_type": "markdown", 341 | "id": "f7ad5237-31b7-417b-9e13-9e5f42ac52a8", 342 | "metadata": {}, 343 | "source": [ 344 | "# 2. Data Preprocessing" 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "id": "e1c53ea4-ba06-43ff-9a31-7706603a1711", 350 | "metadata": {}, 351 | "source": [ 352 | "## 2.1. Dropping the columns that have only one unique value" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 5, 358 | "id": "ac3966d1-bdb2-47e4-9e6f-c8590dabd979", 359 | "metadata": {}, 360 | "outputs": [ 361 | { 362 | "data": { 363 | "text/plain": [ 364 | "_id 5232\n", 365 | "TimeStamp 2625\n", 366 | "PART_FACT_PLAN_DATE 13\n", 367 | "PART_FACT_SERIAL 17\n", 368 | "PART_NAME 6\n", 369 | "EQUIP_CD 3\n", 370 | "EQUIP_NAME 3\n", 371 | "PassOrFail 2\n", 372 | "Reason 4\n", 373 | "Injection_Time 36\n", 374 | "Filling_Time 35\n", 375 | "Plasticizing_Time 121\n", 376 | "Cycle_Time 48\n", 377 | "Clamp_Close_Time 13\n", 378 | "Cushion_Position 22\n", 379 | "Switch_Over_Position 3\n", 380 | "Plasticizing_Position 49\n", 381 | "Clamp_Open_Position 5\n", 382 | "Max_Injection_Speed 55\n", 383 | "Max_Screw_RPM 11\n", 384 | "Average_Screw_RPM 16\n", 385 | "Max_Injection_Pressure 35\n", 386 | "Max_Switch_Over_Pressure 69\n", 387 | "Max_Back_Pressure 68\n", 388 | "Average_Back_Pressure 53\n", 389 | "Barrel_Temperature_1 67\n", 390 | "Barrel_Temperature_2 60\n", 391 | "Barrel_Temperature_3 45\n", 392 | "Barrel_Temperature_4 79\n", 393 | "Barrel_Temperature_5 56\n", 394 | "Barrel_Temperature_6 37\n", 395 | "Barrel_Temperature_7 2\n", 396 | "Hopper_Temperature 94\n", 397 | "Mold_Temperature_1 1\n", 398 | "Mold_Temperature_2 1\n", 399 | "Mold_Temperature_3 56\n", 400 | "Mold_Temperature_4 55\n", 401 | "Mold_Temperature_5 1\n", 402 | "Mold_Temperature_6 1\n", 403 | "Mold_Temperature_7 1\n", 404 | "Mold_Temperature_8 1\n", 405 | "Mold_Temperature_9 1\n", 406 | "Mold_Temperature_10 1\n", 407 | "Mold_Temperature_11 1\n", 408 | "Mold_Temperature_12 1\n", 409 | "dtype: int64" 410 | ] 411 | }, 412 | "execution_count": 5, 413 | "metadata": {}, 414 | "output_type": "execute_result" 415 | } 416 | ], 417 | "source": [ 418 | "# Check on the Unique value\n", 419 | "\n", 420 | "df.nunique()" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 6, 426 | "id": "f25568ca-d13f-4db1-8cbc-4b7980f91dd1", 427 | "metadata": {}, 428 | "outputs": [], 429 | "source": [ 430 | "# Mold_Temperature_s that have only one unique value are dropped\n", 431 | "\n", 432 | "df.drop(\n", 433 | " columns=[\"Mold_Temperature_1\", \"Mold_Temperature_2\", \"Mold_Temperature_5\", \n", 434 | " \"Mold_Temperature_6\", \"Mold_Temperature_7\", \"Mold_Temperature_8\",\n", 435 | " \"Mold_Temperature_9\", \"Mold_Temperature_10\", \"Mold_Temperature_11\",\n", 436 | " \"Mold_Temperature_12\"],\n", 437 | " inplace=True\n", 438 | ")" 439 | ] 440 | }, 441 | { 442 | "cell_type": "markdown", 443 | "id": "2401c4fd-8cd8-434f-ac18-dfeadce7b0ac", 444 | "metadata": {}, 445 | "source": [ 446 | "## 2.2. Removal of duplicated rows" 447 | ] 448 | }, 449 | { 450 | "cell_type": "code", 451 | "execution_count": 7, 452 | "id": "f2ace337-690b-4776-9a5c-712cc7198e53", 453 | "metadata": {}, 454 | "outputs": [], 455 | "source": [ 456 | "# The number of unique _id is smaller than the number of rows --> Duplicated rows are removed\n", 457 | "\n", 458 | "df.drop_duplicates(keep=\"first\", inplace=True)" 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "execution_count": 8, 464 | "id": "a3ef0eda-b637-4083-b3fa-3a133e89ed7c", 465 | "metadata": {}, 466 | "outputs": [ 467 | { 468 | "name": "stdout", 469 | "output_type": "stream", 470 | "text": [ 471 | "\n", 472 | "Int64Index: 5232 entries, 0 to 5231\n", 473 | "Data columns (total 35 columns):\n", 474 | " # Column Non-Null Count Dtype \n", 475 | "--- ------ -------------- ----- \n", 476 | " 0 _id 5232 non-null object \n", 477 | " 1 TimeStamp 5232 non-null object \n", 478 | " 2 PART_FACT_PLAN_DATE 5232 non-null object \n", 479 | " 3 PART_FACT_SERIAL 5232 non-null int64 \n", 480 | " 4 PART_NAME 5232 non-null object \n", 481 | " 5 EQUIP_CD 5232 non-null object \n", 482 | " 6 EQUIP_NAME 5232 non-null object \n", 483 | " 7 PassOrFail 5232 non-null object \n", 484 | " 8 Reason 5232 non-null object \n", 485 | " 9 Injection_Time 5232 non-null float64\n", 486 | " 10 Filling_Time 5232 non-null float64\n", 487 | " 11 Plasticizing_Time 5232 non-null float64\n", 488 | " 12 Cycle_Time 5232 non-null float64\n", 489 | " 13 Clamp_Close_Time 5232 non-null float64\n", 490 | " 14 Cushion_Position 5232 non-null float64\n", 491 | " 15 Switch_Over_Position 5232 non-null float64\n", 492 | " 16 Plasticizing_Position 5232 non-null float64\n", 493 | " 17 Clamp_Open_Position 5232 non-null float64\n", 494 | " 18 Max_Injection_Speed 5232 non-null float64\n", 495 | " 19 Max_Screw_RPM 5232 non-null float64\n", 496 | " 20 Average_Screw_RPM 5232 non-null float64\n", 497 | " 21 Max_Injection_Pressure 5232 non-null float64\n", 498 | " 22 Max_Switch_Over_Pressure 5232 non-null float64\n", 499 | " 23 Max_Back_Pressure 5232 non-null float64\n", 500 | " 24 Average_Back_Pressure 5232 non-null float64\n", 501 | " 25 Barrel_Temperature_1 5232 non-null float64\n", 502 | " 26 Barrel_Temperature_2 5232 non-null float64\n", 503 | " 27 Barrel_Temperature_3 5232 non-null float64\n", 504 | " 28 Barrel_Temperature_4 5232 non-null float64\n", 505 | " 29 Barrel_Temperature_5 5232 non-null float64\n", 506 | " 30 Barrel_Temperature_6 5232 non-null float64\n", 507 | " 31 Barrel_Temperature_7 5232 non-null float64\n", 508 | " 32 Hopper_Temperature 5232 non-null float64\n", 509 | " 33 Mold_Temperature_3 5232 non-null float64\n", 510 | " 34 Mold_Temperature_4 5232 non-null float64\n", 511 | "dtypes: float64(26), int64(1), object(8)\n", 512 | "memory usage: 1.4+ MB\n" 513 | ] 514 | } 515 | ], 516 | "source": [ 517 | "df.info()" 518 | ] 519 | }, 520 | { 521 | "cell_type": "markdown", 522 | "id": "3104e75a-9359-46cb-b9e1-2ad56bdbe492", 523 | "metadata": {}, 524 | "source": [ 525 | "## 2.3. Change the time formate for the column, `PART_FACT_PLAN_DATE`" 526 | ] 527 | }, 528 | { 529 | "cell_type": "code", 530 | "execution_count": 9, 531 | "id": "e225f665-c1f6-4733-b6fc-833eb76eacf7", 532 | "metadata": {}, 533 | "outputs": [ 534 | { 535 | "data": { 536 | "text/plain": [ 537 | "array(['2020-10-16 오전 12:00:00', '2020-10-20 오전 12:00:00',\n", 538 | " '2020-10-21 오전 12:00:00', '2020-10-22 오전 12:00:00',\n", 539 | " '2020-10-23 오전 12:00:00', '2020-10-27 오전 12:00:00',\n", 540 | " '2020-10-28 오전 12:00:00', '2020-10-29 오전 12:00:00',\n", 541 | " '2020-10-30 오전 12:00:00', '2020-11-03 오전 12:00:00',\n", 542 | " '2020-11-04 오전 12:00:00', '2020-11-05 오전 12:00:00',\n", 543 | " '2020-11-06 오전 12:00:00'], dtype=object)" 544 | ] 545 | }, 546 | "execution_count": 9, 547 | "metadata": {}, 548 | "output_type": "execute_result" 549 | } 550 | ], 551 | "source": [ 552 | "df[\"PART_FACT_PLAN_DATE\"].unique()" 553 | ] 554 | }, 555 | { 556 | "cell_type": "code", 557 | "execution_count": 10, 558 | "id": "f6c432b8-d445-4bc7-8f05-ee3ae002e87e", 559 | "metadata": {}, 560 | "outputs": [], 561 | "source": [ 562 | "df[\"PART_FACT_PLAN_DATE\"] = df[\"PART_FACT_PLAN_DATE\"].str.replace(\"오전 12\", \"00\")" 563 | ] 564 | }, 565 | { 566 | "cell_type": "code", 567 | "execution_count": 11, 568 | "id": "9ba9f9b3-0203-45ec-828c-5f4639f3d840", 569 | "metadata": {}, 570 | "outputs": [ 571 | { 572 | "data": { 573 | "text/plain": [ 574 | "array(['2020-10-16 00:00:00', '2020-10-20 00:00:00',\n", 575 | " '2020-10-21 00:00:00', '2020-10-22 00:00:00',\n", 576 | " '2020-10-23 00:00:00', '2020-10-27 00:00:00',\n", 577 | " '2020-10-28 00:00:00', '2020-10-29 00:00:00',\n", 578 | " '2020-10-30 00:00:00', '2020-11-03 00:00:00',\n", 579 | " '2020-11-04 00:00:00', '2020-11-05 00:00:00',\n", 580 | " '2020-11-06 00:00:00'], dtype=object)" 581 | ] 582 | }, 583 | "execution_count": 11, 584 | "metadata": {}, 585 | "output_type": "execute_result" 586 | } 587 | ], 588 | "source": [ 589 | "df[\"PART_FACT_PLAN_DATE\"].unique()" 590 | ] 591 | }, 592 | { 593 | "cell_type": "markdown", 594 | "id": "bb2d9157-15c7-4eaa-bd9c-e268451f4bc1", 595 | "metadata": {}, 596 | "source": [ 597 | "## 2.4. Transformation of the values in `PassOrFail`" 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": 12, 603 | "id": "48642f31-e21a-4022-b303-71fd2d1da081", 604 | "metadata": {}, 605 | "outputs": [ 606 | { 607 | "data": { 608 | "text/plain": [ 609 | "Y 5172\n", 610 | "N 60\n", 611 | "Name: PassOrFail, dtype: int64" 612 | ] 613 | }, 614 | "execution_count": 12, 615 | "metadata": {}, 616 | "output_type": "execute_result" 617 | } 618 | ], 619 | "source": [ 620 | "df[\"PassOrFail\"].value_counts()" 621 | ] 622 | }, 623 | { 624 | "cell_type": "code", 625 | "execution_count": 13, 626 | "id": "c6739f67-c643-4f79-8231-5209f2323ad2", 627 | "metadata": {}, 628 | "outputs": [], 629 | "source": [ 630 | "# Change Y/N to 1/0\n", 631 | "\n", 632 | "df[\"PassOrFail\"] = df[\"PassOrFail\"].apply(lambda x: 1 if x == \"N\" else 0) " 633 | ] 634 | }, 635 | { 636 | "cell_type": "markdown", 637 | "id": "26b01a20-7da5-43c7-9418-def53b4f9b29", 638 | "metadata": {}, 639 | "source": [ 640 | "# 3. Saving the preprocessed dataframe as csv" 641 | ] 642 | }, 643 | { 644 | "cell_type": "code", 645 | "execution_count": 14, 646 | "id": "0567f5c2-6dee-469c-a434-f1cd8489111c", 647 | "metadata": {}, 648 | "outputs": [], 649 | "source": [ 650 | "df.to_csv(\"../data/interim/labeled_data_preprocessed.csv\", index=False)" 651 | ] 652 | } 653 | ], 654 | "metadata": { 655 | "kernelspec": { 656 | "display_name": "Python [conda env:inj_env]", 657 | "language": "python", 658 | "name": "conda-env-inj_env-py" 659 | }, 660 | "language_info": { 661 | "codemirror_mode": { 662 | "name": "ipython", 663 | "version": 3 664 | }, 665 | "file_extension": ".py", 666 | "mimetype": "text/x-python", 667 | "name": "python", 668 | "nbconvert_exporter": "python", 669 | "pygments_lexer": "ipython3", 670 | "version": "3.10.8" 671 | } 672 | }, 673 | "nbformat": 4, 674 | "nbformat_minor": 5 675 | } 676 | -------------------------------------------------------------------------------- /notebooks/3-2_ML_on_CN7_MD.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "bfeabc3c-3ebe-4c8f-85ad-e3c058209de0", 6 | "metadata": {}, 7 | "source": [ 8 | "# 0. Imports" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "97be1e08-f742-4664-9aae-cd34068183dc", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import pandas as pd\n", 19 | "import numpy as np\n", 20 | "import scipy as sp\n", 21 | "from scipy.stats import chi2\n", 22 | "import matplotlib.pyplot as plt\n", 23 | "import seaborn as sns\n", 24 | "\n", 25 | "from collections import defaultdict\n", 26 | "import time\n", 27 | "from datetime import timedelta\n", 28 | "\n", 29 | "from sklearn.preprocessing import MinMaxScaler, StandardScaler\n", 30 | "from sklearn.model_selection import train_test_split\n", 31 | "from sklearn.metrics import confusion_matrix, classification_report" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "6749c29f-62cb-4c13-96a5-980a90d12888", 37 | "metadata": {}, 38 | "source": [ 39 | "# 1. Data" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "id": "11d01b97-0d88-470d-b99a-72626c8b3e34", 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "cn7 = pd.read_csv(\"../data/processed/labeled_data_cn7.csv\", parse_dates=True)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "id": "0ffc6350-b5b1-4bc6-9ee3-e9c15362bb36", 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "\n", 63 | "RangeIndex: 3974 entries, 0 to 3973\n", 64 | "Data columns (total 27 columns):\n", 65 | " # Column Non-Null Count Dtype \n", 66 | "--- ------ -------------- ----- \n", 67 | " 0 TimeStamp 3974 non-null object \n", 68 | " 1 PassOrFail 3974 non-null int64 \n", 69 | " 2 Hopper_Temperature 3974 non-null float64\n", 70 | " 3 Plasticizing_Position 3974 non-null float64\n", 71 | " 4 Barrel_Temperature_3 3974 non-null float64\n", 72 | " 5 Reason 3974 non-null object \n", 73 | " 6 Injection_Time 3974 non-null float64\n", 74 | " 7 Max_Injection_Pressure 3974 non-null float64\n", 75 | " 8 Barrel_Temperature_6 3974 non-null float64\n", 76 | " 9 Barrel_Temperature_2 3974 non-null float64\n", 77 | " 10 Cushion_Position 3974 non-null float64\n", 78 | " 11 Max_Screw_RPM 3974 non-null float64\n", 79 | " 12 Barrel_Temperature_5 3974 non-null float64\n", 80 | " 13 Average_Screw_RPM 3974 non-null float64\n", 81 | " 14 _id 3974 non-null object \n", 82 | " 15 Average_Back_Pressure 3974 non-null float64\n", 83 | " 16 Plasticizing_Time 3974 non-null float64\n", 84 | " 17 Max_Back_Pressure 3974 non-null float64\n", 85 | " 18 Filling_Time 3974 non-null float64\n", 86 | " 19 Max_Switch_Over_Pressure 3974 non-null float64\n", 87 | " 20 Barrel_Temperature_1 3974 non-null float64\n", 88 | " 21 Barrel_Temperature_4 3974 non-null float64\n", 89 | " 22 Cycle_Time 3974 non-null float64\n", 90 | " 23 Clamp_Close_Time 3974 non-null float64\n", 91 | " 24 Mold_Temperature_4 3974 non-null float64\n", 92 | " 25 Mold_Temperature_3 3974 non-null float64\n", 93 | " 26 Max_Injection_Speed 3974 non-null float64\n", 94 | "dtypes: float64(23), int64(1), object(3)\n", 95 | "memory usage: 838.4+ KB\n" 96 | ] 97 | } 98 | ], 99 | "source": [ 100 | "cn7.info()" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "id": "d476ba58-0785-4370-b416-c80dfc0cad52", 106 | "metadata": {}, 107 | "source": [ 108 | "# 2. Data Preprocessing" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 4, 114 | "id": "ca4ce13b-11ca-46db-aeba-08de5d94ef80", 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "# Preparation of features for model training\n", 119 | "numerical_features = [x for x in cn7.columns if np.dtype(cn7[x]) == \"float64\"]" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 5, 125 | "id": "7509fb43-d58a-4dda-afec-5c702ff26081", 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "No. of passed CN7 parts: 3946\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "# Data for passed parts\n", 138 | "cn7_Y = cn7[cn7[\"PassOrFail\"] == 0]\n", 139 | "cn7_Y = cn7_Y[numerical_features]\n", 140 | "print(\"No. of passed CN7 parts:\", len(cn7_Y))" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 6, 146 | "id": "0ac9183e-d9b0-4380-a2c7-19126573a000", 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "name": "stdout", 151 | "output_type": "stream", 152 | "text": [ 153 | "No. of failed CN7 parts: 28\n" 154 | ] 155 | } 156 | ], 157 | "source": [ 158 | "# Data for failed parts\n", 159 | "cn7_N = cn7[cn7[\"PassOrFail\"] == 1]\n", 160 | "cn7_N = cn7_N[numerical_features]\n", 161 | "print(\"No. of failed CN7 parts:\", len(cn7_N))" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 7, 167 | "id": "20110606-19d5-4e81-baaa-8eba73ca661a", 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "No. of Train Set (Passed Parts): 3551\n", 175 | "No. of Test Set (Passed Parts): 395\n", 176 | "No. of Test Set (Failed Parts): 28\n" 177 | ] 178 | } 179 | ], 180 | "source": [ 181 | "# The model using Mahalanobis Distance is trained by Data for passed parts (i.e., data with a majority class)\n", 182 | "cn7_train_Y, cn7_test_Y = train_test_split(cn7_Y, test_size=0.1)\n", 183 | "\n", 184 | "# Test set with failed parts\n", 185 | "cn7_test_N = cn7_N\n", 186 | "\n", 187 | "print(f\"No. of Train Set (Passed Parts): {len(cn7_train_Y)}\")\n", 188 | "print(f\"No. of Test Set (Passed Parts): {len(cn7_test_Y)}\")\n", 189 | "print(f\"No. of Test Set (Failed Parts): {len(cn7_test_N)}\")" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 8, 195 | "id": "d2032b24-477d-4a02-87e8-a990aef8fea2", 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [ 199 | "# Data normalization\n", 200 | "\n", 201 | "scaler = StandardScaler()\n", 202 | "\n", 203 | "cn7_train_Y = scaler.fit_transform(cn7_train_Y)\n", 204 | "cn7_test_Y = scaler.transform(cn7_test_Y)\n", 205 | "cn7_test_N = scaler.transform(cn7_test_N)" 206 | ] 207 | }, 208 | { 209 | "cell_type": "markdown", 210 | "id": "0acdf843-6077-4018-b3ea-423452b90e39", 211 | "metadata": {}, 212 | "source": [ 213 | "# 3. Mahalanobis Distance" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 9, 219 | "id": "0ed8a91b-47be-49cc-945f-3c2a8ce09780", 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "def mahalanobis(x=None, data=None, cov=None):\n", 224 | " \"\"\"\n", 225 | " Compute the Mahalanobis Distance between each row of x and the data \n", 226 | " x : vector or matrix of data with, say, p columns.\n", 227 | " data : ndarray of the distribution from which Mahalanobis distance of each observation of x is to be computed.\n", 228 | " cov : covariance matrix (p x p) of the distribution. If None, will be computed from data.\n", 229 | " \"\"\"\n", 230 | " x_minus_mu = x - np.mean(data, axis=0)\n", 231 | " if not cov:\n", 232 | " cov = np.cov(data.T)\n", 233 | " # cov = np.cov(data.values.T)\n", 234 | " inv_covmat = sp.linalg.inv(cov)\n", 235 | " left_term = np.dot(x_minus_mu, inv_covmat)\n", 236 | " mahal = np.dot(left_term, x_minus_mu.T)\n", 237 | " return mahal.diagonal() # Can't understand why .diagonal() is used" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 10, 243 | "id": "cd7152de-3dd5-485c-ad8f-9db5628b3257", 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "class MahalanobisOneclassClassifier():\n", 248 | " def __init__(self, xtrain, significance_level=0.01):\n", 249 | " self.xtrain = xtrain\n", 250 | " self.critical_value = chi2.ppf((1-significance_level), df=xtrain.shape[1] - 1) # df = degree of freedom\n", 251 | " print('Critical value is: ', self.critical_value)\n", 252 | "\n", 253 | " def predict_proba(self, xtest):\n", 254 | " mahalanobis_dist = mahalanobis(xtest, self.xtrain)\n", 255 | " self.pvalues = 1 - chi2.cdf(mahalanobis_dist, 2)\n", 256 | " return mahalanobis_dist\n", 257 | "\n", 258 | " def predict(self, xtest):\n", 259 | " return np.array([int(i) for i in self.predict_proba(xtest) > self.critical_value])" 260 | ] 261 | }, 262 | { 263 | "cell_type": "markdown", 264 | "id": "7a439320-3074-4e43-b4c8-450c1b4fde4a", 265 | "metadata": {}, 266 | "source": [ 267 | "# 4. Setup of Threshold" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 11, 273 | "id": "260c938a-f2fb-4c64-99fb-fbf59d80887f", 274 | "metadata": {}, 275 | "outputs": [ 276 | { 277 | "name": "stdout", 278 | "output_type": "stream", 279 | "text": [ 280 | "Critical value is: 30.813282343953027\n" 281 | ] 282 | } 283 | ], 284 | "source": [ 285 | "clf = MahalanobisOneclassClassifier(cn7_train_Y, significance_level=0.1)" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": 12, 291 | "id": "8ee61460-5e70-46e8-aba0-7527f193dcb7", 292 | "metadata": {}, 293 | "outputs": [], 294 | "source": [ 295 | "threshold = clf.critical_value" 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "id": "6e674593-3220-409c-82bf-08b3f330cf2e", 301 | "metadata": {}, 302 | "source": [ 303 | "# 5. Classification of Test Set by Mahalanobis Distance" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "id": "bcb19903-b68f-4fb5-9169-2f1c2f4bde9e", 309 | "metadata": {}, 310 | "source": [ 311 | "## 5.1. Evaluation Using Test Set (Passed Parts)" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": 13, 317 | "id": "f13a656e-0223-41e7-8c88-a854000bcb48", 318 | "metadata": {}, 319 | "outputs": [], 320 | "source": [ 321 | "# Prediction of Mahalanobis Distance\n", 322 | "cn7_MD_Y = clf.predict_proba(cn7_test_Y)" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": 14, 328 | "id": "5e57b830-3e15-4684-bdb7-ef7d5e1af119", 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "data": { 333 | "image/png": "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1Zmpr52Ruqh15XHM8jwGAMA5pQoyK1eu1IIFC3Ts2DHZbDZlZGRwVQYAALhdqYJMcHCw5s6dK0lq0qSJVqxYwXQEAADA7Zz+QryUlJTyqAMAAMBpZfr4dXx8vPr166fw8HCFh4erf//++uqrr1xdGwAAQImcDjIrV65UVFSUfH19NWHCBPvA3169emnVqlXlUSMAAECRnL619Pe//13z5s3TpEmT7OsmTJig+fPn629/+5seeughlxYIAABQHKevyPzwww/q169fofX9+/dn/AwAAKhQTgeZsLAwxcXFFVr/5ZdfKiwszCVFAQAAlIbTt5aefvppTZgwQcnJyerataskKSEhQbGxsVq0aJHLCwQAACiO00HmiSeeUEhIiF599VW9//77kqQWLVpozZo1GjBggMsLBAAAKI7TQUaSBg0apEGDBrm6FgAAAKeU6XtkAAAAPAFBBgAAWBZBBvBQjad+5jDjNgCgMIIMAACwrBsKMsYYGWNcVQsAAIBTyhRkli9frjZt2sjHx0c+Pj6KjIzUihUrXF0bAABAiZz++PX8+fP1/PPPa9y4cerWrZskadu2bRozZozOnj3rMAcTAABAeXI6yLz++utavHixHnnkEfu6/v37q1WrVpo1axZBBgAAVBinby2lpaXZpya4VteuXZWWluaSogAAAErD6SATHh5un5rgWmvWrFFERIRLigIAACgNp28tzZ49Ww8++KC2bt1qHyOTkJCguLi4IgMOAABAeXH6iswDDzygnTt3KigoSOvWrdO6desUFBSkXbt2Mf8SAACoUGX6+HX79u21cuVKJSUlKSkpSStXrlS7du2c3s/WrVvVr18/hYaGymazad26dQ7bjTF64YUXVL9+ffn4+CgqKkpHjhwpS8kAAKAScus3+2ZnZ6tt27Z64403itw+b948vfbaa1qyZIl27typGjVqKDo6Wr/88ksFVwoAADxRqcfIVKlSRTabrcQ2NptNv/76a6kP3rt3b/Xu3bvIbcYYLVy4UDNmzNCAAQMk/fZFfMHBwVq3bp2GDBlS6uMAAIDKqdRBZu3atcVuS0xM1Guvvab8/HyXFCVJKSkpSk9PV1RUlH1dQECAOnXqpMTExGKDTG5urnJzc+2PMzMzXVYTAADwLKUOMlevilzr8OHDmjp1qj799FMNGzZMc+bMcVlh6enpkqTg4GCH9cHB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MSkpKSYhIcFERUWZoKAgc+bMGWNM5T/3zvbfneeeW0slWLx4sSSpZ8+eDuuXLl2qkSNHSpJOnDihKlX+34Wtrl27atWqVZoxY4b++te/KiIiQuvWrStxgKynKkv/L1y4oNGjRys9PV21a9dW+/bttX379mIHiHqyM2fO6JFHHlFaWpoCAgIUGRmpL774Qnfffbekyn3uJef7X5nOfWlV9vfA9VTm98DJkyc1dOhQnTt3TnXr1lX37t21Y8cO1a1bV1LlP/fO9t+d595mjDHlfhQAAIBywBgZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZAABgWQQZwMV69uypiRMnlsu+e/TooVWrVpXLviUpNjZWtWrVuuH92Gw2rVu37ob344wtW7bIZrPp4sWLxbZxVf9cUYsVfPvtt2rQoIGys7PdXQpQLIIMYBGffPKJTp8+rSFDhtjXNW7cWDabTatXry7UvlWrVrLZbIqNja3AKj3bgw8+qO+//77Mz7/6ettsNvn4+Khx48YaPHiwNm3a5NCua9eu9qkdrseTQ0/Lli3VuXNnzZ8/392lAMUiyAAW8dprr+nRRx91mN9EksLCwrR06VKHdTt27FB6erpq1KhRkSV6PB8fH9WrV++G9jFnzhylpaXp8OHDWr58uWrVqqWoqCj9/e9/t7epXr26QkJCZLPZbrRkt3v00Ue1ePFi/frrr+4uBSgSQQYoZxcuXNAjjzyi2rVry9fXV71799aRI0cc2rz99tsKCwuTr6+vBg0apPnz5zvcAvnpp5+0adMm9evXr9D+hw0bpvj4eKWmptrXvfvuuxo2bJiqVnWcF3b+/Plq06aNatSoobCwMD355JPKysoqtM8vvvhCLVq0UM2aNXXvvfcqLS3Nvm337t26++67FRQUpICAAN15553au3dvia/Bc889p+bNm8vX11dNmzbV888/r7y8PPv2WbNm6bbbbtOKFSvUuHFjBQQEaMiQIbp06ZK9TW5uriZMmKB69erJ29tb3bt31+7duwsdKyEhQZGRkfL29lbnzp114MAB+7aCt5b27dunu+66S35+fvL391f79u21Z8+eEvvi5+enkJAQNWzYUD169NBbb72l559/Xi+88IIOHz4sqfBVlh9//FH9+vVT7dq1VaNGDbVq1Ur/+te/dPz4cd11112SpNq1a8tms9knZN2wYYO6d++uWrVqKTAwUPfdd5+OHTtmr+P48eOy2Wz66KOPdNddd8nX11dt27ZVYmJiodejZ8+e8vX1Ve3atRUdHa0LFy5IkvLz8xUTE6MmTZrIx8dHbdu21f/93/85PP/uu+/W+fPnFR8fX+LrArgLQQYoZyNHjtSePXv0ySefKDExUcYY9enTx/6HPCEhQWPGjNFTTz2l5ORk3X333Q7/u5ekbdu2ydfXVy1atCi0/+DgYEVHR2vZsmWSpJycHK1Zs0ajRo0q1LZKlSp67bXXdPDgQS1btkybNm3Ss88+69AmJydHr7zyilasWKGtW7fqxIkTeuaZZ+zbL126pBEjRmjbtm3asWOHIiIi1KdPH4fQUZCfn59iY2P17bffatGiRXr77be1YMEChzbHjh3TunXrtH79eq1fv17x8fGaO3euffuzzz6rDz/8UMuWLdPevXsVHh6u6OhonT9/3mE/U6ZM0auvvqrdu3erbt266tevn0NoutawYcPUoEED7d69W0lJSZo6daqqVatWbD+K89RTT8kYo48//rjI7WPHjlVubq62bt2q/fv366WXXlLNmjUVFhamDz/8UJJ0+PBhpaWladGiRZKk7OxsTZ48WXv27FFcXJyqVKmiQYMGKT8/32Hf06dP1zPPPKPk5GQ1b95cQ4cOtV89SU5OVq9evdSyZUslJiZq27Zt6tevn65cuSJJiomJ0fLly7VkyRIdPHhQkyZN0sMPP+wQWqpXr67bbrtNX331ldOvC1AhDACXuvPOO81TTz1ljDHm+++/N5JMQkKCffvZs2eNj4+Pef/9940xxjz44IOmb9++DvsYNmyYCQgIsD9esGCBadq0aaFjNWrUyCxYsMCsW7fONGvWzOTn55tly5aZdu3aGWOMCQgIMEuXLi221g8++MAEBgbaHy9dutRIMkePHrWve+ONN0xwcHCx+7hy5Yrx8/Mzn376qX2dJLN27dpin/Pyyy+b9u3b2x/PnDnT+Pr6mszMTPu6KVOmmE6dOhljjMnKyjLVqlUz7733nn375cuXTWhoqJk3b54xxpjNmzcbSWb16tX2NufOnTM+Pj5mzZo19v5d+7r6+fmZ2NjYYuss6OrrXZTg4GDzxBNPONRy4cIFY4wxbdq0MbNmzSryeQXbFuenn34yksz+/fuNMcakpKQYSeadd96xtzl48KCRZA4dOmSMMWbo0KGmW7duRe7vl19+Mb6+vmb79u0O6x977DEzdOhQh3WDBg0yI0eOLLE+wF24IgOUo0OHDqlq1arq1KmTfV1gYKBuueUWHTp0SNJv/xPv2LGjw/MKPv7555/l7e1d7HH69u2rrKwsbd26Ve+++26RV2Mk6csvv1SvXr108803y8/PT8OHD9e5c+eUk5Njb+Pr66tmzZrZH9evX19nzpyxPz59+rRGjx6tiIgIBQQEyN/fX1lZWTpx4kSx9a1Zs0bdunVTSEiIatasqRkzZhRq37hxY/n5+RV53GPHjikvL0/dunWzb69WrZo6duxofx2v6tKli/3nOnXqOLzWBU2ePFmPP/64oqKiNHfuXIdbN84yxhQ7JmbChAl68cUX1a1bN82cOVPffPPNdfd35MgRDR06VE2bNpW/v78aN24sSYVet8jISPvP9evXlyT763b1ikxRjh49qpycHN19992qWbOmfVm+fHmh18HHx8fhPQJ4EoIMYAFBQUH2cQ1FqVq1qoYPH66ZM2dq586dGjZsWKE2x48f13333afIyEh9+OGHSkpK0htvvCFJunz5sr1dwVsrNptNxhj74xEjRig5OVmLFi3S9u3blZycrMDAQId9XCsxMVHDhg1Tnz59tH79en399deaPn16ofZFHbfgbRRXmzVrlg4ePKi+fftq06ZNatmypdauXev0fs6dO6effvpJTZo0KXL7448/rh9++EHDhw/X/v371aFDB73++usl7rNfv346f/683n77be3cuVM7d+6UpBJft6tB6urr5uPjU+z+r46N+uyzz5ScnGxfvv3220LjZM6fP6+6deuWWC/gLgQZoBy1aNFCv/76q/2PkPTbH73Dhw+rZcuWkqRbbrml0KDVgo/btWun9PT0EsPMqFGjFB8frwEDBqh27dqFticlJSk/P1+vvvqqOnfurObNm+vUqVNO9ykhIUETJkxQnz591KpVK3l5eens2bPFtt++fbsaNWqk6dOnq0OHDoqIiNCPP/7o1DGbNWum6tWrKyEhwb4uLy9Pu3fvtr+OV+3YscP+84ULF/T9998XObboqubNm2vSpEn697//rfvvv7/QJ8BKY9GiRapSpYoGDhxYbJuwsDCNGTNGH330kZ5++mm9/fbbkn4bgyLJPm5F+n/vkRkzZqhXr15q0aJFiee+OJGRkYqLiytyW8uWLeXl5aUTJ04oPDzcYQkLC3Noe+DAAbVr187p4wMVoer1mwAoq4iICA0YMECjR4/Wm2++KT8/P02dOlU333yzBgwYIEkaP368evToofnz56tfv37atGmTPv/8c4fbFO3atVNQUJASEhJ03333FXmsFi1a6OzZs/L19S1ye3h4uPLy8vT666+rX79+SkhI0JIlS8rUpxUrVqhDhw7KzMzUlClTSvyff0REhE6cOKHVq1fr9ttv12effeb0VY8aNWroiSee0JQpU1SnTh01bNhQ8+bNU05Ojh577DGHtnPmzFFgYKCCg4M1ffp0BQUFFRkwfv75Z02ZMkV/+tOf1KRJE508eVK7d+/WAw88UGItly5dUnp6uvLy8pSSkqKVK1fqnXfeUUxMjMLDw4t8zsSJE9W7d281b95cFy5c0ObNm+3hqlGjRrLZbFq/fr369OkjHx8f1a5dW4GBgXrrrbdUv359nThxQlOnTnXqNZOkadOmqU2bNnryySc1ZswYVa9eXZs3b9af//xnBQUF6ZlnntGkSZOUn5+v7t27KyMjQwkJCfL399eIESMk/XYl7z//+Y+ioqKcPj5QIdw9SAeobK4d7GuMMefPnzfDhw83AQEBxsfHx0RHR5vvv//e4TlvvfWWufnmm42Pj48ZOHCgefHFF01ISIhDm2effdYMGTLEYV1Jg0+NKTzYd/78+aZ+/fr2OpYvX+4w0LTgYFhjjFm7dq259p+KvXv3mg4dOhhvb28TERFhPvjgg0J1qMBg3ylTppjAwEBTs2ZN8+CDD5oFCxY4HGfmzJmmbdu2DsddsGCBadSokf3xzz//bMaPH2+CgoKMl5eX6datm9m1a5d9+9VBs59++qlp1aqVqV69uunYsaPZt2+fvc21/cvNzTVDhgwxYWFhpnr16iY0NNSMGzfO/Pzzz8W+no0aNTKSjCRTvXp107BhQzN48GCzadMmh3YFB/COGzfONGvWzHh5eZm6deua4cOHm7Nnz9rbz5kzx4SEhBibzWZGjBhhjDFm48aNpkWLFsbLy8tERkaaLVu2OLyuVwf7fv311/b9XLhwwUgymzdvtq/bsmWL6dq1q/Hy8jK1atUy0dHR9rry8/PNwoULzS233GKqVatm6tata6Kjo018fLz9+f/93/9toqOji31NAHezGXPNzW8AHmH06NH67rvvHD7ymp6erlatWmnv3r1q1KiRG6vD78Xly5cVERGhVatWOQy0BjwJY2QAD/DKK69o3759Onr0qF5//XUtW7bMfmn/qpCQEP3jH/8o8dNBgCudOHFCf/3rXwkx8GhckQE8wODBg7VlyxZdunRJTZs21fjx4zVmzBh3lwUAHo8gAwAALItbSwAAwLIIMgAAwLIIMgAAwLIIMgAAwLIIMgAAwLIIMgAAwLIIMgAAwLIIMgAAwLL+PzyklaezPwXfAAAAAElFTkSuQmCC", 334 | "text/plain": [ 335 | "
" 336 | ] 337 | }, 338 | "metadata": {}, 339 | "output_type": "display_data" 340 | } 341 | ], 342 | "source": [ 343 | "# Data Visualization \n", 344 | "# Log was used for better visualization\n", 345 | "\n", 346 | "plt.hist(np.log(cn7_MD_Y), bins=200)\n", 347 | "plt.xlabel(\"log(Mahalanobis Distance)\")\n", 348 | "plt.ylabel(\"No of samples\")\n", 349 | "plt.vlines(np.log(threshold), 0, 25, color=\"red\")\n", 350 | "plt.show();" 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 15, 356 | "id": "1bbc188b-403f-4751-a161-ed63f8abc49f", 357 | "metadata": {}, 358 | "outputs": [ 359 | { 360 | "name": "stdout", 361 | "output_type": "stream", 362 | "text": [ 363 | "No. of Failed Parts: 24\n", 364 | "Accuracy: 0.9392405063291139\n" 365 | ] 366 | } 367 | ], 368 | "source": [ 369 | "# Check on the data that were predicted as failed parts\n", 370 | "\n", 371 | "cn7_test_Y_anomalies = cn7_MD_Y > threshold\n", 372 | "print(\"No. of Failed Parts:\", np.sum(cn7_test_Y_anomalies))\n", 373 | "print(\"Accuracy:\", (cn7_test_Y.shape[0]-np.sum(cn7_test_Y_anomalies))/cn7_test_Y.shape[0])" 374 | ] 375 | }, 376 | { 377 | "cell_type": "markdown", 378 | "id": "055407b1-4ea7-40c4-abca-00580ba44869", 379 | "metadata": {}, 380 | "source": [ 381 | "## 5.2. Evaluation Using Test Set (Failed Parts)" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": 16, 387 | "id": "2dd8090b-ff11-4c2e-a7df-d23c4a1af6d3", 388 | "metadata": {}, 389 | "outputs": [], 390 | "source": [ 391 | "# Prediction of Mahalanobis Distance\n", 392 | "cn7_MD_N = clf.predict_proba(cn7_test_N)" 393 | ] 394 | }, 395 | { 396 | "cell_type": "code", 397 | "execution_count": 17, 398 | "id": "81d6064b-f17e-43cf-a8fc-bbc96900e8af", 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "image/png": "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fNxuHDM/P79bZs7OzlZCQoIeeuihAut8fX1v+VrgTsQZFcBGXbp00bVr13T9+nV17ty5wPoLFy7oyJEjeumll9SxY0eFh4fr+++/d3s/27dvV69evTRgwAA1a9ZM9erV05dffnnT8f/5z3904cIFTZo0Sffff78aNWqU70baogoPD9f27dsLZGncuHG+Zbt27SowHx4eftPt1qhRQ3FxcXrvvfc0Y8aMAjejFsX//d//6dChQ3r44YdvOiYgIECPPfaY5s+fr+XLl+uDDz7QxYsXJf1cNnJzc/ON3759uwYNGqQ+ffooMjJSgYGBOnnypFu5mjZtqtTUVNd+fikqKkpHjhxRWFhYgalcOf5JR+nDGRXARl5eXq5LHF5eXgXWV6lSRdWqVdO8efMUFBSkU6dOaezYsW7vp379+vrXv/6lHTt2qEqVKpo+fbrOnTtXoDDcEBoaKh8fH82ePVtPPfWUDh8+rPHjx7u93+eee059+/ZV8+bN1alTJ3344YdauXJlgU/CvP/++4qOjla7du20ePFi7dmzR2+//Xah23z55ZfVokULNWnSRDk5OVq3bt0tS40k5eTk6OzZs8rNzdW5c+e0YcMGJSYmqkePHho4cGChr5k+fbqCgoLUvHlzlStXTu+//74CAwNVuXJlST9/eic5OVlt27aV0+lUlSpVVL9+fa1cuVIxMTFyOBwaN26c22eX+vXrp4kTJ6p3795KTExUUFCQDhw4oODgYLVu3Vovv/yyevToodDQUD3yyCMqV66cDh48qMOHD+u1115za1/AnYD6DdgsICBAAQEBha4rV66cli1bpn379ikiIkKjRo3S1KlT3d7HSy+9pKioKHXu3FkdOnRQYGCgevfufdPxNWrU0MKFC/X++++rcePGmjRpUrEurfTu3VszZ87U66+/riZNmmju3LlasGCBOnTokG9cQkKCli1bpqZNm+qf//ynli5detMS5ePjo/j4eDVt2lR/+MMf5OXlpWXLlt0yx4YNGxQUFKQ6deqoS5cu2rx5s2bNmqU1a9YUWhAlyd/fX1OmTFF0dLRatmypkydP6t///rfrrMW0adO0ceNGhYSEuD5SPn36dFWpUkVt2rRRTEyMOnfurKioKLeOmY+Pjz755BPVrFlT3bp1U2RkpCZNmuTK2blzZ61bt06ffPKJWrZsqfvuu09vvPGGateu7dZ+gDuFw7Isy+4QAAAAheGMCgAAMBZFBQAAGIuiAgAAjEVRAQAAxqKoAAAAY1FUAACAsSgqAADAWBQVAABgLIoKAAAwFkUFAAAYi6ICAACM9f8BamhPe2MWiYYAAAAASUVORK5CYII=", 404 | "text/plain": [ 405 | "
" 406 | ] 407 | }, 408 | "metadata": {}, 409 | "output_type": "display_data" 410 | } 411 | ], 412 | "source": [ 413 | "# Data visualization \n", 414 | "# Log was used for better visualization\n", 415 | "\n", 416 | "plt.hist(np.log(cn7_MD_N), bins=50)\n", 417 | "plt.xlabel(\"Mahalanobis Distance\")\n", 418 | "plt.ylabel(\"No of samples\")\n", 419 | "plt.vlines(np.log(threshold), 0, 5, color=\"red\")\n", 420 | "plt.show();" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 18, 426 | "id": "695fe8ac-cdda-4b8b-b41a-649f41993637", 427 | "metadata": {}, 428 | "outputs": [ 429 | { 430 | "name": "stdout", 431 | "output_type": "stream", 432 | "text": [ 433 | "No. of Failed Parts: 20\n", 434 | "Accuracy: 0.7142857142857143\n" 435 | ] 436 | } 437 | ], 438 | "source": [ 439 | "# Check on the data that were predicted as failed parts\n", 440 | "\n", 441 | "cn7_test_N_anomalies = cn7_MD_N > threshold\n", 442 | "print(\"No. of Failed Parts:\", np.sum(cn7_test_N_anomalies))\n", 443 | "print(\"Accuracy:\", np.sum(cn7_test_N_anomalies)/cn7_test_N.shape[0])" 444 | ] 445 | }, 446 | { 447 | "cell_type": "markdown", 448 | "id": "d950e685-039b-415c-95e4-cccf396de964", 449 | "metadata": {}, 450 | "source": [ 451 | "# 6. Result Analysis" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": 19, 457 | "id": "9068d6e4-eda8-464f-8f6d-ff38bd2cad87", 458 | "metadata": {}, 459 | "outputs": [], 460 | "source": [ 461 | "# True values for the test set\n", 462 | "\n", 463 | "cn7_true = np.concatenate(\n", 464 | " [np.zeros(len(cn7_test_Y_anomalies)), np.ones(len(cn7_test_N_anomalies))]\n", 465 | ")" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": 20, 471 | "id": "0130a09a-8455-4d42-884b-ae31fbb4e326", 472 | "metadata": {}, 473 | "outputs": [], 474 | "source": [ 475 | "# Predicted values for the test set\n", 476 | "\n", 477 | "cn7_prediction = np.concatenate(\n", 478 | " [cn7_test_Y_anomalies, cn7_test_N_anomalies]\n", 479 | ")" 480 | ] 481 | }, 482 | { 483 | "cell_type": "code", 484 | "execution_count": 21, 485 | "id": "09bf7653-cf80-414b-936c-16282d427e8a", 486 | "metadata": {}, 487 | "outputs": [ 488 | { 489 | "data": { 490 | "text/plain": [ 491 | "array([[371, 24],\n", 492 | " [ 8, 20]], dtype=int64)" 493 | ] 494 | }, 495 | "execution_count": 21, 496 | "metadata": {}, 497 | "output_type": "execute_result" 498 | } 499 | ], 500 | "source": [ 501 | "confusion_matrix(cn7_true, cn7_prediction)" 502 | ] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "execution_count": 22, 507 | "id": "295332c3-ad08-4c02-84ce-1bdcc6194e2e", 508 | "metadata": {}, 509 | "outputs": [ 510 | { 511 | "data": { 512 | "image/png": "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", 513 | "text/plain": [ 514 | "
" 515 | ] 516 | }, 517 | "metadata": {}, 518 | "output_type": "display_data" 519 | } 520 | ], 521 | "source": [ 522 | "target_names = [\"Pass\", \"Fail\"]\n", 523 | "clf_report = classification_report(\n", 524 | " cn7_true, cn7_prediction, target_names=target_names, output_dict=True\n", 525 | ")\n", 526 | "clf_plot = sns.heatmap(pd.DataFrame(clf_report).iloc[:-1, :].T, annot=True)\n", 527 | "plt.title('Classification Report for Mahalanobis Distance on CN7')\n", 528 | "clf_plot.figure.savefig(\"../img/clf_report_cn7_MD.png\")" 529 | ] 530 | }, 531 | { 532 | "cell_type": "markdown", 533 | "id": "5946b2a7-fb65-4f04-b33d-dbee8550b438", 534 | "metadata": {}, 535 | "source": [ 536 | "- Performance of the model using Mahalanobis Distance was slightly less effective than the machine learning models." 537 | ] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "execution_count": null, 542 | "id": "c093eb72-959e-453e-91d8-d525a6ede8fe", 543 | "metadata": {}, 544 | "outputs": [], 545 | "source": [] 546 | } 547 | ], 548 | "metadata": { 549 | "kernelspec": { 550 | "display_name": "Python [conda env:inj_env]", 551 | "language": "python", 552 | "name": "conda-env-inj_env-py" 553 | }, 554 | "language_info": { 555 | "codemirror_mode": { 556 | "name": "ipython", 557 | "version": 3 558 | }, 559 | "file_extension": ".py", 560 | "mimetype": "text/x-python", 561 | "name": "python", 562 | "nbconvert_exporter": "python", 563 | "pygments_lexer": "ipython3", 564 | "version": "3.10.8" 565 | } 566 | }, 567 | "nbformat": 4, 568 | "nbformat_minor": 5 569 | } 570 | -------------------------------------------------------------------------------- /notebooks/4-2_ML_on_RG3_MD.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "bfeabc3c-3ebe-4c8f-85ad-e3c058209de0", 6 | "metadata": {}, 7 | "source": [ 8 | "# 0. Imports" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "97be1e08-f742-4664-9aae-cd34068183dc", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import pandas as pd\n", 19 | "import numpy as np\n", 20 | "import scipy as sp\n", 21 | "from scipy.stats import chi2\n", 22 | "import matplotlib.pyplot as plt\n", 23 | "import seaborn as sns\n", 24 | "\n", 25 | "from collections import defaultdict\n", 26 | "import time\n", 27 | "from datetime import timedelta\n", 28 | "\n", 29 | "from sklearn.preprocessing import MinMaxScaler, StandardScaler\n", 30 | "from sklearn.model_selection import train_test_split\n", 31 | "from sklearn.metrics import confusion_matrix, classification_report" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "id": "6749c29f-62cb-4c13-96a5-980a90d12888", 37 | "metadata": {}, 38 | "source": [ 39 | "# 1. Data" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "id": "11d01b97-0d88-470d-b99a-72626c8b3e34", 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "rg3 = pd.read_csv(\"../data/processed/labeled_data_rg3.csv\", parse_dates=True)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "id": "0ffc6350-b5b1-4bc6-9ee3-e9c15362bb36", 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "\n", 63 | "RangeIndex: 1256 entries, 0 to 1255\n", 64 | "Data columns (total 27 columns):\n", 65 | " # Column Non-Null Count Dtype \n", 66 | "--- ------ -------------- ----- \n", 67 | " 0 TimeStamp 1256 non-null object \n", 68 | " 1 Clamp_Close_Time 1256 non-null float64\n", 69 | " 2 Barrel_Temperature_4 1256 non-null float64\n", 70 | " 3 Hopper_Temperature 1256 non-null float64\n", 71 | " 4 Reason 1256 non-null object \n", 72 | " 5 Injection_Time 1256 non-null float64\n", 73 | " 6 Barrel_Temperature_1 1256 non-null float64\n", 74 | " 7 Plasticizing_Time 1256 non-null float64\n", 75 | " 8 Max_Back_Pressure 1256 non-null float64\n", 76 | " 9 Filling_Time 1256 non-null float64\n", 77 | " 10 Max_Injection_Pressure 1256 non-null float64\n", 78 | " 11 Plasticizing_Position 1256 non-null float64\n", 79 | " 12 Barrel_Temperature_6 1256 non-null float64\n", 80 | " 13 Cushion_Position 1256 non-null float64\n", 81 | " 14 Max_Injection_Speed 1256 non-null float64\n", 82 | " 15 _id 1256 non-null object \n", 83 | " 16 Average_Back_Pressure 1256 non-null float64\n", 84 | " 17 Mold_Temperature_3 1256 non-null float64\n", 85 | " 18 Barrel_Temperature_3 1256 non-null float64\n", 86 | " 19 Barrel_Temperature_5 1256 non-null float64\n", 87 | " 20 Cycle_Time 1256 non-null float64\n", 88 | " 21 Mold_Temperature_4 1256 non-null float64\n", 89 | " 22 Average_Screw_RPM 1256 non-null float64\n", 90 | " 23 Max_Screw_RPM 1256 non-null float64\n", 91 | " 24 Max_Switch_Over_Pressure 1256 non-null float64\n", 92 | " 25 Barrel_Temperature_2 1256 non-null float64\n", 93 | " 26 PassOrFail 1256 non-null int64 \n", 94 | "dtypes: float64(23), int64(1), object(3)\n", 95 | "memory usage: 265.1+ KB\n" 96 | ] 97 | } 98 | ], 99 | "source": [ 100 | "rg3.info()" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "id": "d476ba58-0785-4370-b416-c80dfc0cad52", 106 | "metadata": {}, 107 | "source": [ 108 | "# 2. Data Preprocessing" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 4, 114 | "id": "ca4ce13b-11ca-46db-aeba-08de5d94ef80", 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "# Preparation of features for model training\n", 119 | "numerical_features = [x for x in rg3.columns if np.dtype(rg3[x]) == \"float64\"]" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 5, 125 | "id": "7509fb43-d58a-4dda-afec-5c702ff26081", 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "No. of passed RG3 parts: 1224\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "# Data for passed parts\n", 138 | "rg3_Y = rg3[rg3[\"PassOrFail\"] == 0]\n", 139 | "rg3_Y = rg3_Y[numerical_features]\n", 140 | "print(\"No. of passed RG3 parts:\", len(rg3_Y))" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 6, 146 | "id": "0ac9183e-d9b0-4380-a2c7-19126573a000", 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "name": "stdout", 151 | "output_type": "stream", 152 | "text": [ 153 | "No. of failed RG3 parts: 32\n" 154 | ] 155 | } 156 | ], 157 | "source": [ 158 | "# Data for failed parts\n", 159 | "rg3_N = rg3[rg3[\"PassOrFail\"] == 1]\n", 160 | "rg3_N = rg3_N[numerical_features]\n", 161 | "print(\"No. of failed RG3 parts:\", len(rg3_N))" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 7, 167 | "id": "20110606-19d5-4e81-baaa-8eba73ca661a", 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "No. of Train Set (Passed Parts): 1101\n", 175 | "No. of Test Set (Passed Parts): 123\n", 176 | "No. of Test Set (Failed Parts): 32\n" 177 | ] 178 | } 179 | ], 180 | "source": [ 181 | "# The model using Mahalanobis Distance is trained by Data for passed parts (i.e., data with a majority class)\n", 182 | "rg3_train_Y, rg3_test_Y = train_test_split(rg3_Y, test_size=0.1)\n", 183 | "\n", 184 | "# Test set with failed parts\n", 185 | "rg3_test_N = rg3_N\n", 186 | "\n", 187 | "print(f\"No. of Train Set (Passed Parts): {len(rg3_train_Y)}\")\n", 188 | "print(f\"No. of Test Set (Passed Parts): {len(rg3_test_Y)}\")\n", 189 | "print(f\"No. of Test Set (Failed Parts): {len(rg3_test_N)}\")" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 8, 195 | "id": "d2032b24-477d-4a02-87e8-a990aef8fea2", 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [ 199 | "# Data normalization\n", 200 | "\n", 201 | "scaler = StandardScaler()\n", 202 | "\n", 203 | "rg3_train_Y = scaler.fit_transform(rg3_train_Y)\n", 204 | "rg3_test_Y = scaler.transform(rg3_test_Y)\n", 205 | "rg3_test_N = scaler.transform(rg3_test_N)" 206 | ] 207 | }, 208 | { 209 | "cell_type": "markdown", 210 | "id": "0acdf843-6077-4018-b3ea-423452b90e39", 211 | "metadata": {}, 212 | "source": [ 213 | "# 3. Mahalanobis Distance" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 9, 219 | "id": "0ed8a91b-47be-49cc-945f-3c2a8ce09780", 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "def mahalanobis(x=None, data=None, cov=None):\n", 224 | " \"\"\"\n", 225 | " Compute the Mahalanobis Distance between each row of x and the data \n", 226 | " x : vector or matrix of data with, say, p columns.\n", 227 | " data : ndarray of the distribution from which Mahalanobis distance of each observation of x is to be computed.\n", 228 | " cov : covariance matrix (p x p) of the distribution. If None, will be computed from data.\n", 229 | " \"\"\"\n", 230 | " x_minus_mu = x - np.mean(data, axis=0)\n", 231 | " if not cov:\n", 232 | " cov = np.cov(data.T)\n", 233 | " # cov = np.cov(data.values.T)\n", 234 | " inv_covmat = sp.linalg.inv(cov)\n", 235 | " left_term = np.dot(x_minus_mu, inv_covmat)\n", 236 | " mahal = np.dot(left_term, x_minus_mu.T)\n", 237 | " return mahal.diagonal() # Can't understand why .diagonal() is used" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 10, 243 | "id": "cd7152de-3dd5-485c-ad8f-9db5628b3257", 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "class MahalanobisOneclassClassifier():\n", 248 | " def __init__(self, xtrain, significance_level=0.01):\n", 249 | " self.xtrain = xtrain\n", 250 | " self.critical_value = chi2.ppf((1-significance_level), df=xtrain.shape[1] - 1) # df = degree of freedom\n", 251 | " print('Critical value is: ', self.critical_value)\n", 252 | "\n", 253 | " def predict_proba(self, xtest):\n", 254 | " mahalanobis_dist = mahalanobis(xtest, self.xtrain)\n", 255 | " self.pvalues = 1 - chi2.cdf(mahalanobis_dist, 2)\n", 256 | " return mahalanobis_dist\n", 257 | "\n", 258 | " def predict(self, xtest):\n", 259 | " return np.array([int(i) for i in self.predict_proba(xtest) > self.critical_value])" 260 | ] 261 | }, 262 | { 263 | "cell_type": "markdown", 264 | "id": "7a439320-3074-4e43-b4c8-450c1b4fde4a", 265 | "metadata": {}, 266 | "source": [ 267 | "# 4. Setup of Threshold" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 11, 273 | "id": "260c938a-f2fb-4c64-99fb-fbf59d80887f", 274 | "metadata": {}, 275 | "outputs": [ 276 | { 277 | "name": "stdout", 278 | "output_type": "stream", 279 | "text": [ 280 | "Critical value is: 30.813282343953027\n" 281 | ] 282 | } 283 | ], 284 | "source": [ 285 | "clf = MahalanobisOneclassClassifier(rg3_train_Y, significance_level=0.1)" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": 12, 291 | "id": "8ee61460-5e70-46e8-aba0-7527f193dcb7", 292 | "metadata": {}, 293 | "outputs": [], 294 | "source": [ 295 | "threshold = clf.critical_value" 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "id": "6e674593-3220-409c-82bf-08b3f330cf2e", 301 | "metadata": {}, 302 | "source": [ 303 | "# 5. Classification of Test Set by Mahalanobis Distance" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "id": "bcb19903-b68f-4fb5-9169-2f1c2f4bde9e", 309 | "metadata": {}, 310 | "source": [ 311 | "## 5.1. Evaluation Using Test Set (Passed Parts)" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": 13, 317 | "id": "f13a656e-0223-41e7-8c88-a854000bcb48", 318 | "metadata": {}, 319 | "outputs": [], 320 | "source": [ 321 | "# Prediction of Mahalanobis Distance\n", 322 | "rg3_MD_Y = clf.predict_proba(rg3_test_Y)" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": 14, 328 | "id": "5e57b830-3e15-4684-bdb7-ef7d5e1af119", 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "data": { 333 | "image/png": "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l+uXsTH+OVeM8Xxc/GGulKb4L2R/nS/FXWxc/GG+DB061DRt2tQEBASYq6++2gwdOtTs37/ftf9KnisOY4zxzbUcAACA8vGMCgAAsBZBBQAAWIugAgAArEVQAQAA1iKoAAAAaxFUAACAtQgqAADAWgQVAABgLYIK4KGePXtqwoQJVdL3Lbfcotdff71K+paklJQU1a9f/5L7cTgcWr169SX344mNGzfK4XDoxx9/LLONt16fN2q5HHzxxRdq3ry58vPzfV0KUCaCCmCJd999V0ePHtWwYcNc26KiouRwOLRixYoS7WNjY+VwOJSSklKNVdpt6NCh+uqrryp9/PnxdjgcCgwMVFRUlIYMGaINGza4tevevbuys7MVGhp60T5tDjXt2rXTjTfeqOTkZF+XApSJoAJY4vnnn9fIkSNVo4b7X8uIiAgtXbrUbdu2bdt05MgR1a1btzpLtF5gYKCuuuqqS+pj9uzZys7O1r59+/Tqq6+qfv366t27t5566ilXm4CAAIWHh8vhcFxqyT43cuRILVy4UL/88ouvSwFKRVABLtGpU6d0zz33qEGDBgoKClLfvn319ddfu7VZsmSJIiIiFBQUpMGDBys5OdntFsUPP/ygDRs2KD4+vkT/CQkJSk1NVVZWlmvbK6+8ooSEBNWqVcutbXJystq3b6+6desqIiJCDz/8sPLy8kr0+eGHH6pt27YKDg7Wb3/7W2VnZ7v2paen6/bbb1ejRo0UGhqqW2+9Vbt27Sp3DP74xz+qdevWCgoKUqtWrfT444/r3Llzrv0zZ87U9ddfr+XLlysqKkqhoaEaNmyYTp8+7WpTUFCgcePG6aqrrlKdOnV00003KT09vcS50tLSFBcXpzp16ujGG2/U7t27XfuK3/r5/PPPddtttykkJET16tVTp06dtGPHjnJfS0hIiMLDw9WiRQvdcsstevHFF/X444/riSee0L59+ySVvEry7bffKj4+Xg0aNFDdunUVGxurf/7znzp06JBuu+02SVKDBg3kcDh07733SpLWrl2rm266SfXr11dYWJjuvPNOHThwwFXHoUOH5HA49Pbbb+u2225TUFCQOnTooK1bt5YYj549eyooKEgNGjRQnz59dOrUKUlSUVGRkpKS1LJlSwUGBqpDhw76xz/+4Xb87bffrpMnTyo1NbXccQF8haACXKJ7771XO3bs0LvvvqutW7fKGKN+/fq5flGnpaXpwQcf1Pjx45WRkaHbb7/d7X/nkrR582YFBQWpbdu2Jfpv0qSJ+vTpo2XLlkmSzpw5o5UrV2rUqFEl2taoUUPPP/+89uzZo2XLlmnDhg169NFH3dqcOXNGzzzzjJYvX65Nmzbp8OHDmjx5smv/6dOnlZiYqM2bN2vbtm2KiYlRv3793EJFcSEhIUpJSdEXX3yh+fPna8mSJZo3b55bmwMHDmj16tVas2aN1qxZo9TUVM2ZM8e1/9FHH9Vbb72lZcuWadeuXYqOjlafPn108uRJt36mTJmiZ599Vunp6WrcuLHi4+PdQtGFEhIS1Lx5c6Wnp2vnzp2aOnWqateuXebrKMv48eNljNE777xT6v7Ro0eroKBAmzZtUmZmpubOnavg4GBFRETorbfekiTt27dP2dnZmj9/viQpPz9fkyZN0o4dO7R+/XrVqFFDgwcPVlFRkVvf06dP1+TJk5WRkaHWrVtr+PDhrqsfGRkZ6tWrl9q1a6etW7dq8+bNio+PV2FhoSQpKSlJr776qhYtWqQ9e/Zo4sSJ+sMf/uAWSgICAnT99dfrk08+8XhcgGrh2y9vBi4/F37l/FdffWUkmbS0NNf+48ePm8DAQPPGG28YY379evb+/fu79ZGQkGBCQ0Nd6/PmzTOtWrUqca7IyEgzb948s3r1anPNNdeYoqIis2zZMtOxY0djjDGhoaFm6dKlZdb65ptvmrCwMNf60qVLjSS3r4d/4YUXTJMmTcrso7Cw0ISEhJj33nvPtU2SWbVqVZnH/OUvfzGdOnVyrc+YMcMEBQWZ3Nxc17YpU6aYrl27GmOMycvLM7Vr1zZ/+9vfXPvPnj1rmjVrZp5++mljjDEff/yxkWRWrFjhanPixAkTGBhoVq5c6Xp9F45rSEiISUlJKbPO4s6Pd2maNGliHnroIbdaTp06ZYwxpn379mbmzJmlHle8bVl++OEHI8lkZmYaY4w5ePCgkWReeuklV5s9e/YYSWbv3r3GGGOGDx9uevToUWp/P//8swkKCjJbtmxx237fffeZ4cOHu20bPHiwuffee8utD/AVrqgAl2Dv3r2qVauWunbt6toWFhamNm3aaO/evZJ+/Z90ly5d3I4rvv7TTz+pTp06ZZ6nf//+ysvL06ZNm/TKK6+UejVFkj766CP16tVLV199tUJCQjRixAidOHFCZ86ccbUJCgrSNddc41pv2rSpjh075lo/evSoHnjgAcXExCg0NFT16tVTXl6eDh8+XGZ9K1euVI8ePRQeHq7g4GA99thjJdpHRUUpJCSk1PMeOHBA586dU48ePVz7a9eurS5durjG8bxu3bq5fm7YsKHbWBc3adIk3X///erdu7fmzJnjdmvFU8aYMp9JGTdunJ588kn16NFDM2bM0L///e+L9vf1119r+PDhatWqlerVq6eoqChJKjFucXFxrp+bNm0qSa5xO39FpTT79+/XmTNndPvttys4ONi1vPrqqyXGITAw0G2OADYhqAAWaNSokeu5gtLUqlVLI0aM0IwZM/Tpp58qISGhRJtDhw7pzjvvVFxcnN566y3t3LlTL7zwgiTp7NmzrnbFb304HA4ZY1zriYmJysjI0Pz587VlyxZlZGQoLCzMrY8Lbd26VQkJCerXr5/WrFmjzz77TNOnTy/RvrTzFr/N4W0zZ87Unj171L9/f23YsEHt2rXTqlWrPO7nxIkT+uGHH9SyZctS999///365ptvNGLECGVmZqpz585asGBBuX3Gx8fr5MmTWrJkiT799FN9+umnklTuuJ0PSufHLTAwsMz+zz+b9P777ysjI8O1fPHFFyWeUzl58qQaN25cbr2ArxBUgEvQtm1b/fLLL65fMtKvv9T27dundu3aSZLatGlT4qHQ4usdO3bUkSNHyg0ro0aNUmpqqgYOHKgGDRqU2L9z504VFRXp2Wef1Y033qjWrVvr+++/9/g1paWlady4cerXr59iY2PldDp1/PjxMttv2bJFkZGRmj59ujp37qyYmBh9++23Hp3zmmuuUUBAgNLS0lzbzp07p/T0dNc4nrdt2zbXz6dOndJXX31V6rM957Vu3VoTJ07Uv/71L911110l3kFVEfPnz1eNGjU0aNCgMttERETowQcf1Ntvv61HHnlES5YskfTrMyCSXM+NSP9/jjz22GPq1auX2rZtW+6ffVni4uK0fv36Uve1a9dOTqdThw8fVnR0tNsSERHh1nb37t3q2LGjx+cHqkOtizcBUJaYmBgNHDhQDzzwgBYvXqyQkBBNnTpVV199tQYOHChJGjt2rG655RYlJycrPj5eGzZs0AcffOB2G6Fjx45q1KiR0tLSdOedd5Z6rrZt2+r48eMKCgoqdX90dLTOnTunBQsWKD4+XmlpaVq0aFGlXtPy5cvVuXNn5ebmasqUKeX+zz0mJkaHDx/WihUr9Jvf/Ebvv/++x1ct6tatq4ceekhTpkxRw4YN1aJFCz399NM6c+aM7rvvPre2s2fPVlhYmJo0aaLp06erUaNGpQaIn376SVOmTNF///d/q2XLlvruu++Unp6u3/3ud+XWcvr0aR05ckTnzp3TwYMH9dprr+mll15SUlKSoqOjSz1mwoQJ6tu3r1q3bq1Tp07p448/doWnyMhIORwOrVmzRv369VNgYKAaNGigsLAwvfjii2ratKkOHz6sqVOnejRmkjRt2jS1b99eDz/8sB588EEFBATo448/1u9//3s1atRIkydP1sSJE1VUVKSbbrpJOTk5SktLU7169ZSYmCjp1ytx//nPf9S7d2+Pzw9UC18/JANcbi58mNYYY06ePGlGjBhhQkNDTWBgoOnTp4/56quv3I558cUXzdVXX20CAwPNoEGDzJNPPmnCw8Pd2jz66KNm2LBhbtvKe7jTmJIP0yYnJ5umTZu66nj11VfdHuQs/rCpMcasWrXKXPhPwa5du0znzp1NnTp1TExMjHnzzTdL1KFiD9NOmTLFhIWFmeDgYDN06FAzb948t/PMmDHDdOjQwe288+bNM5GRka71n376yYwdO9Y0atTIOJ1O06NHD7N9+3bX/vMPpb733nsmNjbWBAQEmC5dupjPP//c1ebC11dQUGCGDRtmIiIiTEBAgGnWrJkZM2aM+emnn8ocz8jISCPJSDIBAQGmRYsWZsiQIWbDhg1u7Yo/IDtmzBhzzTXXGKfTaRo3bmxGjBhhjh8/7mo/e/ZsEx4ebhwOh0lMTDTGGLNu3TrTtm1b43Q6TVxcnNm4caPbuJ5/mPazzz5z9XPq1CkjyXz88ceubRs3bjTdu3c3TqfT1K9f3/Tp08dVV1FRkXnuuedMmzZtTO3atU3jxo1Nnz59TGpqquv4P//5z6ZPnz5ljgngaw5jLrg5DaBaPPDAA/ryyy/d3hJ65MgRxcbGateuXYqMjPRhdfAXZ8+eVUxMjF5//XW3B5kBm/CMClANnnnmGX3++efav3+/FixYoGXLlrkuvZ8XHh6ul19+udx31wDedPjwYf3f//0fIQVW44oKUA2GDBmijRs36vTp02rVqpXGjh2rBx980NdlAYD1CCoAAMBa3PoBAADWIqgAAABrEVQAAIC1CCoAAMBaBBUAAGAtggoAALAWQQUAAFiLoAIAAKz1/wBWaKPoq5TqYwAAAABJRU5ErkJggg==", 334 | "text/plain": [ 335 | "
" 336 | ] 337 | }, 338 | "metadata": {}, 339 | "output_type": "display_data" 340 | } 341 | ], 342 | "source": [ 343 | "# Data Visualization \n", 344 | "# Log was used for better visualization\n", 345 | "\n", 346 | "plt.hist(np.log(rg3_MD_Y), bins=200)\n", 347 | "plt.xlabel(\"log(Mahalanobis Distance)\")\n", 348 | "plt.ylabel(\"No of samples\")\n", 349 | "plt.vlines(np.log(threshold), 0, 5, color=\"red\")\n", 350 | "plt.show();" 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 15, 356 | "id": "1bbc188b-403f-4751-a161-ed63f8abc49f", 357 | "metadata": {}, 358 | "outputs": [ 359 | { 360 | "name": "stdout", 361 | "output_type": "stream", 362 | "text": [ 363 | "No. of Failed Parts: 19\n", 364 | "Accuracy: 0.8455284552845529\n" 365 | ] 366 | } 367 | ], 368 | "source": [ 369 | "# Check on the data that were predicted as failed parts\n", 370 | "\n", 371 | "rg3_test_Y_anomalies = rg3_MD_Y > threshold\n", 372 | "print(\"No. of Failed Parts:\", np.sum(rg3_test_Y_anomalies))\n", 373 | "print(\"Accuracy:\", (rg3_test_Y.shape[0]-np.sum(rg3_test_Y_anomalies))/rg3_test_Y.shape[0])" 374 | ] 375 | }, 376 | { 377 | "cell_type": "markdown", 378 | "id": "055407b1-4ea7-40c4-abca-00580ba44869", 379 | "metadata": {}, 380 | "source": [ 381 | "## 5.2. Evaluation Using Test Set (Failed Parts)" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": 16, 387 | "id": "2dd8090b-ff11-4c2e-a7df-d23c4a1af6d3", 388 | "metadata": {}, 389 | "outputs": [], 390 | "source": [ 391 | "# Prediction of Mahalanobis Distance\n", 392 | "rg3_MD_N = clf.predict_proba(rg3_test_N)" 393 | ] 394 | }, 395 | { 396 | "cell_type": "code", 397 | "execution_count": 17, 398 | "id": "81d6064b-f17e-43cf-a8fc-bbc96900e8af", 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "image/png": "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l5dp6+PjIx8fH6f7AAAAtZPTZ1See+45PfTQQ9q/f7992/79+zVjxgwtWrTomgsqLS11uA8FAAB4LqfPqEyaNElnz55V3759Vbfury//5ZdfVLduXU2ZMkVTpkyxt/3xxx+veKy4uDgNGzZMbdq00ZkzZ/TWW29p+/bt+vDDD50tCwAAXIecDipLlixxWed5eXmaOHGicnNz1ahRI4WHh+vDDz/Ub3/7W5f1AQAAai+ng0pMTIzLOn/99ddddiwAAHD9qfID3/Ly8pSXl6fS0lKH7eHh4ddcFAAAgFSFoHLgwAHFxMQoKytLlmU57LPZbCopKXFZcQAAwLM5HVSmTJmizp076/XXX1erVq0q/a3KAAAAznI6qHzzzTd699137c8+AQAAqC5OP0dl0KBBOnz4cHXUAgAA4MDpMyqvvfaaYmJilJmZqR49eqhevXoO+0eOHOmy4gAAgGdzOqjs3r1bO3fu1JYtW8rs42ZaAADgSk5f+nnooYd03333KTc3V6WlpQ4LIQUAALiS00Hl9OnTevjhh9WqVavqqAcAAMDO6aBy99136+OPP66OWgAAABw4fY9K586dFRcXp08//VRhYWFlbqadPn26y4oDAACerUqf+vH391daWprS0tIc9tlsNoIKAABwGaeDyrFjx6qjDgAAgDKcvkcFAACgplTp25NPnDih9957T8ePH9f58+cd9i1evNglhQEAADgdVFJTUzVy5Eh16NBBX375pXr06KHs7GxZlqWIiIjqqBEAAHgopy/9xMXFac6cOcrIyJCvr6/effdd5eTkaMCAAfr9739fHTUCAAAP5XRQycrK0sSJEyVJdevW1c8//yx/f3899dRTWrhwocsLBAAAnsvpoNKgQQP7fSlBQUE6evSofd8PP/zgusoAAIDHc/oelVtuuUWffvqpunXrpuHDh2v27NnKyMjQ+vXrdcstt1RHjQAAwEM5HVQWL16swsJCSVJ8fLwKCwu1Zs0aderUiU/8AAAAl3I6qHTo0MH+c4MGDfTyyy+7tCAAAICLnL5HJScnRydOnLCv7927VzNnztQrr7zi0sIAAACcDirjx4+3f3vyyZMnNXjwYO3du1ePPvqonnrqKZcXCAAAPJfTQSUzM1M333yzJGnt2rUKCwvTrl279OabbyopKcnV9QEAAA/mdFC5cOGCfHx8JEnbtm3TyJEjJUldu3ZVbm6ua6sDAAAezemgEhoaqpdfflmffPKJUlJSNHToUEnSd999p2bNmrm8QAAA4LmcDioLFy7U8uXLNXDgQEVHR6tnz56SpPfee89+SQgAAMAVnP548sCBA/XDDz+ooKBATZo0sW//05/+pPr167u0OAAA4NmcDiqS5OXl5RBSJKldu3auqAcAAMDO6Us/AAAANYWgAgAAjEVQAQAAxqpUUGnatKl++OEHSdKUKVN05syZai0KAABAqmRQOX/+vAoKCiRJq1at0rlz56q1KAAAAKmSn/qJjIzU6NGj1bt3b1mWpenTp8vPz6/ctitWrHBpgQAAwHNVKqi88cYbeuGFF3T06FHZbDbl5+dzVgUAAFS7SgWVVq1aacGCBZKk9u3ba/Xq1TwuHwAAVDunH/h27Nix6qgDAACgjCp9PDktLU1RUVHq2LGjOnbsqJEjR+qTTz5xdW0AAMDDOR1U3njjDQ0ePFj169fX9OnT7TfWDho0SG+99VZ11AgAADyU05d+nn76aT377LN6+OGH7dumT5+uxYsXa/78+Ro/frxLCwQAAJ7L6TMq33zzjaKiospsHzlyJPevAAAAl3I6qISEhCg1NbXM9m3btikkJMQlRQEAAEhVuPQze/ZsTZ8+Xenp6erXr58kaefOnUpKStLSpUtdXiAAAPBcTgeVqVOnKjAwUM8//7zWrl0rSerWrZvWrFmjUaNGubxAAADguZwOKpI0ZswYjRkzxtW1AAAAOKjSc1QAAABqAkEFAAAYi6ACAACMRVABAADGuqagYlmWLMtyVS0AAAAOqhRU/vGPfygsLEx+fn7y8/NTeHi4Vq9e7eraAACAh3P648mLFy/W448/rmnTpql///6SpE8//VQPPvigfvjhB4fvAAIAALgWTgeVZcuWKTExURMnTrRvGzlypEJDQ/Xkk08SVAAAgMs4feknNzfX/uj8S/Xr10+5ubkuKQoAAECqQlDp2LGj/dH5l1qzZo06derkkqIAAACkKlz6iY+P17hx47Rjxw77PSo7d+5UampquQEGAACgqpw+o3LPPffos88+U/PmzbVx40Zt3LhRzZs31969e/n+HwAA4FJV+lLC3r1764033rjmzhMSErR+/Xp9+eWX8vPzU79+/bRw4UJ16dLlmo8NAABqP7c+mTYtLU2xsbHas2ePUlJSdOHCBd15550q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QA2bNGmSbDabHnzwwTL7YmNjZbPZNGnSpJovzFAhISHKzc1Vjx49qvT6i+Nts9lUr149tWrVSr/97W+1YsUKlZaWOrTNzc3VsGHDKnVcQg1QMwgqgBuEhIQoOTlZP//8s33buXPn9NZbb6lNmzZurMw8Xl5eCgwMVN26dat8jKFDhyo3N1fZ2dnasmWLbr/9ds2YMUN33XWXfvnlF3u7wMBA+fj4uKJsAC5CUAHcICIiQiEhIVq/fr192/r169WmTRv16tXLoe3WrVt16623qnHjxmrWrJnuuusuHT16tMwxv/nmG91+++2qX7++evbsqd27d9v3nT59WtHR0brhhhtUv359hYWF6e23375ijatXr1afPn0UEBCgwMBAjR8/Xnl5efb927dvl81mU2pqqvr06aP69eurX79+OnLkiMNxEhMT9V//9V/y9vZWly5dtHr16jJ9XTyT4efnpw4dOuidd96x77v80s9//vMfTZgwQS1atJCfn586deqklStXXvG9+Pj4KDAwUDfccIMiIiL0P//zP9q0aZO2bNmipKQke7tLz5KcP39e06ZNU1BQkHx9fdW2bVslJCRIktq1aydJGjNmjGw2m3396NGjGjVqlFq1aiV/f3/ddNNN2rZtm0Mt7dq10zPPPKMpU6YoICBAbdq00SuvvOLQ5sSJE4qOjlbTpk3VoEED9enTR5999pl9/6ZNmxQRESFfX1916NBB8fHxDoELuJ4QVAA3mTJlisMv2BUrVmjy5Mll2hUVFWnWrFnav3+/UlNTVadOHY0ZM6bMZYtHH31Uc+bMUXp6ujp37qzo6Gj7L69z586pd+/eev/995WZmak//elP+sMf/qC9e/dWWN+FCxc0f/58HT58WBs3blR2dna5l6QeffRRPf/889q/f7/q1q2rKVOm2Pdt2LBBM2bM0OzZs5WZmak///nPmjx5sj7++GOHYzz++OO65557dPjwYU2YMEH33nuvsrKyyq3r8ccf1xdffKEtW7YoKytLiYmJat68eYXvoyJ33HGHevbs6RAWL/Xiiy/qvffe09q1a3XkyBG9+eab9kCyb98+SdLKlSuVm5trXy8sLNTw4cOVmpqqQ4cOaejQoYqKitLx48cdjv3888+rT58+OnTokP7yl79o6tSp9oBXWFioAQMG6N///rfee+89HT58WH/961/t/96ffPKJJk6cqBkzZuiLL77Q8uXLlZSUpKefftrpMQBqBXd/fTPgaWJiYqxRo0ZZeXl5lo+Pj5WdnW1lZ2dbvr6+1vfff2+NGjWqzFe6X+r777+3JFkZGRmWZVnWsWPHLEnWa6+9Zm/z+eefW5KsrKysCo8zYsQIa/bs2fb1AQMGWDNmzKiw/b59+yxJ1pkzZyzLsqyPP/7YkmRt27bN3ub999+3JFk///yzZVmW1a9fP+uBBx5wOM7vf/97a/jw4fZ1SdaDDz7o0KZv377W1KlTHd7foUOHLMuyrKioKGvy5MkV1nm5i+NdnnHjxlndunVzqGXDhg2WZVnWQw89ZN1xxx1WaWlpua+9tO2VhIaGWsuWLbOvt23b1rrvvvvs66WlpVbLli2txMREy7Isa/ny5VZAQIB1+vTpco83aNAg65lnnnHYtnr1aisoKOiqtQC1EWdUADdp0aKFRowYoaSkJK1cuVIjRowo98zAV199pejoaHXo0EENGza0/1V/+V/p4eHh9p+DgoIkyX6ppqSkRPPnz1dYWJiaNm0qf39/ffjhh2WOcakDBw4oKipKbdq0UUBAgAYMGOB0v1lZWerfv79D+/79+5c5WxIZGVlmvaIzKlOnTlVycrJuvPFG/fWvf9WuXbsqfA9XY1mWbDZbufsmTZqk9PR0denSRdOnT9dHH3101eMVFhZqzpw56tatmxo3bix/f39lZWVdccxsNpsCAwPtY5aenq5evXqpadOm5fZx+PBhPfXUU/L397cvDzzwgHJzc3X27NnKvnWg1qj63WkArtmUKVM0bdo0SdJLL71UbpuoqCi1bdtWr776qoKDg1VaWqoePXro/PnzDu3q1atn//niL9+Llwuee+45LV26VEuWLFFYWJgaNGigmTNnljnGRUVFRRoyZIiGDBmiN998Uy1atNDx48c1ZMgQp/qtDsOGDdO3336rDz74QCkpKRo0aJBiY2O1aNEip4+VlZWl9u3bl7svIiJCx44d05YtW7Rt2zaNHTtWgwcPdrh/5nJz5sxRSkqKFi1apI4dO8rPz0+/+93vrjhm0q/jdnHM/Pz8rlhzYWGh4uPjdffdd5fZ5+vre8XXArURZ1QANxo6dKjOnz+vCxcuaMiQIWX2nz59WkeOHNFjjz2mQYMGqVu3bvrPf/7jdD87d+7UqFGjdN9996lnz57q0KGD/u///q/C9l9++aVOnz6tBQsW6LbbblPXrl0dbqStrG7dumnnzp1launevbvDtj179pRZ79atW4XHbdGihWJiYvTGG29oyZIlZW5GrYx//etfysjI0D333FNhm4YNG2rcuHF69dVXtWbNGr377rv68ccfJf0aNkpKShza79y5U5MmTdKYMWMUFhamwMBAZWdnO1VXeHi40tPT7f1cLiIiQkeOHFHHjh3LLHXq8L90XH84owK4kZeXl/0Sh5eXV5n9TZo0UbNmzfTKK68oKChIx48f19y5c53up1OnTnrnnXe0a9cuNWnSRIsXL9apU6fKBIaL2rRpI29vby1btkwPPvigMjMzNX/+fKf7feSRRzR27Fj16tVLgwcP1j//+U+tX7++zCdh1q1bpz59+ujWW2/Vm2++qb179+r1118v95hPPPGEevfurdDQUBUXF2vz5s1XDDWSVFxcrJMnT6qkpESnTp3S1q1blZCQoLvuuksTJ04s9zWLFy9WUFCQevXqpTp16mjdunUKDAxU48aNJf366Z3U1FT1799fPj4+atKkiTp16qT169crKipKNptNjz/+uNNnl6Kjo/XMM89o9OjRSkhIUFBQkA4dOqTg4GBFRkbqiSee0F133aU2bdrod7/7nerUqaPDhw8rMzNTf/vb35zqC6gNiN+AmzVs2FANGzYsd1+dOnWUnJysAwcOqEePHnr44Yf13HPPOd3HY489poiICA0ZMkQDBw5UYGCgRo8eXWH7Fi1aKCkpSevWrVP37t21YMGCKl1aGT16tJYuXapFixYpNDRUy5cv18qVKzVw4ECHdvHx8UpOTlZ4eLj+8Y9/6O23364wRHl7eysuLk7h4eH6zW9+Iy8vLyUnJ1+xjq1btyooKEjt2rXT0KFD9fHHH+vFF1/Upk2byg2IkhQQEKBnn31Wffr00U033aTs7Gx98MEH9rMWzz//vFJSUhQSEmL/SPnixYvVpEkT9evXT1FRURoyZIgiIiKcGjNvb2999NFHatmypYYPH66wsDAtWLDAXueQIUO0efNmffTRR7rpppt0yy236IUXXlDbtm2d6geoLWyWZVnuLgIAAKA8nFEBAADGIqgAAABjEVQAAICxCCoAAMBYBBUAAGAsggoAADAWQQUAABiLoAIAAIxFUAEAAMYiqAAAAGMRVAAAgLH+HxGXoagJ/O3HAAAAAElFTkSuQmCC", 404 | "text/plain": [ 405 | "
" 406 | ] 407 | }, 408 | "metadata": {}, 409 | "output_type": "display_data" 410 | } 411 | ], 412 | "source": [ 413 | "# Data visualization \n", 414 | "# Log was used for better visualization\n", 415 | "\n", 416 | "plt.hist(np.log(rg3_MD_N), bins=50)\n", 417 | "plt.xlabel(\"Mahalanobis Distance\")\n", 418 | "plt.ylabel(\"No of samples\")\n", 419 | "plt.vlines(np.log(threshold), 0, 5, color=\"red\")\n", 420 | "plt.show();" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 18, 426 | "id": "695fe8ac-cdda-4b8b-b41a-649f41993637", 427 | "metadata": {}, 428 | "outputs": [ 429 | { 430 | "name": "stdout", 431 | "output_type": "stream", 432 | "text": [ 433 | "No. of Failed Parts: 8\n", 434 | "Accuracy: 0.25\n" 435 | ] 436 | } 437 | ], 438 | "source": [ 439 | "# Check on the data that were predicted as failed parts\n", 440 | "\n", 441 | "rg3_test_N_anomalies = rg3_MD_N > threshold\n", 442 | "print(\"No. of Failed Parts:\", np.sum(rg3_test_N_anomalies))\n", 443 | "print(\"Accuracy:\", np.sum(rg3_test_N_anomalies)/rg3_test_N.shape[0])" 444 | ] 445 | }, 446 | { 447 | "cell_type": "markdown", 448 | "id": "d950e685-039b-415c-95e4-cccf396de964", 449 | "metadata": {}, 450 | "source": [ 451 | "# 6. Result Analysis" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": 19, 457 | "id": "9068d6e4-eda8-464f-8f6d-ff38bd2cad87", 458 | "metadata": {}, 459 | "outputs": [], 460 | "source": [ 461 | "# True values for the test set\n", 462 | "\n", 463 | "rg3_true = np.concatenate(\n", 464 | " [np.zeros(len(rg3_test_Y_anomalies)), np.ones(len(rg3_test_N_anomalies))]\n", 465 | ")" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": 20, 471 | "id": "0130a09a-8455-4d42-884b-ae31fbb4e326", 472 | "metadata": {}, 473 | "outputs": [], 474 | "source": [ 475 | "# Predicted values for the test set\n", 476 | "\n", 477 | "rg3_prediction = np.concatenate(\n", 478 | " [rg3_test_Y_anomalies, rg3_test_N_anomalies]\n", 479 | ")" 480 | ] 481 | }, 482 | { 483 | "cell_type": "code", 484 | "execution_count": 21, 485 | "id": "09bf7653-cf80-414b-936c-16282d427e8a", 486 | "metadata": {}, 487 | "outputs": [ 488 | { 489 | "data": { 490 | "text/plain": [ 491 | "array([[104, 19],\n", 492 | " [ 24, 8]], dtype=int64)" 493 | ] 494 | }, 495 | "execution_count": 21, 496 | "metadata": {}, 497 | "output_type": "execute_result" 498 | } 499 | ], 500 | "source": [ 501 | "confusion_matrix(rg3_true, rg3_prediction)" 502 | ] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "execution_count": 22, 507 | "id": "cff3821f-1959-42d7-96d1-2b7c4d727726", 508 | "metadata": {}, 509 | "outputs": [ 510 | { 511 | "data": { 512 | "image/png": "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", 513 | "text/plain": [ 514 | "
" 515 | ] 516 | }, 517 | "metadata": {}, 518 | "output_type": "display_data" 519 | } 520 | ], 521 | "source": [ 522 | "target_names = [\"Pass\", \"Fail\"]\n", 523 | "clf_report = classification_report(\n", 524 | " rg3_true, rg3_prediction, target_names=target_names, output_dict=True\n", 525 | ")\n", 526 | "clf_plot = sns.heatmap(pd.DataFrame(clf_report).iloc[:-1, :].T, annot=True)\n", 527 | "plt.title('Classification Report for Mahalanobis Distance on RG3')\n", 528 | "clf_plot.figure.savefig(\"../img/clf_report_rg3_MD.png\")" 529 | ] 530 | }, 531 | { 532 | "cell_type": "markdown", 533 | "id": "5946b2a7-fb65-4f04-b33d-dbee8550b438", 534 | "metadata": {}, 535 | "source": [ 536 | "- While it was impossible to classify the failed parts using machine learning models, the model using Mahalanobis Distance could classify the passed and failed parts for `RG3` parts.\n", 537 | "- However, the f1 score for `RG3` was much lower that that for `CN7`" 538 | ] 539 | }, 540 | { 541 | "cell_type": "code", 542 | "execution_count": null, 543 | "id": "c093eb72-959e-453e-91d8-d525a6ede8fe", 544 | "metadata": {}, 545 | "outputs": [], 546 | "source": [] 547 | } 548 | ], 549 | "metadata": { 550 | "kernelspec": { 551 | "display_name": "Python [conda env:inj_env]", 552 | "language": "python", 553 | "name": "conda-env-inj_env-py" 554 | }, 555 | "language_info": { 556 | "codemirror_mode": { 557 | "name": "ipython", 558 | "version": 3 559 | }, 560 | "file_extension": ".py", 561 | "mimetype": "text/x-python", 562 | "name": "python", 563 | "nbconvert_exporter": "python", 564 | "pygments_lexer": "ipython3", 565 | "version": "3.10.8" 566 | } 567 | }, 568 | "nbformat": 4, 569 | "nbformat_minor": 5 570 | } 571 | -------------------------------------------------------------------------------- /src/utils.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from sklearn.model_selection import cross_validate 3 | import matplotlib.pyplot as plt 4 | from sklearn.metrics import roc_curve 5 | 6 | 7 | def mean_std_cross_val_scores(model, X_train, y_train, **kwargs): 8 | """ 9 | Returns mean and std of cross validation 10 | 11 | Parameters 12 | ---------- 13 | model : 14 | scikit-learn model 15 | X_train : numpy array or pandas DataFrame 16 | X in the training data 17 | y_train : 18 | y in the training data 19 | 20 | Returns 21 | ---------- 22 | pandas Series with mean scores from cross_validation 23 | """ 24 | 25 | scores = cross_validate(model, X_train, y_train, **kwargs) 26 | 27 | mean_scores = pd.DataFrame(scores).mean() 28 | std_scores = pd.DataFrame(scores).std() 29 | out_col = [] 30 | 31 | for i in range(len(mean_scores)): 32 | out_col.append((f"%0.3f (+/- %0.3f)" % (mean_scores[i], std_scores[i]))) 33 | 34 | return pd.Series(data=out_col, index=mean_scores.index) 35 | 36 | 37 | def plot_roc_curve(true_y, y_prob): 38 | """ 39 | plots the roc curve based of the probabilities 40 | """ 41 | plt.figure(figsize=(3, 2.5)) 42 | fpr, tpr, thresholds = roc_curve(true_y, y_prob) 43 | plt.plot(fpr, tpr) 44 | plt.xlabel('False Positive Rate') 45 | plt.ylabel('True Positive Rate') 46 | plt.show(); --------------------------------------------------------------------------------