{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"provenance":[]},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# [Outlier Detection](https://scikit-learn.org/stable/modules/outlier_detection.html)\n","metadata":{}},{"cell_type":"markdown","source":"## 1. Frame the problem\n\nIn this notebook we will see if we can improve upon our benchmark pipeline by removing outliers from our training set.","metadata":{}},{"cell_type":"code","source":"from sklearn import metrics\n\n\nmetrics.accuracy_score?","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:04:38.409451Z","iopub.execute_input":"2024-11-27T13:04:38.411199Z","iopub.status.idle":"2024-11-27T13:04:39.221830Z","shell.execute_reply.started":"2024-11-27T13:04:38.411114Z","shell.execute_reply":"2024-11-27T13:04:39.220556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SCORING = \"accuracy\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:04:53.134314Z","iopub.execute_input":"2024-11-27T13:04:53.135280Z","iopub.status.idle":"2024-11-27T13:04:53.140194Z","shell.execute_reply.started":"2024-11-27T13:04:53.135204Z","shell.execute_reply":"2024-11-27T13:04:53.138830Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Exercise: Load the Data\n","metadata":{"id":"a9b241c6-de2e-4c9a-ac4f-6c5a010e2929"}},{"cell_type":"code","source":"%%bash\n\nls /kaggle/input/digit-recognizer","metadata":{"id":"M2nXzqRak_xw","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Solution","metadata":{}},{"cell_type":"code","source":"import pathlib\n\nimport numpy as np\nimport pandas as pd\nfrom sklearn import model_selection\n\n# load the training data and write to parquet\nTRAIN_DF = pd.read_csv(\n    \"/kaggle/input/digit-recognizer/train.csv\",\n    dtype=np.uint8,\n)\n\n_train_parquet_filepath = pathlib.Path(\"train.parquet\")\n_ = TRAIN_DF.to_parquet(_train_parquet_filepath)\n\n\n# sample the training data for faster experimentation\nPRNG = np.random.RandomState(42)\nSAMPLE_TRAIN_DF, _ = model_selection.train_test_split(\n    TRAIN_DF,\n    random_state=PRNG,\n    stratify=TRAIN_DF.loc[:, \"label\"],\n    train_size=0.2,\n)\n\n_sample_train_parquet_filepath = pathlib.Path(\"sample-train.parquet\")\nSAMPLE_TRAIN_DF.to_parquet(_sample_train_parquet_filepath)\n\n# load the test features and write to parquet\nTEST_FEATURES_DF = pd.read_csv(\n    \"/kaggle/input/digit-recognizer/test.csv\",\n    dtype=np.uint8,\n)\n\n_test_features_parquet_filepath = pathlib.Path(\"test-features.parquet\")\n_ = TEST_FEATURES_DF.to_parquet(_test_features_parquet_filepath)\n","metadata":{"id":"c1fded7d-02a7-48c3-99e4-d19d001c8ccf","trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:05:59.714504Z","iopub.execute_input":"2024-11-27T13:05:59.714984Z","iopub.status.idle":"2024-11-27T13:06:07.172453Z","shell.execute_reply.started":"2024-11-27T13:05:59.714945Z","shell.execute_reply":"2024-11-27T13:06:07.171035Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TRAIN_DF.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:06:07.175504Z","iopub.execute_input":"2024-11-27T13:06:07.176098Z","iopub.status.idle":"2024-11-27T13:06:07.208926Z","shell.execute_reply.started":"2024-11-27T13:06:07.176027Z","shell.execute_reply":"2024-11-27T13:06:07.207757Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SAMPLE_TRAIN_DF.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:06:07.210471Z","iopub.execute_input":"2024-11-27T13:06:07.211463Z","iopub.status.idle":"2024-11-27T13:06:07.228463Z","shell.execute_reply.started":"2024-11-27T13:06:07.211409Z","shell.execute_reply":"2024-11-27T13:06:07.227160Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TEST_FEATURES_DF.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:06:07.230448Z","iopub.execute_input":"2024-11-27T13:06:07.230749Z","iopub.status.idle":"2024-11-27T13:06:07.248191Z","shell.execute_reply.started":"2024-11-27T13:06:07.230717Z","shell.execute_reply":"2024-11-27T13:06:07.246930Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%bash\n\nls -lh /kaggle/working/*.parquet","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:06:24.412409Z","iopub.execute_input":"2024-11-27T13:06:24.412979Z","iopub.status.idle":"2024-11-27T13:06:24.442399Z","shell.execute_reply.started":"2024-11-27T13:06:24.412928Z","shell.execute_reply":"2024-11-27T13:06:24.441295Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. Benchmark pipeline","metadata":{}},{"cell_type":"code","source":"from sklearn import model_selection\n\n\nCV_N_SPLITS = 5\nCV_N_ITER = 10\nCV_N_JOBS = min(4, CV_N_ITER, CV_N_SPLITS)\n\nCV_SPLITTER = model_selection.StratifiedShuffleSplit(\n    n_splits=CV_N_SPLITS,\n    train_size=0.9,\n    random_state=PRNG,\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:10:33.640275Z","iopub.execute_input":"2024-11-27T13:10:33.640777Z","iopub.status.idle":"2024-11-27T13:10:33.647247Z","shell.execute_reply.started":"2024-11-27T13:10:33.640737Z","shell.execute_reply":"2024-11-27T13:10:33.646008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from scipy import stats\nfrom sklearn import ensemble, feature_selection, pipeline\n\n\nrandom_forest_classifier = pipeline.make_pipeline(\n    feature_selection.VarianceThreshold(\n        threshold=0.0\n    ),\n    ensemble.RandomForestClassifier(\n        n_jobs=-1,\n        random_state=PRNG\n    ),\n    verbose=False\n)\n\nparam_distributions = [\n    {\n        \"variancethreshold__threshold\": stats.lognorm(s=1.0)\n    }\n]\n\n_train_features_df = (\n    SAMPLE_TRAIN_DF.drop(\"label\", axis=1)\n)\n_train_labels = (\n    SAMPLE_TRAIN_DF.loc[:, \"label\"]\n)\n\n_cv_splits = CV_SPLITTER.split(\n    _train_features_df,\n    _train_labels,\n)\n\nbenchmark_pipeline_cv = model_selection.RandomizedSearchCV(\n    random_forest_classifier,\n    param_distributions,\n    cv=_cv_splits,\n    n_iter=CV_N_ITER,\n    n_jobs=CV_N_JOBS,\n    refit=True,\n    scoring=SCORING,\n)\n\n_ = benchmark_pipeline_cv.fit(\n    _train_features_df,\n    _train_labels\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:11:33.300205Z","iopub.execute_input":"2024-11-27T13:11:33.300713Z","iopub.status.idle":"2024-11-27T13:13:09.939723Z","shell.execute_reply.started":"2024-11-27T13:11:33.300675Z","shell.execute_reply":"2024-11-27T13:13:09.938084Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"benchmark_pipeline_cv.best_score_","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:13:17.859641Z","iopub.execute_input":"2024-11-27T13:13:17.860112Z","iopub.status.idle":"2024-11-27T13:13:17.872342Z","shell.execute_reply.started":"2024-11-27T13:13:17.860056Z","shell.execute_reply":"2024-11-27T13:13:17.871062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"benchmark_pipeline_cv.best_params_","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:13:18.157994Z","iopub.execute_input":"2024-11-27T13:13:18.158762Z","iopub.status.idle":"2024-11-27T13:13:18.169119Z","shell.execute_reply.started":"2024-11-27T13:13:18.158692Z","shell.execute_reply":"2024-11-27T13:13:18.167309Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3. Outlier detection using [IsolationForest](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html)","metadata":{"id":"43fc80e6-5e4b-42dc-8584-7dfdb397cb27"}},{"cell_type":"code","source":"isolation_forest = pipeline.make_pipeline(\n    feature_selection.VarianceThreshold(\n        threshold=0.0\n    ),\n    ensemble.IsolationForest(\n        contamination=\"auto\",\n        max_samples=0.1,\n        n_jobs=-1,\n        random_state=PRNG\n    ),\n    verbose=False,\n)\n\n_ = isolation_forest.fit(SAMPLE_TRAIN_DF)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:18:50.337185Z","iopub.execute_input":"2024-11-27T13:18:50.337800Z","iopub.status.idle":"2024-11-27T13:18:50.838111Z","shell.execute_reply.started":"2024-11-27T13:18:50.337762Z","shell.execute_reply":"2024-11-27T13:18:50.837125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1 is inlier, -1 is outlier\nisolation_forest.predict(SAMPLE_TRAIN_DF)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:18:50.839808Z","iopub.execute_input":"2024-11-27T13:18:50.840143Z","iopub.status.idle":"2024-11-27T13:18:52.291923Z","shell.execute_reply.started":"2024-11-27T13:18:50.840110Z","shell.execute_reply":"2024-11-27T13:18:52.290700Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# positive scores are inliers, negative scores are outliers\nisolation_forest.decision_function(SAMPLE_TRAIN_DF)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:20:40.256762Z","iopub.execute_input":"2024-11-27T13:20:40.257576Z","iopub.status.idle":"2024-11-27T13:20:41.667418Z","shell.execute_reply.started":"2024-11-27T13:20:40.257533Z","shell.execute_reply":"2024-11-27T13:20:41.666280Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ANOMALY_THRESHOLD = 0.0\nanomaly_score = isolation_forest.decision_function(SAMPLE_TRAIN_DF)\n\ninliers_train_df = (\n    SAMPLE_TRAIN_DF.assign(\n        anomaly_score=anomaly_score\n    ).query(\n        f\"anomaly_score > {ANOMALY_THRESHOLD}\"\n    )\n)\n\noutliers_train_df = (\n    SAMPLE_TRAIN_DF.assign(\n        anomaly_score=anomaly_score\n    ).query(\n        f\"anomaly_score <= {ANOMALY_THRESHOLD}\"\n    )\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:22:25.457878Z","iopub.execute_input":"2024-11-27T13:22:25.458399Z","iopub.status.idle":"2024-11-27T13:22:27.380975Z","shell.execute_reply.started":"2024-11-27T13:22:25.458358Z","shell.execute_reply":"2024-11-27T13:22:27.379917Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"outliers_train_df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:22:27.382921Z","iopub.execute_input":"2024-11-27T13:22:27.383299Z","iopub.status.idle":"2024-11-27T13:22:27.417631Z","shell.execute_reply.started":"2024-11-27T13:22:27.383261Z","shell.execute_reply":"2024-11-27T13:22:27.416433Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def remove_outliers(outlier_detector, df, anomaly_threshold=0.0):\n\n    outlier_detector_ = outlier_detector.fit(df)\n    anomaly_score = outlier_detector_.decision_function(df)\n    \n    inliers_df = (\n        df.assign(\n            anomaly_score=anomaly_score\n        ).query(\n            f\"anomaly_score > {anomaly_threshold}\"\n        )\n    )\n    \n    outliers_df = (\n        df.assign(\n            anomaly_score=anomaly_score\n        ).query(\n            f\"anomaly_score <= {anomaly_threshold}\"\n        )\n    )\n\n    return outlier_detector_, inliers_df, outliers_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:24:41.040218Z","iopub.execute_input":"2024-11-27T13:24:41.041215Z","iopub.status.idle":"2024-11-27T13:24:41.048475Z","shell.execute_reply.started":"2024-11-27T13:24:41.041166Z","shell.execute_reply":"2024-11-27T13:24:41.047131Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"outlier_detector, inliers_train_df, outliers_train_df = remove_outliers(\n    isolation_forest,\n    SAMPLE_TRAIN_DF,\n    ANOMALY_THRESHOLD\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:24:41.672891Z","iopub.execute_input":"2024-11-27T13:24:41.673972Z","iopub.status.idle":"2024-11-27T13:24:44.012452Z","shell.execute_reply.started":"2024-11-27T13:24:41.673926Z","shell.execute_reply":"2024-11-27T13:24:44.011267Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n\nfig, axes = plt.subplots(7, 7, sharex=True, sharey=True, figsize=(15, 15))\nfor i in range(7):\n    for j in range(7):\n        m, _ = outliers_train_df.shape\n        k = np.random.randint(m)\n        img = (outliers_train_df.iloc[k, 1:-1]\n                                .to_numpy()\n                                .reshape((28, 28)))\n        _ = axes[i, j].imshow(img)\n        _ = axes[i, j].set_title(f\"Label: {outliers_train_df.iloc[k, 0]}, Score {outliers_train_df.iloc[k, -1]:.3f}\")\n\nfig.suptitle(\"Random outlier images\", x=0.5, y=1.05, fontsize=25)\nfig.tight_layout()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:27:22.633337Z","iopub.execute_input":"2024-11-27T13:27:22.633819Z","iopub.status.idle":"2024-11-27T13:27:34.255767Z","shell.execute_reply.started":"2024-11-27T13:27:22.633778Z","shell.execute_reply":"2024-11-27T13:27:34.254618Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n\nfig, axes = plt.subplots(7, 7, sharex=True, sharey=True, figsize=(15, 15))\nfor i in range(7):\n    for j in range(7):\n        m, _ = inliers_train_df.shape\n        k = np.random.randint(m)\n        img = (inliers_train_df.iloc[k, 1:-1]\n                                .to_numpy()\n                                .reshape((28, 28)))\n        _ = axes[i, j].imshow(img)\n        _ = axes[i, j].set_title(f\"Label: {inliers_train_df.iloc[k, 0]}, Score {inliers_train_df.iloc[k, -1]:.3f}\")\n\nfig.suptitle(\"Random inlier images\", x=0.5, y=1.05, fontsize=25)\nfig.tight_layout()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:28:51.259112Z","iopub.execute_input":"2024-11-27T13:28:51.260087Z","iopub.status.idle":"2024-11-27T13:29:04.271481Z","shell.execute_reply.started":"2024-11-27T13:28:51.260030Z","shell.execute_reply":"2024-11-27T13:29:04.270289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sorted_outliers_df = outliers_train_df.sort_values(\"anomaly_score\", ascending=True)\n\nfig, axes = plt.subplots(7, 7, sharex=True, sharey=True, figsize=(15, 15))\nfor i in range(7):\n    for j in range(7):\n        k = 7 * i + j\n        img = (\n            sorted_outliers_df.iloc[k, 1:-1]\n                              .to_numpy()\n                              .reshape((28, 28))\n        )\n        _ = axes[i, j].imshow(img)\n        _ = axes[i, j].set_title(f\"Label: {sorted_outliers_df.iloc[k, 0]}, Score {sorted_outliers_df.iloc[k, -1]:.3f}\")\n\nfig.suptitle(\"Best outlier images\", x=0.5, y=1.05, fontsize=25)\nfig.tight_layout()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:30:05.901670Z","iopub.execute_input":"2024-11-27T13:30:05.902114Z","iopub.status.idle":"2024-11-27T13:30:17.816092Z","shell.execute_reply.started":"2024-11-27T13:30:05.902072Z","shell.execute_reply":"2024-11-27T13:30:17.814674Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sorted_inliers_df = inliers_train_df.sort_values(\"anomaly_score\", ascending=True)\n\nfig, axes = plt.subplots(7, 7, sharex=True, sharey=True, figsize=(15, 15))\nfor i in range(7):\n    for j in range(7):\n        k = 7 * i + j + 1\n        img = (\n            sorted_inliers_df.iloc[-k, 1:-1]\n                             .to_numpy()\n                             .reshape((28, 28))\n        )\n        _ = axes[i, j].imshow(img)\n        _ = axes[i, j].set_title(f\"Label: {sorted_inliers_df.iloc[-k, 0]}, Score {sorted_inliers_df.iloc[-k, -1]:.3f}\")\n\nfig.suptitle(\"Best inlier images\", x=0.5, y=1.05, fontsize=25)\nfig.tight_layout()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:33:24.725506Z","iopub.execute_input":"2024-11-27T13:33:24.726923Z","iopub.status.idle":"2024-11-27T13:33:36.751663Z","shell.execute_reply.started":"2024-11-27T13:33:24.726868Z","shell.execute_reply":"2024-11-27T13:33:36.750363Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(7, 7, sharex=True, sharey=True, figsize=(15, 15))\nfor i in range(7):\n    for j in range(7):\n        k = 7 * i + j\n        img = (\n            sorted_inliers_df.iloc[k, 1:-1]\n                             .to_numpy()\n                             .reshape((28, 28))\n        )\n        _ = axes[i, j].imshow(img)\n        _ = axes[i, j].set_title(f\"Label: {sorted_inliers_df.iloc[k, 0]}, Score {sorted_inliers_df.iloc[k, -1]:.3f}\")\n\nfig.suptitle(\"Worst inlier images\", x=0.5, y=1.05, fontsize=25)\nfig.tight_layout()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:35:58.434549Z","iopub.execute_input":"2024-11-27T13:35:58.435792Z","iopub.status.idle":"2024-11-27T13:36:10.199791Z","shell.execute_reply.started":"2024-11-27T13:35:58.435744Z","shell.execute_reply":"2024-11-27T13:36:10.198705Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"_train_features_df = (\n    inliers_train_df.drop([\"label\", \"anomaly_score\"], axis=1)\n)\n_train_labels = (\n    inliers_train_df.loc[:, \"label\"]\n)\n\n_cv_splits = CV_SPLITTER.split(\n    _train_features_df,\n    _train_labels \n)\n\ncv_scores = model_selection.cross_val_score(\n    benchmark_pipeline_cv.best_estimator_,\n    _train_features_df,\n    _train_labels,\n    cv=_cv_splits,\n    n_jobs=CV_N_JOBS,\n    scoring=SCORING,\n)\n\nprint(f\"Mean CV Score {np.mean(cv_scores)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:38:41.728456Z","iopub.execute_input":"2024-11-27T13:38:41.728967Z","iopub.status.idle":"2024-11-27T13:38:52.627648Z","shell.execute_reply.started":"2024-11-27T13:38:41.728928Z","shell.execute_reply":"2024-11-27T13:38:52.626095Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. Fine-tune the pipeline","metadata":{}},{"cell_type":"code","source":"param_distributions = [\n    {\n        \"variancethreshold__threshold\": stats.lognorm(s=1.0),\n        \"randomforestclassifier__min_samples_leaf\": stats.beta(a=1, b=99)\n    }\n]\n\n_train_features_df = (\n    inliers_train_df.drop(\"label\", axis=1)\n)\n_train_labels = (\n    inliers_train_df.loc[:, \"label\"]\n)\n\n_cv_splits = CV_SPLITTER.split(\n    _train_features_df,\n    _train_labels\n)\n\nrandomized_search_cv = model_selection.RandomizedSearchCV(\n    random_forest_classifier,\n    param_distributions,\n    cv=_cv_splits,\n    n_iter=CV_N_ITER * 10,\n    n_jobs=CV_N_JOBS,\n    refit=True,\n    scoring=SCORING,\n)\n\n_ = randomized_search_cv.fit(\n    _train_features_df,\n    _train_labels\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-27T13:50:20.693916Z","iopub.execute_input":"2024-11-27T13:50:20.694481Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"randomized_search_cv.best_score_","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"randomized_search_cv.best_params_","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5. Re-fit tuned pipeline using full training set","metadata":{}},{"cell_type":"code","source":"_, inliers_train_df, _ = remove_outliers(isolation_forest, TRAIN_DF)\n\n_train_features_df = (\n    inliers_train_df.drop([\"label\", \"anomaly_score\"], axis=1)\n)\n_train_labels = (\n    inliers_train_df.loc[:, \"label\"]\n)\n\nbest_estimator = (\n    randomized_search_cv.best_estimator_\n                        .fit(\n                            _train_features_df,\n                            _train_labels\n                        )\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 6. Submit predictions","metadata":{}},{"cell_type":"code","source":"_test_predictions = best_estimator.predict(TEST_FEATURES_DF)\n\n_ = (\n    pd.read_csv(\n        \"/kaggle/input/digit-recognizer/sample_submission.csv\",\n        index_col=\"ImageId\"\n    ).assign(\n        Label=_test_predictions\n    ).to_csv(\"submission.csv\", index=True)\n)","metadata":{"id":"17sj0qA6ehAS","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%bash\n\ncat submission.csv | head -n 5","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}