{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.12"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"databundleVersionId":46665,"sourceId":4117,"sourceType":"competition"},{"databundleVersionId":16635023,"datasetId":10054120,"sourceId":15696207,"sourceType":"datasetVersion"}],"dockerImageVersionId":31329,"isGpuEnabled":true,"isInternetEnabled":true,"language":"python","sourceType":"notebook"},"papermill":{"default_parameters":{},"duration":9.338228,"end_time":"2026-04-12T17:29:27.305176+00:00","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-04-12T17:29:17.966948+00:00","version":"2.7.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"9675736d","cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport xgboost as xgb\nfrom sklearn.metrics import log_loss\nimport joblib\n\n# ==========================================\n# CẤU HÌNH ĐƯỜNG DẪN\n# ==========================================\nOUT_DIR = '/kaggle/input/datasets/huylhn1810/linear-stacking-dataset'\n\n# Tự động dò đường dẫn file submission mẫu\npath_1 = '/kaggle/input/competitions/malware-classification/sampleSubmission.csv'\npath_2 = '/kaggle/input/malware-classification/sampleSubmission.csv'\nSUBMISSION_CSV = path_1 if os.path.exists(path_1) else path_2\n\nprint(\"=\"*50)\nprint(\"BẮT ĐẦU FUSE BẰNG TREE-BASED META-LEARNER (XGBOOST)\")\nprint(\"=\"*50)\n\n# 1. TẢI DỮ LIỆU ĐÃ LƯU TỪ CÁC BƯỚC TRƯỚC\nprint(\"1. Đang tải dữ liệu Meta-features...\")\ny_train  = np.load(os.path.join(OUT_DIR, 'y_train.npy'))\n\ntrain_ml = np.load(os.path.join(OUT_DIR, 'X_train_level1.npy'))\ntest_ml  = np.load(os.path.join(OUT_DIR, 'X_test_level1.npy'))\n\ntrain_dl = np.load(os.path.join(OUT_DIR, 'DL_train_probs.npy'))\ntest_dl  = np.load(os.path.join(OUT_DIR, 'DL_test_probs.npy'))\n\ndef add_meta_features(ML_probs, DL_probs):\n    # features gốc vẫn giữ nguyên: 27 cột ML + 9 cột DL = 36 cột\n    features = np.hstack([ML_probs, DL_probs])\n    \n    # --- BƯỚC KHẮC PHỤC LỖI SHAPE ---\n    # ML_probs có 27 cột: [0:9] là XGB, [9:18] là LGB, [18:27] là ExtraTrees\n    # Gom 3 mô hình ML lại thành 1 mảng 9 cột duy nhất\n    ML_avg = (ML_probs[:, 0:9] + ML_probs[:, 9:18] + ML_probs[:, 18:27]) / 3.0\n    \n    # 1. Sự đồng thuận (Mean): Trung bình dự đoán của khối ML và khối DL\n    mean_probs = (ML_avg + DL_probs) / 2.0\n    \n    # 2. Sự bất đồng (Absolute Difference): Khối ML và khối DL cãi nhau bao nhiêu?\n    diff_probs = np.abs(ML_avg - DL_probs)\n    \n    # 3. Độ tự tin (Max Prob): Lấy xác suất cao nhất (Tự tin nhất)\n    # XGB/LGB/ET tự tin nhất ở mức bao nhiêu?\n    max_ml = ML_probs.max(axis=1).reshape(-1, 1)\n    # Swin/ResNet tự tin nhất ở mức bao nhiêu?\n    max_dl = DL_probs.max(axis=1).reshape(-1, 1)\n    \n    # Ghép tất cả lại: 36 (Gốc) + 9 (Mean) + 9 (Diff) + 1 (MaxML) + 1 (MaxDL) = 56 cột Meta-Features\n    return np.hstack([features, mean_probs, diff_probs, max_ml, max_dl])\n\n# 2. GHÉP NỐI ĐẶC TRƯNG (FUSION)\nprint(\"2. Đang tạo Meta-features mở rộng (Advanced)...\")\nX_train_advanced = add_meta_features(train_ml, train_dl)\nX_test_advanced = add_meta_features(test_ml, test_dl)\n\n# Sửa lại tên biến ở đây\nprint(f\"-> Kích thước tập Train Fusion: {X_train_advanced.shape} (Kỳ vọng: n_samples x 56)\")\n\n# 3. HUẤN LUYỆN XGBOOST LÀM META-LEARNER\nprint(\"\\n3. Đang huấn luyện XGBoost Meta-Learner...\")\n# Cài đặt siêu tham số chống Overfitting khắt khe\nmeta_tree = xgb.XGBClassifier(\n    objective='multi:softprob',\n    num_class=9,\n    n_estimators=150,       # Số lượng cây vừa phải\n    max_depth=3,            # QUAN TRỌNG: Chỉ cho phép cây rẽ nhánh tối đa 2 tầng\n    learning_rate=0.05,     # Học chậm và cẩn thận\n    subsample=1,          # Chỉ lấy 80% data cho mỗi cây để tăng tính ngẫu nhiên\n    colsample_bytree=1,   # Chỉ lấy ngẫu nhiên 80% features (cột) cho mỗi cây\n    tree_method='hist',\n    random_state=42\n)\n\n# Sửa lại tên biến train ở đây\nmeta_tree.fit(X_train_advanced, y_train)\n\n# Đánh giá LogLoss (Sửa lại tên biến ở đây)\ntrain_preds = meta_tree.predict_proba(X_train_advanced)\ntrain_logloss = log_loss(y_train, train_preds)\nprint(f\"✅ Hoàn tất Train! LogLoss trên tập Train: {train_logloss:.5f}\")\n\n# 4. CHẠY DỰ ĐOÁN TRÊN TẬP TEST\nprint(\"\\n4. Đang dự đoán xác suất cuối cùng trên tập Test...\")\n# Sửa lại tên biến test ở đây\nfinal_probabilities = meta_tree.predict_proba(X_test_advanced)\n\n# 5. XUẤT FILE SUBMISSION\nprint(\"5. Đang tạo file Submit chuẩn định dạng Kaggle...\")\nsub_df = pd.read_csv(SUBMISSION_CSV)\ntest_ids = sub_df['Id'].tolist()\n\nif len(test_ids) != final_probabilities.shape[0]:\n    raise ValueError(f\"Lỗi: Số lượng ID ({len(test_ids)}) không khớp số dòng dự đoán ({final_probabilities.shape[0]})!\")\n\ncol_names = [f'Prediction{i}' for i in range(1, 10)]\nsubmission = pd.DataFrame(final_probabilities, columns=col_names)\nsubmission.insert(0, 'Id', test_ids)\n\n# Lưu file CSV\nsub_filename = '/kaggle/working/submission_tree_fusion.csv'\nsubmission.to_csv(sub_filename, index=False)\n\nprint(f\"\\n🎉 HOÀN TẤT! File submit đã được lưu tại: {sub_filename}\")","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.execute_input":"2026-04-12T17:29:20.566074Z","iopub.status.busy":"2026-04-12T17:29:20.565793Z","iopub.status.idle":"2026-04-12T17:29:26.683937Z","shell.execute_reply":"2026-04-12T17:29:26.682799Z"},"papermill":{"duration":6.122948,"end_time":"2026-04-12T17:29:26.685548+00:00","exception":false,"start_time":"2026-04-12T17:29:20.562600+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null}]}