{"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"}],"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,"execution":{"iopub.status.busy":"2026-01-03T07:53:59.278388Z","iopub.execute_input":"2026-01-03T07:53:59.278784Z","iopub.status.idle":"2026-01-03T07:53:59.291447Z","shell.execute_reply.started":"2026-01-03T07:53:59.278752Z","shell.execute_reply":"2026-01-03T07:53:59.290539Z"}},"outputs":[{"name":"stdout","text":"/kaggle/input/cafa-6-protein-function-prediction/sample_submission.tsv\n/kaggle/input/cafa-6-protein-function-prediction/IA.tsv\n/kaggle/input/cafa-6-protein-function-prediction/Test/testsuperset.fasta\n/kaggle/input/cafa-6-protein-function-prediction/Test/testsuperset-taxon-list.tsv\n/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv\n/kaggle/input/cafa-6-protein-function-prediction/Train/train_sequences.fasta\n/kaggle/input/cafa-6-protein-function-prediction/Train/train_taxonomy.tsv\n/kaggle/input/cafa-6-protein-function-prediction/Train/go-basic.obo\n","output_type":"stream"}],"execution_count":5},{"cell_type":"code","source":"import os\n\nos.listdir(\"/kaggle/input/cafa-6-protein-function-prediction/Train\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:53:59.293248Z","iopub.execute_input":"2026-01-03T07:53:59.293546Z","iopub.status.idle":"2026-01-03T07:53:59.313811Z","shell.execute_reply.started":"2026-01-03T07:53:59.293518Z","shell.execute_reply":"2026-01-03T07:53:59.3129Z"}},"outputs":[{"execution_count":6,"output_type":"execute_result","data":{"text/plain":"['train_terms.tsv',\n 'train_sequences.fasta',\n 'train_taxonomy.tsv',\n 'go-basic.obo']"},"metadata":{}}],"execution_count":6},{"cell_type":"code","source":"import pandas as pd\n\ntrain_terms = pd.read_csv(\n    \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv\",\n    sep=\"\\t\"\n)\ntrain_terms.head(2000)\n# len(train_terms)\n# train_terms.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:53:59.315303Z","iopub.execute_input":"2026-01-03T07:53:59.315657Z","iopub.status.idle":"2026-01-03T07:53:59.592344Z","shell.execute_reply.started":"2026-01-03T07:53:59.315618Z","shell.execute_reply":"2026-01-03T07:53:59.591294Z"}},"outputs":[{"execution_count":7,"output_type":"execute_result","data":{"text/plain":"     EntryID        term aspect\n0     Q5W0B1  GO:0000785      C\n1     Q5W0B1  GO:0004842      F\n2     Q5W0B1  GO:0051865      P\n3     Q5W0B1  GO:0006275      P\n4     Q5W0B1  GO:0006513      P\n...      ...         ...    ...\n1995  P56564  GO:0031223      P\n1996  P56564  GO:0048667      P\n1997  P56564  GO:0006883      P\n1998  P56564  GO:0050806      P\n1999  P56564  GO:0050885      P\n\n[2000 rows x 3 columns]","text/html":"<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>EntryID</th>\n      <th>term</th>\n      <th>aspect</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>Q5W0B1</td>\n      <td>GO:0000785</td>\n      <td>C</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>Q5W0B1</td>\n      <td>GO:0004842</td>\n      <td>F</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>Q5W0B1</td>\n      <td>GO:0051865</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>Q5W0B1</td>\n      <td>GO:0006275</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>Q5W0B1</td>\n      <td>GO:0006513</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>...</th>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n    </tr>\n    <tr>\n      <th>1995</th>\n      <td>P56564</td>\n      <td>GO:0031223</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>1996</th>\n      <td>P56564</td>\n      <td>GO:0048667</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>1997</th>\n      <td>P56564</td>\n      <td>GO:0006883</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>1998</th>\n      <td>P56564</td>\n      <td>GO:0050806</td>\n      <td>P</td>\n    </tr>\n    <tr>\n      <th>1999</th>\n      <td>P56564</td>\n      <td>GO:0050885</td>\n      <td>P</td>\n    </tr>\n  </tbody>\n</table>\n<p>2000 rows × 3 columns</p>\n</div>"},"metadata":{}}],"execution_count":7},{"cell_type":"code","source":"pip install Bio","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:53:59.593569Z","iopub.execute_input":"2026-01-03T07:53:59.593954Z","iopub.status.idle":"2026-01-03T07:54:09.490836Z","shell.execute_reply.started":"2026-01-03T07:53:59.593917Z","shell.execute_reply":"2026-01-03T07:54:09.489725Z"}},"outputs":[{"name":"stdout","text":"Collecting Bio\n  Downloading bio-1.8.1-py3-none-any.whl.metadata (5.7 kB)\nCollecting biopython>=1.80 (from Bio)\n  Downloading biopython-1.86-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (13 kB)\nCollecting gprofiler-official (from Bio)\n  Downloading gprofiler_official-1.0.0-py3-none-any.whl.metadata (11 kB)\nCollecting mygene (from Bio)\n  Downloading mygene-3.2.2-py2.py3-none-any.whl.metadata (10 kB)\nRequirement already satisfied: pandas in /usr/local/lib/python3.12/dist-packages (from Bio) (2.2.2)\nRequirement already satisfied: pooch in /usr/local/lib/python3.12/dist-packages (from Bio) (1.8.2)\nRequirement already satisfied: requests in /usr/local/lib/python3.12/dist-packages (from Bio) (2.32.5)\nRequirement already satisfied: tqdm in /usr/local/lib/python3.12/dist-packages (from Bio) (4.67.1)\nRequirement already satisfied: numpy in /usr/local/lib/python3.12/dist-packages (from biopython>=1.80->Bio) (2.0.2)\nCollecting biothings-client>=0.2.6 (from mygene->Bio)\n  Downloading biothings_client-0.4.1-py3-none-any.whl.metadata (10 kB)\nRequirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas->Bio) (2.9.0.post0)\nRequirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas->Bio) (2025.2)\nRequirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas->Bio) (2025.3)\nRequirement already satisfied: platformdirs>=2.5.0 in /usr/local/lib/python3.12/dist-packages (from pooch->Bio) (4.5.1)\nRequirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from pooch->Bio) (25.0)\nRequirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests->Bio) (3.4.4)\nRequirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests->Bio) (3.11)\nRequirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests->Bio) (2.6.2)\nRequirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests->Bio) (2025.11.12)\nRequirement already satisfied: httpx>=0.22.0 in /usr/local/lib/python3.12/dist-packages (from biothings-client>=0.2.6->mygene->Bio) (0.28.1)\nRequirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas->Bio) (1.17.0)\nRequirement already satisfied: anyio in /usr/local/lib/python3.12/dist-packages (from httpx>=0.22.0->biothings-client>=0.2.6->mygene->Bio) (4.12.0)\nRequirement already satisfied: httpcore==1.* in /usr/local/lib/python3.12/dist-packages (from httpx>=0.22.0->biothings-client>=0.2.6->mygene->Bio) (1.0.9)\nRequirement already satisfied: h11>=0.16 in /usr/local/lib/python3.12/dist-packages (from httpcore==1.*->httpx>=0.22.0->biothings-client>=0.2.6->mygene->Bio) (0.16.0)\nRequirement already satisfied: typing_extensions>=4.5 in /usr/local/lib/python3.12/dist-packages (from anyio->httpx>=0.22.0->biothings-client>=0.2.6->mygene->Bio) (4.15.0)\nDownloading bio-1.8.1-py3-none-any.whl (321 kB)\n\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m321.3/321.3 kB\u001b[0m \u001b[31m8.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m:00:01\u001b[0m\n\u001b[?25hDownloading biopython-1.86-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.2 MB)\n\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.2/3.2 MB\u001b[0m \u001b[31m68.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m:00:01\u001b[0m\n\u001b[?25hDownloading gprofiler_official-1.0.0-py3-none-any.whl (9.3 kB)\nDownloading mygene-3.2.2-py2.py3-none-any.whl (5.4 kB)\nDownloading biothings_client-0.4.1-py3-none-any.whl (46 kB)\n\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m46.7/46.7 kB\u001b[0m \u001b[31m2.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n\u001b[?25hInstalling collected packages: biopython, gprofiler-official, biothings-client, mygene, Bio\nSuccessfully installed Bio-1.8.1 biopython-1.86 biothings-client-0.4.1 gprofiler-official-1.0.0 mygene-3.2.2\nNote: you may need to restart the kernel to use updated packages.\n","output_type":"stream"}],"execution_count":8},{"cell_type":"code","source":"from Bio import SeqIO\n\nfasta_path = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_sequences.fasta\"\n\nnum_sequences = sum(1 for _ in SeqIO.parse(fasta_path, \"fasta\"))\nnum_sequences","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:09.493666Z","iopub.execute_input":"2026-01-03T07:54:09.493997Z","iopub.status.idle":"2026-01-03T07:54:10.920576Z","shell.execute_reply.started":"2026-01-03T07:54:09.493963Z","shell.execute_reply":"2026-01-03T07:54:10.919728Z"}},"outputs":[{"execution_count":9,"output_type":"execute_result","data":{"text/plain":"82404"},"metadata":{}}],"execution_count":9},{"cell_type":"code","source":"from Bio import SeqIO\n\n\n\nprotein_to_seq = {}\n\nfor record in SeqIO.parse(fasta_path, \"fasta\"):\n    protein_to_seq[record.id] = str(record.seq)\n\nlen(protein_to_seq)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:10.921596Z","iopub.execute_input":"2026-01-03T07:54:10.92192Z","iopub.status.idle":"2026-01-03T07:54:11.472256Z","shell.execute_reply.started":"2026-01-03T07:54:10.921863Z","shell.execute_reply":"2026-01-03T07:54:11.47127Z"}},"outputs":[{"execution_count":10,"output_type":"execute_result","data":{"text/plain":"82404"},"metadata":{}}],"execution_count":10},{"cell_type":"code","source":"import pandas as pd\n\nterms_path = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv\"\n\nterms_df = pd.read_csv(terms_path, sep=\"\\t\")\nterms_df.head()\nlen(terms_df)\nterms_df[\"aspect\"].value_counts()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:11.47374Z","iopub.execute_input":"2026-01-03T07:54:11.474149Z","iopub.status.idle":"2026-01-03T07:54:11.80642Z","shell.execute_reply.started":"2026-01-03T07:54:11.474113Z","shell.execute_reply":"2026-01-03T07:54:11.805312Z"}},"outputs":[{"execution_count":11,"output_type":"execute_result","data":{"text/plain":"aspect\nP    250805\nC    157770\nF    128452\nName: count, dtype: int64"},"metadata":{}}],"execution_count":11},{"cell_type":"code","source":"mf_df = terms_df[terms_df[\"aspect\"] == \"F\"]\nlen(mf_df)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:11.808017Z","iopub.execute_input":"2026-01-03T07:54:11.808411Z","iopub.status.idle":"2026-01-03T07:54:11.8723Z","shell.execute_reply.started":"2026-01-03T07:54:11.808374Z","shell.execute_reply":"2026-01-03T07:54:11.871371Z"}},"outputs":[{"execution_count":12,"output_type":"execute_result","data":{"text/plain":"128452"},"metadata":{}}],"execution_count":12},{"cell_type":"code","source":"protein_to_terms = (\n    mf_df\n    .groupby(\"EntryID\")[\"term\"]\n    .apply(list)\n    .to_dict()\n)\nlist(protein_to_terms.items())[:3]\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:11.873726Z","iopub.execute_input":"2026-01-03T07:54:11.874118Z","iopub.status.idle":"2026-01-03T07:54:13.139402Z","shell.execute_reply.started":"2026-01-03T07:54:11.874081Z","shell.execute_reply":"2026-01-03T07:54:13.138325Z"}},"outputs":[{"execution_count":13,"output_type":"execute_result","data":{"text/plain":"[('A0A023FBW4', ['GO:0019958']),\n ('A0A023FBW7', ['GO:0019957']),\n ('A0A023FDY8', ['GO:0019957'])]"},"metadata":{}}],"execution_count":13},{"cell_type":"code","source":"from Bio import SeqIO\n\nfasta_path = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_sequences.fasta\"\n\nprotein_to_seq = {}\n\nfor record in SeqIO.parse(fasta_path, \"fasta\"):\n    # FASTA header example: sp|Q5W0B1|XXXX\n    protein_id = record.id.split(\"|\")[1]\n    protein_to_seq[protein_id] = str(record.seq)\n\nlen(protein_to_seq)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.141177Z","iopub.execute_input":"2026-01-03T07:54:13.141507Z","iopub.status.idle":"2026-01-03T07:54:13.709009Z","shell.execute_reply.started":"2026-01-03T07:54:13.141479Z","shell.execute_reply":"2026-01-03T07:54:13.707991Z"}},"outputs":[{"execution_count":14,"output_type":"execute_result","data":{"text/plain":"82404"},"metadata":{}}],"execution_count":14},{"cell_type":"code","source":"X_sequences = []\nY_terms = []\n\nfor protein_id, terms in protein_to_terms.items():\n    if protein_id in protein_to_seq:\n        X_sequences.append(protein_to_seq[protein_id])\n        Y_terms.append(terms)\n\nlen(X_sequences), len(Y_terms)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.71009Z","iopub.execute_input":"2026-01-03T07:54:13.710483Z","iopub.status.idle":"2026-01-03T07:54:13.763761Z","shell.execute_reply.started":"2026-01-03T07:54:13.710456Z","shell.execute_reply":"2026-01-03T07:54:13.76291Z"}},"outputs":[{"execution_count":15,"output_type":"execute_result","data":{"text/plain":"(58001, 58001)"},"metadata":{}}],"execution_count":15},{"cell_type":"code","source":"all_go_terms = sorted({go for terms in Y_terms for go in terms})\n\ngo_to_idx = {go: i for i, go in enumerate(all_go_terms)}\nidx_to_go = {i: go for go, i in go_to_idx.items()}\n\nlen(go_to_idx)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.764981Z","iopub.execute_input":"2026-01-03T07:54:13.765321Z","iopub.status.idle":"2026-01-03T07:54:13.790414Z","shell.execute_reply.started":"2026-01-03T07:54:13.765287Z","shell.execute_reply":"2026-01-03T07:54:13.789209Z"}},"outputs":[{"execution_count":16,"output_type":"execute_result","data":{"text/plain":"6616"},"metadata":{}}],"execution_count":16},{"cell_type":"code","source":"k = 3\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.791555Z","iopub.execute_input":"2026-01-03T07:54:13.791838Z","iopub.status.idle":"2026-01-03T07:54:13.811538Z","shell.execute_reply.started":"2026-01-03T07:54:13.79181Z","shell.execute_reply":"2026-01-03T07:54:13.810379Z"}},"outputs":[],"execution_count":17},{"cell_type":"code","source":"def get_kmers(sequence, k):\n    return [sequence[i:i+k] for i in range(len(sequence) - k + 1)]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.815472Z","iopub.execute_input":"2026-01-03T07:54:13.815801Z","iopub.status.idle":"2026-01-03T07:54:13.833451Z","shell.execute_reply.started":"2026-01-03T07:54:13.815773Z","shell.execute_reply":"2026-01-03T07:54:13.832549Z"}},"outputs":[],"execution_count":18},{"cell_type":"code","source":"import numpy as np\n\ndef get_kmers(sequence, k):\n    return [sequence[i:i+k] for i in range(len(sequence) - k + 1)]\n\ndef encode_sequence(seq, kmer_to_idx, k):\n    vec = np.zeros(len(kmer_to_idx), dtype=np.float32)\n    for kmer in get_kmers(seq, k):\n        if kmer in kmer_to_idx:\n            vec[kmer_to_idx[kmer]] += 1\n    return vec\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.834606Z","iopub.execute_input":"2026-01-03T07:54:13.834931Z","iopub.status.idle":"2026-01-03T07:54:13.857258Z","shell.execute_reply.started":"2026-01-03T07:54:13.834894Z","shell.execute_reply":"2026-01-03T07:54:13.856324Z"}},"outputs":[],"execution_count":19},{"cell_type":"code","source":"all_kmers = set()\n\nfor seq in X_sequences:\n    all_kmers.update(get_kmers(seq, k))\n\nlen(all_kmers)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:13.858304Z","iopub.execute_input":"2026-01-03T07:54:13.858558Z","iopub.status.idle":"2026-01-03T07:54:18.849362Z","shell.execute_reply.started":"2026-01-03T07:54:13.858534Z","shell.execute_reply":"2026-01-03T07:54:18.84833Z"}},"outputs":[{"execution_count":20,"output_type":"execute_result","data":{"text/plain":"8350"},"metadata":{}}],"execution_count":20},{"cell_type":"code","source":"kmer_to_idx = {kmer: i for i, kmer in enumerate(sorted(all_kmers))}\nidx_to_kmer = {i: kmer for kmer, i in kmer_to_idx.items()}\n\nlen(kmer_to_idx)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:18.850411Z","iopub.execute_input":"2026-01-03T07:54:18.850713Z","iopub.status.idle":"2026-01-03T07:54:18.863305Z","shell.execute_reply.started":"2026-01-03T07:54:18.85068Z","shell.execute_reply":"2026-01-03T07:54:18.862343Z"}},"outputs":[{"execution_count":21,"output_type":"execute_result","data":{"text/plain":"8350"},"metadata":{}}],"execution_count":21},{"cell_type":"code","source":"encoded = encode_sequence(X_sequences[0], kmer_to_idx, k)\nencoded.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:18.86447Z","iopub.execute_input":"2026-01-03T07:54:18.864774Z","iopub.status.idle":"2026-01-03T07:54:18.886205Z","shell.execute_reply.started":"2026-01-03T07:54:18.864747Z","shell.execute_reply":"2026-01-03T07:54:18.885313Z"}},"outputs":[{"execution_count":22,"output_type":"execute_result","data":{"text/plain":"(8350,)"},"metadata":{}}],"execution_count":22},{"cell_type":"code","source":"X = np.vstack([\n    encode_sequence(seq, kmer_to_idx, k)\n    for seq in X_sequences\n])\n\nX.shape\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:54:18.887328Z","iopub.execute_input":"2026-01-03T07:54:18.887634Z","iopub.status.idle":"2026-01-03T07:54:40.531049Z","shell.execute_reply.started":"2026-01-03T07:54:18.887607Z","shell.execute_reply":"2026-01-03T07:54:40.529933Z"}},"outputs":[{"execution_count":23,"output_type":"execute_result","data":{"text/plain":"(58001, 8350)"},"metadata":{}}],"execution_count":23},{"cell_type":"code","source":"import numpy as np\n\nnum_samples = len(Y_terms)\nnum_labels = len(go_to_idx)\n\nY = np.zeros((num_samples, num_labels), dtype=np.float32)\n\nfor i, terms in enumerate(Y_terms):\n    for go in terms:\n        Y[i, go_to_idx[go]] = 1.0\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:55:07.221799Z","iopub.execute_input":"2026-01-03T07:55:07.222208Z","iopub.status.idle":"2026-01-03T07:55:07.617867Z","shell.execute_reply.started":"2026-01-03T07:55:07.222175Z","shell.execute_reply":"2026-01-03T07:55:07.616649Z"}},"outputs":[],"execution_count":25},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_val, Y_train, Y_val = train_test_split(\n    X,\n    Y,\n    test_size=0.2,\n    random_state=42\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:55:10.251094Z","iopub.execute_input":"2026-01-03T07:55:10.251427Z","iopub.status.idle":"2026-01-03T07:55:11.964315Z","shell.execute_reply.started":"2026-01-03T07:55:10.2514Z","shell.execute_reply":"2026-01-03T07:55:11.963311Z"}},"outputs":[],"execution_count":26},{"cell_type":"code","source":"X_train.shape, X_val.shape, Y_train.shape, Y_val.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:55:13.093778Z","iopub.execute_input":"2026-01-03T07:55:13.094138Z","iopub.status.idle":"2026-01-03T07:55:13.100999Z","shell.execute_reply.started":"2026-01-03T07:55:13.094109Z","shell.execute_reply":"2026-01-03T07:55:13.099864Z"}},"outputs":[{"execution_count":27,"output_type":"execute_result","data":{"text/plain":"((46400, 8350), (11601, 8350), (46400, 6616), (11601, 6616))"},"metadata":{}}],"execution_count":27},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:55:17.304306Z","iopub.execute_input":"2026-01-03T07:55:17.304643Z","iopub.status.idle":"2026-01-03T07:55:24.956407Z","shell.execute_reply.started":"2026-01-03T07:55:17.304617Z","shell.execute_reply":"2026-01-03T07:55:24.955137Z"}},"outputs":[],"execution_count":28},{"cell_type":"code","source":"X_train_t = torch.tensor(X_train, dtype=torch.float32)\nY_train_t = torch.tensor(Y_train, dtype=torch.float32)\n\nX_val_t = torch.tensor(X_val, dtype=torch.float32)\nY_val_t = torch.tensor(Y_val, dtype=torch.float32)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:55:28.499421Z","iopub.execute_input":"2026-01-03T07:55:28.49976Z","iopub.status.idle":"2026-01-03T07:55:29.971263Z","shell.execute_reply.started":"2026-01-03T07:55:28.499731Z","shell.execute_reply":"2026-01-03T07:55:29.97028Z"}},"outputs":[],"execution_count":31},{"cell_type":"code","source":"class KMerMLP(nn.Module):\n    def __init__(self, input_dim, output_dim):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.Linear(input_dim, 1024),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n\n            nn.Linear(1024, 512),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n\n            nn.Linear(512, output_dim)\n            # NO sigmoid here (important)\n        )\n\n    def forward(self, x):\n        return self.net(x)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T07:56:13.084689Z","iopub.execute_input":"2026-01-03T07:56:13.08508Z","iopub.status.idle":"2026-01-03T07:56:13.092512Z","shell.execute_reply.started":"2026-01-03T07:56:13.085048Z","shell.execute_reply":"2026-01-03T07:56:13.091144Z"}},"outputs":[],"execution_count":32},{"cell_type":"code","source":"input_dim = X_train.shape[1]   # 8350\noutput_dim = Y_train.shape[1]  # 6616\n\nmodel = KMerMLP(input_dim, output_dim)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:04:14.942857Z","iopub.execute_input":"2026-01-03T08:04:14.946512Z","iopub.status.idle":"2026-01-03T08:04:15.10892Z","shell.execute_reply.started":"2026-01-03T08:04:14.94637Z","shell.execute_reply":"2026-01-03T08:04:15.107703Z"}},"outputs":[],"execution_count":33},{"cell_type":"code","source":"criterion = nn.BCEWithLogitsLoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-3)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:04:20.818806Z","iopub.execute_input":"2026-01-03T08:04:20.820094Z","iopub.status.idle":"2026-01-03T08:04:26.275856Z","shell.execute_reply.started":"2026-01-03T08:04:20.820046Z","shell.execute_reply":"2026-01-03T08:04:26.275014Z"}},"outputs":[],"execution_count":34},{"cell_type":"code","source":"batch_size = 128\nepochs = 5\n\ndef train_epoch(X, Y, model, optimizer, criterion):\n    model.train()\n    total_loss = 0.0\n\n    for i in range(0, X.size(0), batch_size):\n        xb = X[i:i+batch_size]\n        yb = Y[i:i+batch_size]\n\n        optimizer.zero_grad()\n        logits = model(xb)\n        loss = criterion(logits, yb)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n    return total_loss / (X.size(0) // batch_size)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:04:31.629752Z","iopub.execute_input":"2026-01-03T08:04:31.630751Z","iopub.status.idle":"2026-01-03T08:04:31.637866Z","shell.execute_reply.started":"2026-01-03T08:04:31.630713Z","shell.execute_reply":"2026-01-03T08:04:31.636647Z"}},"outputs":[],"execution_count":35},{"cell_type":"code","source":"def validate(X, Y, model, criterion):\n    model.eval()\n    total_loss = 0.0\n\n    with torch.no_grad():\n        for i in range(0, X.size(0), batch_size):\n            xb = X[i:i+batch_size]\n            yb = Y[i:i+batch_size]\n\n            logits = model(xb)\n            loss = criterion(logits, yb)\n            total_loss += loss.item()\n\n    return total_loss / (X.size(0) // batch_size)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:04:46.259478Z","iopub.execute_input":"2026-01-03T08:04:46.260572Z","iopub.status.idle":"2026-01-03T08:04:46.266444Z","shell.execute_reply.started":"2026-01-03T08:04:46.260527Z","shell.execute_reply":"2026-01-03T08:04:46.265414Z"}},"outputs":[],"execution_count":36},{"cell_type":"code","source":"for epoch in range(epochs):\n    train_loss = train_epoch(X_train_t, Y_train_t, model, optimizer, criterion)\n    val_loss = validate(X_val_t, Y_val_t, model, criterion)\n\n    print(f\"Epoch {epoch+1}/{epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:04:50.329789Z","iopub.execute_input":"2026-01-03T08:04:50.33018Z","iopub.status.idle":"2026-01-03T08:10:22.045035Z","shell.execute_reply.started":"2026-01-03T08:04:50.330147Z","shell.execute_reply":"2026-01-03T08:10:22.043934Z"}},"outputs":[{"name":"stdout","text":"Epoch 1/5 | Train Loss: 0.0131 | Val Loss: 0.0028\nEpoch 2/5 | Train Loss: 0.0025 | Val Loss: 0.0024\nEpoch 3/5 | Train Loss: 0.0022 | Val Loss: 0.0022\nEpoch 4/5 | Train Loss: 0.0020 | Val Loss: 0.0021\nEpoch 5/5 | Train Loss: 0.0019 | Val Loss: 0.0020\n","output_type":"stream"}],"execution_count":37},{"cell_type":"code","source":"def predict_go_terms(\n    sequence,\n    model,\n    k,\n    kmer_to_idx,\n    idx_to_go,\n    \n    threshold=0.5,\n    top_k=None\n):\n    \"\"\"\n    Predict GO terms for a single protein sequence.\n\n    Args:\n        sequence (str): amino acid sequence\n        model (nn.Module): trained model\n        k (int): k-mer size\n        kmer_to_idx (dict): k-mer -> index\n        idx_to_go (dict): index -> GO term\n        device: torch device\n        threshold (float): probability threshold\n        top_k (int or None): if set, return only top-k predictions\n\n    Returns:\n        list of (GO_term, confidence)\n    \"\"\"\n    model.eval()\n\n    # Encode sequence\n    vec = encode_sequence(sequence, kmer_to_idx, k)\n    x = torch.tensor(vec, dtype=torch.float32).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        logits = model(x)\n        probs = torch.sigmoid(logits).squeeze(0).cpu().numpy()\n\n    results = []\n\n    for idx, prob in enumerate(probs):\n        if prob >= threshold:\n            results.append((idx_to_go[idx], float(prob)))\n\n    # Sort by confidence\n    results.sort(key=lambda x: x[1], reverse=True)\n\n    if top_k is not None:\n        results = results[:top_k]\n\n    return results\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:10:34.269739Z","iopub.execute_input":"2026-01-03T08:10:34.27153Z","iopub.status.idle":"2026-01-03T08:10:34.280186Z","shell.execute_reply.started":"2026-01-03T08:10:34.271445Z","shell.execute_reply":"2026-01-03T08:10:34.279117Z"}},"outputs":[],"execution_count":41},{"cell_type":"code","source":"def predict_go_terms_cpu(\n    sequence,\n    model,\n    k,\n    kmer_to_idx,\n    idx_to_go,\n    threshold=0.5,\n    top_k=None\n):\n    \"\"\"\n    Predict GO terms for a single protein sequence (CPU version).\n    \"\"\"\n    model.eval()\n\n    # Encode sequence\n    vec = encode_sequence(sequence, kmer_to_idx, k)\n    x = torch.tensor(vec, dtype=torch.float32).unsqueeze(0)\n\n    with torch.no_grad():\n        logits = model(x)\n        probs = torch.sigmoid(logits).squeeze(0).numpy()\n\n    results = []\n\n    for idx, prob in enumerate(probs):\n        if prob >= threshold:\n            results.append((idx_to_go[idx], float(prob)))\n\n    results.sort(key=lambda x: x[1], reverse=True)\n\n    if top_k is not None:\n        results = results[:top_k]\n\n    return results\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:11:05.386349Z","iopub.execute_input":"2026-01-03T08:11:05.387553Z","iopub.status.idle":"2026-01-03T08:11:05.395799Z","shell.execute_reply.started":"2026-01-03T08:11:05.387498Z","shell.execute_reply":"2026-01-03T08:11:05.394531Z"}},"outputs":[],"execution_count":45},{"cell_type":"code","source":"test_sequence = X_sequences[0]\n\npreds = predict_go_terms_cpu(\n    sequence=test_sequence,\n    model=model,\n    k=k,\n    kmer_to_idx=kmer_to_idx,\n    idx_to_go=idx_to_go,\n    threshold=0.5,\n    top_k=10\n)\n\nfor go, score in preds:\n    print(go, f\"{score:.3f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:11:00.092697Z","iopub.execute_input":"2026-01-03T08:11:00.093094Z","iopub.status.idle":"2026-01-03T08:11:00.109848Z","shell.execute_reply.started":"2026-01-03T08:11:00.093061Z","shell.execute_reply":"2026-01-03T08:11:00.108412Z"}},"outputs":[{"name":"stdout","text":"GO:0005515 0.572\n","output_type":"stream"}],"execution_count":44},{"cell_type":"code","source":"import torch\n\nmodel.eval()\n\nwith torch.no_grad():\n    logits = model(X_val_t)              # raw outputs\n    probs = torch.sigmoid(logits)        # probabilities\n    Y_val_pred = (probs >= 0.5).float()  # binary predictions\n\nY_val_pred = Y_val_pred.cpu().numpy()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:11:54.191544Z","iopub.execute_input":"2026-01-03T08:11:54.191966Z","iopub.status.idle":"2026-01-03T08:11:57.195449Z","shell.execute_reply.started":"2026-01-03T08:11:54.191932Z","shell.execute_reply":"2026-01-03T08:11:57.194654Z"}},"outputs":[],"execution_count":46},{"cell_type":"code","source":"Y_val_np = Y_val if isinstance(Y_val, np.ndarray) else Y_val_t.cpu().numpy()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:12:05.849302Z","iopub.execute_input":"2026-01-03T08:12:05.849704Z","iopub.status.idle":"2026-01-03T08:12:05.855317Z","shell.execute_reply.started":"2026-01-03T08:12:05.849671Z","shell.execute_reply":"2026-01-03T08:12:05.854345Z"}},"outputs":[],"execution_count":47},{"cell_type":"code","source":"from sklearn.metrics import precision_score, recall_score, f1_score\n\nprecision = precision_score(Y_val_np, Y_val_pred, average=\"micro\", zero_division=0)\nrecall    = recall_score(Y_val_np, Y_val_pred, average=\"micro\", zero_division=0)\nf1        = f1_score(Y_val_np, Y_val_pred, average=\"micro\", zero_division=0)\n\nprint(\"Micro Precision:\", precision)\nprint(\"Micro Recall:   \", recall)\nprint(\"Micro F1-score: \", f1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T08:12:16.707209Z","iopub.execute_input":"2026-01-03T08:12:16.707567Z","iopub.status.idle":"2026-01-03T08:12:27.972169Z","shell.execute_reply.started":"2026-01-03T08:12:16.707536Z","shell.execute_reply":"2026-01-03T08:12:27.970972Z"}},"outputs":[{"name":"stdout","text":"Micro Precision: 0.6546619531595228\nMicro Recall:    0.22863536401867357\nMicro F1-score:  0.33890938205942067\n","output_type":"stream"}],"execution_count":48},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}