{"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 Bio","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:41:51.870668Z","iopub.execute_input":"2025-12-10T03:41:51.870977Z","iopub.status.idle":"2025-12-10T03:42:00.269407Z","shell.execute_reply.started":"2025-12-10T03:41:51.870954Z","shell.execute_reply":"2025-12-10T03:42:00.268337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom Bio import SeqIO\nimport matplotlib.pyplot as plt\n\n# (optional: nicer plots)\nplt.rcParams[\"figure.figsize\"] = (8, 5)\n\nBASE = \"/kaggle/input/cafa-6-protein-function-prediction\"\n\n\nprint(\"=== FILE TREE ===\")\nfor root, dirs, files in os.walk(BASE):\n    for f in files:\n        print(os.path.join(root, f))\nprint()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:53:24.18415Z","iopub.execute_input":"2025-12-10T03:53:24.184496Z","iopub.status.idle":"2025-12-10T03:53:24.195123Z","shell.execute_reply.started":"2025-12-10T03:53:24.184469Z","shell.execute_reply":"2025-12-10T03:53:24.194157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 1. TRAINING SEQUENCES: train_sequences.fasta\n# ============================================================\n# Role:\n#   - Contains amino-acid sequences of proteins used for training.\n#   - Every ID here *should* have at least one GO term in train_terms.tsv.\n#   - You will featurize these sequences (e.g. embeddings, k-mers, etc.)\n#     and use them as input X for your model.\ntrain_fasta = os.path.join(BASE, \"Train\", \"train_sequences.fasta\")\n\ntrain_records = []\nfor rec in SeqIO.parse(train_fasta, \"fasta\"):\n    raw_id = str(rec.id)\n    # UniProt accession is usually the middle part: sp|P12345|NAME\n    uni_id = raw_id.split(\"|\")[1] if \"|\" in raw_id else raw_id\n    seq = str(rec.seq)\n    train_records.append({\n        \"id\": uni_id,\n        \"raw_id\": raw_id,\n        \"length\": len(seq),\n        \"seq\": seq,\n    })\n\ndf_train_seq = pd.DataFrame(train_records)\nprint(\"=== TRAIN SEQUENCES ===\")\nprint(df_train_seq.head(), \"\\n\")\nprint(\"Number of training proteins:\", len(df_train_seq))\nprint(df_train_seq[\"length\"].describe(), \"\\n\")\n\n# Visualize sequence length distribution\nplt.hist(df_train_seq[\"length\"], bins=60)\nplt.title(\"Training Protein Sequence Lengths\")\nplt.xlabel(\"Length (aa)\")\nplt.ylabel(\"Count\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:42:13.39523Z","iopub.execute_input":"2025-12-10T03:42:13.39558Z","iopub.status.idle":"2025-12-10T03:42:15.14972Z","shell.execute_reply.started":"2025-12-10T03:42:13.395554Z","shell.execute_reply":"2025-12-10T03:42:15.148792Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 2. TRAINING LABELS: train_terms.tsv\n# ============================================================\n# Role:\n#   - Each row: (protein_id, GO_term, ontology)\n#   - This is your ground-truth Y for supervised learning.\n#   - ontology column:\n#       BPO – Biological Process\n#       MFO – Molecular Function\n#       CCO – Cellular Component\n\nterms_path = os.path.join(BASE, \"Train\", \"train_terms.tsv\")\ndf_terms = pd.read_csv(\n    terms_path,\n    sep=\"\\t\",\n)\n\nprint(\"\\n=== TRAIN TERMS (GO LABELS) ===\")\nprint(df_terms.head(), \"\\n\")\nprint(\"Total annotations:\", len(df_terms))\nprint(\"Unique proteins with labels:\", df_terms[\"EntryID\"].nunique())\nprint(\"Unique GO terms:\", df_terms[\"term\"].nunique(), \"\\n\")\n\nprint(\"Annotations by ontology:\")\nprint(df_terms[\"aspect\"].value_counts(), \"\\n\")\n\n# Visualize label counts per ontology\ndf_terms[\"aspect\"].value_counts().plot.bar()\nplt.title(\"Number of Annotations per Ontology\")\nplt.xlabel(\"Ontology\")\nplt.ylabel(\"Count\")\nplt.show()\n\n# Distribution of number of labels per protein\nlabels_per_protein = df_terms[\"EntryID\"].value_counts()\nlabels_per_protein.hist(bins=50)\nplt.title(\"Number of GO Terms per Training Protein\")\nplt.xlabel(\"# GO terms\")\nplt.ylabel(\"Number of proteins\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:52:26.251197Z","iopub.execute_input":"2025-12-10T03:52:26.251521Z","iopub.status.idle":"2025-12-10T03:52:27.11894Z","shell.execute_reply.started":"2025-12-10T03:52:26.251493Z","shell.execute_reply":"2025-12-10T03:52:27.118024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 3. TRAIN TAXONOMY: train_taxonomy.tsv\n# ============================================================\n# Role:\n#   - Links each training protein to a NCBI taxon ID (species / strain).\n#   - Useful for taxonomy-aware models:\n#       e.g., separate models per clade, or taxon features.\n\ntax_path = os.path.join(BASE, \"Train\", \"train_taxonomy.tsv\")\ndf_tax = pd.read_csv(\n    tax_path,\n    sep=\"\\t\",\n    header=None,\n    names=[\"id\", \"taxon\"]\n)\n\nprint(\"\\n=== TRAIN TAXONOMY ===\")\nprint(df_tax.head(), \"\\n\")\nprint(\"Unique taxon IDs in training:\", df_tax[\"taxon\"].nunique())\n\nprint(\"\\nTop 10 most frequent taxa:\")\nprint(df_tax[\"taxon\"].value_counts().head(10))\n\n# Merge one example protein with its labels + taxon\nexample_id = df_train_seq[\"id\"].iloc[0]\nprint(f\"\\nExample protein: {example_id}\")\nprint(\"Sequence length:\",\n      int(df_train_seq.loc[df_train_seq[\"id\"] == example_id, \"length\"]))\n\nprint(\"\\nIts GO terms:\")\nprint(df_terms[df_terms[\"id\"] == example_id])\n\nprint(\"\\nIts taxon:\")\nprint(df_tax[df_tax[\"id\"] == example_id])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:46:35.729264Z","iopub.execute_input":"2025-12-10T03:46:35.730099Z","iopub.status.idle":"2025-12-10T03:46:35.863022Z","shell.execute_reply.started":"2025-12-10T03:46:35.730065Z","shell.execute_reply":"2025-12-10T03:46:35.862109Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 4. GO ONTOLOGY GRAPH: go-basic.obo\n# ============================================================\n# Role:\n#   - Encodes the Gene Ontology DAG (nodes = GO terms, edges = relations).\n#   - Needed to understand term relationships, propagate predictions\n#     up the hierarchy, enforce constraints, etc.\n\n# We'll use `obonet` to parse the OBO file.\n!pip install -q obonet\nimport obonet\n\nobo_path = os.path.join(BASE, \"Train\", \"go-basic.obo\")\ngo_graph = obonet.read_obo(obo_path)\n\nprint(\"\\n=== GO ONTOLOGY GRAPH ===\")\nprint(\"Number of GO terms in graph:\", go_graph.number_of_nodes())\nprint(\"Number of edges (relations):\", go_graph.number_of_edges())\n\n# Known roots of each sub-ontology:\nsubontology_roots = {\n    \"BPO\": \"GO:0008150\",  # biological process\n    \"CCO\": \"GO:0005575\",  # cellular component\n    \"MFO\": \"GO:0003674\",  # molecular function\n}\n\nfor name, root in subontology_roots.items():\n    data = go_graph.nodes[root]\n    print(f\"\\nRoot {name} ({root}):\", data.get(\"name\"))\n\n    children = list(go_graph.successors(root))\n    print(f\"  Direct children (first 5): {children[:5]}\")\n\n# (Optional) How many GO terms appear in training labels and exist in graph?\nterms_in_graph = [t for t in df_terms[\"term\"].unique() if t in go_graph.nodes]\nprint(\"\\nLabeled GO terms found in GO graph:\", len(terms_in_graph))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:47:32.324914Z","iopub.execute_input":"2025-12-10T03:47:32.325254Z","iopub.status.idle":"2025-12-10T03:47:43.5534Z","shell.execute_reply.started":"2025-12-10T03:47:32.325227Z","shell.execute_reply":"2025-12-10T03:47:43.552417Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 5. INFORMATION ACCRETION: IA.tsv\n# ============================================================\n# Role:\n#   - Provides a weight for each GO term.\n#   - These weights are used in official CAFA evaluation\n#     to compute IA-weighted precision/recall/F_max.\n#   - Typically, more specific/rare terms have higher IA.\n\nia_path = os.path.join(BASE, \"IA.tsv\")\ndf_ia = pd.read_csv(\n    ia_path,\n    sep=\"\\t\",\n    header=None,\n    names=[\"term\", \"weight\"]\n)\n\nprint(\"\\n=== IA (Information Accretion) ===\")\nprint(df_ia.head(), \"\\n\")\nprint(\"Number of terms with IA weight:\", len(df_ia))\nprint(df_ia[\"weight\"].describe(), \"\\n\")\n\nplt.hist(df_ia[\"weight\"], bins=50)\nplt.title(\"Distribution of IA Weights\")\nplt.xlabel(\"IA weight\")\nplt.ylabel(\"Number of GO terms\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:48:18.277256Z","iopub.execute_input":"2025-12-10T03:48:18.278368Z","iopub.status.idle":"2025-12-10T03:48:18.586231Z","shell.execute_reply.started":"2025-12-10T03:48:18.278309Z","shell.execute_reply":"2025-12-10T03:48:18.585436Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 6. TEST SUPERSET SEQUENCES: testsuperset.fasta\n# ============================================================\n# Role:\n#   - Contains sequences on which you must predict GO terms.\n#   - Only a subset of these will be evaluated later (those that\n#     gain new experimental annotations after the competition).\n#   - You never see labels for these during the competition.\n\ntest_fasta = os.path.join(BASE, \"Test\", \"testsuperset.fasta\")\n\ntest_records = []\nfor rec in SeqIO.parse(test_fasta, \"fasta\"):\n    raw_id = str(rec.id)\n    uni_id = raw_id.split(\"|\")[1] if \"|\" in raw_id else raw_id\n    seq = str(rec.seq)\n    test_records.append({\n        \"id\": uni_id,\n        \"raw_id\": raw_id,\n        \"length\": len(seq),\n        \"seq\": seq,\n    })\n\ndf_test_seq = pd.DataFrame(test_records)\nprint(\"\\n=== TEST SUPERSET SEQUENCES ===\")\nprint(df_test_seq.head(), \"\\n\")\nprint(\"Number of test superset proteins:\", len(df_test_seq))\nprint(df_test_seq[\"length\"].describe(), \"\\n\")\n\nplt.hist(df_test_seq[\"length\"], bins=60)\nplt.title(\"Test Superset Protein Sequence Lengths\")\nplt.xlabel(\"Length (aa)\")\nplt.ylabel(\"Count\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:49:52.326723Z","iopub.execute_input":"2025-12-10T03:49:52.327142Z","iopub.status.idle":"2025-12-10T03:49:54.676571Z","shell.execute_reply.started":"2025-12-10T03:49:52.327112Z","shell.execute_reply":"2025-12-10T03:49:54.675647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 7. TEST SUPERSET TAXONOMY: testsuperset-taxon-list.tsv\n# ============================================================\n# Role:\n#   - Gives taxon ID for each test superset protein.\n#   - Similar role as train_taxonomy.tsv, but for test data.\n\ntest_tax_path = os.path.join(BASE, \"Test\", \"testsuperset-taxon-list.tsv\")\ndf_test_tax = pd.read_csv(\n    test_tax_path,\n    sep=\"\\t\",\n    header=None,\n    names=[\"id\", \"taxon\"]\n)\n\nprint(\"\\n=== TEST SUPERSET TAXONOMY ===\")\nprint(df_test_tax.head(), \"\\n\")\nprint(\"Unique taxon IDs in test superset:\", df_test_tax[\"taxon\"].nunique())\n\n# Check alignment between test sequences and test taxonomy\ncommon_test_ids = set(df_test_seq[\"id\"]).intersection(df_test_tax[\"id\"])\nprint(\"Proteins with both sequence and taxon:\", len(common_test_ids))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T03:53:00.838226Z","iopub.execute_input":"2025-12-10T03:53:00.838948Z","iopub.status.idle":"2025-12-10T03:53:00.930638Z","shell.execute_reply.started":"2025-12-10T03:53:00.838917Z","shell.execute_reply":"2025-12-10T03:53:00.929805Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# 8. SAMPLE SUBMISSION FORMAT: sample_submission.tsv\n# ============================================================\n# Role:\n#   - Shows exactly how your submission must be formatted.\n#   - Each row: (protein_id, GO_term, score)\n#   - You can output any number of GO terms for each protein.\n#   - Score is a confidence (0–1) – used only for ranking/picking\n#     threshold during evaluation.\n\nsample_path = os.path.join(BASE, \"sample_submission.tsv\")\ndf_sample = pd.read_csv(\n    sample_path,\n    sep=\"\\t\",\n    header=None,\n    names=[\"protein\", \"go_term\", \"score\", \"text\"],\n)\ndf_sample = df_sample[df_sample[\"go_term\"].str.startswith(\"GO:\")]\n\nprint(\"\\n=== SAMPLE SUBMISSION FORMAT ===\")\nprint(df_sample.head(), \"\\n\")\n\nprint(\"Columns:\")\nprint(\"  id    → protein UniProt accession (same as in test FASTA)\")\nprint(\"  term  → GO term ID you predict\")\nprint(\"  score → confidence between 0 and 1 (float)\\n\")\n\nprint(\"In your own solution, you will generate a file with the same three columns.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-10T04:01:05.240398Z","iopub.execute_input":"2025-12-10T04:01:05.240686Z","iopub.status.idle":"2025-12-10T04:01:05.279375Z","shell.execute_reply.started":"2025-12-10T04:01:05.240666Z","shell.execute_reply":"2025-12-10T04:01:05.278326Z"}},"outputs":[],"execution_count":null}]}