{"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":"ebd546a2-326f-4a93-9042-31cb470d1cc4","_cell_guid":"fe85bd07-ce02-43ce-933f-2d24429c163b","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;\">\nCơ sở dữ liệu <b>MNIST</b> (<i>Modified National Institute of Standards and Technology database</i>) là một cơ sở dữ liệu lớn chứa các <b>chữ số viết tay</b> thường được sử dụng để huấn luyện các hệ thống xử lý hình ảnh khác nhau. Khi các kỹ thuật học máy mới xuất hiện, MNIST vẫn là một tài nguyên đáng tin cậy cho các nhà nghiên cứu và người học.<br><br>\nCác <b>hình ảnh ban đầu</b> đen trắng đã được chuẩn hóa để vừa với một <b>hộp giới hạn 28x28 pixel</b> và được làm mịn, điều này đã giới thiệu các mức xám. Cơ sở dữ liệu MNIST gốc chứa 60.000 hình ảnh huấn luyện và 10.000 hình ảnh kiểm tra, nhưng trong cuộc thi này, chúng ta chỉ được cung cấp <b>42.000 hình ảnh huấn luyện</b> (70%) và <b>18.000 hình ảnh kiểm tra</b> (30%).<br><br>\nCác kỹ thuật <i>tiên tiến nhất</i> để tiếp cận bất kỳ vấn đề Phân loại Hình ảnh nào thường phụ thuộc vào <i>Mạng Nơ-ron Tích chập</i> (Convolutional Neural Networks). Tuy nhiên, vì MNIST là một vấn đề đơn giản, trong sổ tay này, chúng ta sẽ áp dụng các <i>Thuật toán Học máy đơn giản</i> (và chúng ta sẽ đạt được một độ chính xác tốt!).<br><br>\nĐầu tiên, chúng ta sẽ thực hiện <b>Phân tích thành phần chính (PCA)</b> để giảm chiều dữ liệu (từ 784 giá trị pixel xuống còn 10 thành phần chính). Sau đó, chúng ta sẽ chạy thuật toán yêu thích của chúng ta là <b>Thuật toán láng giềng gần nhất (K-Nearest Neighbors)</b>. Kết hợp này đạt được <b>Độ chính xác kiểm tra là 0.9271</b>, điều đó là khá đáng chú ý !!!<br><br>\n<b>Bảng Mục lục:</b>\n<ul>\n    <li>🔎 <b>Đọc & Khám phá Dữ liệu</b> 🔍:<br>\n    - Kiểm tra xem có <i>giá trị còn thiếu</i> không.<br>\n    - Kiểm tra <i>phạm vi</i> của các giá trị pixel.<br>\n    - <i>Hiển thị</i> dữ liệu (Hình ảnh).<br>\n    - Kiểm tra xem mục tiêu có <i>cân bằng</i> không.</li><br>\n    <li>🔶 <b>PCA</b> 🔶:<br>\n        - Giới thiệu thuật toán PCA.<br>\n        - Tiền xử lý (<i>chuẩn hóa</i>) dữ liệu.<br>\n        - Thực hiện thuật toán PCA sử dụng thư viện <code>Sklearn</code>.<br>\n        - Nhúng các module vào một <code>Sklearn Pipeline</code>.<br>\n        - Vẽ đồ thị <i>giải thích phương sai</i> của các thành phần.<br>\n        - Hiển thị hai chiều dữ liệu sử dụng <code>seaborn</code>.<br>\n        - Hiển thị động ba chiều của dữ liệu sử dụng <code>plotly</code>.<br>\n        - Hiển thị <i>biến đổi ngược</i>.<br>\n        - Kiểm tra xem các thành phần có <i>không tương quan</i> không.</li><br>\n    <li>🔶 <b>Bộ phân loại KNN</b> 🔶:<br>\n        - Xây dựng một Bộ phân loại KNN bằng cách sử dụng <code>Sklearn</code>.<br>\n        - Sử dụng kỹ thuật PCA như một <i>trích xuất đặc trưng</i> cho KNN.<br>\n        - Chạy một <i>Tìm kiếm Siêu tham số Bắt kỳ</i> để tối ưu hóa các siêu tham số <code>n_neighbors</code>.<br>\n        - So sánh các chỉ số huấn luyện và xác thực để kiểm tra <i>quá mức</i>.<br>\n        - Vẽ đồ thị <i>Ma trận nhầm lẫn</i>.<br>\n        - Tính toán <i>Báo cáo Phân loại</i>.</li>\n</ul>\n</div>\n","metadata":{"_uuid":"e00355b6-e203-4d64-9600-35f736d67626","_cell_guid":"6c36196c-42f6-4b0c-bfbd-a2d573e6a320","trusted":true}},{"cell_type":"code","source":"## IMPORT THE NECESSARY PYTHON LIBRARIES\n\n# Read & Explore Data\nimport numpy as np  # Nhập thư viện numpy để làm việc với mảng đa chiều và các hàm toán học\nimport pandas as pd  # Nhập thư viện pandas để làm việc với dữ liệu dạng bảng\nimport seaborn as sns  # Nhập thư viện seaborn để vẽ đồ thị thống kê\nimport matplotlib.pyplot as plt  # Nhập thư viện matplotlib để vẽ đồ thị\nfrom sklearn.preprocessing import MinMaxScaler  # Nhập phương thức MinMaxScaler từ thư viện sklearn để chuẩn hóa dữ liệu\n\n# Principal Component Analysis (PCA)\nfrom sklearn.decomposition import PCA  # Nhập phương thức PCA từ thư viện sklearn để thực hiện phân tích thành phần chính\nfrom sklearn.pipeline import Pipeline  # Nhập phương thức Pipeline từ thư viện sklearn để xây dựng một chuỗi các bước xử lý dữ liệu\nimport plotly.express as px \n\n# K-Nearest Neighbor Classifier (KNN)\nfrom sklearn.neighbors import KNeighborsClassifier  # Nhập phương thức KNeighborsClassifier từ thư viện sklearn để xây dựng mô hình phân loại KNN\nfrom sklearn.model_selection import GridSearchCV  # Nhập phương thức GridSearchCV từ thư viện sklearn để tìm kiếm siêu tham số tốt nhất cho mô hình\nfrom sklearn.metrics import classification_report, confusion_matrix, ConfusionMatrixDisplay  # Nhập các phương thức và lớp từ thư viện sklearn để đánh giá mô hình\n\n# VHT\nfrom scipy.ndimage import rotate  # Nhập phương thức rotate từ thư viện scipy.ndimage để xoay hình ảnh\n\n\n\n\n\n","metadata":{"_uuid":"c9f6edfd-588d-4af2-97d8-1073e4883692","_cell_guid":"8d8d769c-d2a0-4558-b63f-86352b4bafb8","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:49:59.937179Z","iopub.execute_input":"2024-05-25T08:49:59.938169Z","iopub.status.idle":"2024-05-25T08:49:59.944492Z","shell.execute_reply.started":"2024-05-25T08:49:59.938132Z","shell.execute_reply":"2024-05-25T08:49:59.943583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# Định nghĩa hàm có tên là func_array1d_rotate2d, nhận ba tham số đầu vào là Narray1d, rotate_angle, và sizePixel\ndef func_array1d_rotate2d(Narray1d, rotate_angle, sizePixel):\n    \n    # Lấy kích thước của mảng Narray1d theo chiều dài và gán cho biến N\n    N = Narray1d.shape[0]\n\n    # Tạo một mảng mới có cùng kích thước với Narray1d và gán giá trị ban đầu là 0. Mảng này sẽ chứa các mảng một chiều sau khi được xoay.\n    Narray1d_rotate = np.zeros(Narray1d.shape)\n    \n    # Bắt đầu một vòng lặp qua các chỉ số từ 0 đến N-1\n    for i in range(N):\n        \n        # Chuyển mảng một chiều tại chỉ số i thành một ma trận hai chiều có kích thước sizePixel x sizePixel\n        image = np.reshape(Narray1d[i, :], (sizePixel, sizePixel))\n        \n        # Xoay hình ảnh image một góc rotate_angle (được tính theo độ) và lưu vào biến rotated_image. Tham số reshape=False cho biết không cần phải điều chỉnh kích thước sau khi xoay.\n        rotated_image = rotate(image, rotate_angle, reshape=False)\n        \n        # Chuyển rotated_image từ ma trận hai chiều thành mảng một chiều\n        rotated_array1d = np.reshape(rotated_image, (1, -1))\n        \n        # Gán mảng một chiều đã được xoay vào hàng thứ i của mảng Narray1d_rotate\n        Narray1d_rotate[i, :] = rotated_array1d\n    \n    # Trả về mảng Narray1d_rotate chứa các mảng một chiều đã được xoay\n    return Narray1d_rotate\n","metadata":{"_uuid":"76ecec72-7aaa-4e9c-9366-c53a6fb1d164","_cell_guid":"f51ca997-1fbb-4259-94ee-5b05b70a035a","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:00.124259Z","iopub.execute_input":"2024-05-25T08:50:00.124653Z","iopub.status.idle":"2024-05-25T08:50:00.132004Z","shell.execute_reply.started":"2024-05-25T08:50:00.124622Z","shell.execute_reply":"2024-05-25T08:50:00.130736Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"----\n Phần 2: Đọc dữ liệu và khai thác dữ liệu","metadata":{"_uuid":"0ff27da2-835c-4122-aca0-9e731f3dc7ea","_cell_guid":"6248d1ca-53a8-45d0-9ab6-9003187ef756","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;\">\nTrong phần này, chúng ta sẽ sử dụng thư viện Python nổi tiếng <code>Pandas</code> để đọc dữ liệu từ các tệp <code>.csv</code>.<br><br>\nChúng ta sẽ trực quan hóa <b>phân phối của các giá trị pixel</b> (biểu đồ tần số) bằng cách sử dụng các thư viện Python <code>Seaborn</code> và <code>Matplotlib</code>. Chúng ta cũng sẽ kiểm tra xem có <b>giá trị còn thiếu</b> không và các <b>lớp mục tiêu có cân bằng</b> không.<br><br>\nCuối cùng, chúng ta sẽ <b>trực quan hóa các hình ảnh</b> bằng cách vẽ một hình ảnh từ mỗi lớp.\n</div>\n","metadata":{"_uuid":"08c1c024-9f04-4d45-80af-6f8b9ed71f30","_cell_guid":"e27a867c-ee7f-4c03-85fd-bec46a9f2fd2","trusted":true}},{"cell_type":"code","source":"\n# Đọc tệp dữ liệu sử dụng Pandas\n# df_train: Dữ liệu dùng để huấn luyện mô hình\n# df_test: Dữ liệu dùng để kiểm tra mô hình\ndf_train = pd.read_csv('/kaggle/input/digit-recognizer/train.csv')  # Đọc tệp train.csv và lưu vào df_train\ndf_test = pd.read_csv('/kaggle/input/digit-recognizer/test.csv')    # Đọc tệp test.csv và lưu vào df_test\n","metadata":{"_uuid":"078702a8-cfea-4f1c-bb0b-1018fea19c2c","_cell_guid":"8b4f5e4b-fc80-473b-bd7a-7e620b412c90","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:00.269132Z","iopub.execute_input":"2024-05-25T08:50:00.269508Z","iopub.status.idle":"2024-05-25T08:50:04.043693Z","shell.execute_reply.started":"2024-05-25T08:50:00.269477Z","shell.execute_reply":"2024-05-25T08:50:04.042727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n\n# In ra kích thước của DataFrame df_train\nprint(\"df_train shape:\", df_train.shape)  # df_train shape: (số hàng, số cột)\n\n# In ra kích thước của DataFrame df_test\nprint(\"df_test shape: \", df_test.shape)   # df_test shape: (số hàng, số cột)\n","metadata":{"_uuid":"ca8aa9af-b761-403d-aa85-a3642ea77c5c","_cell_guid":"ba38193d-5d27-48f6-a7b3-f505b93dfe84","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:04.045622Z","iopub.execute_input":"2024-05-25T08:50:04.045947Z","iopub.status.idle":"2024-05-25T08:50:04.050065Z","shell.execute_reply.started":"2024-05-25T08:50:04.045919Z","shell.execute_reply":"2024-05-25T08:50:04.049394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n\n# Kiểm tra và in ra số lượng giá trị thiếu trong df_train\nprint(\n    \"Missing values in df_train: \", \\\n    df_train.isna().sum().sum()\n)\n\n# Kiểm tra và in ra số lượng giá trị thiếu trong df_test\nprint(\n    \"Missing values in df_test: \", \\\n    df_test.isna().sum().sum()\n)\n","metadata":{"_uuid":"a10fb707-86d3-4a6b-98f0-ace8a866768f","_cell_guid":"7cede701-9df4-4ac1-a358-2c567d72cd67","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:04.051098Z","iopub.execute_input":"2024-05-25T08:50:04.051532Z","iopub.status.idle":"2024-05-25T08:50:04.114402Z","shell.execute_reply.started":"2024-05-25T08:50:04.051505Z","shell.execute_reply":"2024-05-25T08:50:04.113306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Let's have a look at the first five training rows\ndf_train.head()","metadata":{"_uuid":"087da919-79ff-4a00-a357-fdb65381edda","_cell_guid":"cbfdc56f-8ade-4af2-b159-a2f526b273a5","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:04.116588Z","iopub.execute_input":"2024-05-25T08:50:04.116928Z","iopub.status.idle":"2024-05-25T08:50:04.134556Z","shell.execute_reply.started":"2024-05-25T08:50:04.116898Z","shell.execute_reply":"2024-05-25T08:50:04.133077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Phân chia dữ liệu thành dữ liệu đầu vào (X_train) và nhãn (y_train)\n\n# Dữ liệu đầu vào (X_train): Là các cột trong DataFrame df_train ngoại trừ cột 'label'. .values chuyển đổi DataFrame thành mảng NumPy.\nX_train = df_train.drop(columns=['label']).values  \n\n# Nhãn (y_train): Là cột 'label' trong DataFrame df_train. .values chuyển đổi Series thành mảng NumPy.\ny_train = df_train['label'].values  \n","metadata":{"_uuid":"2aefa02a-2611-42d1-9764-6ab390b73c0b","_cell_guid":"ccfff756-d687-424c-877d-028bb3180a59","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:04.136275Z","iopub.execute_input":"2024-05-25T08:50:04.136684Z","iopub.status.idle":"2024-05-25T08:50:04.224437Z","shell.execute_reply.started":"2024-05-25T08:50:04.136643Z","shell.execute_reply":"2024-05-25T08:50:04.223431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Vẽ biểu đồ phân phối của các giá trị pixel\n\n# sns.histplot(): Tạo biểu đồ histogram sử dụng thư viện Seaborn (sns).\n# Biểu đồ sẽ có trục x là các giá trị pixel, được trải ra bằng cách sử dụng .flatten() để làm phẳng ma trận 2D thành mảng 1D.\n# Các giá trị pixel được hiển thị bằng màu xanh dương '#4895EE'.\nax = sns.histplot(x=X_train.flatten(), color='#4895EE')\n\n# Thiết lập tiêu đề và nhãn trục x cho biểu đồ\n_ = ax.set(title='Pixel Value Histogram', xlabel='Pixel Value')\n\n# Ghi chú: '_ =' được sử dụng để lưu trữ kết quả của hàm set() nhưng không cần thiết lập một biến tên. \n","metadata":{"_uuid":"7a976629-a208-4444-970a-6f990f01b730","_cell_guid":"f8a9174d-c11e-4467-8dcd-bba2e0d51ac3","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:04.225828Z","iopub.execute_input":"2024-05-25T08:50:04.226257Z","iopub.status.idle":"2024-05-25T08:50:15.343817Z","shell.execute_reply.started":"2024-05-25T08:50:04.226225Z","shell.execute_reply":"2024-05-25T08:50:15.342759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Kiểm tra xem nhãn có cân bằng không\n\n# sns.countplot(): Tạo biểu đồ đếm sử dụng Seaborn (sns), đếm số lượng mẫu cho mỗi nhãn và hiển thị trên trục x.\n# Màu của cột được thiết lập thành màu xanh dương '#4895EE'.\nax = sns.countplot(x=y_train, color='#4895EE')\n\n# Thiết lập tiêu đề và nhãn trục x cho biểu đồ\nax.set(\n    title='Target distribution is balanced? Yes!',\n    xlabel='Label'\n)\n\n# Vẽ đường ngang tại giá trị kỳ vọng của số lượng mẫu trong mỗi lớp\n# Số lượng mẫu kỳ vọng cho một phân phối cân bằng là 42000/10 = 4200\n_ = ax.axhline(y=4200, color='#12086F', linestyle='--')\n\n# Ghi chú: '_ =' được sử dụng để lưu trữ kết quả của hàm axhline() nhưng không cần thiết lập một biến tên.\n","metadata":{"_uuid":"56cd7484-96d5-4052-a732-31184b3010be","_cell_guid":"31dd96d2-e9fc-4ec8-8027-6182b59bbb56","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:15.345052Z","iopub.execute_input":"2024-05-25T08:50:15.345356Z","iopub.status.idle":"2024-05-25T08:50:15.861113Z","shell.execute_reply.started":"2024-05-25T08:50:15.345329Z","shell.execute_reply":"2024-05-25T08:50:15.860044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Tạo ra một hình vẽ (figure) chứa một lưới hình ảnh với 2 hàng và 5 cột\nfig, axs = plt.subplots(nrows=2, ncols=5, figsize=(10, 5))\n\n# Duyệt qua mỗi lớp (từ 0 đến 9)\nfor i in range(10):\n    # Tìm chỉ mục của một mẫu từ lớp hiện tại (lớp i)\n    idx = np.where(y_train == i)[0][2]\n    \n    # Hiển thị hình ảnh tại chỉ mục đã tìm thấy, với các thiết lập:\n    # cmap='Blues': Sử dụng màu xanh dương để hiển thị hình ảnh\n    img = axs[int(i >= 5), i % 5].imshow(\n        X=X_train[idx].reshape(28, 28),\n        cmap='Blues'\n    )\n    \n    # Ẩn trục y và x\n    img.axes.get_yaxis().set_visible(False)\n    img.axes.get_xaxis().set_visible(False)\n    \n    # Thiết lập tiêu đề cho hình ảnh với nhãn tương ứng (label)\n    img.axes.set_title(f'Label: {i}')","metadata":{"_uuid":"6e57247a-308f-4d8c-b860-3fcca06504e8","_cell_guid":"85fb1afc-211b-4d78-a121-385e208ece49","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:15.862412Z","iopub.execute_input":"2024-05-25T08:50:15.862738Z","iopub.status.idle":"2024-05-25T08:50:16.259671Z","shell.execute_reply.started":"2024-05-25T08:50:15.862709Z","shell.execute_reply":"2024-05-25T08:50:16.258552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"transform data","metadata":{"_uuid":"9d4cd46f-3405-4ee3-a2e3-758b928024b1","_cell_guid":"abe3ee94-93c7-4941-9358-150e526414ec","trusted":true}},{"cell_type":"code","source":"\n\n\n\n\n# -------------------------------------------------- declare\nnumRotate_prior = 1  # Số lượng phép xoay trước\n\nangleOffset_prior = 0  # Góc bắt đầu\nangleRange_prior = 90  # Khoảng góc xoay\n\n# Tạo một từ điển chứa các chỉ mục mẫu để xoay và các giá trị lệch góc cho từng lớp\nX_train_pick2rotate = {\n    'index': np.array([2900, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909,2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959]),  # Chỉ mục mẫu để xoay\n    'offset': np.array([\n    [-10, 20, 0, 0, 30, 20, 10, 0, 0, 0],\n    [50, 30, 0, -20, 0, -5, -10, 10, 10, 10],\n    [10, 15, 30, 0, 0, 0, 10, 0, 20, 0],\n    [45, 10, -20, 0, 0, 0, -15, 0, -35, 0],\n    [0, -5, 0, 0, 10, 10, -25, 0, 20, 0],\n    [0, 12, 0, 0, 5, 20, 0, 0, 0, 0],\n    [0, 20, 0, 0, 0, 0, -80, 0, 10, -10],\n    [0, 0, 0, 0, 0, 20, 0, 0, 0, 10],\n    [0, 0, 0, 0, 90, 0, 0, 0, 0, 0],\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 10],\n        \n    [-10, 0, 0, 0, 10, 0, 0, 0, 0, 0],\n    [50, 20, 0, 0, 0, -5, -10, 0, 10, 10],\n    [10, 5, 0, 0, 0, 0, 10, 0, 20, 0],\n    [45, 10, -20, 0, 0, 0, -15, 0, -35, 0],\n    [0, -5, 0, 0, 10, 10, -25, 0, 20, 0],\n    [0, 12, 0, 0, 5, 20, 0, 0, 0, 0],\n    [0, 20, 0, 0, 0, 0, -80, 0, 10, -10],\n    [0, 0, 0, 0, 0, 20, 0, 0, 0, 10],\n    [0, 0, 0, 0, 90, 0, 0, 0, 0, 0],\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 10],\n        \n    [-10, 0, 0, 0, 10, 0, 0, 0, 0, 0],\n    [50, 20, 0, 0, 0, -5, -10, 0, 10, 10],\n    [10, 5, 0, 0, 0, 0, 10, 0, 20, 0],\n    [45, 10, -20, 0, 0, 0, -15, 0, -35, 0],\n    [0, -5, 0, 0, 10, 10, -25, 0, 20, 0],\n    [0, 12, 0, 0, 5, 20, 0, 0, 0, 0],\n    [0, 20, 0, 0, 0, 0, -80, 0, 10, -10],\n    [0, 0, 0, 0, 0, 20, 0, 0, 0, 10],\n    [0, 0, 0, 0, 90, 0, 0, 0, 0, 0],\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 10],\n        \n    [-10, 0, 0, 0, 10, 0, 0, 0, 0, 0],\n    [50, 20, 0, 0, 0, -5, -10, 0, 10, 10],\n    [10, 5, 0, 0, 0, 0, 10, 0, 20, 0],\n    [45, 10, -20, 0, 0, 0, -15, 0, -35, 0],\n    [0, -5, 0, 0, 10, 10, -25, 0, 20, 0],\n    [0, 12, 0, 0, 5, 20, 0, 0, 0, 0],\n    [0, 20, 0, 0, 0, 0, -80, 0, 10, -10],\n    [0, 0, 0, 0, 0, 20, 0, 0, 0, 10],\n    [0, 0, 0, 0, 90, 0, 0, 0, 0, 0],\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 10],\n        \n    [-10, 0, 0, 0, 10, 0, 0, 0, 0, 0],\n    [50, 20, 0, 0, 0, -5, -10, 0, 10, 10],\n    [10, 5, 0, 0, 0, 0, 10, 0, 20, 0],\n    [45, 10, -20, 0, 0, 0, -15, 0, -35, 0],\n    [0, -5, 0, 0, 10, 10, -25, 0, 20, 0],\n    [0, 12, 0, 0, 5, 20, 0, 0, 0, 0],\n    [0, 20, 0, 0, 0, 0, -80, 0, 10, -10],\n    [0, 0, 0, 0, 0, 20, 0, 0, 0, 10],\n    [0, 0, 0, 0, 90, 0, 0, 0, 0, 0],\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 10],\n        \n    [-10, 0, 0, 0, 10, 0, 0, 0, 0, 0],\n    [50, 20, 0, 0, 0, -5, -10, 0, 10, 10],\n    [10, 5, 0, 0, 0, 0, 10, 0, 20, 0],\n    [45, 10, -20, 0, 0, 0, -15, 0, -35, 0],\n    [0, -5, 0, 0, 10, 10, -25, 0, 20, 0],\n    [0, 12, 0, 0, 5, 20, 0, 0, 0, 0],\n    [0, 20, 0, 0, 0, 0, -80, 0, 10, -10],\n    [0, 0, 0, 0, 0, 20, 0, 0, 0, 10],\n    [0, 0, 0, 0, 90, 0, 0, 0, 0, 0],\n    [0, 0, 0, 0, 0, 0, 0, 0, 0, 10],\n    \n])\n}\n\nnumPickRotate = len(X_train_pick2rotate['index'])  # Số lượng mẫu để xoay\nprint('numPickRotate = ', numPickRotate)  # In ra số lượng mẫu để xoay\n\n# -------------------------------------------------- rotate\n\n# Tạo mảng để lưu trữ mẫu sau khi xoay và nhãn tương ứng\nX_sample_rotate = np.zeros((10, numRotate_prior, numPickRotate, X_train.shape[1]))\ny_sample_rotate = np.zeros((10, numRotate_prior, numPickRotate))\n\n# Duyệt qua từng lớp và mẫu để xoay\nfor k0 in range(10):\n    for k1 in range(numRotate_prior):\n        for k2 in range(numPickRotate):\n            idxPick_X_train = X_train_pick2rotate['index'][k2]  # Chỉ mục mẫu để xoay\n            idx = np.where(y_train == k0)[0][idxPick_X_train]  # Chỉ mục của mẫu trong tập dữ liệu huấn luyện\n\n            y_sample_rotate[k0, k1, k2] = k0  # Lưu nhãn tương ứng\n\n            # Tính góc xoay\n            angleRotate = (k1 / numRotate_prior * angleRange_prior) + angleOffset_prior + X_train_pick2rotate['offset'][k2][k0]\n\n            # Xoay mẫu và lưu vào mảng X_sample_rotate\n            X_sample_rotate[k0, k1, k2, :] = func_array1d_rotate2d(X_train[idx][np.newaxis, :], angleRotate, 28)\n\n# Thực hiện chuẩn hóa giá trị pixel\nX_sample_rotate[X_sample_rotate < 10] = 0  # Đặt các giá trị nhỏ hơn 10 thành 0\n\n# -------------------------------------------------- Normalize pixel values\nprint(\"Before applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_sample_rotate.min())\nprint(\"  - Maximum value:\", X_sample_rotate.max())\n\n# Tạo một MinMaxScaler để chuẩn hóa giá trị pixel về khoảng [0, 255]\nminmax_scaler = MinMaxScaler()\n\n# Duyệt qua từng lớp và mẫu để chuẩn hóa\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\n# In ra giá trị tối thiểu và tối đa sau khi chuẩn hóa\nprint(\"\\nAfter applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_sample_rotate.min())\nprint(\"  - Maximum value:\", X_sample_rotate.max())\n\n# -------------------------------------------------- Visualize rotated images\nfor k2 in range(numPickRotate):\n    # Tạo một lưới hình ảnh để hiển thị hình ảnh từ mỗi lớp sau khi xoay\n    fig, axs = plt.subplots(nrows=2, ncols=5, figsize=(10, 5))\n\n    # Duyệt qua từng lớp và hiển thị hình ảnh\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\n# Reshape dữ liệu để sử dụng trong việc huấn luyện mô hình\nX_train_rotate = np.reshape(X_sample_rotate, (-1, 784))\ny_train_rotate = np.reshape(y_sample_rotate, (-1, 1)).flatten()\n","metadata":{"_uuid":"e87363e6-d051-4009-be4f-a825679930e7","_cell_guid":"db89b71d-4901-4716-9507-e9497e268d74","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:16.261250Z","iopub.execute_input":"2024-05-25T08:50:16.261712Z","iopub.status.idle":"2024-05-25T08:50:44.046197Z","shell.execute_reply.started":"2024-05-25T08:50:16.261680Z","shell.execute_reply":"2024-05-25T08:50:44.045035Z"},"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":"8794e86b-0a44-46a2-8d06-c6186454767d","_cell_guid":"d404fd37-ba51-4a9f-9de3-878c4bb0ad21","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    <b>Phân tích thành phần chính</b> (PCA) là một kỹ thuật thống kê để giảm chiều dữ liệu. Điều này được thực hiện bằng cách <b>biến đổi tuyến tính dữ liệu</b> thành một hệ tọa độ mới trong đó (hầu hết) biến thể trong dữ liệu có thể được mô tả với ít chiều hơn so với dữ liệu ban đầu.<br><br>\n    Phần tử chính thứ nhất cũng có thể được định nghĩa tương đương như một <b>hướng mà tối đa hóa phương sai của dữ liệu đã chiếu</b>. Phần tử chính thứ <i>i</i> có thể được chọn là một hướng vuông góc với các phần tử chính đầu tiên <i>i-1</i> mà tối đa hóa phương sai của dữ liệu đã chiếu.<br><br>\n    <code>sklearn.decomposition.PCA</code>: Giảm chiều dữ liệu tuyến tính bằng cách sử dụng Phân tích Giá trị Đơn vị Suy Biến của dữ liệu để chiếu nó xuống không gian chiều thấp hơn.<br><br>\n    Ở đây, chúng ta sẽ sử dụng <b>10 phần tử chính hàng đầu</b>, giải thích <b>gần 50% phương sai</b> trong dữ liệu. Điều này có nghĩa là chúng ta có thể diễn tả 50% phương sai của dữ liệu với một không gian đặc trưng <b>>98% nhỏ hơn so với ban đầu</b> (10 đặc trưng so với 784 đặc trưng).\n</div>","metadata":{"_uuid":"988c70b6-e9d9-4ae7-b127-921423ab0f0e","_cell_guid":"231a3cf2-1f44-475b-a745-a28f3eb35d1e","trusted":true}},{"cell_type":"code","source":"\n# In ra giá trị tối thiểu và tối đa của dữ liệu huấn luyện trước khi chuẩn hóa\nprint(\"Before applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_train.min())\nprint(\"  - Maximum value:\", X_train.max())\n\n# Tạo một MinMaxScaler để chuẩn hóa dữ liệu\nminmax_scaler = MinMaxScaler()\n\n# Sử dụng MinMaxScaler để chuẩn hóa dữ liệu huấn luyện đã xoay\nX_train_rotate_scaled = minmax_scaler.fit_transform(X_train_rotate)\n\n# In ra giá trị tối thiểu và tối đa của dữ liệu huấn luyện sau khi chuẩn hóa\nprint(\"\\nAfter applying MinMax Scaler:\")\nprint(\"  - Minimum value:\", X_train_rotate_scaled.min())\nprint(\"  - Maximum value:\", X_train_rotate_scaled.max())\n","metadata":{"_uuid":"2f018749-1981-43d6-b1b8-b1716a72e3fb","_cell_guid":"7c68f163-b747-4392-9a1e-8792cb07ccde","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:44.051239Z","iopub.execute_input":"2024-05-25T08:50:44.052095Z","iopub.status.idle":"2024-05-25T08:50:44.110395Z","shell.execute_reply.started":"2024-05-25T08:50:44.052029Z","shell.execute_reply":"2024-05-25T08:50:44.109482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Tạo một Sklearn Pipeline với các bước sau:\n# 1. 'scaler': MinMaxScaler để chuẩn hóa giá trị pixel về khoảng [0, 1].\n# 2. 'pca': PCA (Principal Component Analysis) với số lượng thành phần chính là 10.\npca = Pipeline(steps=[\n    ('scaler', MinMaxScaler()),  # Bước 1: MinMaxScaler\n    ('pca', PCA(n_components=10))  # Bước 2: PCA\n])\n\n# Áp dụng Pipeline lên dữ liệu huấn luyện đã xoay\nX_train_rotate_pca = pca.fit_transform(X=X_train_rotate)\n\n# In ra kích thước của dữ liệu sau khi áp dụng PCA\nprint('X_train_pca shape:', X_train_rotate_pca.shape)\n","metadata":{"_uuid":"4bfc3273-16ce-4a37-93ae-9cf46373e2c4","_cell_guid":"2d2d1d92-8b2d-4b97-af06-40a19024b09e","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:44.111676Z","iopub.execute_input":"2024-05-25T08:50:44.112044Z","iopub.status.idle":"2024-05-25T08:50:44.235872Z","shell.execute_reply.started":"2024-05-25T08:50:44.112004Z","shell.execute_reply":"2024-05-25T08:50:44.234705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# Trích xuất đối tượng PCA từ Pipeline\npca_object = pca.named_steps['pca']\n\n# Tính tỷ lệ phương sai giải thích và lưu vào Series\nvar_ratio = pd.Series(\n    data=pca_object.explained_variance_ratio_,  # Tỷ lệ phương sai giải thích từ PCA\n    index=range(1, 11)  # Chỉ số các thành phần chính\n)\n\n# Tính tổng tích lũy của tỷ lệ phương sai giải thích\ncumsum_var_ratio = var_ratio.cumsum()\n","metadata":{"_uuid":"e551b2e2-ce61-4b14-abca-472ab8f8fa6f","_cell_guid":"8fe76194-de6d-44ef-89b7-489a936a3a12","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:44.242387Z","iopub.execute_input":"2024-05-25T08:50:44.246506Z","iopub.status.idle":"2024-05-25T08:50:44.260257Z","shell.execute_reply.started":"2024-05-25T08:50:44.246455Z","shell.execute_reply":"2024-05-25T08:50:44.259100Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Tạo một lưới biểu đồ với 1 hàng và 2 cột\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))\n\n# Biểu đồ tỷ lệ phương sai giải thích cho từng thành phần (bên trái)\nsns.barplot(\n    x=var_ratio.index,  # Chỉ số của từng thành phần chính\n    y=var_ratio.values,  # Giá trị tỷ lệ phương sai giải thích\n    color='#4895EE',  # Màu của các thanh trong biểu đồ\n    ax=ax1\n)\nax1.set(\n    title='Explained Variance Ratio PCA',  # Tiêu đề của biểu đồ\n    xlabel='Component',  # Nhãn trục x\n    ylabel='Var Ratio',  # Nhãn trục y\n)\nax1.set_ylim(0, 0.5)  # Đặt giới hạn trục y\n\n# Biểu đồ tổng tích lũy của tỷ lệ phương sai giải thích (bên phải)\nsns.barplot(\n    x=cumsum_var_ratio.index,  # Chỉ số của từng thành phần chính\n    y=cumsum_var_ratio.values,  # Giá trị tổng tích lũy của tỷ lệ phương sai giải thích\n    color='#4895EE',  # Màu của các thanh trong biểu đồ\n    ax=ax2\n)\nax2.set(\n    title='Cumulative Explained Variance Ratio PCA',  # Tiêu đề của biểu đồ\n    xlabel='Component',  # Nhãn trục x\n    ylabel='Cumulative Var Ratio',  # Nhãn trục y\n)\n_ = ax2.set_ylim(0, 0.5)  # Đặt giới hạn trục y\n","metadata":{"_uuid":"34ab9680-e976-4c81-bf92-6e9d8a0236bb","_cell_guid":"5e8c9489-629b-45b3-a577-b855fe33869f","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:44.268090Z","iopub.execute_input":"2024-05-25T08:50:44.272320Z","iopub.status.idle":"2024-05-25T08:50:45.043056Z","shell.execute_reply.started":"2024-05-25T08:50:44.272266Z","shell.execute_reply":"2024-05-25T08:50:45.041910Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Tạo một DataFrame Pandas từ các thành phần chính của dữ liệu huấn luyện sau khi PCA\ndf_train_pca = pd.DataFrame(\n    data=X_train_rotate_pca[:, :3],  # Chỉ lấy 3 thành phần chính đầu tiên\n    columns=['x', 'y', 'z']  # Đặt tên cột cho các thành phần chính\n)\n\n# Thêm cột target vào DataFrame để đặt màu\ndf_train_pca['target'] = y_train_rotate\n\n# In ra kích thước của DataFrame và các dòng đầu tiên\nprint(df_train_pca.shape)\ndf_train_pca.head()\n","metadata":{"_uuid":"b779e0bc-6938-424a-9c08-3579404299da","_cell_guid":"8d64a105-5b85-4924-9d4c-d5bc95d474e8","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:45.044443Z","iopub.execute_input":"2024-05-25T08:50:45.044748Z","iopub.status.idle":"2024-05-25T08:50:45.063238Z","shell.execute_reply.started":"2024-05-25T08:50:45.044719Z","shell.execute_reply":"2024-05-25T08:50:45.061962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Đặt kiểu mặc định cho biểu đồ\nsns.set_style(\"dark\")\n\n# Tạo biểu đồ phân tán sử dụng seaborn scatterplot\nax = sns.scatterplot(\n    data=df_train_pca,  # Dữ liệu từ DataFrame Pandas\n    x='x',  # Thành phần chính thứ nhất là trục x\n    y='y',  # Thành phần chính thứ hai là trục y\n    hue='target',  # Sử dụng cột target để đặt màu cho các điểm\n    palette='Blues',  # Sử dụng màu xanh lam từ bảng màu 'Blues'\n)\n\n# Đặt tiêu đề và nhãn cho biểu đồ\nax.set(\n    title='PCA Two-Dimensional Projection',  # Tiêu đề của biểu đồ\n    xlabel='1st Comp.',  # Nhãn trục x\n    ylabel='2nd Comp.'  # Nhãn trục y\n)\n\n# Vẽ các đường đỏ dạng đứt ở trục x và trục y\nax.axhline(y=0, linestyle='--', color='#FFBF00', zorder=-1)\nax.axvline(x=0, linestyle='--', color='#FFBF00', zorder=-1)\n","metadata":{"_uuid":"90d9d1e3-fbcb-400a-b8d5-68d2a5f4f646","_cell_guid":"c05ac3f3-ec1c-4fd0-8e88-cd0991afb146","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:45.064950Z","iopub.execute_input":"2024-05-25T08:50:45.066147Z","iopub.status.idle":"2024-05-25T08:50:47.145651Z","shell.execute_reply.started":"2024-05-25T08:50:45.066105Z","shell.execute_reply":"2024-05-25T08:50:47.144794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n\n\n# Đặt kiểu mặc định cho biểu đồ\nsns.set_style(\"white\")\n\n# Tạo biểu đồ phân tán ba chiều sử dụng plotly express scatter_3d\nfig = px.scatter_3d(\n    data_frame=df_train_pca,  # Dữ liệu từ DataFrame Pandas\n    x='x',  # Thành phần chính thứ nhất là trục x\n    y='y',  # Thành phần chính thứ hai là trục y\n    z='z',  # Thành phần chính thứ ba là trục z\n    labels={  # Nhãn cho các trục\n        'x': '1st Comp.',  # Nhãn cho trục x\n        'y': '2nd Comp.',  # Nhãn cho trục y\n        'z': '3rd Comp.'  # Nhãn cho trục z\n    },\n    color='target',  # Sử dụng cột target để đặt màu cho các điểm\n    title='PCA Three-Dimensional Projection',  # Tiêu đề của biểu đồ\n    color_continuous_scale='blues',  # Bảng màu cho biểu đồ\n    template='ggplot2'  # Giao diện cho biểu đồ\n)\n\n# Hiển thị biểu đồ\nfig.show()\n","metadata":{"_uuid":"1fb19f51-6852-4f02-8660-90a8a537fa30","_cell_guid":"b76b9b11-2a7e-4cc9-983c-0ae311d92428","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:47.146700Z","iopub.execute_input":"2024-05-25T08:50:47.147516Z","iopub.status.idle":"2024-05-25T08:50:47.211284Z","shell.execute_reply.started":"2024-05-25T08:50:47.147485Z","shell.execute_reply":"2024-05-25T08:50:47.210040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Trích xuất đối tượng PCA từ Pipeline\npca_object = pca.named_steps['pca']\n\n# Tạo một lưới hình ảnh với 10 hàng và 2 cột\nfig, axs = plt.subplots(nrows=10, ncols=2, figsize=(6,20))\n\n# Duyệt qua từng lớp và hiển thị hình ảnh gốc và ảnh gần đúng tương ứng\nfor i in range(10):\n    # Chọn một hình ảnh gốc từ mỗi lớp\n    idx = np.where(y_train_rotate==i)[0][0]\n    \n    # Hiển thị hình ảnh gốc\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    # Tính toán và hiển thị ảnh gần đúng sử dụng inverse_transform\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}]:')\n","metadata":{"_uuid":"0d814515-0bec-4c78-af57-09ed84b2dfc4","_cell_guid":"7e42f02f-c973-4898-8c10-80b0ca2d625b","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:47.212467Z","iopub.execute_input":"2024-05-25T08:50:47.212760Z","iopub.status.idle":"2024-05-25T08:50:48.010860Z","shell.execute_reply.started":"2024-05-25T08:50:47.212734Z","shell.execute_reply":"2024-05-25T08:50:48.009739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# Tính ma trận tương quan giữa các thành phần PCA\ncorr = np.corrcoef(x=X_train_rotate_pca, rowvar=False)\ncorr = np.around(corr, decimals=2)\n\n# Vẽ biểu đồ heatmap của ma trận tương quan\nax = sns.heatmap(\n    data=corr,  # Dữ liệu là ma trận tương quan\n    vmax=1,  # Giá trị tối đa của màu (tương quan tuyệt đối là 1)\n    vmin=-1,  # Giá trị tối thiểu của màu (tương quan tuyệt đối là -1)\n    square=True,  # Đảm bảo kích thước ô là vuông\n    linewidths=.5,  # Độ dày của đường viền\n    annot=True,  # Hiển thị giá trị trên ô\n    cmap='Blues',  # Bảng màu cho heatmap\n)\n\n# Đặt tiêu đề và nhãn cho biểu đồ\n_ = ax.set(\n    title='Correlation PCA Components [Uncorrelated]',  # Tiêu đề của biểu đồ\n    xlabel='Components',  # Nhãn trục x\n    ylabel='Components'  # Nhãn trục y\n)\n","metadata":{"_uuid":"8a21533b-a961-49b1-b24c-d4e7050cc806","_cell_guid":"32e1e369-193f-4071-9914-b2f03cce2893","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:48.011984Z","iopub.execute_input":"2024-05-25T08:50:48.012267Z","iopub.status.idle":"2024-05-25T08:50:48.694906Z","shell.execute_reply.started":"2024-05-25T08:50:48.012241Z","shell.execute_reply":"2024-05-25T08:50:48.693894Z"},"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":"370f38cc-e5fb-4b4e-8dd3-6b9e303ee060","_cell_guid":"43a48481-ea7f-470e-b826-8fd2fcc9e37f","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;\">\nThuật toán <b>K-Nearest Neighbors</b> là một bộ phân loại học có giám sát <i>không tham số</i>, sử dụng <b>khoảng cách gần nhất</b> để thực hiện phân loại hoặc dự đoán về việc gom nhóm của một điểm dữ liệu cụ thể. Dự đoán: Một nhãn lớp được gán dựa trên một <b>đa số phiếu bầu</b>, nhãn xuất hiện nhiều nhất xung quanh một điểm dữ liệu cụ thể.<br><br>\nTrong dự án này, đầu vào của Bộ phân loại KNN sẽ là 10 phần tử chính hàng đầu từ PCA.<br><br>\n<code>sklearn.neighbors.KNeighborsClassifier</code>: Bộ phân loại thực hiện phiếu bầu của k điểm láng giềng gần nhất. Chúng tôi sẽ chạy một GridSearchCV để tối ưu hóa siêu tham số <code>n_neighbors</code>.\n</div>","metadata":{"_uuid":"db9e5ad7-aa3d-4606-9848-526bc3dc048f","_cell_guid":"efff5a1e-7ac3-41a4-b464-77ed4de056d3","trusted":true}},{"cell_type":"markdown","source":"---\n#  mô hình học máy trên tập dữ liệu Train","metadata":{"_uuid":"7c0a4822-eedd-4aa0-bac6-a2cf5a7b89bf","_cell_guid":"39e3a7f5-5363-4914-b78d-295251352529","trusted":true}},{"cell_type":"code","source":"# Tạo một Pipeline kết hợp các bước chuẩn hóa dữ liệu, giảm chiều dữ liệu và mô hình phân loại KNN\nknn_clf = Pipeline(steps=[\n    ('scaler', MinMaxScaler()),  # Chuẩn hóa dữ liệu\n    ('pca', PCA(n_components=10)),  # Giảm chiều dữ liệu với PCA\n    ('knn', KNeighborsClassifier())  # Mô hình phân loại KNN\n])\n\n# Thiết lập các tham số cho mô hình KNN\nknn_clf_params = {\n    'knn__n_neighbors': [2, 4, 8, 16, 32]  # Chọn số lượng hàng xóm gần nhất\n}\n\n# Tạo một GridSearchCV để tìm kiếm siêu tham số tốt nhất cho mô hình KNN\nknn_clf_gs = GridSearchCV(\n    estimator=knn_clf,  # Mô hình phân loại được sử dụng\n    param_grid=knn_clf_params,  # Danh sách các tham số cần tìm kiếm\n    scoring='accuracy',  # Sử dụng độ chính xác để đánh giá\n    n_jobs=-1,  # Số lượng công việc song song được chạy (-1 là sử dụng tất cả các lõi)\n    cv=5,  # Số lượng fold trong cross-validation\n    verbose=1,  # Mức độ thông báo trong quá trình tìm kiếm\n    return_train_score=True  # Trả về kết quả đào tạo trong quá trình tìm kiếm\n)\n\n# Huấn luyện GridSearchCV trên dữ liệu huấn luyện đã giảm chiều\nknn_clf_gs.fit(X=X_train_rotate_pca, y=y_train_rotate)\n\n# In ra tham số tốt nhất và độ chính xác tốt nhất\nprint('best PCA+KNN params:', knn_clf_gs.best_params_)\nprint('best PCA+KNN cv accuracy:', knn_clf_gs.best_score_)\n","metadata":{"_uuid":"2d7cd392-e51f-420a-aad2-0eb5c72ff742","_cell_guid":"797ae756-d6fc-4456-83e5-447d3cc034e2","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:48.696259Z","iopub.execute_input":"2024-05-25T08:50:48.696554Z","iopub.status.idle":"2024-05-25T08:50:50.324773Z","shell.execute_reply.started":"2024-05-25T08:50:48.696527Z","shell.execute_reply":"2024-05-25T08:50:50.323443Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots()\n\n# Vẽ đường dữ liệu huấn luyệ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)\n\n# Vẽ đường dữ liệu kiểm tra\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)\n\n# Đặt nhãn cho trục x và đánh dấu các điểm trên trục x\nax.set_xticks(\n    ticks=range(len(knn_clf_params['knn__n_neighbors'])),\n    labels=knn_clf_params['knn__n_neighbors']\n)\n\n# Đánh dấu vị trí của tham số tốt nhất\nii = knn_clf_params['knn__n_neighbors'].index(\n    knn_clf_gs.best_params_['knn__n_neighbors']\n)\nplt.axvline(x=ii, linestyle='--', color='red', label='best', alpha=0.3)\n\n# Đặt tiêu đề và nhãn cho biểu đồ\nplt.legend()\nplt.xlabel(\"'n_neighbors' vals\")  # Nhãn trục x\nplt.ylabel('Accuracy')  # Nhãn trục y\nplt.title(\"PCA+KNN GridSearchCV Results\")  # Tiêu đề của biểu đồ\nplt.show()  # Hiển thị biểu đồ\n","metadata":{"_uuid":"2abf36ed-c1a2-4581-8a67-414fbfe556f5","_cell_guid":"38a69c14-7bf2-4328-abc9-45a9ef2c1b11","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:50.329336Z","iopub.execute_input":"2024-05-25T08:50:50.329652Z","iopub.status.idle":"2024-05-25T08:50:50.656949Z","shell.execute_reply.started":"2024-05-25T08:50:50.329618Z","shell.execute_reply":"2024-05-25T08:50:50.655934Z"},"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":"2254c327-a8ec-41ca-9fa2-c41a850f4c75","_cell_guid":"adcdd26f-00ba-479f-8e33-e1bc6d65eafb","trusted":true}},{"cell_type":"code","source":"# Lấy mô hình tốt nhất từ GridSearchCV\nbest_cv_clf = knn_clf_gs.best_estimator_\n\n# Dự đoán nhãn của dữ liệu huấn luyện bằng mô hình tốt nhất\ny_pred = best_cv_clf.predict(X=X_train_rotate_pca)\n\n# Tính toán ma trận nhầm lẫn\nconf_matrix = confusion_matrix(y_true=y_train_rotate, y_pred=y_pred)\n\n# Hiển thị ma trận nhầm lẫn\nconf_matrix_disp = ConfusionMatrixDisplay(conf_matrix)\nconf_matrix_disp.plot(cmap='Blues')\n","metadata":{"_uuid":"c3ac8535-57d6-4c40-9146-3b229c95284e","_cell_guid":"aa178b6c-9094-48f3-a36e-5cc5da6e3c50","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:50.658490Z","iopub.execute_input":"2024-05-25T08:50:50.658896Z","iopub.status.idle":"2024-05-25T08:50:51.338037Z","shell.execute_reply.started":"2024-05-25T08:50:50.658856Z","shell.execute_reply":"2024-05-25T08:50:51.336939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Tính toán báo cáo phân loại\nclf_report = classification_report(\n    y_true=y_train_rotate,  # Nhãn thực tế\n    y_pred=y_pred,  # Nhãn dự đoán\n    labels=range(10),  # Các nhãn của lớp (0 đến 9)\n)\n\n# In ra báo cáo phân loại\nprint(clf_report)\n","metadata":{"_uuid":"80ad0fa3-460a-4b42-aaf6-52edfa03afe9","_cell_guid":"04c9e15a-0874-4e08-b997-858cbcc9a37e","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2024-05-25T08:50:51.341732Z","iopub.execute_input":"2024-05-25T08:50:51.342104Z","iopub.status.idle":"2024-05-25T08:50:51.358765Z","shell.execute_reply.started":"2024-05-25T08:50:51.342072Z","shell.execute_reply":"2024-05-25T08:50:51.357606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Lấy mô hình tốt nhất từ GridSearchCV\nbest_cv_clf = knn_clf_gs.best_estimator_\n\n# Dự đoán nhãn của dữ liệu huấn luyện bằng mô hình tốt nhất\ny_pred = best_cv_clf.predict(X=pca_object.transform(X_train))\n\n# Tính toán và hiển thị ma trận nhầm lẫn\nconf_matrix = confusion_matrix(y_true=y_train, y_pred=y_pred)\nconf_matrix_disp = ConfusionMatrixDisplay(conf_matrix)\nconf_matrix_disp.plot(cmap='Blues')\n\n# Tính toán báo cáo phân loại\nclf_report = classification_report(\n    y_true=y_train,\n    y_pred=y_pred,\n    labels=range(10),\n)\n\n# In ra báo cáo phân loại\nprint(clf_report)\n","metadata":{"execution":{"iopub.status.busy":"2024-05-25T08:50:51.360404Z","iopub.execute_input":"2024-05-25T08:50:51.360897Z","iopub.status.idle":"2024-05-25T08:50:55.444181Z","shell.execute_reply.started":"2024-05-25T08:50:51.360858Z","shell.execute_reply":"2024-05-25T08:50:55.443088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📃 References 📃","metadata":{"_uuid":"0bf02057-e66b-4045-bf4b-b91fb25f67ba","_cell_guid":"b35209f1-8bed-48cd-986d-7c85a99a4519","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    <ul>\n        <li>MNIST database. (2023, September 8). In Wikipedia. [<a href=https://en.wikipedia.org/wiki/MNIST_database>LINK</a>]</li>\n        <li>Principal component analysis. (2023, November 18). In Wikipedia. [<a href=https://en.wikipedia.org/wiki/Principal_component_analysis>LINK</a>]</li>\n        <li>PCA, scikit-learn documentation. [<a href=https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html>LINK</a>]\n        <li>K. (2023, September 27). In Wikipedia. [<a href=https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm>LINK</a>]</li>\n        <li>KNNeighborsClassifier, scikit-learn documentation. [<a href=https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier>LINK</a>]</li>\n    </ul>\n</div>","metadata":{"_uuid":"ba488a1a-be81-42a7-8169-c106278b9f85","_cell_guid":"7d3e9231-c38d-42ac-ae5b-8c18407ec2ff","trusted":true}}]}