{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"datasetVersion","sourceId":15596748,"datasetId":9979903,"databundleVersionId":16529585}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport scipy.sparse as sp\nfrom sklearn.feature_selection import SelectKBest, f_classif\n\nDATA_IN_DIR = '/kaggle/input/datasets/huylhn1810/weight' # Đổi tên thư mục Data bạn đã upload\nOUT_DIR = '/kaggle/working/processed_data/'\nos.makedirs(OUT_DIR, exist_ok=True)\n\nTOTAL_TRAIN_PARTS = 2\nTOTAL_TEST_PARTS = 8\n\nprint(\"1. Đang tải và gộp dữ liệu TRAIN...\")\ntrain_tab_list, train_ng_list, y_train_list = [], [], []\nfor i in range(1, TOTAL_TRAIN_PARTS + 1):\n    train_tab_list.append(np.load(os.path.join(DATA_IN_DIR, f'X_train_tab_part{i}.npy')))\n    train_ng_list.append(sp.load_npz(os.path.join(DATA_IN_DIR, f'X_train_ng_part{i}.npz')))\n    y_train_list.append(np.load(os.path.join(DATA_IN_DIR, f'y_train_part{i}.npy')))\n\nX_train_tab = np.vstack(train_tab_list)\nX_train_ng_sparse = sp.vstack(train_ng_list)\ny_train = np.concatenate(y_train_list)\n\nprint(\"2. Đang tải và gộp dữ liệu TEST...\")\ntest_tab_list, test_ng_list = [], []\nfor i in range(1, TOTAL_TEST_PARTS + 1):\n    test_tab_list.append(np.load(os.path.join(DATA_IN_DIR, f'X_test_tab_part{i}.npy')))\n    test_ng_list.append(sp.load_npz(os.path.join(DATA_IN_DIR, f'X_test_ng_part{i}.npz')))\n\nX_test_tab = np.vstack(test_tab_list)\nX_test_ng_sparse = sp.vstack(test_ng_list)\n\nprint(f\"-> Tổng số mẫu Train: {X_train_tab.shape[0]}\")\nprint(f\"-> Tổng số mẫu Test: {X_test_tab.shape[0]}\")\n\nprint(\"3. Đang chạy SelectKBest lọc 2000 N-grams tốt nhất...\")\nselector = SelectKBest(f_classif, k=2000)\nX_train_ngrams = selector.fit_transform(X_train_ng_sparse, y_train).toarray()\nX_test_ngrams = selector.transform(X_test_ng_sparse).toarray()\n\nprint(\"4. Lưu ra mảng hoàn chỉnh chuẩn bị Train...\")\nnp.save(os.path.join(OUT_DIR, 'X_train_tab.npy'), X_train_tab)\nnp.save(os.path.join(OUT_DIR, 'X_test_tab.npy'), X_test_tab)\nnp.save(os.path.join(OUT_DIR, 'X_train_ngrams.npy'), X_train_ngrams)\nnp.save(os.path.join(OUT_DIR, 'X_test_ngrams.npy'), X_test_ngrams)\nnp.save(os.path.join(OUT_DIR, 'y_train.npy'), y_train)\n\nprint(\"✅ Đã nối xong toàn bộ dữ liệu!\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport time\nimport joblib\nimport numpy as np\nimport lightgbm as lgb\nimport xgboost as xgb\nfrom sklearn.ensemble import ExtraTreesClassifier\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom sklearn.metrics import log_loss\n\nOUT_DIR = 'processed_data/'\nMODEL_DIR = 'models/'\nos.makedirs(MODEL_DIR, exist_ok=True)\n\n# Load dữ liệu\nX_train_tab = np.load(os.path.join(OUT_DIR, 'X_train_tab.npy'))\nX_test_tab = np.load(os.path.join(OUT_DIR, 'X_test_tab.npy'))\nX_train_ngrams = np.load(os.path.join(OUT_DIR, 'X_train_ngrams.npy'))\nX_test_ngrams = np.load(os.path.join(OUT_DIR, 'X_test_ngrams.npy'))\ny_train = np.load(os.path.join(OUT_DIR, 'y_train.npy'))\n\n# Ghép (Concat) đặc trưng bảng và N-grams\nX_train_final = np.hstack([X_train_tab, X_train_ngrams])\nX_test_final = np.hstack([X_test_tab, X_test_ngrams])\nprint(f\"Kích thước X_train: {X_train_final.shape}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_classes = 9\nnfolds = 5\nclasses = np.unique(y_train)\nweights = compute_class_weight('balanced', classes=classes, y=y_train)\nclass_weights_dict = dict(zip(classes, weights))\n\nbase_models = {\n    'xgb': xgb.XGBClassifier(\n        objective='multi:softprob', \n        num_class=num_classes, \n        max_depth=6, \n        # Cập nhật thông số để chạy trên GPU T4\n        tree_method='hist',   \n        device='cuda',        # Bật tăng tốc GPU phần cứng\n        random_state=42\n    ),\n    'lgb': lgb.LGBMClassifier(\n        objective='multiclass', \n        num_class=num_classes, \n        class_weight=class_weights_dict, \n        # Cập nhật thông số để chạy trên GPU\n        device='gpu',         \n        random_state=42, \n        verbose=-1\n    ),\n    'extra_trees': ExtraTreesClassifier(\n        n_estimators=500, \n        max_depth=15, \n        class_weight='balanced', \n        n_jobs=-1,            # ExtraTrees chỉ dùng được CPU, n_jobs=-1 để dùng full 4 lõi CPU\n        random_state=42\n    )\n}\n\nmeta_X_train_list, meta_X_test_list = [], []\nskf = StratifiedKFold(n_splits=nfolds, shuffle=True, random_state=2026)\n\nprint(\"=\"*50)\nprint(\"BẮT ĐẦU HUẤN LUYỆN LEVEL-0 (META-FEATURES EXTRATION)\")\nprint(\"=\"*50)\n\nfor model_name, model in base_models.items():\n    print(f\"\\n🚀 [Level-0] Đang xử lý mô hình: {model_name.upper()}\")\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    # --- 1. Train toàn bộ trên tập Train ---\n    print(f\" ➔ Đang huấn luyện trên toàn bộ tập Train (Full Model)...\", end=\"\", flush=True)\n    start_time = time.time()\n    \n    model_full = model.fit(X_train_final, y_train)\n    joblib.dump(model_full, os.path.join(MODEL_DIR, f'{model_name}_full.pkl'))\n    \n    print(f\" Xong! ({time.time() - start_time:.1f}s)\")\n    \n    # --- 2. Cross Validation (Tạo OOF) ---\n    print(f\" ➔ Bắt đầu Cross-Validation ({nfolds} Folds):\")\n    for i, (train_idx, valid_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        x_val = X_train_final[valid_idx]\n        \n        # Huấn luyện trên Fold hiện tại\n        model.fit(x_tr, y_tr)\n        \n        # Dự đoán\n        oof_train[valid_idx] = model.predict_proba(x_val)\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    # Đánh giá OOF: mỗi sample được dự đoán bởi fold không dùng sample đó để train.\n    oof_ll = log_loss(y_train, oof_train)\n\n    print(f\"    OOF Log Loss của {model_name.upper()}: {oof_ll:.6f}\")\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 mô hình {model_name.upper()}!\")\n\n# Nối các OOF predictions lại thành Input cho Meta-Learner\nX_train_level1 = np.hstack(meta_X_train_list)\nX_test_level1 = np.hstack(meta_X_test_list)\n\nprint(\"\\nĐang lưu Meta-features của tập Test (X_test_level1.npy)...\")\nnp.save(os.path.join(OUT_DIR, 'X_test_level1.npy'), X_test_level1) \nprint(\"Hoàn tất Level-0! Đã sẵn sàng cho tầng Meta-Learner.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\n[Trick] Áp dụng Pseudo-labeling trên tập Test...\")\ntemp_meta = xgb.XGBClassifier(objective='multi:softprob', max_depth=3, random_state=99)\ntemp_meta.fit(X_train_level1, y_train)\ntest_probs = temp_meta.predict_proba(X_test_level1)\n\n# Lọc các dự đoán có độ tự tin > 0.99\nconfident_indices = np.where(test_probs.max(axis=1) > 0.99)[0]\npseudo_labels = test_probs.argmax(axis=1)[confident_indices]\n\nn_pseudo = len(confident_indices)\npseudo_rate = n_pseudo / len(X_test_level1)\n\nprint(f\"Pseudo-labeled samples: {n_pseudo:,}\")\nprint(f\"Pseudo-label rate: {pseudo_rate:.2%}\")\n\nX_test_confident = X_test_level1[confident_indices]\n\n# Ghép thêm dữ liệu Test vào tập Train cho Meta-learner\nX_train_level1_extended = np.vstack([X_train_level1, X_test_confident])\ny_train_extended = np.concatenate([y_train, pseudo_labels])\n\nprint(f\"-> Đã đóng băng và thêm {len(confident_indices)} mẫu từ tập Test.\")\n\nprint(\"\\n[Level-1] Training Meta-Learner (XGBoost)...\")\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', # Bật GPU\n    random_state=99\n)\nmeta_learner.fit(X_train_level1_extended, y_train_extended)\n\n# Lưu Meta-Learner\njoblib.dump(meta_learner, os.path.join(MODEL_DIR, 'meta_learner.pkl'))\nprint(\"Hoàn tất Phần 2! Models đã lưu vào thư mục models/\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}