{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3004,"databundleVersionId":861823,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, classification_report, precision_recall_fscore_support\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\n\nsns.set(style=\"whitegrid\", context=\"notebook\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:46:38.675591Z","iopub.execute_input":"2025-09-30T00:46:38.675930Z","iopub.status.idle":"2025-09-30T00:46:56.808699Z","shell.execute_reply.started":"2025-09-30T00:46:38.675902Z","shell.execute_reply":"2025-09-30T00:46:56.807810Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(\"/kaggle/input/digit-recognizer/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/digit-recognizer/test.csv\")\n\nprint(\"Train shape:\", train.shape)\nprint(\"Test shape:\", test.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:46:56.810473Z","iopub.execute_input":"2025-09-30T00:46:56.811230Z","iopub.status.idle":"2025-09-30T00:47:01.767362Z","shell.execute_reply.started":"2025-09-30T00:46:56.811201Z","shell.execute_reply":"2025-09-30T00:47:01.766188Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = train.drop(\"label\", axis=1).values / 255.0\ny = train[\"label\"].values\ntest_data = test.values / 255.0\n\nprint(\"X shape:\", X.shape)\nprint(\"y shape:\", y.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:47:01.768204Z","iopub.execute_input":"2025-09-30T00:47:01.768490Z","iopub.status.idle":"2025-09-30T00:47:02.142203Z","shell.execute_reply.started":"2025-09-30T00:47:01.768460Z","shell.execute_reply":"2025-09-30T00:47:02.141214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, axes = plt.subplots(1, 5, figsize=(12, 4))\nfor i, ax in enumerate(axes):\n    ax.imshow(X[i].reshape(28, 28), cmap=\"gray\")\n    ax.set_title(f\"Label: {y[i]}\")\n    ax.axis(\"off\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:47:02.144251Z","iopub.execute_input":"2025-09-30T00:47:02.144503Z","iopub.status.idle":"2025-09-30T00:47:02.719819Z","shell.execute_reply.started":"2025-09-30T00:47:02.144483Z","shell.execute_reply":"2025-09-30T00:47:02.718878Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Baseline logistic regression","metadata":{}},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(\n    X, y, test_size=0.1, random_state=42, stratify=y\n)\n\nlr = LogisticRegression(\n    max_iter=1000,\n    solver=\"lbfgs\",\n    multi_class=\"multinomial\",\n    n_jobs=-1\n)\nlr.fit(X_train, y_train)\n\ny_pred = lr.predict(X_val)\n\ncm = confusion_matrix(y_val, y_pred)\nplt.figure(figsize=(10, 8))\nsns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\")\nplt.xlabel(\"Predicted\")\nplt.ylabel(\"True\")\nplt.title(\"Confusion Matrix - Validation Set\")\nplt.show()\n\nprint(classification_report(y_val, y_pred))\n\nprecision, recall, f1, support = precision_recall_fscore_support(y_val, y_pred)\nmetrics_df = pd.DataFrame({\n    \"Digit\": np.arange(10),\n    \"Precision\": precision,\n    \"Recall\": recall,\n    \"F1-score\": f1,\n    \"Support\": support\n})\n\nmetrics_melted = metrics_df.melt(\n    id_vars=\"Digit\",\n    value_vars=[\"Precision\", \"Recall\", \"F1-score\"],\n    var_name=\"Metric\", value_name=\"Score\"\n)\n\nplt.figure(figsize=(12,6))\nsns.barplot(data=metrics_melted, x=\"Digit\", y=\"Score\", hue=\"Metric\")\nplt.title(\"Precision, Recall and F1-score by Digit (Validation Set)\")\nplt.ylim(0,1.05)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:47:02.720663Z","iopub.execute_input":"2025-09-30T00:47:02.720962Z","iopub.status.idle":"2025-09-30T00:48:20.612629Z","shell.execute_reply.started":"2025-09-30T00:47:02.720937Z","shell.execute_reply":"2025-09-30T00:48:20.611720Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CNN","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nX = train.drop(\"label\", axis=1).values.reshape(-1,28,28,1) / 255.0\ny = keras.utils.to_categorical(train[\"label\"].values, 10)\ntest_data = test.values.reshape(-1,28,28,1) / 255.0\n\nX_train, X_val, y_train, y_val = train_test_split(\n    X, y, test_size=0.1, random_state=42, stratify=train[\"label\"].values\n)\n\ndatagen = ImageDataGenerator(\n    rotation_range=10,\n    width_shift_range=0.1,\n    height_shift_range=0.1,\n    zoom_range=0.1\n)\ndatagen.fit(X_train)\n\nmodel = keras.Sequential([\n    layers.Conv2D(64, (3,3), activation=\"relu\", input_shape=(28,28,1)),\n    layers.BatchNormalization(),\n    layers.MaxPooling2D((2,2)),\n\n    layers.Conv2D(128, (3,3), activation=\"relu\"),\n    layers.BatchNormalization(),\n    layers.MaxPooling2D((2,2)),\n\n    layers.Flatten(),\n    layers.Dense(256, activation=\"relu\"),\n    layers.Dropout(0.5),\n    layers.Dense(10, activation=\"softmax\")\n])\n\nmodel.compile(optimizer=\"adam\", loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])\n\ncallbacks = [\n    keras.callbacks.EarlyStopping(\n        monitor=\"val_accuracy\",\n        patience=3,\n        restore_best_weights=True\n    )\n]\n\nhistory = model.fit(\n    datagen.flow(X_train, y_train, batch_size=128),\n    epochs=30,\n    validation_data=(X_val, y_val),\n    callbacks=callbacks,\n    verbose=2\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:48:20.613620Z","iopub.execute_input":"2025-09-30T00:48:20.613982Z","iopub.status.idle":"2025-09-30T00:59:19.608376Z","shell.execute_reply.started":"2025-09-30T00:48:20.613944Z","shell.execute_reply":"2025-09-30T00:59:19.607522Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_loss, val_acc = model.evaluate(X_val, y_val, verbose=0)\nprint(f\"Validation accuracy: {val_acc:.4f}\")\n\nplt.figure(figsize=(12,5))\n\nplt.subplot(1,2,1)\nplt.plot(history.history[\"val_accuracy\"], label=\"Validation Accuracy\")\nplt.title(\"Validation Accuracy\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\n\nplt.subplot(1,2,2)\nplt.plot(history.history[\"val_loss\"], label=\"Validation Loss\")\nplt.title(\"Validation Loss\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Loss\")\nplt.legend()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:59:19.609523Z","iopub.execute_input":"2025-09-30T00:59:19.609891Z","iopub.status.idle":"2025-09-30T00:59:21.559568Z","shell.execute_reply.started":"2025-09-30T00:59:19.609855Z","shell.execute_reply":"2025-09-30T00:59:21.558678Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"ImageId\": list(range(1, len(test_data)+1)),\n    \"Label\": np.argmax(model.predict(test_data), axis=1)\n})\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-30T00:59:21.560393Z","iopub.execute_input":"2025-09-30T00:59:21.560631Z","iopub.status.idle":"2025-09-30T00:59:31.669803Z","shell.execute_reply.started":"2025-09-30T00:59:21.560612Z","shell.execute_reply":"2025-09-30T00:59:31.668899Z"}},"outputs":[],"execution_count":null}]}