{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","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":"gpu","dataSources":[{"sourceId":116062,"databundleVersionId":14084779,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# CAFA 6 Protein fold competition\n\n---\n\nThis notebook was automatically generated by Alexandria with comprehensive research data.\n","metadata":{}},{"cell_type":"markdown","source":"## 1. Setup & Imports\n\nInstall and import required libraries.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, classification_report\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Set random seeds\nnp.random.seed(42)\ntorch.manual_seed(42)\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f'Using device: {device}')","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. Load Dataset\n\nLoading dataset: **physionet-ecg-images**\n\nCompetition: `cafa-6-protein-function-prediction`","metadata":{}},{"cell_type":"code","source":"from pathlib import Path\nimport pandas as pd\nimport os\n\n# Setup\nDATA_PATH = Path(f'/kaggle/input/cafa-6-protein-function-prediction')\nprint(f'📁 Data path: {DATA_PATH}')\nprint(f'📁 Path exists: {DATA_PATH.exists()}')\n\n# List all files\nif DATA_PATH.exists():\n    all_files = list(DATA_PATH.glob('**/*'))\n    print(f'\\n📊 Found {len(all_files)} total files/folders:')\n    for f in all_files:\n        print(f'  - {f.relative_to(DATA_PATH)}')\nelse:\n    print(f'❌ Data path does not exist')\n\n# Identify TSV files\ntsv_files = [f for f in all_files if f.suffix.lower() == '.tsv']\nprint(f'\\n📝 Found {len(tsv_files)} TSV files:')\nfor f in tsv_files:\n    print(f'  - {f.name}')\n\n# Load and inspect TSV files (train/test splits if available)\nfor tsv_file in tsv_files:\n    print(f'\\n🔍 Inspecting file: {tsv_file.name}')\n    try:\n        df = pd.read_csv(tsv_file, sep='\\t')\n        print(f'  Shape: {df.shape}')\n        print(f'  Columns: {list(df.columns)}')\n        print(f'  Sample data:')\n        display(df.head())\n        print(f'  Info:')\n        df.info()\n    except Exception as e:\n        print(f'  ❌ Could not load {tsv_file.name}: {e}')\n\n# Attempt to identify train/test splits by filename\ntrain_files = [f for f in tsv_files if 'train' in f.name.lower()]\ntest_files = [f for f in tsv_files if 'test' in f.name.lower() or 'val' in f.name.lower()]\n\nif train_files:\n    print(f'\\n🟢 Train files:')\n    for f in train_files:\n        print(f'  - {f.name}')\nif test_files:\n    print(f'\\n🔵 Test/Validation files:')\n    for f in test_files:\n        print(f'  - {f.name}')","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3. Exploratory Data Analysis\n\n**Analyzing the competition data structure**","metadata":{}},{"cell_type":"code","source":"# Exploratory Data Analysis\ntry:\n    print('🔧 === EXPLORATORY DATA ANALYSIS ===\\n')\n    \n    import matplotlib.pyplot as plt\n    import seaborn as sns\n    import pandas as pd\n    import numpy as np\n\n    # Helper for displaying multiple dataframes\n    from IPython.display import display\n\n    # Load train/test DataFrames from identified files\n    dfs = {}\n    for split, files in [('train', train_files), ('test', test_files)]:\n        for f in files:\n            try:\n                df = pd.read_csv(f, sep='\\t')\n                dfs[f'{split}_{f.stem}'] = df\n                print(f'✅ Loaded {split} file: {f.name} | shape: {df.shape}')\n            except Exception as e:\n                print(f'✗ Could not load {split} file {f.name}: {e}')\n\n    # Show basic info for each dataframe\n    for name, df in dfs.items():\n        print(f'\\n📄 DataFrame: {name}')\n        print(f'  Shape: {df.shape}')\n        print(f'  Columns: {list(df.columns)}')\n        print('  Sample rows:')\n        display(df.head())\n        print('  Info:')\n        df.info()\n\n    # Analyze column types and missing values\n    for name, df in dfs.items():\n        print(f'\\n🔎 Missing values in {name}:')\n        print(df.isnull().sum())\n\n    # Distribution of sequence lengths (if sequence column exists)\n    for name, df in dfs.items():\n        seq_cols = [col for col in df.columns if 'sequence' in col.lower()]\n        for seq_col in seq_cols:\n            print(f'\\n📊 Sequence length distribution in {name} [{seq_col}]:')\n            seq_lengths = df[seq_col].dropna().apply(len)\n            print(seq_lengths.describe())\n            plt.figure(figsize=(8,4))\n            sns.histplot(seq_lengths, bins=50, kde=True)\n            plt.title(f'Sequence Length Distribution: {name} [{seq_col}]')\n            plt.xlabel('Sequence Length')\n            plt.ylabel('Count')\n            plt.show()\n\n    # Distribution of target labels (if any label columns exist)\n    for name, df in dfs.items():\n        label_cols = [col for col in df.columns if 'label' in col.lower() or 'go_' in col.lower() or 'function' in col.lower()]\n        for label_col in label_cols:\n            print(f'\\n📊 Label distribution in {name} [{label_col}]:')\n            label_counts = df[label_col].value_counts(dropna=False)\n            print(label_counts.head(20))\n            plt.figure(figsize=(8,4))\n            sns.barplot(x=label_counts.index.astype(str)[:20], y=label_counts.values[:20])\n            plt.title(f'Label Distribution: {name} [{label_col}] (Top 20)')\n            plt.xlabel('Label')\n            plt.ylabel('Count')\n            plt.xticks(rotation=45, ha='right')\n            plt.tight_layout()\n            plt.show()\n\n    # If multi-label columns (e.g., GO terms as lists/strings), analyze number of labels per sample\n    for name, df in dfs.items():\n        go_cols = [col for col in df.columns if 'go_' in col.lower() or 'function' in col.lower()]\n        for go_col in go_cols:\n            if df[go_col].dtype == object:\n                print(f'\\n📊 Number of GO terms per sample in {name} [{go_col}]:')\n                # Try splitting by semicolon/comma/space\n                sample = df[go_col].dropna().astype(str)\n                if sample.str.contains(';').any():\n                    splitter = ';'\n                elif sample.str.contains(',').any():\n                    splitter = ','\n                else:\n                    splitter = ' '\n                n_terms = sample.apply(lambda x: len([t for t in x.split(splitter) if t.strip()]))\n                print(n_terms.describe())\n                plt.figure(figsize=(8,4))\n                sns.histplot(n_terms, bins=30, kde=False)\n                plt.title(f'GO Terms per Sample: {name} [{go_col}]')\n                plt.xlabel('Number of GO Terms')\n                plt.ylabel('Count')\n                plt.show()\n\n    # Check for duplicate sequences or IDs\n    for name, df in dfs.items():\n        id_cols = [col for col in df.columns if 'id' in col.lower()]\n        for id_col in id_cols:\n            n_unique = df[id_col].nunique()\n            n_total = df.shape[0]\n            print(f'\\n🆔 {name}: {id_col} - {n_unique} unique / {n_total} total ({n_total-n_unique} duplicates)')\n        seq_cols = [col for col in df.columns if 'sequence' in col.lower()]\n        for seq_col in seq_cols:\n            n_unique = df[seq_col].nunique()\n            n_total = df.shape[0]\n            print(f'🧬 {name}: {seq_col} - {n_unique} unique / {n_total} total ({n_total-n_unique} duplicates)')\n\n    # Correlation heatmap for numeric columns (if any)\n    for name, df in dfs.items():\n        num_cols = df.select_dtypes(include=[np.number]).columns\n        if len(num_cols) > 1:\n            print(f'\\n📈 Correlation heatmap for {name}:')\n            plt.figure(figsize=(8,6))\n            sns.heatmap(df[num_cols].corr(), annot=True, fmt='.2f', cmap='coolwarm')\n            plt.title(f'Numeric Feature Correlation: {name}')\n            plt.show()\n\n    print('\\n✅ Exploratory Data Analysis complete!')\n\nexcept Exception as e:\n    print(f'✗ Error in Exploratory Data Analysis: {e}')\n    import traceback\n    traceback.print_exc()","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. Data Preprocessing\n\n**Competition:** cafa-6-protein-function-prediction\n\n**Note:** Following research-based implementation strategy","metadata":{}},{"cell_type":"code","source":"# Data Preprocessing\ntry:\n    print('🔧 === DATA PREPROCESSING ===\\n')\n    \n    # Suppress warnings for cleaner output\n    warnings.filterwarnings('ignore')\n    \n    # Load all train/test TSV files into dataframes\n    dfs = {}\n    for f in train_files + test_files:\n        name = f.stem\n        print(f'Loading: {name}')\n        df = pd.read_csv(f, sep='\\t')\n        dfs[name] = df\n        print(f'  Shape: {df.shape}')\n    \n    # Clean and preprocess each dataframe\n    for name, df in dfs.items():\n        print(f'\\n🧹 Preprocessing: {name}')\n        \n        # Standardize column names\n        df.columns = [c.strip().lower().replace(' ', '_') for c in df.columns]\n        \n        # Remove duplicate rows based on 'id' or 'sequence' columns\n        id_cols = [col for col in df.columns if 'id' in col]\n        seq_cols = [col for col in df.columns if 'sequence' in col]\n        for id_col in id_cols:\n            before = df.shape[0]\n            df = df.drop_duplicates(subset=[id_col])\n            after = df.shape[0]\n            print(f'  Removed {before-after} duplicate IDs')\n        for seq_col in seq_cols:\n            before = df.shape[0]\n            df = df.drop_duplicates(subset=[seq_col])\n            after = df.shape[0]\n            print(f'  Removed {before-after} duplicate sequences')\n        \n        # Remove rows with missing or invalid sequences\n        for seq_col in seq_cols:\n            before = df.shape[0]\n            df = df[df[seq_col].notnull() & df[seq_col].str.match('^[ACDEFGHIKLMNPQRSTVWY]+$', na=False)]\n            after = df.shape[0]\n            print(f'  Removed {before-after} rows with invalid/missing sequences')\n        \n        # Fill missing GO terms with empty string\n        go_cols = [col for col in df.columns if 'go' in col]\n        for go_col in go_cols:\n            df[go_col] = df[go_col].fillna('')\n        \n        # Normalize GO term delimiters to semicolon\n        for go_col in go_cols:\n            df[go_col] = df[go_col].astype(str).str.replace(',', ';').str.replace(' ', ';')\n            df[go_col] = df[go_col].apply(lambda x: ';'.join([t.strip() for t in x.split(';') if t.strip()]))\n        \n        # Remove duplicate GO terms per sample\n        for go_col in go_cols:\n            df[go_col] = df[go_col].apply(lambda x: ';'.join(sorted(set(x.split(';')))) if x else '')\n        \n        # Reset index after cleaning\n        df = df.reset_index(drop=True)\n        dfs[name] = df\n        \n        print(f'  Final shape: {df.shape}')\n    \n    # Visualize GO term distribution after cleaning\n    for name, df in dfs.items():\n        go_cols = [col for col in df.columns if 'go' in col]\n        for go_col in go_cols:\n            sample = df[go_col].dropna().astype(str)\n            n_terms = sample.apply(lambda x: len([t for t in x.split(';') if t.strip()]))\n            print(f'\\nGO Terms per Sample: {name} [{go_col}]')\n            print(n_terms.describe())\n            plt.figure(figsize=(8,4))\n            sns.histplot(n_terms, bins=30, kde=False)\n            plt.title(f'GO Terms per Sample: {name} [{go_col}]')\n            plt.xlabel('Number of GO Terms')\n            plt.ylabel('Count')\n            plt.show()\n    \n    # Save cleaned dataframes for downstream tasks\n    for name, df in dfs.items():\n        out_path = DATA_PATH / f'{name}_cleaned.tsv'\n        df.to_csv(out_path, sep='\\t', index=False)\n        print(f'  Saved cleaned dataframe: {out_path}')\n    \n    print('\\n✅ Data Preprocessing complete!')\n    \nexcept Exception as e:\n    print(f'✗ Error in Data Preprocessing: {e}')\n    import traceback\n    traceback.print_exc()","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5. Model Architecture\n\n**Approach:** Neural network baseline","metadata":{}},{"cell_type":"code","source":"# Model Architecture\ntry:\n    print('🔧 === MODEL ARCHITECTURE ===\\n')\n    import torch\n    import torch.nn as nn\n    import torch.nn.functional as F\n\n    # =========================\n    # Protein Function Prediction Model\n    # =========================\n    # Reference: ProteInfer[1], DPFunc[2], TAWFN[3], DeepFRI[4]\n    # - Sequence encoder: 1D CNN + optional protein language model embedding\n    # - Structure encoder: Graph Convolutional Network (GCN)\n    # - Fusion: Adaptive weighted sum of sequence and structure features\n    # - Output: Multi-label classification (GO terms)\n\n    # --- Sequence Encoder: 1D CNN ---\n    class SequenceCNN(nn.Module):\n        def __init__(self, vocab_size, embed_dim, cnn_channels, kernel_sizes, dropout=0.2):\n            super().__init__()\n            self.embedding = nn.Embedding(vocab_size, embed_dim, padding_idx=0)\n            self.convs = nn.ModuleList([\n                nn.Conv1d(embed_dim, cnn_channels, k, padding=k//2)\n                for k in kernel_sizes\n            ])\n            self.dropout = nn.Dropout(dropout)\n\n        def forward(self, x):\n            # x: (batch, seq_len)\n            x = self.embedding(x)  # (batch, seq_len, embed_dim)\n            x = x.transpose(1, 2)  # (batch, embed_dim, seq_len)\n            feats = [F.relu(conv(x)) for conv in self.convs]  # list of (batch, cnn_channels, seq_len)\n            x = torch.cat(feats, dim=1)  # (batch, cnn_channels * len(kernel_sizes), seq_len)\n            x = F.adaptive_max_pool1d(x, 1).squeeze(-1)  # (batch, cnn_channels * len(kernel_sizes))\n            x = self.dropout(x)\n            return x\n\n    # --- Structure Encoder: Graph Convolutional Network (GCN) ---\n    class GCNLayer(nn.Module):\n        def __init__(self, in_dim, out_dim):\n            super().__init__()\n            self.linear = nn.Linear(in_dim, out_dim)\n\n        def forward(self, x, adj):\n            # x: (batch, n_nodes, in_dim)\n            # adj: (batch, n_nodes, n_nodes)\n            h = torch.bmm(adj, x)  # (batch, n_nodes, in_dim)\n            h = self.linear(h)\n            return F.relu(h)\n\n    class StructureGCN(nn.Module):\n        def __init__(self, in_dim, hidden_dim, n_layers=2, dropout=0.2):\n            super().__init__()\n            self.layers = nn.ModuleList()\n            for i in range(n_layers):\n                self.layers.append(GCNLayer(in_dim if i == 0 else hidden_dim, hidden_dim))\n            self.dropout = nn.Dropout(dropout)\n\n        def forward(self, x, adj):\n            for layer in self.layers:\n                x = layer(x, adj)\n                x = self.dropout(x)\n            # Global pooling\n            x = x.mean(dim=1)  # (batch, hidden_dim)\n            return x\n\n    # --- Fusion and Output ---\n    class ProteinFunctionPredictor(nn.Module):\n        def __init__(self, vocab_size, seq_embed_dim, cnn_channels, kernel_sizes,\n                     gcn_in_dim, gcn_hidden_dim, gcn_layers, n_classes, dropout=0.3):\n            super().__init__()\n            self.seq_encoder = SequenceCNN(vocab_size, seq_embed_dim, cnn_channels, kernel_sizes, dropout)\n            self.struct_encoder = StructureGCN(gcn_in_dim, gcn_hidden_dim, gcn_layers, dropout)\n            fusion_dim = cnn_channels * len(kernel_sizes) + gcn_hidden_dim\n            self.fusion = nn.Sequential(\n                nn.Linear(fusion_dim, fusion_dim),\n                nn.ReLU(),\n                nn.Dropout(dropout)\n            )\n            self.classifier = nn.Linear(fusion_dim, n_classes)\n\n        def forward(self, seq, struct_feats, adj):\n            seq_feat = self.seq_encoder(seq)\n            struct_feat = self.struct_encoder(struct_feats, adj)\n            fused = torch.cat([seq_feat, struct_feat], dim=1)\n            fused = self.fusion(fused)\n            out = self.classifier(fused)\n            return out\n\n    # =========================\n    # Example: Model Instantiation\n    # =========================\n    # These values should be set according to your data preprocessing pipeline\n    vocab_size = 26  # 20 amino acids + special tokens\n    seq_embed_dim = 128\n    cnn_channels = 64\n    kernel_sizes = [3, 5, 7]\n    gcn_in_dim = 32   # e.g., residue-level features (set accordingly)\n    gcn_hidden_dim = 64\n    gcn_layers = 2\n    n_classes = 500   # Number of GO terms (set according to your label binarizer)\n    dropout = 0.3\n\n    model = ProteinFunctionPredictor(\n        vocab_size=vocab_size,\n        seq_embed_dim=seq_embed_dim,\n        cnn_channels=cnn_channels,\n        kernel_sizes=kernel_sizes,\n        gcn_in_dim=gcn_in_dim,\n        gcn_hidden_dim=gcn_hidden_dim,\n        gcn_layers=gcn_layers,\n        n_classes=n_classes,\n        dropout=dropout\n    ).to(device)\n\n    print(model)\n    n_params = sum(p.numel() for p in model.parameters() if p.requires_grad)\n    print(f\"\\nTotal trainable parameters: {n_params:,}\")\n\n    # =========================\n    # Visualization: Model Architecture\n    # =========================\n    try:\n        from torchsummary import summary\n        # Example dummy input shapes\n        batch_size = 2\n        seq_len = 512\n        n_nodes = 512\n        seq_input = torch.randint(0, vocab_size, (batch_size, seq_len)).to(device)\n        struct_feats = torch.randn(batch_size, n_nodes, gcn_in_dim).to(device)\n        adj = torch.eye(n_nodes).unsqueeze(0).repeat(batch_size,1,1).to(device)\n        summary(model, [(seq_len,), (n_nodes, gcn_in_dim), (n_nodes, n_nodes)], device=str(device))\n    except Exception as e:\n        print(\"torchsummary not available or failed, skipping summary.\")\n\n    # =========================\n    # Visualize Model Graph (optional)\n    # =========================\n    try:\n        from torchviz import make_dot\n        dummy_seq = torch.randint(0, vocab_size, (1, seq_len)).to(device)\n        dummy_struct = torch.randn(1, n_nodes, gcn_in_dim).to(device)\n        dummy_adj = torch.eye(n_nodes).unsqueeze(0).to(device)\n        out = model(dummy_seq, dummy_struct, dummy_adj)\n        dot = make_dot(out, params=dict(model.named_parameters()))\n        dot.format = 'png'\n        dot.render('protein_function_model_architecture', view=False)\n        print(\"Model graph saved as 'protein_function_model_architecture.png'\")\n    except Exception as e:\n        print(\"torchviz not available or failed, skipping model graph visualization.\")\n\n    print('✅ Model Architecture complete!')\n\nexcept Exception as e:\n    print(f'✗ Error in Model Architecture: {e}')\n    import traceback\n    traceback.print_exc()","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 6. Implementation & Next Steps\n\n**Note:** This section provides guidance, not complete code. Actual implementation depends on competition task.","metadata":{}},{"cell_type":"code","source":"print('📋 === IMPLEMENTATION GUIDE ===\\n')\n\nprint('Competition task determines implementation approach\\n')\nprint('Possible approaches:')\nprint('  - Classification: Train classifier, predict labels')\nprint('  - Regression: Train regressor, predict values')\nprint('  - Generation: Generate required outputs')\nprint('  - Processing: Transform/extract data')\n\nprint('\\n⚠️ TODO: Implement competition-specific solution')\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 7. Submission\n\n**Generate submission file in competition format**","metadata":{}},{"cell_type":"code","source":"print('📤 === SUBMISSION GENERATION ===\\n')\n\nprint('⚠️ TODO: Check competition submission format')\nprint('Typical formats: CSV, Parquet, JSON')\n\n# Generic template (uncomment and modify):\n# submission = pd.DataFrame({\n#     'id': test_ids,\n#     'prediction': predictions  # YOUR PREDICTIONS HERE\n# })\n# submission.to_csv('submission.csv', index=False)\n# print('✅ Submission created!')\n","metadata":{},"outputs":[],"execution_count":null}]}