{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"provenance":[]},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":103436,"databundleVersionId":12476472,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt ","metadata":{"id":"kMGP_Z9AZ7bj","trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:12.999554Z","iopub.execute_input":"2025-06-17T15:58:13.000217Z","iopub.status.idle":"2025-06-17T15:58:13.006448Z","shell.execute_reply.started":"2025-06-17T15:58:13.000185Z","shell.execute_reply":"2025-06-17T15:58:13.005387Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Đọc dữ liệu","metadata":{}},{"cell_type":"code","source":"import os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:13.007802Z","iopub.execute_input":"2025-06-17T15:58:13.008029Z","iopub.status.idle":"2025-06-17T15:58:13.029373Z","shell.execute_reply.started":"2025-06-17T15:58:13.008011Z","shell.execute_reply":"2025-06-17T15:58:13.028457Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data1 = pd.read_csv ('/kaggle/input/ds-108-p-21-assigment-06/delay_7_9_CONDITION_PRODUCT_SUPPLIER.csv')\ndata2 = pd.read_csv ('/kaggle/input/ds-108-p-21-assigment-06/not_delay_7_9_CONDITION_PRODUCT_SUPPLIER.csv')\ndata3 = pd.read_csv ('/kaggle/input/ds-108-p-21-assigment-06/delay_4_6_CONDITION_PRODUCT_SUPPLIER.csv')\ndata4 = pd.read_csv ('/kaggle/input/ds-108-p-21-assigment-06/not_delay_4_6_CONDITION_PRODUCT_SUPPLIER.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:13.030433Z","iopub.execute_input":"2025-06-17T15:58:13.030814Z","iopub.status.idle":"2025-06-17T15:58:23.945110Z","shell.execute_reply.started":"2025-06-17T15:58:13.030790Z","shell.execute_reply":"2025-06-17T15:58:23.944113Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test = pd.read_csv ('/kaggle/input/ds-108-p-21-assigment-06/PILOT_10.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:23.947523Z","iopub.execute_input":"2025-06-17T15:58:23.947816Z","iopub.status.idle":"2025-06-17T15:58:24.612970Z","shell.execute_reply.started":"2025-06-17T15:58:23.947795Z","shell.execute_reply":"2025-06-17T15:58:24.611974Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Tiền xử lý","metadata":{}},{"cell_type":"code","source":"data_4_6 = pd.concat([data3, data4], ignore_index=True)\ndata_7_9 = pd.concat([data1, data2], ignore_index=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:24.613992Z","iopub.execute_input":"2025-06-17T15:58:24.614264Z","iopub.status.idle":"2025-06-17T15:58:25.103440Z","shell.execute_reply.started":"2025-06-17T15:58:24.614245Z","shell.execute_reply":"2025-06-17T15:58:25.102559Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_4_6.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:25.104331Z","iopub.execute_input":"2025-06-17T15:58:25.104540Z","iopub.status.idle":"2025-06-17T15:58:25.543512Z","shell.execute_reply.started":"2025-06-17T15:58:25.104524Z","shell.execute_reply":"2025-06-17T15:58:25.542201Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_7_9.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:25.544480Z","iopub.execute_input":"2025-06-17T15:58:25.544765Z","iopub.status.idle":"2025-06-17T15:58:26.345272Z","shell.execute_reply.started":"2025-06-17T15:58:25.544741Z","shell.execute_reply":"2025-06-17T15:58:26.344116Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Drop các cột không có trong data 4_6 so với data 7_9","metadata":{}},{"cell_type":"code","source":"cols_to_drop = data_4_6.columns.difference(data_7_9.columns)\n# Drop các cột này\ndata_4_6.drop(columns=cols_to_drop, inplace=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:26.346343Z","iopub.execute_input":"2025-06-17T15:58:26.346711Z","iopub.status.idle":"2025-06-17T15:58:26.483547Z","shell.execute_reply.started":"2025-06-17T15:58:26.346681Z","shell.execute_reply":"2025-06-17T15:58:26.482562Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Xử lí dữ liệu datetime","metadata":{}},{"cell_type":"code","source":"def convert_datetime(data):\n    data['Order date'] = pd.to_datetime(data['Order date'])\n    data['VSD'] = pd.to_datetime(data['VSD'])\n    data['num_date'] = (data['VSD'] - data['Order date']).dt.days\n    data = data.drop(columns=['Order date', 'VSD'])\n    return data\n\ndata_4_6 = convert_datetime(data_4_6)\ndata_7_9 = convert_datetime(data_7_9)\ntest = convert_datetime(test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:26.484626Z","iopub.execute_input":"2025-06-17T15:58:26.484915Z","iopub.status.idle":"2025-06-17T15:58:27.559568Z","shell.execute_reply.started":"2025-06-17T15:58:26.484894Z","shell.execute_reply":"2025-06-17T15:58:27.558680Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Chuyển đổi kiểu dữ liệu trong data_4_6","metadata":{}},{"cell_type":"code","source":"columns_to_convert = ['OTHER AREA SHIP DIV', 'REASON_CD', 'Consider count hodiday Saturday']\nfor col in columns_to_convert:\n    if col in data_4_6.columns:\n        data_4_6[col] = data_4_6[col].astype(str)\n        data_4_6[col] = data_4_6[col].str.replace(' ', '')\n        data_4_6[col] = data_4_6[col].replace('nan', np.nan)\n        data_4_6[col] = pd.to_numeric(data_4_6[col])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:27.562741Z","iopub.execute_input":"2025-06-17T15:58:27.562991Z","iopub.status.idle":"2025-06-17T15:58:28.541424Z","shell.execute_reply.started":"2025-06-17T15:58:27.562974Z","shell.execute_reply":"2025-06-17T15:58:28.540467Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.concat([data_4_6, data_7_9])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:28.542234Z","iopub.execute_input":"2025-06-17T15:58:28.542451Z","iopub.status.idle":"2025-06-17T15:58:29.262884Z","shell.execute_reply.started":"2025-06-17T15:58:28.542434Z","shell.execute_reply":"2025-06-17T15:58:29.262046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:29.264279Z","iopub.execute_input":"2025-06-17T15:58:29.264575Z","iopub.status.idle":"2025-06-17T15:58:30.155854Z","shell.execute_reply.started":"2025-06-17T15:58:29.264545Z","shell.execute_reply":"2025-06-17T15:58:30.154982Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Chuyển đổi dữ liệu","metadata":{}},{"cell_type":"code","source":"train['GLOBAL_NO'] = train['GLOBAL_NO'].astype(str)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:30.156869Z","iopub.execute_input":"2025-06-17T15:58:30.157192Z","iopub.status.idle":"2025-06-17T15:58:30.373439Z","shell.execute_reply.started":"2025-06-17T15:58:30.157164Z","shell.execute_reply":"2025-06-17T15:58:30.372538Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Kiểm tra giá trị duy nhất trong các thuộc tính","metadata":{}},{"cell_type":"code","source":"for col in train.columns:\n    unique_value_count = train[col].nunique(dropna=False)\n    if unique_value_count == 1:\n        unique_value = train[col].unique()[0]\n        print(f\"Column '{col}' has only one unique value: '{unique_value}'\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:30.374311Z","iopub.execute_input":"2025-06-17T15:58:30.374526Z","iopub.status.idle":"2025-06-17T15:58:32.187589Z","shell.execute_reply.started":"2025-06-17T15:58:30.374510Z","shell.execute_reply":"2025-06-17T15:58:32.186735Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Hướng xử lý: drop các cột 'SUBSIDIARY_CD' do thuộc tính chỉ chứa giá trị duy nhất nên không có ý nghĩa cho mô hình.","metadata":{}},{"cell_type":"code","source":"columns_to_drop = ['SUBSIDIARY_CD']\ntrain = train.drop(columns=columns_to_drop, axis=1, errors='ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:32.188451Z","iopub.execute_input":"2025-06-17T15:58:32.189323Z","iopub.status.idle":"2025-06-17T15:58:32.658713Z","shell.execute_reply.started":"2025-06-17T15:58:32.189291Z","shell.execute_reply":"2025-06-17T15:58:32.657666Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Missing value","metadata":{}},{"cell_type":"code","source":"# Tỉ lệ missing value trong mỗi thuộc tính\ntotal_rows = len(train)\nmissing_percentages = {}\nfor col in train.columns:\n    missing_count = train[col].isnull().sum()\n    if missing_count > 0:\n        missing_percentage = (missing_count / total_rows) * 100\n        missing_percentages[col] = missing_percentage\n        print(f\"Column '{col}' has {missing_count} missing values, which is {missing_percentage:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:32.659737Z","iopub.execute_input":"2025-06-17T15:58:32.660060Z","iopub.status.idle":"2025-06-17T15:58:33.394659Z","shell.execute_reply.started":"2025-06-17T15:58:32.660038Z","shell.execute_reply":"2025-06-17T15:58:33.393724Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xử lí 'OTHER AREA SHIP DIV'\nprint (train['OTHER AREA SHIP DIV'].unique())\ntrain['OTHER AREA SHIP DIV'] = train['OTHER AREA SHIP DIV'].fillna(0)# Điền 0 - Vận chuyển trong khu vực riêng","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:33.395559Z","iopub.execute_input":"2025-06-17T15:58:33.395817Z","iopub.status.idle":"2025-06-17T15:58:33.429986Z","shell.execute_reply.started":"2025-06-17T15:58:33.395799Z","shell.execute_reply":"2025-06-17T15:58:33.428973Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xử lí các thuộc tính với phần trăm nan nhỏ hơn 10%\nfor col, percentage in missing_percentages.items():\n    if percentage < 10:\n        train = train.dropna(subset=[col])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T15:58:33.430995Z","iopub.execute_input":"2025-06-17T15:58:33.431334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xử lí thuộc tính có missing value lớn:\ncolumns_to_drop = ['REASON_CD', 'SOUF_RCV_NO', 'QTUF_RCV_NO']\ntrain = train.drop(columns=columns_to_drop, axis=1, errors='ignore')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Hướng xử lý: drop các cột 'REASON_CD', 'SOUF_RCV_NO', 'QTUF_RCV_NO' do thuộc tính không có ảnh hưởng đến bối cảnh bài toán dự đoán đơn hàng có bị delay hay không.","metadata":{}},{"cell_type":"markdown","source":"### Kiểm tra mức độ tương quan của các thuộc tính","metadata":{}},{"cell_type":"code","source":"# Tính ma trận tương quan cho các thuộc tính số\ncorrelation_matrix = train.corr(numeric_only=True)\n# Vẽ heatmap\nplt.figure(figsize=(30, 24))\nsns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', fmt=\".2f\", linewidths=.5)\nplt.title('Mức độ tương quan giữa các thuộc tính')\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kiểm tra những thuộc tính không tương quan với label\nnon_correlated_features = []\ncorrelation_threshold = 0.01\n\nfor col in train.columns:\n    if col != 'label' and pd.api.types.is_numeric_dtype(train[col]):\n        correlation = train[col].corr(train['label'])\n        if abs(correlation.round(decimals=2)) < correlation_threshold:\n            non_correlated_features.append(col)\n\nprint(non_correlated_features)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"columns_to_drop = non_correlated_features\ntrain = train.drop(columns=columns_to_drop, axis=1, errors='ignore')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tìm các cặp thuộc tính có độ tương quan cao\nthreshold = 0.8\n\nhigh_corr_pairs = []\n\nfor i in range(len(correlation_matrix.columns)):\n    for j in range(i + 1, len(correlation_matrix.columns)):\n        col1 = correlation_matrix.columns[i]\n        col2 = correlation_matrix.columns[j]\n        corr_value = correlation_matrix.loc[col1, col2]\n\n        if abs(corr_value) >= threshold:\n            high_corr_pairs.append((col1, col2, corr_value))\n\nprint(f\"\\nCác cặp thuộc tính có độ tương quan cao (ngưỡng >= {threshold}):\")\nif high_corr_pairs:\n    for pair in high_corr_pairs:\n        print(f\"  {pair[0]} - {pair[1]}: {pair[2]:.2f}\")\nelse:\n    print(\"Không tìm thấy cặp thuộc tính nào có độ tương quan cao theo ngưỡng đã đặt.\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Các thuộc tính này phụ thuộc hoàn toàn vào nhau nên cần loại bỏ một trong hai.","metadata":{}},{"cell_type":"code","source":"columns_to_drop = ['Stock class', 'SO QTY', 'SUPPLIER INV AMOUNT', 'SPECIAL DIV']\ntrain = train.drop(columns=columns_to_drop, axis=1, errors='ignore')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Xử lí outliers","metadata":{}},{"cell_type":"code","source":"# Kiểm tra và tìm outliers\nnumeric_columns = train.select_dtypes(include=np.number).columns\noutliers_col = []\n\ndef detect_outliers_iqr(df, column):\n    Q1 = df[column].quantile(0.25)\n    Q3 = df[column].quantile(0.75)\n    IQR = Q3 - Q1\n    lower_bound = Q1 - 1.5 * IQR\n    upper_bound = Q3 + 1.5 * IQR\n    outlier_indices = df[(df[column] < lower_bound) | (df[column] > upper_bound)].index\n    return outlier_indices\n\ndef plot_boxplot(df, column):\n    sns.boxplot(x=df[column])\n    plt.title(f'Box Plot của cột {column}')\n    plt.show()\n    \nprint(\"Kiểm tra outliers cho các thuộc tính không missing:\")\nfor col in numeric_columns:\n    if train[col].nunique() > 2 and col not in missing_percentages:\n        print(f\"\\n--- Kiểm tra outliers cho cột '{col}' ---\")\n        outlier_indices_iqr = detect_outliers_iqr(train, col)\n        if not outlier_indices_iqr.empty:\n            outliers_col.append(col)\n            outlier_percentage = len(outlier_indices_iqr) / len(train) * 100\n            print(f\"  Percentage of outliers in {col} (IQR): {outlier_percentage:.2f}%\")\n            # Vẽ Box Plot\n            plot_boxplot(train, col)\n        else:\n            print(\"  Không có outliers đáng kể theo phương pháp IQR.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xứ lí\nfor col in outliers_col:\n    Q1 = train[col].quantile(0.25)\n    Q3 = train[col].quantile(0.75)\n    IQR = Q3 - Q1\n    lower_bound = Q1 - 1.5 * IQR\n    upper_bound = Q3 + 1.5 * IQR\n    # Đưa outliers về giá trị biên dựa trên IQR\n    train[col] = np.where(train[col] < lower_bound, lower_bound,\n                                                np.where(train[col] > upper_bound, upper_bound, train[col]))\n    print(f\"Outliers (IQR) ở cột '{col}' đã được đưa về giá trị biên.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Kiểm tra trùng lặp","metadata":{}},{"cell_type":"code","source":"# Loại bỏ các hàng trùng lặp dựa trên tất cả các cột\ntrain.drop_duplicates()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.info()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Dữ liệu trên tập test","metadata":{}},{"cell_type":"code","source":"cols_to_drop = test.columns.difference(train.columns)\n# Drop các cột này\ntest.drop(columns=cols_to_drop, inplace=True)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test.info()","metadata":{"id":"Qd6B9CKdgj7z","outputId":"49a401f1-8b1f-4474-b366-3c61afb46d32","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Missing value","metadata":{}},{"cell_type":"code","source":"# Tỉ lệ missing value trong mỗi thuộc tính\ntotal_rows = len(test)\nmissing_percentages = {}\nfor col in test.columns:\n    missing_count = test[col].isnull().sum()\n    if missing_count > 0:\n        missing_percentage = (missing_count / total_rows) * 100\n        missing_percentages[col] = missing_percentage\n        print(f\"Column '{col}' has {missing_count} missing values, which is {missing_percentage:.2f}%\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xử lí 'OTHER AREA SHIP DIV'\ntest['OTHER AREA SHIP DIV'] = test['OTHER AREA SHIP DIV'].fillna(0) # Điền 0 - Vận chuyển trong khu vực riêng","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Xử lí outliners","metadata":{}},{"cell_type":"code","source":"# Kiểm tra và tìm outliers\nnumeric_columns = test.select_dtypes(include=np.number).columns\noutliers_col = []\n\ndef detect_outliers_iqr(df, column):\n    Q1 = df[column].quantile(0.25)\n    Q3 = df[column].quantile(0.75)\n    IQR = Q3 - Q1\n    lower_bound = Q1 - 1.5 * IQR\n    upper_bound = Q3 + 1.5 * IQR\n    outlier_indices = df[(df[column] < lower_bound) | (df[column] > upper_bound)].index\n    return outlier_indices\n\ndef plot_boxplot(df, column):\n    sns.boxplot(x=df[column])\n    plt.title(f'Box Plot của cột {column}')\n    plt.show()\n    \nprint(\"Kiểm tra outliers cho các thuộc tính không missing:\")\nfor col in numeric_columns:\n    if test[col].nunique() > 2 and col not in missing_percentages:\n        print(f\"\\n--- Kiểm tra outliers cho cột '{col}' ---\")\n        outlier_indices_iqr = detect_outliers_iqr(test, col)\n        if not outlier_indices_iqr.empty:\n            outliers_col.append(col)\n            outlier_percentage = len(outlier_indices_iqr) / len(test) * 100\n            print(f\"  Percentage of outliers in {col} (IQR): {outlier_percentage:.2f}%\")\n            # Vẽ Box Plot\n            plot_boxplot(test, col)\n        else:\n            print(\"  Không có outliers đáng kể theo phương pháp IQR.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xứ lí\nfor col in outliers_col:\n    Q1 = test[col].quantile(0.25)\n    Q3 = test[col].quantile(0.75)\n    IQR = Q3 - Q1\n    lower_bound = Q1 - 1.5 * IQR\n    upper_bound = Q3 + 1.5 * IQR\n    # Đưa outliers về giá trị biên dựa trên IQR\n    test[col] = np.where(test[col] < lower_bound, lower_bound,\n                                                np.where(test[col] > upper_bound, upper_bound, test[col]))\n    print(f\"Outliers (IQR) ở cột '{col}' đã được đưa về giá trị biên.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_train = train['label']\nX_train = train.drop(columns='label')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler, OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\nimport lightgbm as lgb\nfrom sklearn.pipeline import Pipeline\n\nnumeric_features = X_train.select_dtypes(include=['int64','float64']).columns\ncategorical_features = X_train.select_dtypes(include='object').columns\n\npreprocessor = ColumnTransformer(\n    transformers=[\n        ('num', StandardScaler(), numeric_features),\n        ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)\n    ],\n    remainder='passthrough'\n)\n\n# Các tham số cụ thể\nlgbm_classifier = lgb.LGBMClassifier(\n    objective='binary',\n    metric='logloss',\n    n_estimators=100,\n    learning_rate=0.05,\n    num_leaves=31,\n    max_depth=-1,\n    min_child_samples=20,\n    subsample=0.8,\n    colsample_bytree=0.8,\n    random_state=42,\n    n_jobs=-1,\n    reg_alpha=0.1,\n    reg_lambda=0.1,\n)\n\n# Xây dựng Pipeline\nmodel_lgbm = Pipeline(steps=[\n    ('preprocessor', preprocessor),\n    ('classifier', lgbm_classifier)\n])\n\n# Huấn luyện mô hình\nmodel_lgbm.fit(X_train, y_train)\nprint(\"Huấn luyện mô hình hoàn tất.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Thực hiện dự đoán nhị phân trên tập kiểm tra \ny_pred = model_lgbm.predict(test)\n\nprint(f\"Kích thước của mảng dự đoán: {y_pred.shape}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo DataFrame nộp bài\nid = range(1, len(test) + 1)\n\n# Tạo DataFrame nộp bài\nsubmission = pd.DataFrame({\n    'ID': id,\n    'label': y_pred\n})\n\n# Lưu DataFrame vào file CSV\nsubmission.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}