{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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":14084779,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"pip install pandas numpy torch transformers scikit-learn tqdm biopython matplotlib","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:29:57.960767Z","iopub.execute_input":"2025-12-09T01:29:57.960925Z","iopub.status.idle":"2025-12-09T01:31:10.315956Z","shell.execute_reply.started":"2025-12-09T01:29:57.960906Z","shell.execute_reply":"2025-12-09T01:31:10.314487Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Giai đoạn 0 – Chuẩn bị môi trường (Kaggle đã có sẵn nhiều lib)\n# Nếu thiếu biopython/transformers thì uncomment dòng dưới để cài thêm:\n# !pip install -q biopython transformers\n\nimport os\nimport random\nimport numpy as np\nimport pandas as pd\n\nfrom tqdm import tqdm\nfrom Bio import SeqIO\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score, precision_score, recall_score\n\nfrom transformers import AutoTokenizer, AutoModel\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:39:04.591191Z","iopub.execute_input":"2025-12-09T01:39:04.591703Z","iopub.status.idle":"2025-12-09T01:39:20.850499Z","shell.execute_reply.started":"2025-12-09T01:39:04.591666Z","shell.execute_reply":"2025-12-09T01:39:20.849082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Đường dẫn dữ liệu trên Kaggle\nBASE_DIR = \"/kaggle/input/cafa-6-protein-function-prediction\"\n\nTRAIN_SEQ_PATH = os.path.join(BASE_DIR, \"Train\", \"train_sequences.fasta\")\nTRAIN_TERMS_PATH = os.path.join(BASE_DIR, \"Train\", \"train_terms.tsv\")\n\nTARGET_ASPECT = \"MFO\"\nNUM_TOP_TERMS = 500          # lấy 500 nhãn phổ biến nhất\nMAX_SEQ_LEN = 1024           # truncate cho backbone\nBATCH_SIZE = 64\nEPOCHS = 10\nLR = 1e-3\n\n# Backbone: em dùng ProtBERT trước cho ổn định\nBACKBONE_NAME = \"Rostlab/prot_bert\"\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndevice\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:46:46.709227Z","iopub.execute_input":"2025-12-09T01:46:46.711587Z","iopub.status.idle":"2025-12-09T01:46:46.728778Z","shell.execute_reply.started":"2025-12-09T01:46:46.711522Z","shell.execute_reply":"2025-12-09T01:46:46.726491Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set seed để reproducible\ndef set_seed(seed: int = 42):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n\nset_seed(42)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:47:10.434707Z","iopub.execute_input":"2025-12-09T01:47:10.436363Z","iopub.status.idle":"2025-12-09T01:47:10.445494Z","shell.execute_reply.started":"2025-12-09T01:47:10.436246Z","shell.execute_reply":"2025-12-09T01:47:10.443779Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def read_fasta_to_df(path):\n    \"\"\"Đọc file FASTA và chuyển thành DataFrame.\"\"\"\n    records = []\n    for record in SeqIO.parse(path, \"fasta\"):\n        records.append({\n            \"EntryID\": record.id,\n            \"Sequence\": str(record.seq),\n            \"Length\": len(record.seq)\n        })\n    return pd.DataFrame(records)\n\ndef normalize_uniprot_id(s: str) -> str:\n    \"\"\"\n    Chuẩn hóa ID UniProt về dạng đơn giản, ví dụ:\n      'sp|Q9XYZ1|SOMETHING'   -> 'Q9XYZ1'\n      'tr|Q9XYZ1|SOMETHING'   -> 'Q9XYZ1'\n      'UniProtKB:Q9XYZ1'      -> 'Q9XYZ1'\n    \"\"\"\n    s = str(s)\n    if \"|\" in s:\n        parts = s.split(\"|\")\n        if len(parts) >= 2 and len(parts[1]) >= 5:\n            return parts[1]\n    if s.startswith(\"UniProtKB:\"):\n        return s.split(\":\", 1)[1]\n    return s\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:47:26.663844Z","iopub.execute_input":"2025-12-09T01:47:26.664262Z","iopub.status.idle":"2025-12-09T01:47:26.672856Z","shell.execute_reply.started":"2025-12-09T01:47:26.664234Z","shell.execute_reply":"2025-12-09T01:47:26.671564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Đang load train_sequences.fasta ...\")\ndf_train_seq = read_fasta_to_df(TRAIN_SEQ_PATH)\nprint(\"df_train_seq:\", df_train_seq.shape)\n\nprint(\"\\nĐang load train_terms.tsv ...\")\ndf_train_terms = pd.read_csv(TRAIN_TERMS_PATH, sep=\"\\t\")\nprint(\"df_train_terms:\", df_train_terms.shape)\n\n# Xác định cột ID phía terms (Kaggle thường là 'EntryID')\nif \"EntryID\" in df_train_terms.columns:\n    TERMS_ID_COL = \"EntryID\"\nelse:\n    TERMS_ID_COL = df_train_terms.columns[0]\n\n# Chuẩn hoá ID\ndf_train_seq[\"ProtID\"] = df_train_seq[\"EntryID\"].apply(normalize_uniprot_id)\ndf_train_terms[\"ProtID\"] = df_train_terms[TERMS_ID_COL].apply(normalize_uniprot_id)\n\nprint(\"\\nVí dụ ID sau chuẩn hoá:\")\nprint(df_train_seq[[\"EntryID\", \"ProtID\"]].head())\nprint(df_train_terms[[TERMS_ID_COL, \"ProtID\"]].head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:47:39.172314Z","iopub.execute_input":"2025-12-09T01:47:39.172762Z","iopub.status.idle":"2025-12-09T01:47:40.604434Z","shell.execute_reply.started":"2025-12-09T01:47:39.172730Z","shell.execute_reply":"2025-12-09T01:47:40.603229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"=== VALIDATE CƠ BẢN ===\")\n\n# NA\nprint(\"\\nNA trong df_train_seq:\")\nprint(df_train_seq.isna().sum())\nprint(\"\\nNA trong df_train_terms:\")\nprint(df_train_terms.isna().sum())\n\n# Trùng ID trong FASTA\ndup_ids = df_train_seq[\"ProtID\"].duplicated().sum()\nif dup_ids == 0:\n    print(\"\\n[OK] Không có ProtID trùng trong FASTA.\")\nelse:\n    print(f\"\\n[WARNING] Có {dup_ids} ProtID trùng trong FASTA.\")\n\n# Giao giữa sequence & label\nseq_ids = set(df_train_seq[\"ProtID\"])\nterm_ids = set(df_train_terms[\"ProtID\"])\ncommon_ids = seq_ids.intersection(term_ids)\n\nprint(f\"\\nProtein có cả Sequence + Label: {len(common_ids)}\")\nprint(f\"Sequence nhưng không có Label: {len(seq_ids - term_ids)}\")\nprint(f\"Label nhưng không có Sequence: {len(term_ids - seq_ids)}\")\n\n# Phân bố độ dài chuỗi\nprint(\"\\nThống kê độ dài chuỗi (Length):\")\nprint(df_train_seq[\"Length\"].describe())\n\n# Phân bố aspect\nif \"aspect\" in df_train_terms.columns:\n    print(\"\\nPhân bố aspect:\")\n    print(df_train_terms[\"aspect\"].value_counts())\nelse:\n    print(\"\\n[WARNING] Không tìm thấy cột 'aspect' trong df_train_terms.\")\n\n# 1 term có nhiều aspect không\nif \"aspect\" in df_train_terms.columns and \"term\" in df_train_terms.columns:\n    term_aspect_counts = df_train_terms.groupby(\"term\")[\"aspect\"].nunique()\n    multi_aspect_terms = term_aspect_counts[term_aspect_counts > 1]\n    print(f\"\\nSố GO term có >1 aspect: {len(multi_aspect_terms)}\")\nelse:\n    print(\"\\n[INFO] Bỏ qua check multi-aspect.\")\n\n# Ký tự lạ trong sequence\nvalid_aas = set(\"ACDEFGHIKLMNPQRSTVWY\")\nallowed_extra = set(\"XBZJUOJ\")  # có thể chỉnh\nall_chars = set(\"\".join(df_train_seq[\"Sequence\"].tolist()))\nunexpected = all_chars - valid_aas - allowed_extra\nprint(\"\\nTập ký tự tìm thấy trong sequence:\", all_chars)\nif unexpected:\n    print(\"[WARNING] Ký tự lạ:\", unexpected)\nelse:\n    print(\"[OK] Không có ký tự lạ ngoài tập cho phép.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:48:32.989039Z","iopub.execute_input":"2025-12-09T01:48:32.989473Z","iopub.status.idle":"2025-12-09T01:48:33.730575Z","shell.execute_reply.started":"2025-12-09T01:48:32.989442Z","shell.execute_reply":"2025-12-09T01:48:33.728938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\n=== LỌC PROTEIN CÓ CẢ SEQ + LABEL & CHIA TRAIN / VAL ===\")\n\n# Chỉ giữ protein có cả sequence & label\ncommon_ids_list = list(common_ids)\n\ndf_seq_full  = df_train_seq[df_train_seq[\"ProtID\"].isin(common_ids_list)].copy()\ndf_terms_full = df_train_terms[df_train_terms[\"ProtID\"].isin(common_ids_list)].copy()\n\nprint(\"df_seq_full:\", df_seq_full.shape)\nprint(\"df_terms_full:\", df_terms_full.shape)\nprint(\"Số ProtID unique:\", df_seq_full[\"ProtID\"].nunique())\n\n# Split theo ProtID unique\nall_ids = df_seq_full[\"ProtID\"].unique()\ntrain_ids, val_ids = train_test_split(\n    all_ids, test_size=0.15, random_state=42, shuffle=True\n)\n\nprint(\"\\nSố ProtID Train:\", len(train_ids))\nprint(\"Số ProtID Val:\", len(val_ids))\n\ndef split_by_ids(df_seq, df_terms, ids):\n    df_seq_split = df_seq[df_seq[\"ProtID\"].isin(ids)].copy()\n    df_terms_split = df_terms[df_terms[\"ProtID\"].isin(ids)].copy()\n    return df_seq_split, df_terms_split\n\ndf_seq_train, df_terms_train = split_by_ids(df_seq_full, df_terms_full, train_ids)\ndf_seq_val,   df_terms_val   = split_by_ids(df_seq_full, df_terms_full, val_ids)\n\nprint(\"\\nSHAPE sau split:\")\nprint(\"Train seq:\", df_seq_train.shape, \" | Train terms:\", df_terms_train.shape)\nprint(\"Val   seq:\", df_seq_val.shape,   \" | Val   terms:\", df_terms_val.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:49:12.812981Z","iopub.execute_input":"2025-12-09T01:49:12.813463Z","iopub.status.idle":"2025-12-09T01:49:13.340548Z","shell.execute_reply.started":"2025-12-09T01:49:12.813442Z","shell.execute_reply":"2025-12-09T01:49:13.339675Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"\\n=== CHUẨN BỊ NHÃN CHO ASPECT: {TARGET_ASPECT} ===\")\n\ndf_terms_train_a = df_terms_train[df_terms_train[\"aspect\"] == TARGET_ASPECT].copy()\ndf_terms_val_a   = df_terms_val[df_terms_val[\"aspect\"] == TARGET_ASPECT].copy()\n\nprint(\"Train terms MFO:\", df_terms_train_a.shape)\nprint(\"Val   terms MFO:\", df_terms_val_a.shape)\n\n# Đếm tần suất theo GO term (trên train)\nterm_counts = df_terms_train_a[\"term\"].value_counts()\nprint(\"Tổng số GO term MFO (train):\", len(term_counts))\n\n# Lấy 500 term phổ biến nhất (hoặc ít hơn nếu không đủ)\ntop_terms = term_counts.head(NUM_TOP_TERMS).index.tolist()\nprint(f\"Số GO term được chọn (top {NUM_TOP_TERMS}):\", len(top_terms))\n\n# Lọc lại terms theo top_terms\ndf_terms_train_a = df_terms_train_a[df_terms_train_a[\"term\"].isin(top_terms)].copy()\ndf_terms_val_a   = df_terms_val_a[df_terms_val_a[\"term\"].isin(top_terms)].copy()\n\nprint(\"\\nSau khi lọc theo top_terms:\")\nprint(\"Train terms MFO:\", df_terms_train_a.shape)\nprint(\"Val   terms MFO:\", df_terms_val_a.shape)\n\n# Mapping term <-> index\nunique_terms = sorted(top_terms)\nterm2idx = {t: i for i, t in enumerate(unique_terms)}\nidx2term = {i: t for t, i in term2idx.items()}\nnum_labels = len(unique_terms)\n\nprint(\"\\nVí dụ 10 term đầu:\")\nfor i in range(min(10, num_labels)):\n    print(i, idx2term[i])\nprint(\"num_labels:\", num_labels)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-09T01:49:52.663076Z","iopub.execute_input":"2025-12-09T01:49:52.663447Z","iopub.status.idle":"2025-12-09T01:49:52.703396Z","shell.execute_reply.started":"2025-12-09T01:49:52.663429Z","shell.execute_reply":"2025-12-09T01:49:52.701846Z"}},"outputs":[],"execution_count":null}]}