{"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":118765,"databundleVersionId":15231210,"sourceType":"competition"}],"dockerImageVersionId":31234,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Stanford RNA 3D Folding Part 2 – Heuristic Baseline Model\n\nThis notebook implements a **baseline pipeline** for predicting RNA 3D structures from sequence alone, following the submission format required by the *Stanford RNA 3D Folding Part 2* Kaggle competition.\n\nThe goal is to establish a **valid, interpretable baseline**, not a state-of-the-art model.\n\nWe will:\n\n1. Load data to perform EDA  \n2. Define RNA base-pair heuristics  \n3. Generate 3D structures  \n4. Build a Kaggle submission  \n5. Visualize predicted RNA structure  ","metadata":{}},{"cell_type":"markdown","source":"## Imports, Dependencies & Loading dataframe","metadata":{}},{"cell_type":"code","source":"# Loading required libraries\nimport numpy as np # linear algebra\nimport pandas as pd # data processing\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\nimport seaborn as sns\nfrom sklearn.decomposition import PCA\n\nprint(\"packages are loaded\")\n\n# Loading sample data in .CSV format\nsample_dataframe = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/sample_submission.csv\")\n# Loading test sequence data in .CSV format \ntest_dataframe = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/test_sequences.csv\")\n# Loading training sequence data in .CSV format\ntrain_seq_dataframe = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv\")\n# Loading validation sequence data in .CSV format\nvalidation_seq_dataframe = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding-2/validation_sequences.csv\")\n\n# Checking if dataframes are loaded successfully\n# Condition: If non zero rows and columns then loading is successful\nprint(\"Sample dataframe shape: \", sample_dataframe.shape)\nprint(\"Test dataframe shape: \", test_dataframe.shape)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:21.492877Z","iopub.execute_input":"2026-01-09T18:47:21.493294Z","iopub.status.idle":"2026-01-09T18:47:21.94354Z","shell.execute_reply.started":"2026-01-09T18:47:21.493261Z","shell.execute_reply":"2026-01-09T18:47:21.942148Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualising rows and columns of the dataframe","metadata":{}},{"cell_type":"code","source":"# Viewing first 10 rows of the sample dataframe\nprint(\"sample dataframe:\")\nsample_dataframe.head(10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:21.946166Z","iopub.execute_input":"2026-01-09T18:47:21.946701Z","iopub.status.idle":"2026-01-09T18:47:21.983329Z","shell.execute_reply.started":"2026-01-09T18:47:21.946666Z","shell.execute_reply":"2026-01-09T18:47:21.981841Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Viewing first 10 rows of the sample dataframe\nprint(\"test dataframe:\")\ntest_dataframe.head(10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:21.985088Z","iopub.execute_input":"2026-01-09T18:47:21.985484Z","iopub.status.idle":"2026-01-09T18:47:22.005133Z","shell.execute_reply.started":"2026-01-09T18:47:21.985444Z","shell.execute_reply":"2026-01-09T18:47:22.003806Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Determining the column details in dataframe\nprint(\"sample dataframe\")\nsample_dataframe.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:22.00741Z","iopub.execute_input":"2026-01-09T18:47:22.007799Z","iopub.status.idle":"2026-01-09T18:47:22.04025Z","shell.execute_reply.started":"2026-01-09T18:47:22.007766Z","shell.execute_reply":"2026-01-09T18:47:22.038902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"test dataframe\")\ntest_dataframe.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:22.041731Z","iopub.execute_input":"2026-01-09T18:47:22.042148Z","iopub.status.idle":"2026-01-09T18:47:22.069144Z","shell.execute_reply.started":"2026-01-09T18:47:22.042104Z","shell.execute_reply":"2026-01-09T18:47:22.067354Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Feature Engineering","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.decomposition import PCA\nimport matplotlib.pyplot as plt\n\n# Base pairs\nBASE_PAIRS = {\n    (\"A\", \"U\"), (\"U\", \"A\"),\n    (\"G\", \"C\"), (\"C\", \"G\"),\n    (\"G\", \"U\"), (\"U\", \"G\")\n}\n\ndef infer_stems(sequence, window=4):\n    n = len(sequence)\n    paired = np.zeros(n, dtype=bool)\n    for i in range(n - window):\n        for j in range(i + window + 3, n - window):\n            matches = 0\n            for k in range(window):\n                if (sequence[i+k], sequence[j-k]) in BASE_PAIRS:\n                    matches += 1\n            if matches >= window - 1:\n                paired[i:i+window] = True\n                paired[j-window+1:j+1] = True\n    return paired\n\ndef gc_radius(base):\n    return 5.5 if base in {\"G\", \"C\"} else 7.5\n\ndef msa_covariance_restraints(seq):\n    n = len(seq)\n    restraints = np.zeros((n, n))\n    for i in range(n):\n        for j in range(i+6, n):\n            if (seq[i], seq[j]) in BASE_PAIRS:\n                restraints[i, j] = restraints[j, i] = 1.0\n    return restraints\n\ndef template_fragment(seq, start_idx):\n    fragment_length = min(5, len(seq) - start_idx)\n    t = np.linspace(0, np.pi, fragment_length)\n    return np.stack([np.cos(t), np.sin(t), t], axis=1)\n\ndef generate_structure(seq, seed=0):\n    if not seq or pd.isna(seq):\n        # Return a small default array for empty sequences\n        return np.zeros((1,3))\n    \n    n = len(seq)\n    rng = np.random.default_rng(seed)\n\n    paired = infer_stems(seq)\n    restraints = msa_covariance_restraints(seq)\n\n    coords = np.zeros((n,3))\n    t = np.linspace(0, 2*np.pi*n/10, n)\n\n    for i, base in enumerate(seq):\n        r = gc_radius(base)\n        if paired[i]:\n            r *= 0.85\n        coords[i] = [r*np.cos(t[i]), r*np.sin(t[i]), 3.2*t[i]]\n\n    # Apply template fragments safely\n    for i in range(0, n-1, 10):\n        frag = template_fragment(seq, i)\n        frag_len = frag.shape[0]\n        coords[i:i+frag_len] += frag\n\n    # Apply MSA-like restraints\n    for i in range(n):\n        for j in range(i+1, n):\n            if restraints[i,j] > 0:\n                diff = coords[j] - coords[i]\n                coords[j] -= 0.05 * diff\n\n    # Noise\n    coords += rng.normal(0, 0.3, coords.shape)\n\n    # PCA smoothing\n    pca = PCA(n_components=3)\n    coords = pca.inverse_transform(pca.fit_transform(coords))\n\n    return coords\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:22.071219Z","iopub.execute_input":"2026-01-09T18:47:22.0719Z","iopub.status.idle":"2026-01-09T18:47:22.106395Z","shell.execute_reply.started":"2026-01-09T18:47:22.071854Z","shell.execute_reply":"2026-01-09T18:47:22.105156Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3D Visualization of Predicted RNA Structure\nVisualize a single predicted RNA to inspect the fold.","metadata":{}},{"cell_type":"code","source":"def plot_rna_structure(coords, seq, title=\"RNA 3D Structure\"):\n    if coords is None or len(coords) != len(seq):\n        print(\"Error: Invalid coordinates. Cannot plot structure.\")\n        return\n    \n    fig = plt.figure(figsize=(8,6))\n    ax = fig.add_subplot(111, projection='3d')\n\n    x, y, z = coords[:,0], coords[:,1], coords[:,2]\n\n    ax.plot(x, y, z, linewidth=1.5, color='blue')\n    ax.scatter(x, y, z, s=25, color='red')\n\n    for i, base in enumerate(seq):\n        ax.text(x[i], y[i], z[i], base, fontsize=8)\n\n    ax.set_title(title)\n    ax.set_xlabel(\"X (Å)\")\n    ax.set_ylabel(\"Y (Å)\")\n    ax.set_zlabel(\"Z (Å)\")\n    plt.show()\n\n# Example usage\nexample_seq = test_dataframe.iloc[0][\"sequence\"]\ncoords_example = generate_structure(example_seq, seed=0)\nplot_rna_structure(coords_example, example_seq, \"Predicted RNA Structure (Seed 0)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-09T18:47:22.108683Z","iopub.execute_input":"2026-01-09T18:47:22.110662Z","iopub.status.idle":"2026-01-09T18:47:22.405827Z","shell.execute_reply.started":"2026-01-09T18:47:22.110616Z","shell.execute_reply":"2026-01-09T18:47:22.404022Z"}},"outputs":[],"execution_count":null}]}