{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<div class=\"alert alert-info\">\n<b> Learning Objective:</b>\n    \n 1. Try both techniques like knn and CNN for digit recognition task\n 2. With knn try different dimentionality reduction (truncated SVD : linear , t-SNE: non-linear)\n 3. Explore using Conv2D layers in CNN\n</div>","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-01T07:44:18.041633Z","iopub.execute_input":"2022-05-01T07:44:18.042001Z","iopub.status.idle":"2022-05-01T07:44:18.049388Z","shell.execute_reply.started":"2022-05-01T07:44:18.041962Z","shell.execute_reply":"2022-05-01T07:44:18.048095Z"}}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport joblib","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:40:58.233858Z","iopub.execute_input":"2022-05-01T19:40:58.23412Z","iopub.status.idle":"2022-05-01T19:40:58.238777Z","shell.execute_reply.started":"2022-05-01T19:40:58.234092Z","shell.execute_reply":"2022-05-01T19:40:58.23768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data=pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\ntrain_data.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:41:00.325488Z","iopub.execute_input":"2022-05-01T19:41:00.325891Z","iopub.status.idle":"2022-05-01T19:41:03.314421Z","shell.execute_reply.started":"2022-05-01T19:41:00.325859Z","shell.execute_reply":"2022-05-01T19:41:03.313709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Visualising the data\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport itertools as itr\n\ndata=[train_data[train_data.label==x] for x in np.sort(train_data.label.unique())]\n\nfig,axes=plt.subplots(10,10,figsize=(10,10))\n\nfor pos in list(itr.product(range(0,10), repeat=2)):    \n    axes[pos].imshow(data[pos[0]].iloc[pos[1],:].values[1:].reshape(28,28), cmap='gray');\n    axes[pos].axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:41:06.256167Z","iopub.execute_input":"2022-05-01T19:41:06.256433Z","iopub.status.idle":"2022-05-01T19:41:10.0144Z","shell.execute_reply.started":"2022-05-01T19:41:06.256404Z","shell.execute_reply":"2022-05-01T19:41:10.013656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Checking class balance: looks balanced as expected\nsns.barplot(data=train_data.label.value_counts().sort_index().to_frame().reset_index(), x=\"index\", y=\"label\");","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:59:10.53257Z","iopub.execute_input":"2022-05-01T19:59:10.532865Z","iopub.status.idle":"2022-05-01T19:59:10.766381Z","shell.execute_reply.started":"2022-05-01T19:59:10.532832Z","shell.execute_reply":"2022-05-01T19:59:10.765668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Trail with truncated SVD and kNN","metadata":{}},{"cell_type":"code","source":"from sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.model_selection import train_test_split, GridSearchCV\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nfrom sklearn.decomposition import TruncatedSVD\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.pipeline import Pipeline\n\npreprocess=Pipeline(\n    [\n        (\"scale\", MinMaxScaler()),\n        (\"tSVD\", TruncatedSVD(n_components=2, random_state=0))\n    ]\n)\nmodel_knn_tSVD= Pipeline(\n    [\n        (\"preprocess\", preprocess),\n        (\"knn\", KNeighborsClassifier(n_neighbors=3))\n    \n    ]\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:21:12.008077Z","iopub.execute_input":"2022-05-01T20:21:12.008373Z","iopub.status.idle":"2022-05-01T20:21:12.014897Z","shell.execute_reply.started":"2022-05-01T20:21:12.008343Z","shell.execute_reply":"2022-05-01T20:21:12.014165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train=train_data.iloc[:, 1:]\ny_train=train_data.loc[:,\"label\"]\n","metadata":{"execution":{"iopub.status.busy":"2022-05-01T07:30:45.983777Z","iopub.execute_input":"2022-05-01T07:30:45.984317Z","iopub.status.idle":"2022-05-01T07:30:48.874949Z","shell.execute_reply.started":"2022-05-01T07:30:45.984278Z","shell.execute_reply":"2022-05-01T07:30:48.874342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"params={\"preprocess__tSVD__n_components\":[5,8,10],\n       \"knn__n_neighbors\":[3,6,9]}\n\nopt_model_knn_tSVD=GridSearchCV(model_knn_tSVD, param_grid=params, cv=5, n_jobs=-1)\nopt_model_knn_tSVD.fit(X_train, y_train)\nopt_result=pd.DataFrame(opt_model_knn_tSVD.cv_results_)\nopt_result","metadata":{"execution":{"iopub.status.busy":"2022-05-01T07:30:48.876332Z","iopub.execute_input":"2022-05-01T07:30:48.876759Z","iopub.status.idle":"2022-05-01T07:31:54.85555Z","shell.execute_reply.started":"2022-05-01T07:30:48.876726Z","shell.execute_reply":"2022-05-01T07:31:54.854572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data=pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\nresult=opt_model_knn_tSVD.predict(test_data)\nresult_df=pd.DataFrame({\"ImageId\":range(1,len(result)+1), \"Label\":result})\nresult_df.to_csv(\"/kaggle/working/submission-knn-tsvd.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T07:31:54.857163Z","iopub.execute_input":"2022-05-01T07:31:54.857496Z","iopub.status.idle":"2022-05-01T07:32:02.88488Z","shell.execute_reply.started":"2022-05-01T07:31:54.857459Z","shell.execute_reply":"2022-05-01T07:32:02.883776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train with knn and t-SNE","metadata":{}},{"cell_type":"code","source":"from sklearn.manifold import TSNE\n\npreprocess2=Pipeline(\n    [\n        (\"scale\", MinMaxScaler()),\n        (\"TSNE\", TSNE(n_components=2, random_state=0))\n    ]\n)\nmodel_knn_TSNE= Pipeline(\n    [\n        #(\"preprocess2\", preprocess2),\n        (\"knn\", KNeighborsClassifier(n_neighbors=3))\n    \n    ]\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:24:47.423998Z","iopub.execute_input":"2022-05-01T20:24:47.424267Z","iopub.status.idle":"2022-05-01T20:24:47.429377Z","shell.execute_reply.started":"2022-05-01T20:24:47.424238Z","shell.execute_reply":"2022-05-01T20:24:47.428652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#tSNE is computationally expensive, will train with reduced data since aim to only understand the method\nX_train=pd.DataFrame()\nfor x in np.sort(train_data.label.unique()):\n    X_train=pd.concat([X_train, train_data[train_data.label==x].iloc[0:500,:]],axis=0) \n\ny_train=X_train.pop(\"label\")","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:42:12.751476Z","iopub.execute_input":"2022-05-01T20:42:12.751725Z","iopub.status.idle":"2022-05-01T20:42:13.053479Z","shell.execute_reply.started":"2022-05-01T20:42:12.751697Z","shell.execute_reply":"2022-05-01T20:42:13.052731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_trans=preprocess2.fit_transform(X_train)\nplot_trans=np.vstack((plot_trans.T, y_train.values)).T\nplot_trans_df=pd.DataFrame(plot_trans, columns=[\"comp1\", \"comp2\", \"label\"])","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:42:20.928523Z","iopub.execute_input":"2022-05-01T20:42:20.928882Z","iopub.status.idle":"2022-05-01T20:43:01.246234Z","shell.execute_reply.started":"2022-05-01T20:42:20.928838Z","shell.execute_reply":"2022-05-01T20:43:01.245654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.scatterplot(data=plot_trans_df, x=\"comp1\", y=\"comp2\", hue=\"label\");\nplt.title(\"TSNE embedding plot\")","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:43:12.56114Z","iopub.execute_input":"2022-05-01T20:43:12.561801Z","iopub.status.idle":"2022-05-01T20:43:13.660347Z","shell.execute_reply.started":"2022-05-01T20:43:12.561752Z","shell.execute_reply":"2022-05-01T20:43:13.659658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"params={\"knn__n_neighbors\":[3,5,7]}\n\nopt_model_knn_TSNE=GridSearchCV(model_knn_TSNE, param_grid=params, cv=5, n_jobs=-1)\nX_train_df=plot_trans_df.loc[:, plot_trans_df.columns!=\"label\"]\nopt_model_knn_TSNE.fit(X_train_df, y_train)\nopt_result_TSNE=pd.DataFrame(opt_model_knn_TSNE.cv_results_)\nopt_result_TSNE","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:44:14.185354Z","iopub.execute_input":"2022-05-01T20:44:14.185612Z","iopub.status.idle":"2022-05-01T20:44:16.084606Z","shell.execute_reply.started":"2022-05-01T20:44:14.185582Z","shell.execute_reply":"2022-05-01T20:44:16.083698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"__Prediction on Test Data__\n\n```\ntest_data=pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\ntest_data=pd.DataFrame(preprocess2.fit_transform(test_data),columns=[\"comp1\", \"comp2\"])\nresult_TSNE=opt_model_knn_TSNE.predict(test_data)\nresult_TSNE_df=pd.DataFrame({\"ImageId\":range(1,len(result_TSNE)+1), \"Label\":result_TSNE})\nresult_TSNE_df.to_csv(\"/kaggle/working/submission-knn-tsne.csv\", index=False)\n```","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:46:15.221498Z","iopub.execute_input":"2022-05-01T20:46:15.221768Z","iopub.status.idle":"2022-05-01T20:47:00.906614Z","shell.execute_reply.started":"2022-05-01T20:46:15.221736Z","shell.execute_reply":"2022-05-01T20:47:00.904481Z"}}},{"cell_type":"markdown","source":"# Trial with CNN using TF\n\n> Ideas regarding building layers adopted from NB: https://www.kaggle.com/code/chingiznurzhanov/digits-keras-cnn-acc-0-99564\n","metadata":{}},{"cell_type":"code","source":"from tensorflow import keras\nimport tensorflow as tf\nfrom keras import layers\nfrom sklearn.model_selection import  train_test_split","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:30:11.000382Z","iopub.execute_input":"2022-05-01T19:30:11.001121Z","iopub.status.idle":"2022-05-01T19:30:11.007717Z","shell.execute_reply.started":"2022-05-01T19:30:11.001085Z","shell.execute_reply":"2022-05-01T19:30:11.006742Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train=train_data.copy()\ny_train=X_train.pop(\"label\")\n\nX_train=X_train.values.reshape(-1,28,28,1)\ny_train=y_train.values\n\ny_train= keras.utils.to_categorical(y_train, num_classes = 10,dtype='uint8')\n\nX_train,X_val, y_train, y_val=train_test_split(X_train, y_train, \n                                               test_size=0.15, \n                                               random_state=42,\n                                               stratify=y_train\n                                              ) # ensure stratified split\nprint(X_train.shape, y_train.shape)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:33:12.440332Z","iopub.execute_input":"2022-05-01T19:33:12.4406Z","iopub.status.idle":"2022-05-01T19:33:13.71506Z","shell.execute_reply.started":"2022-05-01T19:33:12.44057Z","shell.execute_reply":"2022-05-01T19:33:13.714241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf_image_gen=keras.preprocessing.image.ImageDataGenerator()\ntf_image_gen.fit(X_train)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:33:24.373539Z","iopub.execute_input":"2022-05-01T19:33:24.373844Z","iopub.status.idle":"2022-05-01T19:33:24.471706Z","shell.execute_reply.started":"2022-05-01T19:33:24.373807Z","shell.execute_reply":"2022-05-01T19:33:24.470859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model=keras.Sequential([\n    \n    layers.BatchNormalization(input_shape=(28,28,1)), # Normalise values \n    layers.Conv2D(filters=16, kernel_size=(5,5), padding=\"Same\",\n                  activation='relu'),\n    layers.BatchNormalization(),\n        layers.Conv2D(filters=16, kernel_size=(5,5), padding=\"Same\",\n                  activation='relu'),\n    layers.BatchNormalization(),\n    \n    # (28*28-->14*14 after max pooling)\n    \n    layers.MaxPool2D(pool_size=(2,2)),\n    layers.Dropout(rate=0.3),\n    \n    layers.Conv2D(filters=32, kernel_size=(3,3), padding=\"Same\",\n                  activation='relu'),\n    layers.BatchNormalization(),\n        \n    layers.Conv2D(filters=32, kernel_size=(3,3), padding=\"Same\",\n                  activation='relu'),\n    layers.BatchNormalization(),\n    \n    # (14*14) --> (7*7)\n    \n    layers.MaxPool2D(pool_size=(2,2)),\n    layers.Dropout(rate=0.2),\n    \n    layers.Conv2D(filters=32, kernel_size=(3,3), padding=\"Same\",\n                  activation='relu'),\n    layers.BatchNormalization(),\n    layers.Dropout(rate=0.2),\n    \n    # Flatten and feed to dense layers\n    \n    layers.Flatten(),\n    layers.Dense(activation='relu', units=128),\n    layers.BatchNormalization(),\n    layers.Dropout(rate=0.3),\n    layers.Dense(activation='relu', units=128),\n    layers.BatchNormalization(),\n    layers.Dense(activation='softmax', units=10) # Multiclassification, hence using softmax\n    ]\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:33:25.955555Z","iopub.execute_input":"2022-05-01T19:33:25.956071Z","iopub.status.idle":"2022-05-01T19:33:26.120368Z","shell.execute_reply.started":"2022-05-01T19:33:25.956033Z","shell.execute_reply":"2022-05-01T19:33:26.119586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.utils import plot_model\nplot_model(model, to_file='model.png', show_shapes=True)\nfrom IPython.display import Image, display\nImage(\"model.png\", width = 500, height = 600)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:33:27.204041Z","iopub.execute_input":"2022-05-01T19:33:27.204526Z","iopub.status.idle":"2022-05-01T19:33:27.49747Z","shell.execute_reply.started":"2022-05-01T19:33:27.204487Z","shell.execute_reply":"2022-05-01T19:33:27.496665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size=128\nepochs=50\n\nmodel.compile(\n    optimizer=\"adam\",\n    loss = \"categorical_crossentropy\",\n    metrics=[\"accuracy\"]\n)\n","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:33:31.626863Z","iopub.execute_input":"2022-05-01T19:33:31.627709Z","iopub.status.idle":"2022-05-01T19:33:31.641004Z","shell.execute_reply.started":"2022-05-01T19:33:31.627662Z","shell.execute_reply":"2022-05-01T19:33:31.640167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping\n\nearly_stop=EarlyStopping(monitor=\"loss\", \n                         patience=5,\n                        min_delta=0.0001,\n                        restore_best_weights=True)\n\nhistory = model.fit_generator(tf_image_gen.flow(X_train,y_train, batch_size=batch_size),\n                              epochs = epochs, \n                              validation_data = (X_val,y_val),\n                              verbose = 0, \n                              callbacks=[early_stop]\n                             )","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:37:09.372153Z","iopub.execute_input":"2022-05-01T19:37:09.372427Z","iopub.status.idle":"2022-05-01T19:37:37.720072Z","shell.execute_reply.started":"2022-05-01T19:37:09.372399Z","shell.execute_reply":"2022-05-01T19:37:37.719201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.subplots(figsize=(6,6))\n\nloss_df=pd.DataFrame({\"val_loss\": history.history['val_loss'], \"train_loss\":history.history[\"loss\"]})\nsns.lineplot(data=loss_df);\nplt.ylim(0,0.1)\nplt.title(\"loss values with epochs\")\nplt.xlabel(\"epochs\");","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:47:27.942581Z","iopub.execute_input":"2022-05-01T19:47:27.942892Z","iopub.status.idle":"2022-05-01T19:47:28.196339Z","shell.execute_reply.started":"2022-05-01T19:47:27.94286Z","shell.execute_reply":"2022-05-01T19:47:28.195624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred=np.argmax(model.predict(X_val),axis=1)\ny_pred.shape\ny_val_cm=np.argmax(y_val, axis=1)\ny_val_cm.shape","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:56:59.425957Z","iopub.execute_input":"2022-05-01T19:56:59.426248Z","iopub.status.idle":"2022-05-01T19:56:59.876457Z","shell.execute_reply.started":"2022-05-01T19:56:59.426212Z","shell.execute_reply":"2022-05-01T19:56:59.875662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n\ncm=confusion_matrix(y_val_cm, y_pred)\nc=ConfusionMatrixDisplay(confusion_matrix=cm)\nfig,ax=plt.subplots(figsize=(8,8))\nc.plot(colorbar=False, ax=ax)\nplt.title(\"Confusion Matrix with CNN\");","metadata":{"execution":{"iopub.status.busy":"2022-05-01T19:58:45.60876Z","iopub.execute_input":"2022-05-01T19:58:45.609538Z","iopub.status.idle":"2022-05-01T19:58:46.186336Z","shell.execute_reply.started":"2022-05-01T19:58:45.609496Z","shell.execute_reply":"2022-05-01T19:58:46.185593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data=pd.read_csv('/kaggle/input/digit-recognizer/test.csv')\nresult_cnn=np.argmax(model.predict(test_data.values.reshape(-1,28,28,1)), axis=1)\nresult_cnn_df=pd.DataFrame({\"ImageId\":range(1,len(result_cnn)+1), \"Label\":result_cnn})\nresult_cnn_df.to_csv(\"/kaggle/working/submission-cnn.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2022-05-01T20:10:31.338577Z","iopub.execute_input":"2022-05-01T20:10:31.338881Z","iopub.status.idle":"2022-05-01T20:10:35.749279Z","shell.execute_reply.started":"2022-05-01T20:10:31.338852Z","shell.execute_reply":"2022-05-01T20:10:35.748375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Appendix: Trial using KNN without scaling/model decomposition  \n```\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.model_selection import train_test_split, GridSearchCV\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nX=train_data.iloc[:, 1:]\ny=train_data.loc[:,\"label\"]\n\nknn=KNeighborsClassifier()\nparams={\"n_neighbors\":range(1,10,2)}\nmodel=GridSearchCV(knn, param_grid=params, cv=5, n_jobs=-1)\nmodel\n\nX_train=np.array([np.array(X.loc[i,:]) for i in range(len(X))])\ny_train=np.array(y)\n```\n\n* Fitting the model\n\n```\n#Fitting gridsearch model \nmodel.fit(X_train, y_train)\n```\n\n* Model Gridserch Results : Best accu score with k=3 score:0.96669\n\n* Checking the results of hyperparameter tuning\n\npd.DataFrame(model.cv_results_)\n\n\n|  |   mean_fit_time |   std_fit_time |   mean_score_time |   std_score_time |   param_n_neighbors | params             |   split0_test_score |   split1_test_score |   split2_test_score |   split3_test_score |   split4_test_score |   mean_test_score |   std_test_score |   rank_test_score |\n|---:|----------------:|---------------:|------------------:|-----------------:|--------------------:|:-------------------|--------------------:|--------------------:|--------------------:|--------------------:|--------------------:|------------------:|-----------------:|------------------:|\n|  0 |        0.262868 |     0.00861217 |           34.5169 |         0.213232 |                   1 | {'n_neighbors': 1} |            0.96631  |            0.968095 |            0.9625   |            0.966905 |            0.967381 |          0.966238 |       0.00195847 |                 2 |\n|  1 |        0.24323  |     0.0298986  |           36.5001 |         0.465284 |                   3 | {'n_neighbors': 3} |            0.969762 |            0.967262 |            0.962857 |            0.964286 |            0.969286 |          0.96669  |       0.00271929 |                 1 |\n|  2 |        0.219933 |     0.0435849  |           36.7803 |         0.434234 |                   5 | {'n_neighbors': 5} |            0.967976 |            0.965595 |            0.963452 |            0.963333 |            0.968929 |          0.965857 |       0.00228671 |                 3 |\n|  3 |        0.18891  |     0.00355703 |           36.7677 |         0.741292 |                   7 | {'n_neighbors': 7} |            0.965476 |            0.965119 |            0.961548 |            0.963452 |            0.968214 |          0.964762 |       0.00221825 |                 4 |\n|  4 |        0.201626 |     0.0186322  |           33.3495 |         6.03319  |                   9 | {'n_neighbors': 9} |            0.964048 |            0.964643 |            0.960714 |            0.960357 |            0.966548 |          0.963262 |       0.0023769  |                 5 |\n\n\n* Saving the model\n\n```\nwith open(\"/kaggle/working/model-knn-class-digit.pkl\", \"wb\") as f:\n    joblib.dump(model, f)\n\n\nwith open(\"/kaggle/input/digit-recog-models/model-knn-class-digit.pkl\",\"rb\") as f:\n    model_knn=joblib.load(f)\ncm=confusion_matrix(y_train, model_knn.predict(X_train))\n\n```\n\n* Generating confusion matrix\n\n```\nc=ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=train_data.label.unique())\nfig,ax=plt.subplots(figsize=(8,8))\nc.plot(colorbar=False, ax=ax)\nplt.title(\"Confusion Matrix\");\n#print(f\"Accuraccy Score: {model_knn.score(X_train, y_train).round(4)}\")\nplt.savefig(\"/kaggle/working/cm-knn-only.png\")\n\n```\n\n> Confusion Matrix with knn only case \n\n<a href=\"https://imgbb.com/\"><img src=\"https://i.ibb.co/3BKXLdg/cm-knn-only.png\" alt=\"cm-knn-only\" border=\"0\"></a>\n\n\n","metadata":{"execution":{"iopub.status.busy":"2022-04-30T19:12:42.595582Z","iopub.execute_input":"2022-04-30T19:12:42.596078Z","iopub.status.idle":"2022-04-30T19:12:43.689795Z","shell.execute_reply.started":"2022-04-30T19:12:42.596044Z","shell.execute_reply":"2022-04-30T19:12:43.688855Z"}}}]}