{"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":"code","source":"!pip install biopython tqdm torch torchvision torchaudio transformers scikit-learn --quiet\n\n\nimport pandas as pd\nimport numpy as np\nfrom Bio import SeqIO\nfrom tqdm import tqdm\nimport torch\nfrom transformers import AutoTokenizer, AutoModel\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import MultiLabelBinarizer\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.multiclass import OneVsRestClassifier\nfrom sklearn.metrics import f1_score, precision_recall_curve\nimport matplotlib.pyplot as plt\n\nprint(\"✅ Environment ready!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:24:03.614058Z","iopub.execute_input":"2025-10-25T17:24:03.614581Z","iopub.status.idle":"2025-10-25T17:24:14.639466Z","shell.execute_reply.started":"2025-10-25T17:24:03.614548Z","shell.execute_reply":"2025-10-25T17:24:14.638176Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PATH_SAMPLE_SUBMISSION = \"/kaggle/input/cafa-6-protein-function-prediction/sample_submission.tsv\"\nPATH_IA = \"/kaggle/input/cafa-6-protein-function-prediction/IA.tsv\"\nPATH_TEST_TAXON = \"/kaggle/input/cafa-6-protein-function-prediction/Test/testsuperset-taxon-list.tsv\"\nPATH_TRAIN_TERMS = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_terms.tsv\"\nPATH_TRAIN_TAXONOMY = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_taxonomy.tsv\"\n\n# FASTA FILES\nPATH_TEST_FASTA = \"/kaggle/input/cafa-6-protein-function-prediction/Test/testsuperset.fasta\"\nPATH_TRAIN_FASTA = \"/kaggle/input/cafa-6-protein-function-prediction/Train/train_sequences.fasta\"\n\n# OBO FILE\nPATH_GO_BASIC = \"/kaggle/input/cafa-6-protein-function-prediction/Train/go-basic.obo\"\n\n# OUTPUT\nPATH_OUTPUT_SUBMISSION = \"/kaggle/working/submission.tsv\"\n\nprint(\"✅ File paths are set!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:24:14.647520Z","iopub.execute_input":"2025-10-25T17:24:14.647787Z","iopub.status.idle":"2025-10-25T17:24:14.654434Z","shell.execute_reply.started":"2025-10-25T17:24:14.647748Z","shell.execute_reply":"2025-10-25T17:24:14.653202Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Load the GO terms ---\ntrain_terms = pd.read_csv(PATH_TRAIN_TERMS, sep=\"\\t\")\nprint(\"GO terms shape:\", train_terms.shape)\nprint(train_terms.head())\n\n# --- Load protein sequences from FASTA ---\nrecords = list(SeqIO.parse(PATH_TRAIN_FASTA, \"fasta\"))\nseq_df = pd.DataFrame({\n    \"EntryID\": [r.id.split(\"|\")[1] if \"|\" in r.id else r.id for r in records],\n    \"sequence\": [str(r.seq) for r in records]\n})\nprint(\"Sequences shape:\", seq_df.shape)\nprint(seq_df.head())\n\n# --- Merge ---\ntrain_merged = train_terms.merge(seq_df, on=\"EntryID\", how=\"left\")\ntrain_merged.dropna(subset=[\"sequence\"], inplace=True)\nprint(\"✅ Merged dataset shape:\", train_merged.shape)\ntrain_merged.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:24:14.660145Z","iopub.execute_input":"2025-10-25T17:24:14.660488Z","iopub.status.idle":"2025-10-25T17:24:16.499022Z","shell.execute_reply.started":"2025-10-25T17:24:14.660442Z","shell.execute_reply":"2025-10-25T17:24:16.498078Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_name = \"facebook/esm2_t6_8M_UR50D\"\ntokenizer = AutoTokenizer.from_pretrained(model_name)\nmodel = AutoModel.from_pretrained(model_name)\nmodel.eval()\n\ndef extract_embedding(seq):\n    \"\"\"Extracts mean-pooled embedding from an amino acid sequence.\"\"\"\n    inputs = tokenizer(seq, return_tensors=\"pt\", truncation=True, max_length=1024)\n    with torch.no_grad():\n        outputs = model(**inputs)\n    return outputs.last_hidden_state.mean(dim=1).squeeze().numpy()\n\n# For demo: only sample a few hundred due to runtime\nsample_df = train_merged.sample(300, random_state=42).reset_index(drop=True)\n\nembeddings = []\nfor seq in tqdm(sample_df[\"sequence\"], desc=\"Embedding Sequences\"):\n    try:\n        emb = extract_embedding(seq)\n        embeddings.append(emb)\n    except Exception as e:\n        print(f\"⚠️ Error embedding: {e}\")\n        embeddings.append(np.zeros(320))\n\nembeddings = np.vstack(embeddings)\nprint(\"✅ Embedding matrix shape:\", embeddings.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:24:16.500194Z","iopub.execute_input":"2025-10-25T17:24:16.500472Z","iopub.status.idle":"2025-10-25T17:26:43.597113Z","shell.execute_reply.started":"2025-10-25T17:24:16.500451Z","shell.execute_reply":"2025-10-25T17:26:43.595401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Group GO terms per protein\nmulti_label_df = (\n    sample_df.groupby(\"EntryID\")[\"term\"]\n    .apply(list)\n    .reset_index()\n    .merge(sample_df[[\"EntryID\", \"sequence\"]].drop_duplicates(), on=\"EntryID\")\n)\n\nmlb = MultiLabelBinarizer()\nY = mlb.fit_transform(multi_label_df[\"term\"])\nprint(\"Label matrix shape:\", Y.shape)\nprint(\"Example labels:\", multi_label_df[\"term\"].iloc[0])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:26:43.598426Z","iopub.execute_input":"2025-10-25T17:26:43.600193Z","iopub.status.idle":"2025-10-25T17:26:43.632844Z","shell.execute_reply.started":"2025-10-25T17:26:43.600151Z","shell.execute_reply":"2025-10-25T17:26:43.631834Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(\n    embeddings, Y, test_size=0.2, random_state=42\n)\n\nclf = OneVsRestClassifier(LogisticRegression(max_iter=200))\nclf.fit(X_train, y_train)\n\ny_pred = clf.predict_proba(X_val)\nprint(\"✅ Model trained.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:26:43.634009Z","iopub.execute_input":"2025-10-25T17:26:43.634410Z","iopub.status.idle":"2025-10-25T17:27:03.884309Z","shell.execute_reply.started":"2025-10-25T17:26:43.634371Z","shell.execute_reply":"2025-10-25T17:27:03.883414Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def fmax_score(y_true, y_pred):\n    \"\"\"Compute CAFA-style Fmax (best F1 across thresholds).\"\"\"\n    precisions, recalls, thresholds = precision_recall_curve(y_true.ravel(), y_pred.ravel())\n    f_scores = 2 * precisions * recalls / (precisions + recalls + 1e-8)\n    return np.nanmax(f_scores)\n\nfmax = fmax_score(y_val, y_pred)\nprint(f\"✅ Fmax Score (Validation): {fmax:.4f}\")\n\n# Plot Precision-Recall Curve\nprecisions, recalls, _ = precision_recall_curve(y_val.ravel(), y_pred.ravel())\nplt.figure(figsize=(6, 4))\nplt.plot(recalls, precisions, color=\"blue\")\nplt.title(\"Precision-Recall Curve\")\nplt.xlabel(\"Recall\")\nplt.ylabel(\"Precision\")\nplt.grid(True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:27:03.887334Z","iopub.execute_input":"2025-10-25T17:27:03.887657Z","iopub.status.idle":"2025-10-25T17:27:04.108011Z","shell.execute_reply.started":"2025-10-25T17:27:03.887634Z","shell.execute_reply":"2025-10-25T17:27:04.106739Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def read_submission_flex(path):\n    \"\"\"\n    Read CAFA-6 sample_submission.tsv safely even if the file\n    has inconsistent delimiters or malformed lines.\n    \"\"\"\n    rows = []\n    with open(path, \"r\", encoding=\"utf-8\", errors=\"ignore\") as f:\n        for line in f:\n            parts = line.strip().split()\n            # Skip empty or invalid lines\n            if len(parts) < 2:\n                continue\n            # Handle lines with 2 or 3 columns\n            if len(parts) == 2:\n                protein, go_term = parts\n                score = np.nan\n            elif len(parts) >= 3:\n                protein, go_term, score = parts[:3]\n            rows.append((protein, go_term, score))\n    df = pd.DataFrame(rows, columns=[\"protein_id\", \"go_term\", \"score\"])\n    return df\n\n# Load sample submission safely\nsubmission = read_submission_flex(PATH_SAMPLE_SUBMISSION)\nprint(\"✅ Loaded sample_submission safely:\", submission.shape)\nprint(submission.head())\n\n# Generate dummy prediction scores for testing\nsubmission[\"score\"] = np.random.uniform(0.5, 0.9, len(submission))\n\n# Save submission file\nsubmission.to_csv(PATH_OUTPUT_SUBMISSION, sep=\"\\t\", index=False)\nprint(\"✅ Submission file created successfully at:\", PATH_OUTPUT_SUBMISSION)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-25T17:31:38.101957Z","iopub.execute_input":"2025-10-25T17:31:38.102989Z","iopub.status.idle":"2025-10-25T17:31:38.205819Z","shell.execute_reply.started":"2025-10-25T17:31:38.102947Z","shell.execute_reply":"2025-10-25T17:31:38.204756Z"}},"outputs":[],"execution_count":null}]}