{"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,"isSourceIdPinned":false,"sourceId":4117,"sourceType":"competition"},{"databundleVersionId":16598046,"datasetId":10027427,"sourceId":15661420,"sourceType":"datasetVersion"},{"isSourceIdPinned":false,"sourceId":310736401,"sourceType":"kernelVersion"}],"dockerImageVersionId":31329,"isGpuEnabled":true,"isInternetEnabled":true,"language":"python","sourceType":"notebook"},"papermill":{"default_parameters":{},"duration":625.166497,"end_time":"2026-04-11T14:30:08.318260+00:00","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-04-11T14:19:43.151763+00:00","version":"2.7.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"110252c8","cell_type":"code","source":"import os\nimport gc\nimport joblib\nimport numpy as np\nimport pandas as pd\nimport time\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.utils.class_weight import compute_class_weight\nimport lightgbm as lgb\nimport xgboost as xgb\nfrom sklearn.ensemble import ExtraTreesClassifier\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.execute_input":"2026-04-11T14:19:45.450622Z","iopub.status.busy":"2026-04-11T14:19:45.450076Z","iopub.status.idle":"2026-04-11T14:19:52.658660Z","shell.execute_reply":"2026-04-11T14:19:52.658085Z"},"papermill":{"duration":7.213312,"end_time":"2026-04-11T14:19:52.660457+00:00","exception":false,"start_time":"2026-04-11T14:19:45.447145+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null},{"id":"0526df26","cell_type":"code","source":"# ==========================================\n# 1. CẤU HÌNH ĐƯỜNG DẪN\n# ==========================================\n# THAY ĐỔI THEO ĐƯỜNG DẪN KAGGLE CỦA BẠN\nTREE_DATA_DIR = '/kaggle/input/datasets/trankimhuu/data-meta-stacking-tree-based'\nDL_FEATURES_DIR = '/kaggle/input/notebooks/nguynthikhang/dual-band-swin-tiny-resnet18-5-folds-version-1' \n\nMODEL_DIR = '/kaggle/working/models_raw/'\nos.makedirs(MODEL_DIR, exist_ok=True)","metadata":{"execution":{"iopub.execute_input":"2026-04-11T14:19:52.664822Z","iopub.status.busy":"2026-04-11T14:19:52.664168Z","iopub.status.idle":"2026-04-11T14:19:52.668487Z","shell.execute_reply":"2026-04-11T14:19:52.667719Z"},"papermill":{"duration":0.007842,"end_time":"2026-04-11T14:19:52.669891+00:00","exception":false,"start_time":"2026-04-11T14:19:52.662049+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null},{"id":"e127cc3a","cell_type":"code","source":"# ==========================================\n# 2. LOAD DATA & GHÉP NỐI TRỰC TIẾP (NO PCA)\n# ==========================================\nprint(\"1. Đang tải dữ liệu Tabular & N-grams...\")\nX_train_tab = np.load(os.path.join(TREE_DATA_DIR, 'X_train_tab.npy'))\nX_test_tab = np.load(os.path.join(TREE_DATA_DIR, 'X_test_tab.npy'))\nX_train_ngrams = np.load(os.path.join(TREE_DATA_DIR, 'X_train_ngrams.npy'))\nX_test_ngrams = np.load(os.path.join(TREE_DATA_DIR, 'X_test_ngrams.npy'))\ny_train = np.load(os.path.join(TREE_DATA_DIR, 'y_train.npy'))\n\nprint(\"2. Đang tải Deep Features (OOF - 512 chiều gốc)...\")\nX_train_deep = np.load(os.path.join(DL_FEATURES_DIR, 'processed_dl_features/X_train_deep_oof.npy'))\nX_test_deep = np.load(os.path.join(DL_FEATURES_DIR, 'processed_dl_features/X_test_deep_final.npy'))\n\nprint(\"3. Ghép nối toàn bộ: Tabular + Ngrams + Deep_Raw...\")\nX_train_final = np.hstack([X_train_tab, X_train_ngrams, X_train_deep])\nX_test_final = np.hstack([X_test_tab, X_test_ngrams, X_test_deep])\n\nprint(f\"Kích thước X_train tổng lực: {X_train_final.shape}\")\n\n# Dọn dẹp RAM\ndel X_train_tab, X_train_ngrams, X_train_deep\ndel X_test_tab, X_test_ngrams, X_test_deep\ngc.collect()","metadata":{"execution":{"iopub.execute_input":"2026-04-11T14:19:52.673503Z","iopub.status.busy":"2026-04-11T14:19:52.673303Z","iopub.status.idle":"2026-04-11T14:19:55.761829Z","shell.execute_reply":"2026-04-11T14:19:55.761057Z"},"papermill":{"duration":3.092105,"end_time":"2026-04-11T14:19:55.763383+00:00","exception":false,"start_time":"2026-04-11T14:19:52.671278+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null},{"id":"4b525202","cell_type":"code","source":"# ==========================================\n# 3. LEVEL 0: BASE LEARNERS K-FOLD STACKING\n# ==========================================\nnum_classes = 9\nnfolds = 5\nclasses = np.unique(y_train)\nweights = compute_class_weight('balanced', classes=classes, y=y_train)\n\nbase_models = {\n    'xgb': xgb.XGBClassifier(objective='multi:softprob', num_class=num_classes, max_depth=8, tree_method='hist', device='cuda', random_state=42),\n    'lgb': lgb.LGBMClassifier(objective='multiclass', num_class=num_classes, class_weight=dict(zip(classes, weights)), device='gpu', random_state=42, verbose=-1),\n    'extra_trees': ExtraTreesClassifier(n_estimators=400, max_depth=20, class_weight='balanced', n_jobs=-1, random_state=42)\n}\n\nskf = StratifiedKFold(n_splits=nfolds, shuffle=True, random_state=2026)\nmeta_X_train_list, meta_X_test_list = [], []\n\nprint(\"\\nBẮT ĐẦU HUẤN LUYỆN LEVEL 0 (META-FEATURES EXTRACTION)\")\nfor model_name, model in base_models.items():\n    print(f\"\\n{'='*50}\")\n    print(f\"➔ Đang huấn luyện Base Learner: {model_name.upper()}\")\n    print(f\"{'='*50}\")\n    \n    oof_train = np.zeros((X_train_final.shape[0], num_classes))\n    oof_test_skf = np.zeros((nfolds, X_test_final.shape[0], num_classes))\n    \n    for i, (train_idx, val_idx) in enumerate(skf.split(X_train_final, y_train)):\n        print(f\"   + Đang chạy Fold {i+1}/{nfolds}... \", end=\"\", flush=True)\n        fold_start_time = time.time()\n        \n        x_tr, y_tr = X_train_final[train_idx], y_train[train_idx]\n        model.fit(x_tr, y_tr)\n        \n        oof_train[val_idx] = model.predict_proba(X_train_final[val_idx])\n        oof_test_skf[i, :, :] = model.predict_proba(X_test_final)\n        \n        print(f\"Xong! ({time.time() - fold_start_time:.1f}s)\")\n        \n    meta_X_train_list.append(oof_train)\n    meta_X_test_list.append(oof_test_skf.mean(axis=0))\n    print(f\"Hoàn thành toàn bộ mô hình {model_name.upper()}!\")\n\nX_train_level1 = np.hstack(meta_X_train_list)\nX_test_level1 = np.hstack(meta_X_test_list)\nprint(\"\\n[Hoàn tất Level-0] Đã sẵn sàng dữ liệu cho Meta-Learner.\")","metadata":{"execution":{"iopub.execute_input":"2026-04-11T14:19:55.768263Z","iopub.status.busy":"2026-04-11T14:19:55.768045Z","iopub.status.idle":"2026-04-11T14:30:01.684452Z","shell.execute_reply":"2026-04-11T14:30:01.683520Z"},"papermill":{"duration":605.920565,"end_time":"2026-04-11T14:30:01.686073+00:00","exception":false,"start_time":"2026-04-11T14:19:55.765508+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null},{"id":"e098cc3f","cell_type":"code","source":"# ==========================================\n# 4. LEVEL 1: META-LEARNER & PSEUDO-LABELING\n# ==========================================\nprint(\"\\n\" + \"=\"*50)\nprint(\"BẮT ĐẦU HUẤN LUYỆN LEVEL 1 (META-LEARNER)\")\nprint(\"=\"*50)\n\n# --- 1. PSEUDO-LABELING TRÊN TẬP TEST ---\nprint(\"\\n[Bước 1] Đang thực hiện Pseudo-labeling trên tập Test...\")\nstart_pseudo = time.time()\n\ntemp_meta = xgb.XGBClassifier(\n    objective='multi:softprob', \n    max_depth=3, \n    tree_method='hist', \n    device='cuda', \n    random_state=99\n)\ntemp_meta.fit(X_train_level1, y_train)\ntest_probs = temp_meta.predict_proba(X_test_level1)\n\nconfident_indices = np.where(test_probs.max(axis=1) > 0.99)[0]\npseudo_labels = test_probs.argmax(axis=1)[confident_indices]\nX_test_confident = X_test_level1[confident_indices]\n\nX_train_level1_extended = np.vstack([X_train_level1, X_test_confident])\ny_train_extended = np.concatenate([y_train, pseudo_labels])\n\nprint(f\"   -> Đã mượn thêm {len(confident_indices)} mẫu Test tự tin đưa vào Train.\")\nprint(f\"   -> Thời gian Pseudo-labeling: {time.time() - start_pseudo:.1f}s\")\nprint(f\"   -> Kích thước tập Train mở rộng: {X_train_level1_extended.shape}\")\n\n# --- 2. HUẤN LUYỆN META-LEARNER CUỐI CÙNG ---\nprint(\"\\n[Bước 2] Huấn luyện Meta-Learner chốt hạ (500 Trees)...\")\nstart_meta = time.time()\n\nmeta_learner = xgb.XGBClassifier(\n    objective='multi:softprob', \n    num_class=num_classes, \n    learning_rate=0.01, \n    max_depth=3, \n    n_estimators=500, \n    tree_method='hist', \n    device='cuda', \n    random_state=99\n)\n\neval_set = [(X_train_level1_extended, y_train_extended)]\nmeta_learner.fit(\n    X_train_level1_extended, \n    y_train_extended,\n    eval_set=eval_set,\n    verbose=50\n)\n\n# Lưu mô hình (Tùy chọn)\njoblib.dump(meta_learner, os.path.join(MODEL_DIR, 'meta_learner_raw.pkl'))\nprint(f\"\\nHoàn tất Level 1! Thời gian huấn luyện: {time.time() - start_meta:.1f}s\")","metadata":{"execution":{"iopub.execute_input":"2026-04-11T14:30:01.693756Z","iopub.status.busy":"2026-04-11T14:30:01.693265Z","iopub.status.idle":"2026-04-11T14:30:05.325116Z","shell.execute_reply":"2026-04-11T14:30:05.324179Z"},"papermill":{"duration":3.637448,"end_time":"2026-04-11T14:30:05.326690+00:00","exception":false,"start_time":"2026-04-11T14:30:01.689242+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null},{"id":"8b81f22f","cell_type":"code","source":"# ==========================================\n# 5. XUẤT FILE SUBMISSION\n# ==========================================\nfinal_probabilities = meta_learner.predict_proba(X_test_level1)\ncol_names = [f'Prediction{i}' for i in range(1, 10)]\nsubmission = pd.DataFrame(final_probabilities, columns=col_names)\n\ndf_sub_template = pd.read_csv('/kaggle/input/competitions/malware-classification/sampleSubmission.csv')\nsubmission.insert(0, 'Id', df_sub_template['Id'])\n\n# Đặt tên file là no_pca để phân biệt\nsub_filename = '/kaggle/working/submission_ensemble_no_pca.csv'\nsubmission.to_csv(sub_filename, index=False)\nprint(f\"\\n🎉 HOÀN TẤT! File '{sub_filename}' đã sẵn sàng. Chúc bạn đạt kết quả cao!\")","metadata":{"execution":{"iopub.execute_input":"2026-04-11T14:30:05.336575Z","iopub.status.busy":"2026-04-11T14:30:05.336085Z","iopub.status.idle":"2026-04-11T14:30:05.656633Z","shell.execute_reply":"2026-04-11T14:30:05.655794Z"},"papermill":{"duration":0.326819,"end_time":"2026-04-11T14:30:05.658318+00:00","exception":false,"start_time":"2026-04-11T14:30:05.331499+00:00","status":"completed"},"tags":[]},"outputs":[],"execution_count":null}]}