{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.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":116062,"databundleVersionId":14875579,"sourceType":"competition"},{"sourceId":703985,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":534321,"modelId":547981}],"dockerImageVersionId":31234,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==============================================================================\n# CAFA 6 PROTEIN FUNCTION PREDICTION - SINGLE CELL PIPELINE\n# HƯỚNG DẪN: Sao chép toàn bộ ô này vào một Notebook trên Kaggle và nhấn Run.\n# INSTRUCTIONS: Copy this entire cell into a Kaggle Notebook and hit Run.\n# ==============================================================================\n\nimport os\nimport numpy as np\nimport pandas as pd\nimport joblib\nfrom sklearn.feature_extraction.text import TfidfVectorizer\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.multiclass import OneVsRestClassifier\n\n# ------------------------------------------------------------------------------\n# 1. CẤU HÌNH ĐƯỜNG DẪN / PATH CONFIGURATION\n# ------------------------------------------------------------------------------\nDATA_DIR = \"/kaggle/input/cafa-6-protein-function-prediction\"\nTRAIN_TERMS = os.path.join(DATA_DIR, \"Train\", \"train_terms.tsv\")\nTRAIN_FASTA = os.path.join(DATA_DIR, \"Train\", \"train_sequences.fasta\")\nTEST_FASTA  = os.path.join(DATA_DIR, \"Test\", \"testsuperset.fasta\")\n\nMODEL_PATH = \"/kaggle/working/ProteinModel.pkl\"\nOUTPUT_FILE = \"/kaggle/working/submission.tsv\"\n\n# Các tham số huấn luyện / Training parameters\nTOP_K_TERMS = 1500      # Số lượng nhãn GO phổ biến nhất / Number of top GO terms\nSUBSET_SIZE = 30000     # Số lượng protein dùng để huấn luyện / Number of proteins for training\nK_MER_SIZE = 3          # Độ dài k-mer cho protein / k-mer length for protein sequences\n\n# ------------------------------------------------------------------------------\n# 2. HÀM ĐỌC FILE FASTA / FASTA READER FUNCTION\n# ------------------------------------------------------------------------------\ndef read_fasta(path):\n    \"\"\"\n    Đọc tệp FASTA và trả về danh sách (ID, Chuỗi)\n    Reads FASTA file and returns a list of (ID, Sequence)\n    \"\"\"\n    records = []\n    if not os.path.exists(path):\n        return records\n    with open(path, \"r\") as f:\n        seq_id, seq_buf = None, []\n        for line in f:\n            line = line.strip()\n            if line.startswith(\">\"):\n                if seq_id and seq_buf:\n                    records.append((seq_id, \"\".join(seq_buf)))\n                # Extract EntryID from header\n                header = line[1:]\n                parts = header.split(\"|\")\n                seq_id = parts[1] if len(parts) >= 2 else header.split()[0]\n                seq_buf = []\n            else:\n                seq_buf.append(line)\n        if seq_id and seq_buf:\n            records.append((seq_id, \"\".join(seq_buf)))\n    return records\n\n# ------------------------------------------------------------------------------\n# 3. TIỀN XỬ LÝ DỮ LIỆU / DATA PREPROCESSING\n# ------------------------------------------------------------------------------\nprint(\"--- [1/5] Loading Data ---\")\ntrain_records = read_fasta(TRAIN_FASTA)\ntest_records  = read_fasta(TEST_FASTA)\ntrain_terms_df = pd.read_csv(TRAIN_TERMS, sep=\"\\t\")\n\nprint(f\"Train sequences: {len(train_records)} | Test sequences: {len(test_records)}\")\n\n# Chọn Top GO terms phổ biến / Select most frequent GO terms\ntop_terms = train_terms_df[\"term\"].value_counts().head(TOP_K_TERMS).index.tolist()\nterm_to_idx = {t: i for i, t in enumerate(top_terms)}\n\n# Chuẩn bị dữ liệu huấn luyện / Prepare training data\ntrain_ids = [r[0] for r in train_records[:SUBSET_SIZE]]\ntrain_seqs = [r[1] for r in train_records[:SUBSET_SIZE]]\nid_to_pos = {uid: i for i, uid in enumerate(train_ids)}\n\n# Tạo ma trận nhãn Y / Create Label matrix Y\nY = np.zeros((len(train_ids), TOP_K_TERMS), dtype=np.float32)\ntrain_subset_terms = train_terms_df[train_terms_df[\"EntryID\"].isin(train_ids)]\nfor row in train_subset_terms.itertuples():\n    if row.term in term_to_idx:\n        Y[id_to_pos[row.EntryID], term_to_idx[row.term]] = 1.0\n\n# Lọc bỏ nhãn hằng (toàn 0 hoặc toàn 1) / Remove constant labels (all 0 or all 1)\nmask_nonconstant = (Y.sum(axis=0) != 0) & (Y.sum(axis=0) != Y.shape[0])\nY_filtered = Y[:, mask_nonconstant]\ntop_terms_filtered = [t for i,t in enumerate(top_terms) if mask_nonconstant[i]]\nprint(\"Filtered label matrix shape:\", Y_filtered.shape)\n\n# Chuyển chuỗi protein thành k-mers / Convert sequences to k-mers\ndef to_kmers(seq, k=K_MER_SIZE):\n    return \" \".join([seq[i:i+k] for i in range(len(seq)-k+1)])\n\nprint(\"--- [2/5] Vectorizing Sequences (TF-IDF) ---\")\nvectorizer = TfidfVectorizer(min_df=2, max_features=10000)\nX_train = vectorizer.fit_transform([to_kmers(s) for s in train_seqs])\nX_test  = vectorizer.transform([to_kmers(r[1]) for r in test_records])\n\n# ------------------------------------------------------------------------------\n# 4. HUẤN LUYỆN VÀ LƯU MÔ HÌNH / TRAINING & SAVING MODEL\n# ------------------------------------------------------------------------------\nprint(f\"--- [3/5] Training Model (Subset: {SUBSET_SIZE}) ---\")\nclf = OneVsRestClassifier(LogisticRegression(max_iter=200, solver='liblinear'))\nclf.fit(X_train, Y_filtered)\n\nprint(f\"--- [4/5] Saving Model to {MODEL_PATH} ---\")\njoblib.dump(clf, MODEL_PATH)\n\n# ------------------------------------------------------------------------------\n# 5. DỰ ĐOÁN VÀ XUẤT FILE SUBMISSION / PREDICTION & SUBMISSION\n# ------------------------------------------------------------------------------\nprint(\"--- [5/5] Generating Predictions & submission.tsv ---\")\n\ndef sigmoid(x): return 1.0 / (1.0 + np.exp(-x))\n\nscores_raw = clf.decision_function(X_test)\nprobs = sigmoid(scores_raw)\n\nsubmission_rows = []\ntest_ids = [r[0] for r in test_records]\n\nfor i, uid in enumerate(test_ids):\n    top_indices = np.argsort(probs[i])[::-1][:50]\n    for idx in top_indices:\n        p = probs[i][idx]\n        if p > 0.001:\n            submission_rows.append([uid, top_terms_filtered[idx], f\"{p:.3f}\"])\n\nsubmission_df = pd.DataFrame(submission_rows)\nsubmission_df.to_csv(OUTPUT_FILE, sep=\"\\t\", header=False, index=False)\n\nprint(\"-\" * 30)\nprint(\"SUCCESS!\")\nprint(f\"Model saved: {MODEL_PATH}\")\nprint(f\"Submission saved: {OUTPUT_FILE}\")\nprint(f\"Total rows in submission: {len(submission_df)}\")\nprint(\"-\" * 30)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---------------------------------------------\n**Backup the results of running the above code:**\n\n(Backup Kết quả chạy code trên:)\n\n---------------------------------------------\n\n--- [1/5] Loading Data ---\n\nTrain sequences: 82404 | Test sequences: 224309\n\nFiltered label matrix shape: (30000, 1488)\n\n--- [2/5] Vectorizing Sequences (TF-IDF) ---\n\n--- [3/5] Training Model (Subset: 30000) ---\n\n--- [4/5] Saving Model to /kaggle/working/ProteinModel.pkl ---\n\n--- [5/5] Generating Predictions & submission.tsv ---\n\n------------------------------\n**SUCCESS!**\n\nModel saved: /kaggle/working/**ProteinModel.pkl**\n\nSubmission saved: /kaggle/working/submission.tsv\n\nTotal rows in submission: **11215450**\n\n------------------------------","metadata":{}},{"cell_type":"code","source":"# ==============================================================================\n# XUẤT FILE SUBMISSION VÀ KIỂM TRA ĐỊNH DẠNG CUỐI CÙNG\n# ==============================================================================\nimport os\n\nprint(\"--- [6/6] Finalizing Files for Kaggle ---\")\n\n# 1. Đảm bảo DataFrame submission có định dạng chuẩn (EntryID, Term, Score)\n# Theo yêu cầu của CAFA, file .tsv không có tiêu đề (header=False)\nif 'submission_df' in locals():\n    # Lưu file submission.tsv vào thư mục làm việc của Kaggle\n    submission_df.to_csv(OUTPUT_FILE, sep=\"\\t\", header=False, index=False)\n    print(f\"✅ Đã xuất tệp nộp bài: {OUTPUT_FILE}\")\n    print(f\"✅ Tổng số dòng dự đoán: {len(submission_df)}\")\nelse:\n    print(\"❌ Lỗi: Không tìm thấy submission_df. Vui lòng chạy ô code trước đó.\")\n\n# 2. Xác nhận lưu mô hình\nif os.path.exists(MODEL_PATH):\n    print(f\"✅ Mô hình đã được lưu tại: {MODEL_PATH}\")\n    print(\"💡 Bạn có thể tìm thấy file này trong tab 'Output' của Kaggle Notebook.\")\nelse:\n    print(f\"⚠️ Cảnh báo: Không tìm thấy file mô hình tại {MODEL_PATH}\")\n\n# 3. Xem trước 5 dòng đầu của file submission\nprint(\"\\n--- Xem trước nội dung file submission ---\")\nprint(submission_df.head())\n\nprint(\"-\" * 30)\nprint(\"HOÀN TẤT! Hãy nhấn nút 'Save Version' (hoặc 'Submit') ở góc trên bên phải Kaggle.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}