{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","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":30587,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Phần 1: Nhập các thư viện cần thiết\n------","metadata":{"_uuid":"b0093541-188e-43e9-acb2-d917ae3a5010","_cell_guid":"cadbfcb2-82c3-470f-bad6-eade54542125","trusted":true}},{"cell_type":"markdown","source":"<div>\n<b>Cơ sở dữ liệu MNIST</b> chứa các ảnh về chữ số viết tay được sử dụng rộng rãi trong việc huấn luyện các hệ thống xử lý ảnh. Dữ liệu này đã được chuẩn hóa để phù hợp với ô bao 28x28 pixel và được biến đổi thành mức độ xám. Cơ sở dữ liệu gốc có 60,000 ảnh huấn luyện và 10,000 ảnh kiểm tra. Trong cuộc thi này, chúng ta chỉ sử dụng 42,000 ảnh train (70%) và 18,000 ảnh test (30%).\n\n- Trong nhiều trường hợp, để giải quyết vấn đề Phân loại Ảnh, ta thường sử dụng Mạng Nơ-ron Tích chập (CNN), nhưng với MNIST, một bài toán đơn giản, ta có thể dùng các thuật toán Học Máy cơ bản và vẫn đạt được độ chính xác tốt.\n<ul>\n    Cụ thể, ta sẽ thực hiện hai bước chính:\n    <li> 🔶 <b>Phân tích thành phần chính (PCA):</b> 🔶:<br>\n        - Thu nhỏ dữ liệu từ 784 giá trị pixel xuống chỉ còn 10 thành phần chính.<br>\n        - Giảm chiều dữ liệu giúp tăng tốc quá trình huấn luyện mà không mất đi nhiều thông tin quan trọng.<br>\n    <li> 🔶 <b>Thuật toán K-Nearest Neighbors (KNN):</b> 🔶:<br>\n        - Sử dụng KNN là một thuật toán lazy learner tức là không cần huấn luyện một mô hình phức tạp.<br>\n        - KNN dựa trên việc so sánh điểm gần nhất để dự đoán nhãn của một điểm mới.<br>\n        - Kết hợp KNN với PCA giúp tăng hiệu suất của thuật toán.<br>\n</ul>\n\n==> Sau khi kết hợp PCA và KNN, chúng ta sẽ có một mô hình có độ chính xác kiểm tra đáng kinh ngạc, xấp xỉ 92.71%. Điều này chứng tỏ rằng, dù sử dụng các phương pháp đơn giản, ta vẫn có thể đạt được kết quả tốt trên bài toán MNIST.\n</div>","metadata":{"_uuid":"85d40f0d-34d6-4e02-90f3-7ef7a60e5573","_cell_guid":"ddf0a964-5157-492a-9699-253bc2caec79"}},{"cell_type":"markdown","source":"IMPORT THƯ VIỆN","metadata":{}},{"cell_type":"code","source":"# Đọc,xử lý dữ liệu\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom sklearn.preprocessing import MinMaxScaler\n\n# Gọi thư viện PCA\nfrom sklearn.decomposition import PCA\nfrom sklearn.pipeline import Pipeline\nimport plotly.express as px\n\n# KNN\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.model_selection import GridSearchCV\nfrom sklearn.metrics import classification_report, \\\n    confusion_matrix, ConfusionMatrixDisplay \n# VHT\nfrom scipy.ndimage import rotate","metadata":{"_uuid":"c382c9dc-2109-4ce6-b779-dc8c447da240","_cell_guid":"e169ec97-1f64-46cd-8099-1d09c757dccc","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:07.057394Z","iopub.execute_input":"2024-06-15T03:26:07.057967Z","iopub.status.idle":"2024-06-15T03:26:07.066292Z","shell.execute_reply.started":"2024-06-15T03:26:07.057921Z","shell.execute_reply":"2024-06-15T03:26:07.064855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm xoay ảnh","metadata":{}},{"cell_type":"code","source":"def func_array1d_rotate2d(Narray1d,rotate_angle,sizePixel):\n\n    N = Narray1d.shape[0]\n\n    Narray1d_rotate = np.zeros(Narray1d.shape)\n    \n    for i in range(N):\n        image = np.reshape(Narray1d[i,:],(sizePixel,sizePixel))\n        rotated_image = rotate(image,rotate_angle, reshape=False)\n        rotated_array1d = np.reshape(rotated_image,(1,-1))\n        Narray1d_rotate[i,:] = rotated_array1d\n        \n    return Narray1d_rotate","metadata":{"_uuid":"b362968d-9828-4257-92ec-b9e4e49a9cb0","_cell_guid":"8ace7936-3ee9-4fe9-b71e-8d7e3b7eee15","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:07.068298Z","iopub.execute_input":"2024-06-15T03:26:07.068817Z","iopub.status.idle":"2024-06-15T03:26:07.084061Z","shell.execute_reply.started":"2024-06-15T03:26:07.068757Z","shell.execute_reply":"2024-06-15T03:26:07.082701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"----\n# Phần 2: Đọc dữ liệu và khai thác dữ liệu","metadata":{"_uuid":"a7abf7cf-fbfb-44f8-a5eb-77885d1283fb","_cell_guid":"1e5c33e8-406f-4da5-929d-034f87443736","trusted":true}},{"cell_type":"markdown","source":"<div style=\"border-radius: 10px; border: #4361EE solid; padding: 15px; background-color: #ffffff00; font-size: 100%; text-align: left;\">\nsử dụng pandas để đọc tệp dữ liệu csv.<br>\n    Trực quan hóa việc phân phối các giá trị pixel (biểu đồ) bằng thư viện Seaborn và Matplotlib Python.<br>\n    và cuối cùng sẽ trực quan hóa các hình ảnh bằng cách vẽ một hình ảnh từ mỗi lớp.\n</div>","metadata":{"_uuid":"d4c82fac-2a10-4c14-a95a-653bd16872cd","_cell_guid":"deaebcb3-115c-4e6b-b843-4522382a052d","trusted":true}},{"cell_type":"code","source":"# sử dụng pandas đọc dữ liệu csv\ndf_train = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')\ndf_test =  pd.read_csv('/kaggle/input/digit-recognizer/test.csv')","metadata":{"_uuid":"4da57b46-cc50-4ae9-9495-d0dbeb6be5ee","_cell_guid":"8967621a-0c55-49ff-b6e2-05d9efdeedf2","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:07.086109Z","iopub.execute_input":"2024-06-15T03:26:07.087091Z","iopub.status.idle":"2024-06-15T03:26:11.272555Z","shell.execute_reply.started":"2024-06-15T03:26:07.087032Z","shell.execute_reply":"2024-06-15T03:26:11.271191Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# chia dữ liệu theo tỉ lệ 7/3\nprint(\"df_train shape:\", df_train.shape)  # 70%\nprint(\"df_test shape: \", df_test.shape)  # 30%","metadata":{"_uuid":"5465a268-9ec4-4482-a0d7-e531d25f4917","_cell_guid":"da0e04b7-5ce3-48ec-be64-cee70c71af07","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:11.275697Z","iopub.execute_input":"2024-06-15T03:26:11.276101Z","iopub.status.idle":"2024-06-15T03:26:11.281974Z","shell.execute_reply.started":"2024-06-15T03:26:11.276068Z","shell.execute_reply":"2024-06-15T03:26:11.280706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# kiểm tra thiếu hụt dữ liệu\nprint(\n    \"Missing values in df_train: \", \\\n    df_train.isna().sum().sum()\n)\nprint(\n    \"Missing values in df_test: \", \\\n    df_test.isna().sum().sum()\n)","metadata":{"_uuid":"f8324800-d007-4d21-9eb6-39bba50ce548","_cell_guid":"758f94a2-69c7-4c9b-b1a3-22cb0f0b1a43","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:11.283444Z","iopub.execute_input":"2024-06-15T03:26:11.283849Z","iopub.status.idle":"2024-06-15T03:26:11.342661Z","shell.execute_reply.started":"2024-06-15T03:26:11.283808Z","shell.execute_reply":"2024-06-15T03:26:11.341467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Trực quan hóa 5 hàng đầu\ndf_train.head()","metadata":{"_uuid":"b1a7f2dc-6cec-4610-ba22-6ad5a7fb06ac","_cell_guid":"f1a8c252-31ba-46a1-b25c-c6ffff3fa2a9","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:11.344363Z","iopub.execute_input":"2024-06-15T03:26:11.344831Z","iopub.status.idle":"2024-06-15T03:26:11.365488Z","shell.execute_reply.started":"2024-06-15T03:26:11.344788Z","shell.execute_reply":"2024-06-15T03:26:11.364395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- cột đầu tiên là label còn tất cả 785 cột còn lại là pixel\n- tiếp tục thực hiện chia thành 2 cột x và y(để nhìn bao quát về dữ liệu)","metadata":{}},{"cell_type":"code","source":"X_train = df_train.drop(columns=['label']).values\ny_train = df_train['label'].values","metadata":{"_uuid":"48085649-c225-4e39-824f-82474ea004ff","_cell_guid":"939c1008-c85e-4ee0-bdab-bcccc4a252e4","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:11.366823Z","iopub.execute_input":"2024-06-15T03:26:11.367150Z","iopub.status.idle":"2024-06-15T03:26:11.462530Z","shell.execute_reply.started":"2024-06-15T03:26:11.367121Z","shell.execute_reply":"2024-06-15T03:26:11.461338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# thực hiện trực quan hóa dữ liệu của các giá trị pixel\n\nax = sns.histplot(x=X_train.flatten(), color='#4895EE')\n_ = ax.set(title='Pixel Value Histogram', xlabel='Pixel Value')\n\n# 0 đại diền cho nền và lớn hơn 0 đại diện cho các chữ số trong ảnh","metadata":{"_uuid":"f724afe4-d098-4f65-aaca-e97a096b8a32","_cell_guid":"36ec9986-72eb-4f04-abf8-84e2df3e3bfa","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:11.464096Z","iopub.execute_input":"2024-06-15T03:26:11.464586Z","iopub.status.idle":"2024-06-15T03:26:22.856709Z","shell.execute_reply.started":"2024-06-15T03:26:11.464534Z","shell.execute_reply":"2024-06-15T03:26:22.855529Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#kiểm tra trực quan để đảm bảo rằng các danh mục của biến mục tiêu được cân bằng, điều này rất quan trọng để xây dựng các mô hình học máy.\n\nax = sns.countplot(x=y_train, color='#4895EE')\nax.set(\n    title='Target distribution is balanced? Yes!',\n    xlabel='Label'\n)\n\n_ = ax.axhline(y=4200, color='#12086F', linestyle='--')","metadata":{"_uuid":"cd488e69-2d9d-4209-ac52-f11e13ab443b","_cell_guid":"d681064d-2dbe-4c2b-8075-9ce2c254d755","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:22.858318Z","iopub.execute_input":"2024-06-15T03:26:22.858751Z","iopub.status.idle":"2024-06-15T03:26:23.266795Z","shell.execute_reply.started":"2024-06-15T03:26:22.858708Z","shell.execute_reply":"2024-06-15T03:26:23.265683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Dựa vào biểu đồ sau khi trực quan ta có thể thấy rằng các chúng được phân chia 1 cách khác cân bằng điều này cho ta thấy bộ dữ liệu khá tốt và có thể tiến hành các bước xử lý dữ liệu tiếp theo,điều này giúp chúng ta yên tâm hơn về phương pháp lấy mẫu và sai lệch của mô hình khi ta dự đoán.","metadata":{}},{"cell_type":"code","source":"#thực hiện trực quan hóa một hình ảnh từ mỗi lớp trong tập dữ liệu(0-9),mỗi hình có ô 2x5,mỗi ô hiển thị một hình ảnh từ một lớp khác, cùng với nhãn lớp tương ứng.\n#Hình ảnh được định hình lại thành 28x28 pixel\n\nfig, axs = plt.subplots(nrows=2, ncols=5, figsize=(10,5))\n\nfor i in range(10):\n    idx = np.where(y_train==i)[0][2]\n    img = axs[int(i >= 5), i%5].imshow(\n        X=X_train[idx].reshape(28, 28),\n        cmap='Blues'\n    )\n    img.axes.get_yaxis().set_visible(False)\n    img.axes.get_xaxis().set_visible(False)\n    img.axes.set_title(f'Label: {i}')","metadata":{"_uuid":"9d6c909c-609f-4b5d-a907-2d75a3c17401","_cell_guid":"1fa8f38f-f989-4007-86c5-590612877157","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:26:23.270533Z","iopub.execute_input":"2024-06-15T03:26:23.270931Z","iopub.status.idle":"2024-06-15T03:26:23.758872Z","shell.execute_reply.started":"2024-06-15T03:26:23.270895Z","shell.execute_reply":"2024-06-15T03:26:23.757789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# transform data","metadata":{"_uuid":"dd9d9d94-7ea8-4f8d-aa91-866959d703e3","_cell_guid":"48cf8b51-1a3e-4d0e-94e5-da53b3aa7c90","trusted":true}},{"cell_type":"code","source":"# -------------------------------------------------- Khai báo\nnumRotate_prior = 15\nangleOffset_prior = -10\nangleRange_prior = 120\n\nX_train_pick2rotate = {\n    'index': np.array([2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,\n                      2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,\n                      2242,2243,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,\n                      2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,\n                      2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299]),\n    'offset': np.array([\n        [0,14,0,-15,0,25,-35,0,17,25],\n        [0,12,-17,32,24,4,-45,0,-5,0],\n        [10,18,0,-20,0,0,10,0,25,0],\n        [45,10,-5,0,0,25,-15,0,-5,-10],\n        [0,10,0,7,10,10,0,0,20,20],\n        [0,13,0,0,10,15,-25,0,4,0],\n        [0,-2,0,-15,0,25,5,0,20,-15],\n        [0,2,-20,-3,-10,15,-45,0,-10,10],\n        [10,38,0,-12,40,0,10,0,20,0],\n        [45,20,-10,-42,0,0,-15,0,5,20],\n        [0,27,0,-16,10,62,-25,0,20,0],\n        \n        [0,-5,0,3,10,10,10,0,14,5],\n        [0,12,5,18,24,22,-45,-10,10,3],\n        \n        [10,-12,0,11,8,0,2,0,10,-8],\n        [45,13,-16,-10,0,10,-15,0,0,10],\n#---------------------------------\n        [0,-5,0,0,10,10,-25,0,10,0],\n        [0,20,0,0,10,10,-25,15,10,30],\n        [0,12,-20,32,24,0,0,0,-3,10],\n        [14,24,0,0,0,0,10,0,18,20],\n        [45,15,10,0,15,0,-25,0,29,40],\n        \n        [17,15,0,0,10,10,25,0,20,0],\n        [0,12,0,0,10,10,-52,0,20,0],\n        [0,6,-20,10,9,12,-45,30,10,10],\n        [10,5,13,0,20,0,-22,0,20,13],\n        [45,18,0,3,0,12,-47,0,5,0],\n        \n        [0,13,0,-12,10,10,-25,0,12,0],\n        [0,5,7,0,40,10,-25,0,20,0],\n        [0,20,8,32,24,0,-45,0,10,10],\n        [10,5,0,0,30,15,-48,18,10,0],\n        [45,10,10,30,0,0,5,0,10,13],\n        \n        [0,30,0,0,10,10,-25,0,12,8],\n        [0,-5,0,0,10,10,-5,0,12,14],\n        [0,14,0,-15,20,25,-35,0,17,25],\n        [0,20,5,24,-4,19,15,0,25,0],\n        [10,18,0,-20,20,17,10,12,25,10],\n        \n        [45,2,25,8,25,25,-15,0,-5,-10],\n        [0,18,23,27,10,10,0,20,9,20],\n        [0,13,20,20,10,35,-37,0,4,60],\n        [0,16,20,0,20,15,5,0,10,5],\n        [0,34,12,-11,22,15,0,0,10,10],\n        \n        [10,8,20,18,20,0,-5,0,2,0],\n        [45,20,25,-30,18,0,-15,0,20,20],\n        [0,14,20,5,0,25,-35,0,17,25],\n        [0,12,3,32,24,4,-45,0,-15,15],\n        [10,18,0,0,0,10,10,0,20,0],\n        \n        [45,10,-5,0,20,25,-5,0,21,20],\n        [0,10,0,17,10,10,0,0,20,20],\n        [0,13,0,0,10,15,5,0,4,30],\n        [0,19,18,3,0,25,5,20,20,-15],\n        [0,2,25,27,10,15,25,0,2,10],\n        #-----------------50--------------\n        [10,20,12,-12,30,0,-10,0,20,0],\n        [45,20,10,-27,0,10,-15,15,5,20],\n        [0,24,8,-15,0,25,15,0,17,10],\n        [0,24,-17,22,24,34,0,30,5,0],\n        [10,18,0,0,20,10,10,0,25,0],\n        #-----------------55--------------\n        [45,23,25,0,10,25,-15,0,-5,-10],\n        [0,10,20,-12,10,10,-15,0,10,8],\n        [0,13,0,0,10,15,-25,0,4,0],\n        [0,-2,0,0,0,25,-45,0,20,5],\n        [0,2,25,-3,-10,35,-45,10,35,10],\n        #-----------------60--------------\n        [10,15,0,-12,40,15,10,0,20,0],\n        [45,12,20,-22,0,20,-15,0,5,20],\n        [0,6,0,-23,20,25,10,0,17,25],\n        [0,12,3,22,14,4,-45,0,7,0],\n        [10,18,0,-20,0,0,10,0,25,0],\n        #-----------------65--------------\n        [45,27,10,15,10,25,-15,0,10,0],\n        [0,34,5,27,30,30,0,0,10,20],\n        [0,13,0,0,10,15,-25,0,4,0],\n        [0,-2,0,-15,20,25,5,20,20,-15],\n        [0,2,0,-3,20,15,0,0,-10,10],\n        #-----------------70--------------\n        [10,-4,0,-12,40,12,0,0,20,0],\n        [45,20,5,-24,0,0,-15,20,5,20],\n        [0,14,0,-15,0,25,-35,20,17,25],\n        [0,12,3,32,14,14,-15,0,-5,0],\n        [10,30,0,-20,20,20,10,0,10,20],\n        #-----------------75--------------\n        [45,10,5,0,17,25,-15,0,-15,-10],\n        [0,30,15,7,20,37,20,15,40,20],\n        [0,33,20,10,10,35,-25,10,4,0],\n        [0,18,20,5,15,25,5,0,0,-15],\n        [0,12,0,22,45,45,-15,20,-10,30],\n        #-----------------80--------------\n        [-5,33,0,-12,10,15,10,0,10,35],\n        [45,5,10,-22,10,45,-15,0,5,20],\n        [45,20,0,-22,0,40,-15,0,5,20],\n        [45,20,0,48,0,0,-15,0,5,20],\n        [45,20,-10,-2,17,0,-15,0,-5,20],\n        #-----------------85--------------\n        [0,20,-10,2,0,40,-15,0,5,20],\n        [10,20,-10,18,30,20,-15,20,5,20],\n        [45,20,20,-12,30,30,5,20,15,20],\n        [5,20,10,-22,12,20,25,10,5,20],\n        [4,40,7,0,10,0,-15,0,-5,20],\n        #-----------------90--------------\n        [45,20,20,-22,30,30,5,0,-5,20],\n        [11,-8,5,0,30,25,-15,0,30,10],\n        [0,10,0,7,40,10,0,20,20,20],\n        [0,13,20,0,40,30,-25,30,4,0],\n        [0,38,0,15,20,25,5,0,20,15],\n        #-----------------95--------------\n        [0,2,-10,10,10,25,-45,20,20,10],\n        [45,20,10,-12,40,10,-15,20,-5,20],\n        [14,35,10,-22,10,20,-15,10,35,20],\n        [20,38,10,3,0,30,-15,40,5,20],\n    ])\n}\n\nnumPickRotate = len(X_train_pick2rotate['index'])\n\nprint('numPickRotate = ', numPickRotate)\n\n# -------------------------------------------------- rotate\nX_sample_rotate = np.zeros((10,numRotate_prior,numPickRotate,X_train.shape[1]))\ny_sample_rotate = np.zeros((10,numRotate_prior,numPickRotate))\n\nfor k0 in range(10):\n    for k1 in range(numRotate_prior):\n        for k2 in range(numPickRotate):\n            \n                idxPick_X_train = X_train_pick2rotate['index'][k2]\n                \n                idx = np.where(y_train==k0)[0][idxPick_X_train]\n                \n                y_sample_rotate[k0,k1,k2] = k0\n                \n                angleRotate = (k1/numRotate_prior * angleRange_prior) + angleOffset_prior + X_train_pick2rotate['offset'][k2][k0]\n                \n                X_sample_rotate[k0,k1,k2,:] = func_array1d_rotate2d(X_train[idx][np.newaxis,:],angleRotate, 28)\n\n                \nX_sample_rotate[X_sample_rotate < 10] = 0\n#X_sample_rotate[X_sample_rotate > 300] = 0\n\nprint(\"Before applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_sample_rotate.min())\nprint(\"  - Maximum value:\", X_sample_rotate.max())\n\nminmax_scaler = MinMaxScaler()\n\nfor k0 in range(10):\n    for k1 in range(numRotate_prior):\n        X_sample_rotate[k0,k1,:,:] = minmax_scaler.fit_transform(X_sample_rotate[k0,k1,:,:]) * 255\n\nprint(\"\\nAfter applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_sample_rotate.min())\nprint(\"  - Maximum value:\", X_sample_rotate.max())\n\nfor k2 in range(numPickRotate):\n# for k2 in range(5,10):\n    k1 = 0\n    #k1 = numRotate_prior - 1\n\n    fig, axs = plt.subplots(nrows=2, ncols=5, figsize=(10,5))\n\n    for k0 in range(10):\n        img = axs[int(k0 >= 5), k0%5].imshow(\n            X=X_sample_rotate[k0,k1,k2,:].reshape(28, 28),\n            cmap='Blues'\n        )\n        img.axes.get_yaxis().set_visible(False)\n        img.axes.get_xaxis().set_visible(False)\n        img.axes.set_title(f'Label: {k0}')\n        \nX_train_rotate = np.reshape(X_sample_rotate, (-1,784))\ny_train_rotate = np.reshape(y_sample_rotate, (-1,1)).flatten()\n","metadata":{"_uuid":"2fd8cd6b-8db8-45dc-b5f7-6721c80f11fd","_cell_guid":"6b163e1f-7fee-43a6-b6f6-40c0d402a4fc","jupyter":{"outputs_hidden":false},"collapsed":false,"execution":{"iopub.status.busy":"2024-06-15T03:26:23.760919Z","iopub.execute_input":"2024-06-15T03:26:23.761386Z","iopub.status.idle":"2024-06-15T03:27:16.194550Z","shell.execute_reply.started":"2024-06-15T03:26:23.761341Z","shell.execute_reply":"2024-06-15T03:27:16.193306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"---------\n# Phần 3: Phân tích thành phần chính","metadata":{"_uuid":"f67ae6c7-11f8-4b88-a23e-bf62fb9fdb43","_cell_guid":"6e9093b4-f586-4545-b99e-b59d492b7958","trusted":true}},{"cell_type":"markdown","source":"<div style=\"border-radius: 10px; border: #4361EE solid; padding: 15px; background-color: #ffffff00; font-size: 100%; text-align: left;\">\n    - PCA là một kỹ thuật thống kê giúp giảm số chiều của tập dữ liệu bằng cách biến đổi tuyến tính dữ liệu vào một hệ tọa độ mới mà sự biến thiên trong dữ liệu có thể được mô tả bằng ít chiều hơn so với dữ liệu ban đầu.<br> - PCA tìm hướng tối đa hóa phương sai của dữ liệu chiếu.<br><i>Trong trường hợp này, chúng ta sử dụng 10 thành phần chính hàng đầu, giải thích gần 50% phương sai trong dữ liệu, giảm kích thước đặc trưng từ 784 xuống còn 10.</i>\n</div>","metadata":{"_uuid":"c9145741-6e7a-4419-bdb0-baca414ed4e7","_cell_guid":"54390ba7-75cb-4867-b577-97f23c85d6f2","trusted":true}},{"cell_type":"code","source":"# chuẩn hóa các giá trị pixel trong tập X_train_rotate ở khoảng [0, 1] bằng cách sử dụng MinMax Scaler\n# sau đó in ra giá trị trước và sau khi áp dụng MinMax Scaler \n# việc sử dụng MinMax Scaler sẽ giúp ta đưa các giá trị pixel về một giá trị chuẩn giúp huấn luyện mô hình hiệu quả hơn \n\n\nprint(\"Before applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_train.min())\nprint(\"  - Maximum value:\", X_train.max())\n\nminmax_scaler = MinMaxScaler()\nX_train_rotate_scaled = minmax_scaler.fit_transform(X_train_rotate)\n\nprint(\"\\nAfter applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_train_rotate_scaled.min())\nprint(\"  - Maximum value:\", X_train_rotate_scaled.max())","metadata":{"_uuid":"aad53bf6-9b1f-4451-844d-ae51f509a68f","_cell_guid":"2f528db2-3b92-425b-a18c-2168dd8862d7","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:16.196253Z","iopub.execute_input":"2024-06-15T03:27:16.197519Z","iopub.status.idle":"2024-06-15T03:27:16.366637Z","shell.execute_reply.started":"2024-06-15T03:27:16.197472Z","shell.execute_reply":"2024-06-15T03:27:16.365553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# bây giờ sẽ hiện thực hiện kết hợp MinMaxScaler và PCA vào một luồng xử lý liên tục bằng Sklearn Pipeline.\n# và PCA với số lượng thành phần chính được chỉnh định là 40.\n\npca = Pipeline(steps=[\n    ('scaler', MinMaxScaler()),\n    ('pca', PCA(n_components=100))\n])\n\nX_train_rotate_pca = pca.fit_transform(X=X_train_rotate)\n\nprint('X_train_pca shape:', X_train_rotate_pca.shape)","metadata":{"_uuid":"6cae5170-3af3-4ed9-a9d8-372ef224e9ba","_cell_guid":"e423b865-ef1d-4c48-9152-917f8b258060","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:16.368149Z","iopub.execute_input":"2024-06-15T03:27:16.368580Z","iopub.status.idle":"2024-06-15T03:27:18.387061Z","shell.execute_reply.started":"2024-06-15T03:27:16.368539Z","shell.execute_reply":"2024-06-15T03:27:18.385643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# sau khi đã thực hiện Sklearn Pipeline ở trên thì giờ sẽ tiến hình rút trích tỉ lệ phương sai trong các thành chính đã được xây dựng trước đó.\n\npca_object = pca.named_steps['pca']\nvar_ratio = pd.Series(\n    data=pca_object.explained_variance_ratio_,\n    index=range(1, 101)\n)\n\ncumsum_var_ratio = var_ratio.cumsum()","metadata":{"_uuid":"68b1ffab-f2de-43fe-a655-e04c6060ec60","_cell_guid":"c3cdf97b-6136-45e0-94c6-bdf23e750bf0","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:18.388744Z","iopub.execute_input":"2024-06-15T03:27:18.389211Z","iopub.status.idle":"2024-06-15T03:27:18.402013Z","shell.execute_reply.started":"2024-06-15T03:27:18.389171Z","shell.execute_reply":"2024-06-15T03:27:18.400587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Giờ chúng ta sẽ thực hiện trực quan hóa hai biểu đồ:\n# bên trái sẽ là tỉ lệ phương sai được giải thích cho từng thành phần.\n# bên phải sẽ là tổng tích lũy tỉ lệ phương sai.\n# biểu đồ trực quan thể hiện được mức độ biến thiên trên từng thành phần chính và mức độ tổng hợp của nó.\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,5))\n\nsns.barplot(\n    x=var_ratio.index, \n    y=var_ratio.values, \n    color='#4895EE', \n    ax=ax1\n)\nax1.set(\n    title='Explained Variance Ratio PCA',\n    xlabel='Component',\n    ylabel='Var Ratio',\n)\nax1.set_ylim(0, 0.5)\n\nsns.barplot(\n    x=cumsum_var_ratio.index, \n    y=cumsum_var_ratio.values, \n    color='#4895EE', \n    ax=ax2\n)\nax2.set(\n    title='Cumulative Explained Variance Ratio PCA',\n    xlabel='Component',\n    ylabel='Cumulative Var Ratio',\n)\n_ = ax2.set_ylim(0, 0.5)","metadata":{"_uuid":"9ea36679-af0c-40f1-bda2-641ef9c73a4e","_cell_guid":"6fe44c61-1ac9-4157-968d-022d42184ff6","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:18.403572Z","iopub.execute_input":"2024-06-15T03:27:18.404011Z","iopub.status.idle":"2024-06-15T03:27:21.943000Z","shell.execute_reply.started":"2024-06-15T03:27:18.403971Z","shell.execute_reply":"2024-06-15T03:27:21.941852Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Thực hiện chuyển đổi từ ma trận sang DataFrame với mục đích là sử dụng cho việc trực quan hóa và nó được biểu diễn bởi 3 cột x y z\n\ndf_train_pca = pd.DataFrame(\n    data=X_train_rotate_pca[:,:3], \n    columns=['x', 'y', 'z']\n)\ndf_train_pca['target'] = y_train_rotate\n\nprint(df_train_pca.shape)\ndf_train_pca.head()","metadata":{"_uuid":"9796e066-c6af-49c5-af8f-8ebde5e07430","_cell_guid":"4fb22220-cc87-410b-a637-55bc57791987","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:21.944632Z","iopub.execute_input":"2024-06-15T03:27:21.945153Z","iopub.status.idle":"2024-06-15T03:27:21.962264Z","shell.execute_reply.started":"2024-06-15T03:27:21.945110Z","shell.execute_reply":"2024-06-15T03:27:21.961050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# sử dụng seaborn để trực quan biểu đồ phân tán 2 chiều với mục đích hiển thị dữ liệu sau khi đã giảm chiều bằng PCA\n\n\nsns.set_style(\"dark\")\nax = sns.scatterplot(\n    data=df_train_pca,\n    x='x', \n    y='y', \n    hue='target', \n    palette='Blues',\n)\nax.set(\n    title='PCA Two-Dimensional Projection',\n    xlabel='1st Comp.',\n    ylabel='2nd Comp.'\n)\nax.axhline(y=0, linestyle='--', color='#FFBF00', zorder=-1)\nax.axvline(x=0, linestyle='--', color='#FFBF00', zorder=-1)","metadata":{"_uuid":"30135dee-d7d0-4dc8-88f7-3a88a135ad5a","_cell_guid":"147fd5ee-e632-4611-b6de-35d64c6946e9","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:21.964104Z","iopub.execute_input":"2024-06-15T03:27:21.964611Z","iopub.status.idle":"2024-06-15T03:27:24.161880Z","shell.execute_reply.started":"2024-06-15T03:27:21.964570Z","shell.execute_reply":"2024-06-15T03:27:24.160727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sử dụng inverse_transform từ đối tượng PCA để tính toán xấp xỉ của các hình ảnh dựa trên 10 thành phần chính. \n\n\npca_object = pca.named_steps['pca']\n\nfig, axs = plt.subplots(nrows=10, ncols=2, figsize=(6,20))\n\nfor i in range(10):\n    idx = np.where(y_train==i)[0][0]\n    original_img = axs[i, 0].imshow(\n        X=X_train_rotate[idx].reshape(28, 28),\n        cmap='Blues'\n    )\n    original_img.axes.get_yaxis().set_visible(False)\n    original_img.axes.get_xaxis().set_visible(False)\n    original_img.axes.set_title(f'Original [{i}]:')\n    \n    approx_img_ = pca_object.inverse_transform(X=X_train_rotate_pca[idx])\n    approx_img = axs[i, 1].imshow(\n        X=approx_img_.reshape(28, 28),\n        cmap='Blues'\n    )\n    approx_img.axes.get_yaxis().set_visible(False)\n    approx_img.axes.get_xaxis().set_visible(False)\n    approx_img.axes.set_title(f'Approximation [{i}]:')","metadata":{"_uuid":"77146579-275e-4359-8ec9-7d175da30220","_cell_guid":"329c95b3-2406-402c-b1f8-38487c4fa2f3","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:24.163509Z","iopub.execute_input":"2024-06-15T03:27:24.163926Z","iopub.status.idle":"2024-06-15T03:27:25.114453Z","shell.execute_reply.started":"2024-06-15T03:27:24.163883Z","shell.execute_reply":"2024-06-15T03:27:25.113319Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tính toán và hiển thị ma trận tương quan giữa các thành phần chính đã được giảm chiều bởi PCA\n# giúp chúng ta kiểm tra và xác nhận rằng các thành phần chính từ PCA là không tương quan.\n\ncorr = np.corrcoef(x=X_train_rotate_pca, rowvar=False)\ncorr = np.around(corr, decimals=2)\n\nax = sns.heatmap(\n    data=corr, \n    vmax=1, \n    vmin=-1,\n    square=True,\n    linewidths=.5,\n    annot=True,\n    cmap='Blues',\n)\n\n_ = ax.set(\n    title='Correlation PCA Components [Uncorrelated]',\n    xlabel='Components',\n    ylabel='Components'\n)","metadata":{"_uuid":"8c3fa8bb-61ab-43dc-bc7e-e5fecc13e6e2","_cell_guid":"ab321270-3628-423b-8fd6-a7ebaf6ccfe5","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:25.115902Z","iopub.execute_input":"2024-06-15T03:27:25.116322Z","iopub.status.idle":"2024-06-15T03:27:49.137879Z","shell.execute_reply.started":"2024-06-15T03:27:25.116280Z","shell.execute_reply":"2024-06-15T03:27:49.136606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"----\n# Phần 4: Sử dụng K-Nearest Neighbors Classifier phân loại 10 thành phần chính hàng đầu từ PCA.","metadata":{"_uuid":"3d69b1a4-faf3-4405-b740-9d5fc82b8424","_cell_guid":"16cefed3-22ad-4c84-ad87-230ed47df34d","trusted":true}},{"cell_type":"markdown","source":"<div style=\"border-radius: 10px; border: #4361EE solid; padding: 15px; background-color: #ffffff00; font-size: 100%; text-align: left;\">\n<li>Thuật toán K-Nearest Neighbors (KNN) là một thuật toán phân loại phi tham số, có giám sát, sử dụng sự gần gũi để thực hiện việc phân loại hoặc dự đoán về việc nhóm hóa của một điểm dữ liệu cá nhân. Để dự đoán, một nhãn lớp được gán dựa trên việc bỏ phiếu đa số, tức là nhãn lớp xuất hiện nhiều nhất xung quanh một điểm dữ liệu đã cho.</li>\n<li>Trong phần này, đầu vào của Bộ phân loại K-Nearest Neighbors (KNN) sẽ là 10 thành phần chính hàng đầu từ PCA.</li>\nsklearn.neighbors.KNeighborsClassifier: Bộ phân loại thực hiện bỏ phiếu của k láng giềng gần nhất. Ta sẽ chạy một GridSearchCV để tối ưu hóa siêu tham số n_neighbors.\n</div>","metadata":{"_uuid":"1abd82c5-f4e1-4142-acb2-bea45e42488e","_cell_guid":"b9e0603d-4dc8-4761-baad-a34cf6709975","trusted":true}},{"cell_type":"markdown","source":"---\n#  mô hình học máy trên tập dữ liệu Train","metadata":{"_uuid":"334a6d45-a6b2-499e-a95b-2477800b968f","_cell_guid":"e1b5a3d3-ced9-409c-b6f9-b07e7143bc66","trusted":true}},{"cell_type":"code","source":"knn_clf = Pipeline(steps=[\n    ('scaler', MinMaxScaler()),\n    ('pca', PCA(n_components=70)),\n    ('knn', KNeighborsClassifier())\n])\n\nknn_clf_params = {\n    'knn__n_neighbors': [2, 4, 8, 16, 32]\n}\n\nknn_clf_gs = GridSearchCV(\n    estimator=knn_clf, \n    param_grid=knn_clf_params,\n    scoring='accuracy',\n    n_jobs=-1,\n    cv=5,\n    verbose=1,\n    return_train_score=True\n)\n\nknn_clf_gs.fit(X=X_train_rotate_pca, y=y_train_rotate)\n\nprint('best PCA+KNN params:', knn_clf_gs.best_params_)\nprint('best PCA+KNN cv accuracy:', knn_clf_gs.best_score_)","metadata":{"_uuid":"7154a244-1406-4e55-9062-2a876ffcfb42","_cell_guid":"f8b23485-498b-446c-83a4-fdf1e50b8285","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:27:49.139427Z","iopub.execute_input":"2024-06-15T03:27:49.139840Z","iopub.status.idle":"2024-06-15T03:28:19.570748Z","shell.execute_reply.started":"2024-06-15T03:27:49.139805Z","shell.execute_reply":"2024-06-15T03:28:19.569016Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Xây dựng mô hình tìm ra tham số tốt nhất cho KNN sau khi đã giảm chiều dữ liệu bằng PCA và chuẩn hóa MinMaxScaler\n- sau khi tìm kiếm sẽ trả về cho ta tham số và độ chính xác tốt nhất,giúp tối ưu hóa mô hình KNN có thể đạt tới khả năng phân loại tốt nhất.","metadata":{}},{"cell_type":"code","source":"# Tiếp tục trực quan hóa ẽ biểu đồ thể hiện độ chính xác của mô hình trên tập huấn luyện và tập validation cho mỗi giá trị tham số n_neighbors đã thử nghiệm trong quá trình Grid Search.\n# Biểu đồ này giúp chúng ta xác định liệu có sự chênh lệch đáng kể giữa độ chính xác trên tập huấn luyện và tập validation không, từ đó đánh giá xem mô hình có bị overfitting không,để có thể chọn được n_neighbors tối ưu nhất\n\nfig, ax = plt.subplots()\n\nax.plot(\n    range(len(knn_clf_params['knn__n_neighbors'])), \n    knn_clf_gs.cv_results_['mean_train_score'],\n    label='train',\n    color='blue'\n)\nax.plot(\n    range(len(knn_clf_params['knn__n_neighbors'])),\n    knn_clf_gs.cv_results_['mean_test_score'],\n    label='test',\n    color='orange'\n)\nax.set_xticks(\n    ticks=range(len(knn_clf_params['knn__n_neighbors'])),\n    labels=knn_clf_params['knn__n_neighbors']\n)\n\nii = knn_clf_params['knn__n_neighbors'].index(\n    knn_clf_gs.best_params_['knn__n_neighbors']\n)\n\nplt.axvline(x=ii, linestyle='--', color='red', label='best', alpha=0.3)\nplt.legend()\nplt.xlabel(\"'n_neighbors' vals\")\nplt.ylabel('Accuracy')\nplt.title(\"PCA+KNN GridSearchCV Results\")\nplt.show()","metadata":{"_uuid":"43e1d701-a89a-463f-b860-3afbf14bbf36","_cell_guid":"b1316942-7e1c-4f06-8742-d3eb8f7918c3","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:19.574337Z","iopub.execute_input":"2024-06-15T03:28:19.576487Z","iopub.status.idle":"2024-06-15T03:28:19.932987Z","shell.execute_reply.started":"2024-06-15T03:28:19.576425Z","shell.execute_reply":"2024-06-15T03:28:19.931823Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"---\n# Phần 5: Tạo một tệp tin chứa các dự đoán của mô hình học máy trên tập dữ liệu Test","metadata":{"_uuid":"b609f283-8a5c-477c-9c29-941acfedc9aa","_cell_guid":"5d9eb764-a90a-48b5-b962-be1b347e4925","trusted":true}},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score\n\n# tính toán và trực quan Confusion Matrix\n# Note: sử dụng toàn bộ tập train\n\nX_val = X_train_rotate_pca\nY_val = y_train_rotate\n\nbest_cv_clf = knn_clf_gs.best_estimator_\ny_pred = best_cv_clf.predict(X=X_val)\n\ny_val_number = Y_val // numRotate_prior\ny_pred_number = y_pred // numRotate_prior\n\ny_val_angle = (Y_val % numRotate_prior)\ny_pred_angle = (y_pred % numRotate_prior)\n\nprint('KNN number + angle, Acc({:.2f}%)', accuracy_score(Y_val, y_pred))\nprint('KNN number, Acc({:.2f}%)', accuracy_score(y_val_number, y_pred_number))\nprint('KNN angle, Acc({:.2f}%)', accuracy_score(y_val_angle, y_pred_angle))\n\n# print('y_val_number =', y_val_number)\n# print('y_pred_number =', y_pred_number)\n\ny_val_angle_degree = y_val_angle/numRotate_prior * angleRange_prior + angleOffset_prior\ny_pred_angle_degree = y_pred_angle/numRotate_prior * angleRange_prior + angleOffset_prior\n\n# print('y_val_angle_degree =', y_val_angle_degree)\n# print('y_pred_angle_degree =', y_pred_angle_degree)\n\nconf_matrix = confusion_matrix(y_val_number, y_pred_number)\nconf_matrix_disp = ConfusionMatrixDisplay(conf_matrix)\nconf_matrix_disp.plot(cmap='Blues')\n\nconf_matrix = confusion_matrix(y_val_angle, y_pred_angle)\nconf_matrix_disp = ConfusionMatrixDisplay(conf_matrix)\nconf_matrix_disp.plot(cmap='Blues')","metadata":{"_uuid":"62d7493a-d5c0-42ca-ad56-df419c3367ee","_cell_guid":"fdfdc4ce-7aa6-4c8a-b7c9-8a069cb98054","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:19.934407Z","iopub.execute_input":"2024-06-15T03:28:19.934745Z","iopub.status.idle":"2024-06-15T03:28:22.618788Z","shell.execute_reply.started":"2024-06-15T03:28:19.934716Z","shell.execute_reply":"2024-06-15T03:28:22.617445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_val = pca.transform(X_train)\nY_val = y_train\n\nbest_cv_clf = knn_clf_gs.best_estimator_\ny_pred = best_cv_clf.predict(X=X_val)\n\ny_pred_number = y_pred\ny_val_number = Y_val\n\nprint('KNN number, Acc({:.2f}%)', accuracy_score(y_val_number, y_pred_number))\n\nconf_matrix = confusion_matrix(y_val_number, y_pred_number)\nconf_matrix_disp = ConfusionMatrixDisplay(conf_matrix)\nconf_matrix_disp.plot(cmap='Blues')\n\ny_pred_angle = (y_pred % numRotate_prior)\n\ny_pred_angle_degree = y_pred_angle/numRotate_prior * angleRange_prior + angleOffset_prior\n\nprint('y_pred_angle_degree =', y_pred_angle_degree)","metadata":{"_uuid":"da419e38-d545-49ee-a8b6-32f3fa9760c3","_cell_guid":"fa5652c2-d596-4880-8396-b6e77177f4ff","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:22.620480Z","iopub.execute_input":"2024-06-15T03:28:22.620929Z","iopub.status.idle":"2024-06-15T03:28:28.278320Z","shell.execute_reply.started":"2024-06-15T03:28:22.620887Z","shell.execute_reply":"2024-06-15T03:28:28.277134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#tiếp tục áp dụng inverse_transform để tính toán \n\npca_object = pca.named_steps['pca']\n\nfig, axs = plt.subplots(nrows=10, ncols=2, figsize=(6,20))\n\nfor i in range(10):\n    idx = np.where(y_train == i )[0][0]\n    original_img = axs[i, 0].imshow(\n        X=X_train[idx].reshape(28, 28),\n        cmap='Blues'\n    )\n    original_img.axes.get_yaxis().set_visible(False)\n    original_img.axes.get_xaxis().set_visible(False)\n    original_img.axes.set_title(f'Original [{i}]:')\n    \n    approx_img_ = pca_object.inverse_transform(X=X_val[idx])\n    approx_img = axs[i, 1].imshow(\n        X=approx_img_.reshape(28, 28),\n        cmap='Blues'\n    )\n    approx_img.axes.get_yaxis().set_visible(False)\n    approx_img.axes.get_xaxis().set_visible(False)\n    approx_img.axes.set_title(f'Predicted angle [{y_pred_angle_degree[idx]}]:')","metadata":{"_uuid":"bc4e4c18-00b8-4441-900b-83786685d798","_cell_guid":"1393d26a-3a87-4a77-a642-c5b68c94fec3","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:28.280039Z","iopub.execute_input":"2024-06-15T03:28:28.280940Z","iopub.status.idle":"2024-06-15T03:28:29.255803Z","shell.execute_reply.started":"2024-06-15T03:28:28.280896Z","shell.execute_reply":"2024-06-15T03:28:29.254661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"text_cell_render border-box-sizing rendered_html\">\n<div style=\"color:white;\n           display:fill;\n           border-radius:5px;\n           background-color:gray;\n           font-size:110%;\n           font-family:Verdana;\n           letter-spacing:0.5px\">\n<h1 style=\"text-align: center;\n           padding: 10px;\n              color:white\">\nLight CNN Classifier\n</h1>\n</div>\n</div>","metadata":{"_uuid":"a1446365-443d-48e8-aa24-514805f2df61","_cell_guid":"f6dca012-b643-484b-8f63-b0e218c6f1e2","trusted":true}},{"cell_type":"markdown","source":"<img src=\"https://taewanmerepo.github.io/2018/01/cnn/head.png\">","metadata":{"_uuid":"5a238d9f-7fbe-4d2a-85c7-b38f1793fe47","_cell_guid":"d606a8da-01ba-4650-b234-842037898d97","trusted":true}},{"cell_type":"markdown","source":"### CNN là một phương pháp rất hiệu quả cho các tác vụ liên quan đến thị giác máy tính.\nMạng nơ-ron tích chập (CNN, hay ConvNet) là một loại mạng nơ-ron nhân tạo (ANN), thường được dùng để phân tích hình ảnh. Chúng còn được gọi là Mạng Nơ-ron Nhân Tạo Bất Biến Dịch Chuyển (SIANN), vì các bộ lọc tích chập trượt dọc theo các đặc trưng đầu vào và tạo ra các phản hồi tương đương với sự dịch chuyển, gọi là bản đồ đặc trưng. Điều bất ngờ là hầu hết các mạng nơ-ron tích chập chỉ tương đương với dịch chuyển, chứ không hoàn toàn bất biến với dịch chuyển. Chúng có nhiều ứng dụng như nhận dạng hình ảnh và video, hệ thống gợi ý, phân loại hình ảnh, phân đoạn hình ảnh, phân tích hình ảnh y tế, xử lý ngôn ngữ tự nhiên, giao diện não-máy tính, và phân tích chuỗi thời gian tài chính.","metadata":{"_uuid":"3f62053b-0364-4ff6-bb7b-5deba2a02280","_cell_guid":"1c349770-f9d8-4f7f-8efb-d87b402f2f10","trusted":true}},{"cell_type":"code","source":"import plotly.express as px\nfrom plotly.offline import init_notebook_mode, iplot\nimport plotly.graph_objects as go\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2024-06-15T03:28:29.257368Z","iopub.execute_input":"2024-06-15T03:28:29.257758Z","iopub.status.idle":"2024-06-15T03:28:29.284145Z","shell.execute_reply.started":"2024-06-15T03:28:29.257725Z","shell.execute_reply":"2024-06-15T03:28:29.283014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_confusion_matrix(cm, labels, title):\n    # cm : confusion matrix list(list)\n    # labels : name of the data list(str)\n    # title : title for the heatmap\n    data = go.Heatmap(z=cm, y=labels, x=labels)\n    annotations = []\n    for i, row in enumerate(cm):\n        for j, value in enumerate(row):\n            annotations.append(\n                {\n                    \"x\": labels[i],\n                    \"y\": labels[j],\n                    \"font\": {\"color\": \"white\"},\n                    \"text\": str(value),\n                    \"xref\": \"x1\",\n                    \"yref\": \"y1\",\n                    \"showarrow\": False\n                }\n            )\n    layout = {\n        \"title\": title,\n        \"xaxis\": {\"title\": \"Predicted value\"},\n        \"yaxis\": {\"title\": \"Real value\"},\n        \"annotations\": annotations\n    }\n    fig = go.Figure(data=data, layout=layout)\n    return fig","metadata":{"execution":{"iopub.status.busy":"2024-06-15T03:28:29.285469Z","iopub.execute_input":"2024-06-15T03:28:29.285839Z","iopub.status.idle":"2024-06-15T03:28:29.293704Z","shell.execute_reply.started":"2024-06-15T03:28:29.285803Z","shell.execute_reply":"2024-06-15T03:28:29.292285Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# from tensorflow.keras.utils import np_utils\nfrom tensorflow.keras import utils\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nfrom tensorflow.keras import datasets, layers, models","metadata":{"execution":{"iopub.status.busy":"2024-06-15T03:28:29.295140Z","iopub.execute_input":"2024-06-15T03:28:29.295495Z","iopub.status.idle":"2024-06-15T03:28:42.316905Z","shell.execute_reply.started":"2024-06-15T03:28:29.295465Z","shell.execute_reply":"2024-06-15T03:28:42.315492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_cnn = X_train_rotate.reshape(-1,28,28,1)\n# X_val = np.array(pca.transform(X_train)).reshape(-1,28,28,1)\ny_train_cnn = utils.to_categorical(np.array(y_train_rotate))\nX_val = X_train.reshape(-1,28,28,1)\nY_val = utils.to_categorical(np.array(y_train))\nprint(\"Shape of y_train_cnn:\", y_train_cnn.shape)  # Nên in ra (14850, 10) nếu có 10 lớp\nprint(\"Shape of Y_val:\", Y_val.shape)  # Nên in ra (số lượng mẫu, 10)\n","metadata":{"_uuid":"17fc4707-d986-4950-b0fe-ac152932ac00","_cell_guid":"0d0efe69-4e03-4204-86d8-3ee2e5125830","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:42.323252Z","iopub.execute_input":"2024-06-15T03:28:42.323985Z","iopub.status.idle":"2024-06-15T03:28:42.332647Z","shell.execute_reply.started":"2024-06-15T03:28:42.323946Z","shell.execute_reply":"2024-06-15T03:28:42.331618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_cnn.shape","metadata":{"execution":{"iopub.status.busy":"2024-06-15T03:28:42.333870Z","iopub.execute_input":"2024-06-15T03:28:42.334182Z","iopub.status.idle":"2024-06-15T03:28:42.372002Z","shell.execute_reply.started":"2024-06-15T03:28:42.334154Z","shell.execute_reply":"2024-06-15T03:28:42.370836Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(layers.Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', \n                 activation ='relu', input_shape = (28,28,1)))\nmodel.add(layers.Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', \n                 activation ='relu'))\nmodel.add(layers.MaxPool2D(pool_size=(2,2)))\nmodel.add(layers.BatchNormalization())\nmodel.add(layers.Dropout(0.25))\nmodel.add(layers.Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(layers.Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(layers.MaxPool2D(pool_size=(2,2), strides=(2,2)))\nmodel.add(layers.BatchNormalization())\nmodel.add(layers.Dropout(0.25))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dense(256, activation = \"relu\"))\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.BatchNormalization())\nmodel.add(layers.Dense(10, activation = \"softmax\"))\n\nmodel.summary()","metadata":{"_uuid":"d30da279-3261-4e97-9b79-6e2a01d703d4","_cell_guid":"43ead369-05c5-4e2d-960c-d5773b8a7f7d","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:42.373394Z","iopub.execute_input":"2024-06-15T03:28:42.373845Z","iopub.status.idle":"2024-06-15T03:28:42.740857Z","shell.execute_reply.started":"2024-06-15T03:28:42.373806Z","shell.execute_reply":"2024-06-15T03:28:42.739812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_path = './best_model.h5'\ncheckpointer = ModelCheckpoint(\n    filepath=model_path,\n    monitor='val_accuracy',\n    verbose=1,\n    mode='max',\n    save_best_only=True)\n\nmodel.compile(loss='categorical_crossentropy',\n             optimizer='adam',\n             metrics=['accuracy'])","metadata":{"_uuid":"d131aa49-918d-43dd-be19-62d3110ca17a","_cell_guid":"db889d42-b8bb-4667-8f07-b831a3fbcf38","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:42.742343Z","iopub.execute_input":"2024-06-15T03:28:42.742765Z","iopub.status.idle":"2024-06-15T03:28:43.586853Z","shell.execute_reply.started":"2024-06-15T03:28:42.742723Z","shell.execute_reply":"2024-06-15T03:28:43.585594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train_cnn, y_train_cnn, validation_data = (X_val, Y_val), epochs=30, batch_size = 128, callbacks=[checkpointer])","metadata":{"_uuid":"620687bc-89d9-40dc-b133-006fef4e7c78","_cell_guid":"cd8420f8-3c35-407f-93de-b1691d1b534f","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-06-15T03:28:43.588403Z","iopub.execute_input":"2024-06-15T03:28:43.588853Z","iopub.status.idle":"2024-06-15T04:02:46.740860Z","shell.execute_reply.started":"2024-06-15T03:28:43.588810Z","shell.execute_reply":"2024-06-15T04:02:46.739542Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"_uuid":"c51476fa-c9d6-4cbc-a5ad-f6ff9706d70e","_cell_guid":"8bdfa1eb-cd3b-4e48-a377-02b2b66506e1","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"text_cell_render border-box-sizing rendered_html\">\n<div style=\"color:white;\n           display:fill;\n           border-radius:5px;\n           background-color:gray;\n           font-size:110%;\n           font-family:Verdana;\n           letter-spacing:0.5px\">\n<h1 style=\"text-align: center;\n           padding: 10px;\n              color:white\">\nSubmit to Leaderboard\n</h1>\n</div>\n</div>","metadata":{"_uuid":"b052fb30-6e45-4c66-87af-ce25efdbe87e","_cell_guid":"739fd7c4-6753-4052-8204-a0038c866f87","trusted":true}}]}