{"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":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Credits\nThis analysis is built upon the foundational work by @leonidkulyk from the CAFA 5 competition, who published the acclaimed notebook titled \"[EDA] 🧬CAFA5-PFP ~ 🕸️Interactive DAGs | 📊Plotly.\" I want to extend my gratitude for his insightful contribution.\n\nIn this notebook, I have adapted and utilized his original code to analyze this year's CAFA competition data.","metadata":{}},{"cell_type":"markdown","source":"<!-- Dark Mode Header -->\n<div style=\"background-color:#1e1e1e; padding: 30px; border-radius: 12px; text-align:center;\">\n    <h1 style=\"font-family: 'Consolas', monospace; font-size: 32px; font-weight: bold; color:#f5f5f5; margin-bottom:10px;\">\n        🧬 CAFA 5 Protein Function Prediction \n    </h1>\n    <p style=\"color:#949494; font-family: 'Consolas', monospace; font-size: 20px; text-align:center; margin-top:0;\">\n        Predict the biological function of a protein\n    </p>\n</div>\n<hr style=\"border:1px solid #333; margin:20px 0;\">\n\n","metadata":{}},{"cell_type":"markdown","source":"<!-- Dark Mode Overview Section -->\n<div style=\"background-color:#1e1e1e; padding: 30px; border-radius: 12px; color:#f5f5f5; font-family: 'Consolas', monospace;\">\n\n  <h2 style=\"font-size:32px; font-weight:bold; text-align:center; margin-bottom:20px;\">\n    (ಠಿ_ಠ) Overview\n  </h2>\n\n  <p style=\"font-size:16px; margin-bottom:12px;\">\n    🔴 <b>Goal</b>: Predict the function of proteins based on their amino acid sequences and other data.\n  </p>\n\n  <p style=\"font-size:16px; margin-bottom:12px;\">\n    ⚪ <b>Importance</b>: Accurate protein function assignment is <span style=\"color:#ffa500;\">crucial for understanding molecular biology</span>, discovering cellular mechanisms, and developing new therapies.\n  </p>\n\n  <p style=\"font-size:16px; margin-bottom:12px;\">\n    ⚪ <b>Context</b>: Proteins are composed of <span style=\"color:#00bfff;\">20 types of amino acids</span>. Humans have tens of thousands of proteins, each a chain of amino acids forming unique structures.\n  </p>\n\n  <p style=\"font-size:16px; margin-bottom:12px;\">\n    ⚪ <b>Challenges</b>: Proteins often have multiple functions and interact with many partners. Predicting functions is complex due to ambiguity, data integration, and structural diversity.\n  </p>\n\n  <p style=\"font-size:16px; margin-bottom:12px;\">\n    ⚪ <b>Host</b>: Function-COSI organizes the competition, bringing together computational biologists, experimental biologists, and biocurators.\n  </p>\n\n  <p style=\"font-size:16px; margin-bottom:12px;\">\n    ⚪ <b>Co-organizers</b>: Iowa State University, Northeastern University, University of Padova, and UniProt.\n  </p>\n\n  <p style=\"font-size:16px; margin-bottom:0;\">\n    ⚪ <b>Acknowledgments</b>: Supported by the organizers above and the International Society for Computational Biology.\n  </p>\n\n</div>\n<hr style=\"border:1px solid #333; margin:25px 0;\">\n","metadata":{}},{"cell_type":"markdown","source":"<!-- Dark Mode Table of Contents -->\n<a id=\"top\"></a>\n\n<div style=\"background-color:#1e1e1e; padding:25px 20px; border-radius:15px; text-align:center; font-family:'Consolas', monospace; color:#3c79f5; font-size:28px; font-weight:bold; box-shadow: 0 0 10px rgba(60,121,245,0.6); margin-bottom:20px;\">\n    Table of Contents\n</div>\n\n<div style=\"background-color:#2a2a2a; padding:25px 30px; border-radius:12px; font-family:'Consolas', monospace; font-size:16px; color:#f5f5f5; line-height:1.8;\">\n    <ul style=\"list-style-type:none; padding-left:0;\">\n        <li>🔹 <a href=\"#iid\" style=\"color:#61dafb; text-decoration:none;\">Install & Import & Define</a></li>\n        <li>🔹 <a href=\"#1\" style=\"color:#61dafb; text-decoration:none;\">1. Data overview</a></li>\n        <li>🔹 <a href=\"#2\" style=\"color:#61dafb; text-decoration:none;\">2. Training Set</a>\n            <ul style=\"list-style-type:none; padding-left:20px; margin-top:5px;\">\n                <li>⚪ <a href=\"#2.1\" style=\"color:#61dafb; text-decoration:none;\">2.1 Gene Ontology</a></li>\n                <li>⚪ <a href=\"#2.2\" style=\"color:#61dafb; text-decoration:none;\">2.2 Training sequences</a></li>\n                <li>⚪ <a href=\"#2.3\" style=\"color:#61dafb; text-decoration:none;\">2.3 Labels</a></li>\n                <li>⚪ <a href=\"#2.4\" style=\"color:#61dafb; text-decoration:none;\">2.4 Taxonomy</a></li>\n                <li>⚪ <a href=\"#2.5\" style=\"color:#61dafb; text-decoration:none;\">2.5 Information accretion</a></li>\n            </ul>\n        </li>\n    </ul>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"\n<div style=\"\n    background-color:#1e1e1e; \n    color:#00ffff; \n    padding:15px 25px; \n    border-radius:12px; \n    font-family:'Consolas', monospace; \n    font-size:18px; \n    font-weight:bold; \n    text-align:center;\n    box-shadow: 0 0 10px rgba(0,255,255,0.3);\n\">\n🛠 Install & Import & Define\n</div>\n\n","metadata":{}},{"cell_type":"code","source":"!pip install obonet -q\n!pip install pyvis -q","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:30:35.054042Z","iopub.execute_input":"2025-10-16T07:30:35.054427Z","iopub.status.idle":"2025-10-16T07:30:45.939413Z","shell.execute_reply.started":"2025-10-16T07:30:35.054396Z","shell.execute_reply":"2025-10-16T07:30:45.938393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install Bio","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:30:45.941550Z","iopub.execute_input":"2025-10-16T07:30:45.941864Z","iopub.status.idle":"2025-10-16T07:30:52.914210Z","shell.execute_reply.started":"2025-10-16T07:30:45.941834Z","shell.execute_reply":"2025-10-16T07:30:52.913095Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport json\nfrom PIL import Image\nfrom typing import Dict\nfrom collections import Counter\n\nimport random\nimport cv2\nimport obonet\nimport networkx\nimport pandas as pd\nimport numpy as np\nimport plotly.express as px\nimport plotly.graph_objects as go\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as mpatch\nfrom Bio import SeqIO\nfrom pyvis.network import Network\nimport plotly.io as pio\npio.renderers.default = 'iframe_connected'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:30:52.915307Z","iopub.execute_input":"2025-10-16T07:30:52.915564Z","iopub.status.idle":"2025-10-16T07:30:57.269899Z","shell.execute_reply.started":"2025-10-16T07:30:52.915541Z","shell.execute_reply":"2025-10-16T07:30:57.268759Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background-color:#1e1e1e; \n    color:#00ffff; \n    padding:15px 25px; \n    border-radius:12px; \n    font-family:'Consolas', monospace; \n    font-size:18px; \n    font-weight:bold; \n    text-align:center;\n    box-shadow: 0 0 10px rgba(0,255,255,0.3);\n\">\n🛠 Define config\n</div>\n","metadata":{}},{"cell_type":"code","source":"class CFG:\n    train_go_obo_path: str = \"/kaggle/input/cafa-6-protein-function-prediction/Train/go-basic.obo\"\n    train_seq_fasta_path: str = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_sequences.fasta\"\n    train_terms_path: str = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv\"\n    train_taxonomy_path: str = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_taxonomy.tsv\"\n    train_ia_path: str = \"/kaggle/input/cafa-6-protein-function-prediction/IA.txt\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:30:57.272174Z","iopub.execute_input":"2025-10-16T07:30:57.272501Z","iopub.status.idle":"2025-10-16T07:30:57.278318Z","shell.execute_reply.started":"2025-10-16T07:30:57.272475Z","shell.execute_reply":"2025-10-16T07:30:57.277350Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background-color:#1e1e1e; \n    color:#00ffff; \n    padding:15px 25px; \n    border-radius:12px; \n    font-family:'Consolas', monospace; \n    font-size:18px; \n    font-weight:bold; \n    text-align:center;\n    box-shadow: 0 0 10px rgba(0,255,255,0.3);\n\">\n🛠 Define utilization methods\n</div>\n","metadata":{}},{"cell_type":"code","source":"def plot_dag(graph, term, radius=1):\n    # create smaller subgraph\n    # radius - include all neighbors of distance<=radius from n (increse it to add further parent's branches).\n    ng_graph = networkx.ego_graph(graph, term, radius=radius)\n\n    for n in ng_graph.nodes(data=True):\n        # concatenate label of the node with its attribute\n        n[1][\"label\"] = n[0] + \" \" +n[1][\"name\"]\n\n    nt = Network(directed=True, notebook=True, cdn_resources=\"in_line\")\n    nt.from_nx(ng_graph)\n    return nt.show(\"network.html\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:30:57.279624Z","iopub.execute_input":"2025-10-16T07:30:57.280429Z","iopub.status.idle":"2025-10-16T07:30:57.305230Z","shell.execute_reply.started":"2025-10-16T07:30:57.280403Z","shell.execute_reply":"2025-10-16T07:30:57.303543Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<a id=\"1\"></a>\n<div style=\"\n    background-color:#1e1e1e;\n    color:#61dafb;\n    padding:20px;\n    font-size:32px;\n    font-family:'Consolas', monospace;\n    text-align:center;\n    border-radius:15px;\n    box-shadow: 0 0 10px rgba(97,218,251,0.5) inset;\n\">\n<b>1. Data overview</b>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#e0e0e0; padding:25px; border-radius:12px; font-family:'Consolas', monospace; font-size:16px; line-height:1.6;\">\n\n🔴 **The [Gene Ontology (GO)](http://geneontology.org/docs/ontology-documentation/)** is a concept hierarchy that describes the biological function of genes and gene products at different levels of abstraction (Ashburner et al., 2000). It is a good model to describe the multi-faceted nature of protein function.  \n\n⚪ GO is a `directed acyclic graph`. The nodes in this graph are functional descriptors (terms or classes) connected by relational ties (is_a, part_of, etc.). For example, terms *protein binding activity* and *binding activity* are related by an is_a relationship; however, the edge is often reversed to point from binding towards protein binding. This graph contains **three subgraphs (subontologies)**: **Molecular Function (MF), Biological Process (BP), and Cellular Component (CC)**. Each represents a different aspect of a protein's function: what it does on a molecular level (MF), which biological processes it participates in (BP), and where in the cell it is located (CC).  \n\n⚪ The protein's function is therefore represented by a subset of one or more subontologies. Annotations are supported by evidence codes, divided into experimental (from research papers) and non-experimental (inferred computationally). Read more about [GO evidence codes](http://geneontology.org/docs/guide-go-evidence-codes/).  \n\n🔴 In this competition, **experimentally determined term-protein assignments** are used as class labels. That is, if a protein is labeled with a term, it means this protein has this function validated by experimental evidence. By processing these annotated terms, we can generate a dataset of proteins and their ground truth labels. The absence of a term does not mean the protein lacks the function—just that it hasn’t been annotated yet. Proteins may have annotations from multiple subontologies.  \n\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#f0f0f0; padding:25px; border-radius:12px; \n            font-family:'Consolas', monospace; font-size:28px; text-align:center; \n            box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px inset;\">\n    <b>2. Training Set</b>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: 'Consolas', monospace; font-size:16px; color:#e0e0e0; line-height:1.6;\">\n⚪ For the <i>training set</i>, we include all proteins with annotated terms that have been validated by experimental or high-throughput evidence, traceable author statement (<code>TAS</code>), or inferred by curator (<code>IC</code>). We use annotations from the UniProtKB release of 2022-11-17. Participants are not required to use these data and are also welcome to use any other data available to them.\n</p>\n\n<p style=\"font-family: 'Consolas', monospace; font-size:16px; color:#e0e0e0; line-height:1.6;\">\n⚪ For the <i>training set</i>, we include all proteins with annotated terms that have been validated by experimental or high-throughput evidence, traceable author statement (<code>TAS</code>), or inferred by curator (<code>IC</code>). We use annotations from the UniProtKB release of 2022-11-17. Participants are not required to use these data and are also welcome to use any other data available to them.\n</p>\n","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: 'Consolas', monospace; font-size:16px; color:#e0e0e0; line-height:1.6;\">\n❔ Let's consider each <i>training file</i> iteratively.\n</p>\n","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#f0f0f0; padding:25px; border-radius:12px; \n            font-family:'Consolas', monospace; font-size:28px; text-align:center; \n            box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px inset;\">\n    <b>2.1 Gene Ontology </b>\n</div>\n","metadata":{}},{"cell_type":"code","source":"%%time\ngraph = obonet.read_obo(CFG.train_go_obo_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:30:57.306377Z","iopub.execute_input":"2025-10-16T07:30:57.306669Z","iopub.status.idle":"2025-10-16T07:31:04.441412Z","shell.execute_reply.started":"2025-10-16T07:30:57.306647Z","shell.execute_reply":"2025-10-16T07:31:04.440204Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Number of nodes.</p>","metadata":{}},{"cell_type":"code","source":"print(f\"Number of nodes: {len(graph)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.443214Z","iopub.execute_input":"2025-10-16T07:31:04.443553Z","iopub.status.idle":"2025-10-16T07:31:04.450746Z","shell.execute_reply.started":"2025-10-16T07:31:04.443529Z","shell.execute_reply":"2025-10-16T07:31:04.449060Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Number of edges.</p>","metadata":{}},{"cell_type":"code","source":"print(f\"Number of edges: {graph.number_of_edges()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.452356Z","iopub.execute_input":"2025-10-16T07:31:04.452774Z","iopub.status.idle":"2025-10-16T07:31:04.569211Z","shell.execute_reply.started":"2025-10-16T07:31:04.452748Z","shell.execute_reply":"2025-10-16T07:31:04.568187Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">🔴 To display a graph, you need to focus on a specific term, let's take term <code>GO:0034655</code> as an example.</p> ","metadata":{}},{"cell_type":"code","source":"term = \"GO:0034655\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.570302Z","iopub.execute_input":"2025-10-16T07:31:04.570651Z","iopub.status.idle":"2025-10-16T07:31:04.575657Z","shell.execute_reply.started":"2025-10-16T07:31:04.570617Z","shell.execute_reply":"2025-10-16T07:31:04.574585Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Lookup <code>nucleobase-containing compound catabolic process</code> node properties (term GO:0034655).</p>","metadata":{}},{"cell_type":"code","source":"graph.nodes[term]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.579323Z","iopub.execute_input":"2025-10-16T07:31:04.579636Z","iopub.status.idle":"2025-10-16T07:31:04.608477Z","shell.execute_reply.started":"2025-10-16T07:31:04.579613Z","shell.execute_reply":"2025-10-16T07:31:04.606633Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's plot DAG for the term GO:0034655.</p>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's plot DAG for the term GO:0034655.</p>","metadata":{}},{"cell_type":"code","source":"def plot_dag(graph, term, radius=1):\n    \"\"\"\n    Plots a DAG subgraph around the specified term using pyvis.\n    Saves a separate HTML file for each term and radius.\n    \"\"\"\n    # Create smaller subgraph\n    ng_graph = networkx.ego_graph(graph, term, radius=radius, undirected=False)\n\n    # Prepare node labels\n    for n in ng_graph.nodes(data=True):\n        n[1][\"label\"] = n[0] + \" \" + n[1].get(\"name\", \"\")\n\n    # Initialize pyvis network\n    nt = Network(\n        height=\"800px\",\n        width=\"100%\",\n        directed=True,\n        notebook=True,\n        bgcolor=\"#1e1e1e\",\n        font_color=\"white\",\n        cdn_resources=\"in_line\"\n    )\n    nt.from_nx(ng_graph)\n\n    # Optional styling\n    nt.set_options(\"\"\"\n    var options = {\n      \"nodes\": {\"color\":{\"background\":\"#1f78b4\",\"border\":\"#ffffff\"},\"font\":{\"color\":\"white\",\"size\":14,\"face\":\"Consolas\"}},\n      \"edges\": {\"color\":\"white\",\"arrows\":{\"to\":{\"enabled\":true}}},\n      \"physics\": {\"enabled\":true,\"stabilization\":{\"iterations\":200}}\n    }\n    \"\"\")\n\n    # Dynamic filename\n    filename = f\"network_{term}_radius{radius}.html\"\n    return nt.show(filename)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.609697Z","iopub.execute_input":"2025-10-16T07:31:04.610044Z","iopub.status.idle":"2025-10-16T07:31:04.636415Z","shell.execute_reply.started":"2025-10-16T07:31:04.610019Z","shell.execute_reply":"2025-10-16T07:31:04.635168Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_dag(graph, term, radius= 1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.637647Z","iopub.execute_input":"2025-10-16T07:31:04.638050Z","iopub.status.idle":"2025-10-16T07:31:04.813388Z","shell.execute_reply.started":"2025-10-16T07:31:04.638019Z","shell.execute_reply":"2025-10-16T07:31:04.811918Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Now let's look how's full DAG looks like for the selected term. To do that just increase value of the radius parameter. <code>radius</code> - responsible include all neighbors of distance ≤ radius from n.</p>","metadata":{}},{"cell_type":"code","source":"plot_dag(graph, term, radius=50000)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.815894Z","iopub.execute_input":"2025-10-16T07:31:04.816365Z","iopub.status.idle":"2025-10-16T07:31:04.949439Z","shell.execute_reply.started":"2025-10-16T07:31:04.816341Z","shell.execute_reply":"2025-10-16T07:31:04.947688Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ In the first graph, only the nodes are connected by relational ties between them, that is, which are located in <code>is_a</code>. But the second one shows a complete graph in which you can see how the connection will look with a non-peripheral relationship between all the nodes in the graph.</p> ","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">🔴 Let's look at another term. The term <code>GO:00048420</code> taken as an example.</p> ","metadata":{}},{"cell_type":"code","source":"term = \"GO:0004842\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.950570Z","iopub.execute_input":"2025-10-16T07:31:04.950866Z","iopub.status.idle":"2025-10-16T07:31:04.957265Z","shell.execute_reply.started":"2025-10-16T07:31:04.950844Z","shell.execute_reply":"2025-10-16T07:31:04.955480Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Lookup <code>cellular nitrogen compound catabolic process</code> node properties (term GO:0044270).</p>","metadata":{}},{"cell_type":"code","source":"graph.nodes[term]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.958802Z","iopub.execute_input":"2025-10-16T07:31:04.959548Z","iopub.status.idle":"2025-10-16T07:31:04.987884Z","shell.execute_reply.started":"2025-10-16T07:31:04.959511Z","shell.execute_reply":"2025-10-16T07:31:04.986657Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_dag(graph, term, radius=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:04.989134Z","iopub.execute_input":"2025-10-16T07:31:04.989467Z","iopub.status.idle":"2025-10-16T07:31:05.146370Z","shell.execute_reply.started":"2025-10-16T07:31:04.989438Z","shell.execute_reply":"2025-10-16T07:31:05.145334Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Now let's look how's full DAG looks like for the selected term. To do that just increase value of the radius parameter. <code>radius</code> - responsible include all neighbors of distance ≤ radius from n.</p>","metadata":{}},{"cell_type":"code","source":"plot_dag(graph, term, radius=1000)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:05.147429Z","iopub.execute_input":"2025-10-16T07:31:05.147769Z","iopub.status.idle":"2025-10-16T07:31:05.283193Z","shell.execute_reply.started":"2025-10-16T07:31:05.147743Z","shell.execute_reply":"2025-10-16T07:31:05.282249Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#f0f0f0; padding:25px; border-radius:12px; \n            font-family:'Consolas', monospace; font-size:28px; text-align:center; \n            box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px inset;\">\n    <b>2.2 Training Sequences </b>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; \n            color:#c5c5c5; \n            font-family:'Consolas', monospace; \n            font-size:16px; \n            line-height:1.6; \n            padding:20px; \n            border-radius:12px;\n            box-shadow: rgba(0,0,0,0.5) 0px 2px 6px inset;\">\n\n<p>⚪ <code>Training sequences</code>: <b>train_sequences.fasta</b> contains the protein sequences for the training dataset.</p>\n\n<p>⚪ These files are in <a href=\"https://en.wikipedia.org/wiki/FASTA_format\" style=\"color:#61dafb;\"><strong>FASTA format</strong></a>, a standard format for describing protein sequences. The proteins were all retrieved from the <a href=\"https://www.uniprot.org/\" style=\"color:#61dafb;\"><strong>UniProt dataset</strong></a> curated at the European Bioinformatics Institute.</p>\n\n<p>⚪ The header contains the protein's UniProt accession ID and additional information about the protein. Most protein sequences were extracted from the Swiss-Prot database, but a subset of proteins not represented in Swiss-Prot were extracted from the TrEMBL database. In both cases, sequences come from the 2022_05 release (14-Dec-2022). More info <a href=\"https://www.uniprot.org/help/uniprotkb_sections\" style=\"color:#61dafb;\"><strong>here</strong></a>.</p>\n\n<p>⚪ The <code>train_sequences.fasta</code> file indicates the database source. For example, <code>sp|P9WHI7|RECN_MYCT</code> in the FASTA header indicates a Swiss-Prot protein (<code>sp</code>) with UniProt ID <code>P9WHI7</code> and gene name <code>RECN_MYCT</code>. TrEMBL sequences use <code>tr</code> instead. Both Swiss-Prot and TrEMBL are part of UniProtKB.</p>\n\n<p>⚪ This file contains only sequences for proteins with annotations (labeled proteins). To get the full set of protein sequences for unlabeled proteins, download Swiss-Prot and TrEMBL <a href=\"https://www.uniprot.org/help/downloads\" style=\"color:#61dafb;\"><strong>here</strong></a>.</p>\n\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">🔴 To read and analyze the protein sequences from the <b>train_sequences.fasta</b> file, we can use the <code>Biopython</code> package.</p> ","metadata":{}},{"cell_type":"code","source":"print(\"Sequence example:\\n\\n\", next(iter(SeqIO.parse(CFG.train_seq_fasta_path, \"fasta\"))))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:05.284136Z","iopub.execute_input":"2025-10-16T07:31:05.284438Z","iopub.status.idle":"2025-10-16T07:31:05.310461Z","shell.execute_reply.started":"2025-10-16T07:31:05.284416Z","shell.execute_reply":"2025-10-16T07:31:05.308967Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's count the number of sequences.</p>","metadata":{}},{"cell_type":"code","source":"sequences = SeqIO.parse(CFG.train_seq_fasta_path, \"fasta\")\nnum_sequences = sum(1 for seq in sequences)\n\nprint(\"Number of sequences:\", num_sequences)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:05.311594Z","iopub.execute_input":"2025-10-16T07:31:05.311946Z","iopub.status.idle":"2025-10-16T07:31:06.296812Z","shell.execute_reply.started":"2025-10-16T07:31:05.311918Z","shell.execute_reply":"2025-10-16T07:31:06.295749Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's plot the length distribution of the protein sequences.</p>","metadata":{}},{"cell_type":"code","source":"from Bio import SeqIO\nimport plotly.express as px\n\n# Load sequences\nsequences = SeqIO.parse(CFG.train_seq_fasta_path, \"fasta\")\n\n# Get the length of each sequence\nlengths = [len(seq) for seq in sequences]\n\n# Create histogram\nfig = px.histogram(\n    x=lengths,\n    nbins=1000,\n    color_discrete_sequence=['goldenrod']\n)\n\n# Dark mode layout\nfig.update_layout(\n    template='plotly_dark',  # Enables dark mode\n    title={\n        'text': \"Distribution of Protein Sequence Lengths\",\n        'y':0.95,\n        'x':0.5,\n        'xanchor': 'center',\n        'yanchor': 'top',\n        'font': {'size': 24, 'color': 'goldenrod'}\n    },\n    xaxis_title=\"Sequence Length\",\n    yaxis_title=\"Count\",\n    xaxis=dict(showgrid=True, gridcolor='gray', zeroline=False),\n    yaxis=dict(showgrid=True, gridcolor='gray', zeroline=False),\n    plot_bgcolor='#1e1e1e',  # Dark background\n    paper_bgcolor='#1e1e1e', # Dark surrounding\n)\n\nfig.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:06.298043Z","iopub.execute_input":"2025-10-16T07:31:06.298331Z","iopub.status.idle":"2025-10-16T07:31:09.388247Z","shell.execute_reply.started":"2025-10-16T07:31:06.298310Z","shell.execute_reply":"2025-10-16T07:31:09.387279Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.percentile(lengths, 99)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:09.389278Z","iopub.execute_input":"2025-10-16T07:31:09.389611Z","iopub.status.idle":"2025-10-16T07:31:09.410891Z","shell.execute_reply.started":"2025-10-16T07:31:09.389585Z","shell.execute_reply":"2025-10-16T07:31:09.409297Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ This also means that only <b>1%</b> of the data is present after the value <b>2375</b>.</p>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's calculate <b>the amino acid composition</b> of each protein sequence. Amino acid composition is the frequency distribution of amino acids in a protein sequence. It can provide valuable information about the protein's structure and function.</p>","metadata":{}},{"cell_type":"code","source":"from Bio import SeqIO\nfrom collections import Counter\nimport plotly.express as px\n\n# Load sequences\nrecords = SeqIO.parse(CFG.train_seq_fasta_path, \"fasta\")\n\n# Create a list of all amino acids\naa_list = [aa for record in records for aa in record.seq]\n\n# Count frequency of each amino acid\naa_count = Counter(aa_list)\n\n# Plot horizontal bar chart\nfig = px.bar(\n    x=list(aa_count.values()),\n    y=list(aa_count.keys()),\n    orientation='h',\n    color_discrete_sequence=['darkslateblue'],\n    height=700\n)\n\n# Dark mode layout\nfig.update_layout(\n    template='plotly_dark',\n    title={\n        'text': \"Amino Acid Composition\",\n        'y':0.95,\n        'x':0.5,\n        'xanchor': 'center',\n        'yanchor': 'top',\n        'font': {'size': 24, 'color': 'darkorange'}\n    },\n    xaxis_title=\"Frequency\",\n    yaxis_title=\"Amino Acid\",\n    xaxis=dict(showgrid=True, gridcolor='gray', zeroline=False),\n    yaxis=dict(showgrid=False),\n    plot_bgcolor='#1e1e1e',\n    paper_bgcolor='#1e1e1e'\n)\n\nfig.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:09.412490Z","iopub.execute_input":"2025-10-16T07:31:09.412799Z","iopub.status.idle":"2025-10-16T07:31:14.163407Z","shell.execute_reply.started":"2025-10-16T07:31:09.412775Z","shell.execute_reply":"2025-10-16T07:31:14.162427Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ Here are a few observations that can be made from the obtained frequency values:</p>\n\n* <p style=\"font-family: consolas; font-size: 16px;\">The most common amino acids in this dataset are leucine (L), serine (S), alanine (A), and glutamic (E), tyrosine (Y). These amino acids are known to be abundant in proteins and play important roles in protein structure and function.</p>\n* <p style=\"font-family: consolas; font-size: 16px;\">The least common amino acids in this dataset are cysteine (C), methionine (M), tryptophan (W), and histidine (H). These amino acids are typically less abundant in proteins, but they can be important for specific functions, such as catalysis, metal binding, or protein-protein interactions.</p>\n* <p style=\"font-family: consolas; font-size: 16px;\">The absence of ambiguous amino acids (X, B, Z) and rare amino acids (O, U) in the dataset suggests that sequences are not incomplete or contain errors unlike CAFA 5.</p>","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#f0f0f0; padding:25px; border-radius:12px; \n            font-family:'Consolas', monospace; font-size:28px; text-align:center; \n            box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px inset;\">\n    <b>2.3 Labels </b>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ <code>Labels</code>: <b>train_terms.tsv</b> contains the list of annotated terms (ground truth) for the proteins in train_sequences.fasta.</p> \n\n* <p style=\"font-family: consolas; font-size: 16px;\">The first column indicates the protein's UniProt accession ID.</p>\n* <p style=\"font-family: consolas; font-size: 16px;\">The second is the GO term ID.</p>\n* <p style=\"font-family: consolas; font-size: 16px;\">The third indicates in which ontology the term appears (BPO, CCO or MFO). BPO, CCO, and MFO are abbreviations for different categories of gene ontology terms. <code>BPO</code>: Biological Process Ontology, which describes biological processes, functions, and pathways. <code>CCO</code>: Cellular Component Ontology, which describes the components of a cell or its extracellular environment. <code>MFO</code>: Molecular Function Ontology, which describes the biochemical activities or capabilities of proteins and other molecules. These categories are used in gene ontology to classify genes and gene products based on their biological roles and functions. By using these categories, researchers can better understand the functions and interactions of different genes and gene products within a biological system.</p>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ Load the train terms dataframe.</p> ","metadata":{}},{"cell_type":"code","source":"train_terms_df = pd.read_csv(CFG.train_terms_path, sep=\"\\t\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:14.164623Z","iopub.execute_input":"2025-10-16T07:31:14.165057Z","iopub.status.idle":"2025-10-16T07:31:14.588796Z","shell.execute_reply.started":"2025-10-16T07:31:14.165030Z","shell.execute_reply":"2025-10-16T07:31:14.587907Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's look how's data looks like.</p>","metadata":{}},{"cell_type":"code","source":"train_terms_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:14.589715Z","iopub.execute_input":"2025-10-16T07:31:14.589947Z","iopub.status.idle":"2025-10-16T07:31:14.613176Z","shell.execute_reply.started":"2025-10-16T07:31:14.589930Z","shell.execute_reply":"2025-10-16T07:31:14.611924Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Display main information about dataframe columns.</p>","metadata":{}},{"cell_type":"code","source":"train_terms_df.describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:14.614278Z","iopub.execute_input":"2025-10-16T07:31:14.614595Z","iopub.status.idle":"2025-10-16T07:31:14.972592Z","shell.execute_reply.started":"2025-10-16T07:31:14.614568Z","shell.execute_reply":"2025-10-16T07:31:14.971529Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Now let's plot pie distribution of aspect values.</p>","metadata":{}},{"cell_type":"code","source":"import plotly.express as px\n\n# Aspect counts\naspect_counts = train_terms_df.aspect.value_counts()\n\n# Pie chart\nfig = px.pie(\n    values=aspect_counts.values,\n    names=aspect_counts.index,\n    color_discrete_sequence=px.colors.sequential.Viridis\n)\n\n# Dark mode layout\nfig.update_traces(\n    textposition='inside',\n    textfont_size=14,\n    textinfo='percent+label',\n    marker=dict(line=dict(color='#1e1e1e', width=2))\n)\nfig.update_layout(\n    template='plotly_dark',\n    title={\n        'text': \"Pie Distribution of Aspect Values\",\n        'y':0.95,\n        'x':0.5,\n        'xanchor': 'center',\n        'yanchor': 'top',\n        'font': {'size': 22, 'color': 'lightblue'}\n    },\n    legend_title_text='Aspect:',\n    paper_bgcolor='#1e1e1e',\n    plot_bgcolor='#1e1e1e'\n)\n\nfig.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:14.973776Z","iopub.execute_input":"2025-10-16T07:31:14.974378Z","iopub.status.idle":"2025-10-16T07:31:15.141561Z","shell.execute_reply.started":"2025-10-16T07:31:14.974353Z","shell.execute_reply":"2025-10-16T07:31:15.140599Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#f0f0f0; padding:25px; border-radius:12px; \n            font-family:'Consolas', monospace; font-size:28px; text-align:center; \n            box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px inset;\">\n    <b>2.4 Taxonomy </b>\n</div>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ <code>Taxonomy</code>: <b>train_taxonomy.tsv</b> contains the list of proteins and the species to which they belong, represented by a \"taxonomic identifier\" (taxon ID) number. The first column is the protein UniProt accession ID and the second is the taxon ID. More information about taxonomies can he found <a href=\"https://www.uniprot.org/help/taxonomic_identifier\"><strong>here</strong></a>.</p>","metadata":{}},{"cell_type":"code","source":"train_taxonomy_df = pd.read_csv(CFG.train_taxonomy_path, sep=\"\\t\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:15.142661Z","iopub.execute_input":"2025-10-16T07:31:15.143023Z","iopub.status.idle":"2025-10-16T07:31:15.210220Z","shell.execute_reply.started":"2025-10-16T07:31:15.142993Z","shell.execute_reply":"2025-10-16T07:31:15.209068Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Let's look how's data looks like.</p>","metadata":{}},{"cell_type":"code","source":"train_taxonomy_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:15.214249Z","iopub.execute_input":"2025-10-16T07:31:15.214539Z","iopub.status.idle":"2025-10-16T07:31:15.223571Z","shell.execute_reply.started":"2025-10-16T07:31:15.214518Z","shell.execute_reply":"2025-10-16T07:31:15.222511Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">❔ Display dataframe length.</p>","metadata":{}},{"cell_type":"code","source":"len(train_taxonomy_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:15.224871Z","iopub.execute_input":"2025-10-16T07:31:15.225261Z","iopub.status.idle":"2025-10-16T07:31:15.244351Z","shell.execute_reply.started":"2025-10-16T07:31:15.225231Z","shell.execute_reply":"2025-10-16T07:31:15.243391Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"background-color:#1e1e1e; color:#f0f0f0; padding:25px; border-radius:12px; \n            font-family:'Consolas', monospace; font-size:28px; text-align:center; \n            box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 6px inset;\">\n    <b>2.5 Information Accreation </b>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-family: consolas; font-size: 16px;\">⚪ <code>Information accretion</code>: <b>IA.txt</b> contains the information accretion (weights) for each GO term. These weights are used to compute weighted precision and recall, as described in the Evaluation section of the competition.</p>","metadata":{}},{"cell_type":"code","source":"limit = 10\n\nwith open(\"/kaggle/input/cafa-6-protein-function-prediction/IA.tsv\") as f:\n    ia_weights = [x.replace(\"\\n\", \"\").split(\"\\t\") for x in f.readlines()]\n\nia_weights[:limit]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T07:31:15.245358Z","iopub.execute_input":"2025-10-16T07:31:15.246131Z","iopub.status.idle":"2025-10-16T07:31:15.826044Z","shell.execute_reply.started":"2025-10-16T07:31:15.246083Z","shell.execute_reply":"2025-10-16T07:31:15.825020Z"}},"outputs":[],"execution_count":null}]}