{"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":"gpu","dataSources":[{"sourceId":118765,"databundleVersionId":15231210,"sourceType":"competition"}],"dockerImageVersionId":31234,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom scipy.spatial.distance import cdist\nfrom scipy.spatial.transform import Rotation as R\nfrom sklearn.metrics import mean_squared_error\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Библиотеки для визуализации\nimport plotly.graph_objects as go\nimport plotly.express as px\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\nimport seaborn as sns\n\n# Стилизация\nplt.style.use('seaborn-v0_8-darkgrid')\nsns.set_palette(\"husl\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class RNA3DVisualizer:\n    \"\"\"Класс для красивой визуализации 3D структур РНК\"\"\"\n    \n    def __init__(self):\n        self.colors = {\n            'A': '#FF6B6B',  # Красный\n            'C': '#4ECDC4',  # Бирюзовый\n            'G': '#FFD166',  # Желтый\n            'U': '#06D6A0'   # Зеленый\n        }\n    \n    def plot_3d_structure(self, coords, sequence, title=\"3D Structure\"):\n        \"\"\"Интерактивная 3D визуализация с Plotly\"\"\"\n        \n        # Создаем трассы для связей\n        x_lines, y_lines, z_lines = [], [], []\n        \n        for i in range(len(coords)-1):\n            x_lines.extend([coords[i,0], coords[i+1,0], None])\n            y_lines.extend([coords[i,1], coords[i+1,1], None])\n            z_lines.extend([coords[i,2], coords[i+1,2], None])\n        \n        # Создаем фигуру\n        fig = go.Figure()\n        \n        # Добавляем связи\n        fig.add_trace(go.Scatter3d(\n            x=x_lines, y=y_lines, z=z_lines,\n            mode='lines',\n            line=dict(color='rgba(100,100,100,0.4)', width=2),\n            name='Backbone'\n        ))\n        \n        # Добавляем точки (нуклеотиды)\n        for i, (coord, nt) in enumerate(zip(coords, sequence)):\n            fig.add_trace(go.Scatter3d(\n                x=[coord[0]], y=[coord[1]], z=[coord[2]],\n                mode='markers+text',\n                marker=dict(\n                    size=8,\n                    color=self.colors[nt],\n                    line=dict(width=2, color='white')\n                ),\n                text=[f\"{nt}{i+1}\"],\n                textposition=\"top center\",\n                name=f\"{nt}{i+1}\"\n            ))\n        \n        # Настройки камеры\n        camera = dict(\n            up=dict(x=0, y=0, z=1),\n            center=dict(x=0, y=0, z=0),\n            eye=dict(x=1.5, y=1.5, z=1.5)\n        )\n        \n        fig.update_layout(\n            title=dict(text=title, font=dict(size=20)),\n            scene=dict(\n                xaxis_title='X (Å)',\n                yaxis_title='Y (Å)',\n                zaxis_title='Z (Å)',\n                aspectmode='data'\n            ),\n            scene_camera=camera,\n            showlegend=False,\n            height=600,\n            template='plotly_dark'\n        )\n        \n        return fig\n    \n    def plot_contact_map(self, coords, sequence, threshold=8.0):\n        \"\"\"Красивая визуализация контактной карты\"\"\"\n        \n        # Вычисляем матрицу расстояний\n        dist_matrix = cdist(coords, coords)\n        \n        # Создаем тепловую карту\n        fig, ax = plt.subplots(figsize=(10, 8))\n        \n        # Маска для верхнего треугольника\n        mask = np.triu(np.ones_like(dist_matrix, dtype=bool))\n        \n        # Визуализируем тепловую карту\n        im = ax.imshow(dist_matrix, cmap='viridis', alpha=0.8)\n        \n        # Добавляем цветную полосу для расстояний\n        plt.colorbar(im, ax=ax, label='Distance (Å)')\n        \n        # Контуры для близких контактов\n        contacts = dist_matrix < threshold\n        contacts = contacts.astype(float)\n        contacts[mask] = np.nan\n        \n        # Отмечаем близкие контакты\n        ax.contour(contacts, colors='white', linewidths=0.5, alpha=0.5)\n        \n        # Настраиваем оси\n        ax.set_xticks(range(len(sequence)))\n        ax.set_yticks(range(len(sequence)))\n        ax.set_xticklabels([f\"{nt}{i+1}\" for i, nt in enumerate(sequence)], \n                          rotation=90, fontsize=8)\n        ax.set_yticklabels([f\"{nt}{i+1}\" for i, nt in enumerate(sequence)], \n                          fontsize=8)\n        \n        ax.set_title('Contact Map', fontsize=16, fontweight='bold')\n        ax.set_xlabel('Residue Index', fontsize=12)\n        ax.set_ylabel('Residue Index', fontsize=12)\n        \n        # Добавляем сетку\n        ax.grid(True, alpha=0.1, linestyle='--')\n        \n        plt.tight_layout()\n        return fig\n    \n    def plot_distance_distribution(self, coords, sequence):\n        \"\"\"Визуализация распределения расстояний\"\"\"\n        \n        fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n        \n        # 1. Распределение последовательных расстояний\n        seq_dists = []\n        for i in range(len(coords)-1):\n            dist = np.linalg.norm(coords[i+1] - coords[i])\n            seq_dists.append(dist)\n        \n        axes[0].hist(seq_dists, bins=30, color='#4ECDC4', edgecolor='black', alpha=0.7)\n        axes[0].axvline(np.mean(seq_dists), color='red', linestyle='--', \n                       label=f'Mean: {np.mean(seq_dists):.2f}Å')\n        axes[0].set_xlabel('Distance (Å)')\n        axes[0].set_ylabel('Frequency')\n        axes[0].set_title('Sequential Distances')\n        axes[0].legend()\n        axes[0].grid(True, alpha=0.3)\n        \n        # 2. Распределение всех попарных расстояний\n        all_dists = []\n        for i in range(len(coords)):\n            for j in range(i+2, len(coords)):\n                dist = np.linalg.norm(coords[i] - coords[j])\n                all_dists.append(dist)\n        \n        axes[1].hist(all_dists, bins=30, color='#FF6B6B', edgecolor='black', alpha=0.7)\n        axes[1].axvline(np.mean(all_dists), color='red', linestyle='--',\n                       label=f'Mean: {np.mean(all_dists):.2f}Å')\n        axes[1].set_xlabel('Distance (Å)')\n        axes[1].set_ylabel('Frequency')\n        axes[1].set_title('Pairwise Distances')\n        axes[1].legend()\n        axes[1].grid(True, alpha=0.3)\n        \n        # 3. Радиальная функция распределения\n        max_dist = np.max(all_dists) if all_dists else 50\n        bins = np.linspace(0, max_dist, 50)\n        hist, bin_edges = np.histogram(all_dists, bins=bins, density=True)\n        bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2\n        \n        axes[2].plot(bin_centers, hist, color='#06D6A0', linewidth=2)\n        axes[2].fill_between(bin_centers, 0, hist, alpha=0.3, color='#06D6A0')\n        axes[2].set_xlabel('Distance (Å)')\n        axes[2].set_ylabel('Probability Density')\n        axes[2].set_title('Radial Distribution Function')\n        axes[2].grid(True, alpha=0.3)\n        \n        plt.suptitle('Distance Analysis', fontsize=16, fontweight='bold', y=1.02)\n        plt.tight_layout()\n        \n        return fig","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TemplateBasedPredictor:\n    \"\"\"Продвинутый template-based предиктор 3D структур РНК\"\"\"\n    \n    def __init__(self, k_neighbors=5, use_ensemble=True):\n        self.k_neighbors = k_neighbors\n        self.use_ensemble = use_ensemble\n        self.templates = {}\n        \n    def encode_sequence(self, seq):\n        \"\"\"One-hot encoding последовательности\"\"\"\n        mapping = {'A': 0, 'C': 1, 'G': 2, 'U': 3}\n        encoded = np.zeros((len(seq), 4))\n        for i, nt in enumerate(seq):\n            if nt in mapping:\n                encoded[i, mapping[nt]] = 1\n        return encoded\n    \n    def compute_profile(self, seq, window=3):\n        \"\"\"Вычисление нуклеотидного профиля\"\"\"\n        profile = []\n        for i in range(len(seq)):\n            start = max(0, i - window)\n            end = min(len(seq), i + window + 1)\n            window_seq = seq[start:end]\n            counts = [window_seq.count(nt) for nt in 'ACGU']\n            total = sum(counts)\n            profile.append([c/total for c in counts] if total > 0 else [0.25]*4)\n        return np.array(profile)\n    \n    def find_similar_templates(self, query_seq, template_seqs, template_coords):\n        \"\"\"Поиск похожих шаблонов с расширенными метриками\"\"\"\n        \n        query_len = len(query_seq)\n        query_profile = self.compute_profile(query_seq)\n        \n        scores = []\n        \n        for target_id, template_seq in template_seqs.items():\n            if target_id not in template_coords:\n                continue\n                \n            template_len = len(template_seq)\n            \n            # Length similarity\n            len_sim = 1 - abs(template_len - query_len) / max(template_len, query_len)\n            \n            # Nucleotide composition similarity\n            comp_sim = np.sum(\n                [min(query_seq.count(nt)/query_len, template_seq.count(nt)/template_len) \n                 for nt in 'ACGU']\n            )\n            \n            # Profile alignment score\n            if len(template_seq) <= 2 * len(query_seq) and len(query_seq) <= 2 * len(template_seq):\n                # Динамическое выравнивание профилей\n                template_profile = self.compute_profile(template_seq)\n                profile_score = self._align_profiles(query_profile, template_profile)\n            else:\n                profile_score = 0\n                \n            # Final score (weighted combination)\n            final_score = 0.4 * len_sim + 0.3 * comp_sim + 0.3 * profile_score\n            \n            if final_score > 0.3:  # Порог сходства\n                scores.append((target_id, final_score, template_len))\n        \n        # Сортировка и выбор топ-K\n        scores.sort(key=lambda x: x[1], reverse=True)\n        return scores[:self.k_neighbors]\n    \n    def _align_profiles(self, profile1, profile2):\n        \"\"\"Выравнивание профилей с помощью динамического программирования\"\"\"\n        n, m = len(profile1), len(profile2)\n        score_matrix = np.zeros((n+1, m+1))\n        \n        # Заполнение матрицы\n        for i in range(1, n+1):\n            for j in range(1, m+1):\n                match_score = np.dot(profile1[i-1], profile2[j-1])\n                score_matrix[i][j] = max(\n                    score_matrix[i-1][j-1] + match_score,\n                    score_matrix[i-1][j] - 0.5,\n                    score_matrix[i][j-1] - 0.5\n                )\n        \n        # Нормализация\n        return score_matrix[n][m] / min(n, m)\n    \n    def generate_prediction(self, query_seq, templates_info, template_coords):\n        \"\"\"Генерация предсказания на основе шаблонов\"\"\"\n        \n        if not templates_info:\n            return self._generate_random_structure(query_seq)\n        \n        # Ensemble предсказания\n        all_coords = []\n        weights = []\n        \n        for target_id, score, template_len in templates_info:\n            template_coord = template_coords[target_id]\n            \n            # Масштабирование и выравнивание\n            scaled_coords = self._scale_and_align(query_seq, template_coord)\n            \n            # Refinement с геометрическими ограничениями\n            refined_coords = self._apply_constraints(scaled_coords, query_seq)\n            \n            all_coords.append(refined_coords)\n            weights.append(score)\n        \n        # Взвешенное усреднение\n        weights = np.array(weights)\n        weights = weights / weights.sum()\n        \n        # Ensemble prediction\n        if self.use_ensemble and len(all_coords) > 1:\n            final_coords = np.zeros_like(all_coords[0])\n            for i, coords in enumerate(all_coords):\n                final_coords += weights[i] * coords\n        else:\n            final_coords = all_coords[0]\n        \n        # Финальная оптимизация\n        final_coords = self._optimize_structure(final_coords, query_seq)\n        \n        return final_coords\n    \n    def _scale_and_align(self, query_seq, template_coords):\n        \"\"\"Масштабирование и выравнивание шаблона\"\"\"\n        target_len = len(query_seq)\n        template_len = len(template_coords)\n        \n        if template_len == target_len:\n            return template_coords.copy()\n        \n        # Линейная интерполяция\n        indices = np.linspace(0, template_len - 1, target_len)\n        interpolated = np.zeros((target_len, 3))\n        \n        for dim in range(3):\n            interpolated[:, dim] = np.interp(\n                indices, \n                np.arange(template_len), \n                template_coords[:, dim]\n            )\n        \n        return interpolated\n    \n    def _apply_constraints(self, coords, sequence):\n        \"\"\"Применение геометрических ограничений РНК\"\"\"\n        refined = coords.copy()\n        n = len(sequence)\n        \n        # Ограничения на последовательные расстояния\n        for i in range(n-1):\n            dist = np.linalg.norm(refined[i+1] - refined[i])\n            if dist < 5.0 or dist > 7.0:\n                direction = refined[i+1] - refined[i]\n                if np.linalg.norm(direction) > 0:\n                    direction = direction / np.linalg.norm(direction)\n                    refined[i+1] = refined[i] + direction * 6.0\n        \n        # Предотвращение стерических clashes\n        for i in range(n):\n            for j in range(i+2, n):\n                dist = np.linalg.norm(refined[i] - refined[j])\n                if dist < 3.0:\n                    vec = refined[j] - refined[i]\n                    if np.linalg.norm(vec) > 0:\n                        move = vec / np.linalg.norm(vec) * (3.0 - dist) / 2\n                        refined[i] -= move\n                        refined[j] += move\n        \n        return refined\n    \n    def _generate_random_structure(self, sequence):\n        \"\"\"Генерация случайной структуры (fallback)\"\"\"\n        n = len(sequence)\n        # Спиральная структура как разумное начальное приближение\n        coords = np.zeros((n, 3))\n        radius = 10.0\n        height_per_step = 2.8\n        \n        for i in range(n):\n            angle = i * 2 * np.pi / 10  # 36 градусов на шаг\n            coords[i] = [\n                radius * np.cos(angle),\n                radius * np.sin(angle),\n                i * height_per_step\n            ]\n        \n        return coords\n    \n    def _optimize_structure(self, coords, sequence):\n        \"\"\"Простая оптимизация структуры\"\"\"\n        n = len(sequence)\n        optimized = coords.copy()\n        \n        # Сглаживание\n        for i in range(1, n-1):\n            optimized[i] = 0.5 * optimized[i] + 0.25 * (optimized[i-1] + optimized[i+1])\n        \n        # Центрирование\n        centroid = np.mean(optimized, axis=0)\n        optimized -= centroid\n        \n        return optimized","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class RNAStructureDataset(Dataset):\n    \"\"\"Кастомный Dataset для РНК структур\"\"\"\n    \n    def __init__(self, sequences, coordinates=None, max_len=200):\n        self.sequences = sequences\n        self.coordinates = coordinates\n        self.max_len = max_len\n        self.nucleotide_map = {'A': 0, 'C': 1, 'G': 2, 'U': 3}\n        \n    def __len__(self):\n        return len(self.sequences)\n    \n    def __getitem__(self, idx):\n        seq = self.sequences[idx]\n        \n        # One-hot encoding\n        encoded = np.zeros((self.max_len, 4), dtype=np.float32)\n        for i, nt in enumerate(seq[:self.max_len]):\n            if nt in self.nucleotide_map:\n                encoded[i, self.nucleotide_map[nt]] = 1\n        \n        # Padding mask\n        mask = np.zeros(self.max_len, dtype=np.float32)\n        mask[:len(seq)] = 1\n        \n        if self.coordinates is not None:\n            coords = self.coordinates[idx]\n            padded_coords = np.zeros((self.max_len, 3), dtype=np.float32)\n            padded_coords[:len(seq)] = coords[:self.max_len]\n            \n            return {\n                'sequence': encoded,\n                'mask': mask,\n                'coordinates': padded_coords,\n                'length': min(len(seq), self.max_len)\n            }\n        else:\n            return {\n                'sequence': encoded,\n                'mask': mask,\n                'length': min(len(seq), self.max_len)\n            }","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AttentionModel(nn.Module):\n    \"\"\"Внимание для улучшения template matching\"\"\"\n    \n    def __init__(self, embed_dim=64, num_heads=4):\n        super().__init__()\n        self.embed_dim = embed_dim\n        \n        self.query_proj = nn.Linear(4, embed_dim)\n        self.key_proj = nn.Linear(4, embed_dim)\n        self.value_proj = nn.Linear(4, embed_dim)\n        \n        self.attention = nn.MultiheadAttention(embed_dim, num_heads, batch_first=True)\n        self.norm = nn.LayerNorm(embed_dim)\n        \n    def forward(self, query_seq, template_seqs):\n        # query_seq: [batch, len_q, 4]\n        # template_seqs: [batch, n_templates, len_t, 4]\n        \n        batch_size = query_seq.shape[0]\n        \n        # Project query\n        query = self.query_proj(query_seq)  # [batch, len_q, embed_dim]\n        \n        # Process each template\n        attention_weights = []\n        \n        for i in range(template_seqs.shape[1]):\n            template = template_seqs[:, i]  # [batch, len_t, 4]\n            \n            # Project key and value\n            key = self.key_proj(template)\n            value = self.value_proj(template)\n            \n            # Attention\n            attn_output, attn_weights = self.attention(\n                query, key, value,\n                need_weights=True\n            )\n            \n            attention_weights.append(attn_weights)\n        \n        # Aggregate attention weights\n        avg_weights = torch.stack(attention_weights).mean(dim=0)\n        \n        return avg_weights","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def run_pipeline():\n    \"\"\"Основной пайплайн предсказания\"\"\"\n    \n    print(\"🚀 Запуск продвинутого RNA 3D folding pipeline...\")\n    print(\"=\"*60)\n    \n    # 1. Загрузка данных\n    print(\"📥 Загрузка данных...\")\n    train_seqs = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv')\n    valid_seqs = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/validation_sequences.csv')\n    test_seqs = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/test_sequences.csv')\n    train_labels = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv')\n    valid_labels = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/validation_labels.csv')\n    \n    print(f\"✅ Загружено:\")\n    print(f\"   - Train sequences: {len(train_seqs)}\")\n    print(f\"   - Validation sequences: {len(valid_seqs)}\")\n    print(f\"   - Test sequences: {len(test_seqs)}\")\n    \n    # 2. Подготовка данных\n    print(\"\\n🔧 Подготовка данных...\")\n    \n    # Словарь координат\n    train_coords = {}\n    for (target_id,), group in train_labels.groupby(['ID']):\n        group = group.sort_values('resid')\n        coords = group[['x_1', 'y_1', 'z_1']].values\n        train_coords[target_id] = coords\n    \n    # Словарь последовательностей\n    train_seq_dict = dict(zip(train_seqs['target_id'], train_seqs['sequence']))\n    \n    # 3. Инициализация предиктора\n    print(\"🤖 Инициализация Template-based предиктора...\")\n    predictor = TemplateBasedPredictor(k_neighbors=5, use_ensemble=True)\n    visualizer = RNA3DVisualizer()\n    \n    # 4. Предсказание для валидационных данных (для демонстрации)\n    print(\"\\n🔍 Тестирование на валидационных данных...\")\n    \n    # Выбираем несколько примеров\n    sample_indices = [0, 5, 10]  # Берем первые три\n    predictions = []\n    \n    for idx in sample_indices:\n        query_id = valid_seqs.iloc[idx]['target_id']\n        query_seq = valid_seqs.iloc[idx]['sequence']\n        \n        print(f\"\\n   📊 Обработка последовательности {idx+1}: {query_id}\")\n        print(f\"   🧬 Длина: {len(query_seq)} нуклеотидов\")\n        \n        # Поиск похожих шаблонов\n        templates = predictor.find_similar_templates(\n            query_seq, \n            train_seq_dict, \n            train_coords\n        )\n        \n        print(f\"   🔍 Найдено шаблонов: {len(templates)}\")\n        \n        # Генерация предсказания\n        pred_coords = predictor.generate_prediction(\n            query_seq, \n            templates, \n            train_coords\n        )\n        \n        predictions.append({\n            'id': query_id,\n            'sequence': query_seq,\n            'predicted': pred_coords,\n            'templates_found': len(templates)\n        })\n    \n    # 5. Визуализация результатов\n    print(\"\\n🎨 Создание визуализаций...\")\n    \n    for i, pred in enumerate(predictions[:2]):  # Визуализируем первые два\n        # 3D структура\n        fig_3d = visualizer.plot_3d_structure(\n            pred['predicted'],\n            pred['sequence'],\n            title=f\"Предсказанная структура: {pred['id']}\"\n        )\n        fig_3d.show()\n        \n        # Контактная карта\n        fig_contact = visualizer.plot_contact_map(\n            pred['predicted'],\n            pred['sequence']\n        )\n        plt.show()\n        \n        # Распределение расстояний\n        fig_dist = visualizer.plot_distance_distribution(\n            pred['predicted'],\n            pred['sequence']\n        )\n        plt.show()\n    \n    # 6. Подготовка submission\n    print(\"\\n📤 Подготовка файла submission...\")\n    \n    submission_data = []\n    \n    for idx, row in test_seqs.iterrows():\n        query_seq = row['sequence']\n        \n        # Поиск шаблонов\n        templates = predictor.find_similar_templates(\n            query_seq,\n            train_seq_dict,\n            train_coords\n        )\n        \n        # Генерация предсказания\n        pred_coords = predictor.generate_prediction(\n            query_seq,\n            templates,\n            train_coords\n        )\n        \n        # Сохранение в формате submission\n        for i, coord in enumerate(pred_coords):\n            resid = i + 1\n            submission_data.append({\n                'ID': f\"{row['target_id']}_{resid}\",\n                'x_1': coord[0],\n                'y_1': coord[1],\n                'z_1': coord[2]\n            })\n    \n    # Создание DataFrame\n    submission_df = pd.DataFrame(submission_data)\n    \n    # Сохранение\n    submission_path = '/kaggle/working/submission.csv'\n    submission_df.to_csv(submission_path, index=False)\n    \n    print(f\"✅ Submission сохранен: {submission_path}\")\n    print(f\"📊 Размер submission: {len(submission_df)} строк\")\n    \n    # 7. Статистика\n    print(\"\\n📈 Статистика предсказаний:\")\n    print(\"=\"*60)\n    \n    seq_lengths = [len(pred['sequence']) for pred in predictions]\n    templates_found = [pred['templates_found'] for pred in predictions]\n    \n    stats_df = pd.DataFrame({\n        'Sequence': [pred['id'] for pred in predictions],\n        'Length': seq_lengths,\n        'Templates Found': templates_found\n    })\n    \n    print(stats_df.to_string(index=False))\n    \n    # Визуализация статистики\n    fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n    \n    axes[0].bar(range(len(seq_lengths)), seq_lengths, color='#4ECDC4')\n    axes[0].set_xlabel('Sequence')\n    axes[0].set_ylabel('Length (nt)')\n    axes[0].set_title('Длина последовательностей')\n    axes[0].set_xticks(range(len(seq_lengths)))\n    axes[0].set_xticklabels([f\"Seq{i+1}\" for i in range(len(seq_lengths))])\n    \n    axes[1].bar(range(len(templates_found)), templates_found, color='#FF6B6B')\n    axes[1].set_xlabel('Sequence')\n    axes[1].set_ylabel('Number of Templates')\n    axes[1].set_title('Найденные шаблоны')\n    axes[1].set_xticks(range(len(templates_found)))\n    axes[1].set_xticklabels([f\"Seq{i+1}\" for i in range(len(templates_found))])\n    \n    plt.suptitle('Статистика предсказаний', fontsize=14, fontweight='bold')\n    plt.tight_layout()\n    plt.show()\n    \n    return submission_df","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Запуск пайплайна\nif __name__ == \"__main__\":\n    print(\"🧬 Stanford RNA 3D Folding Challenge\")\n    print(\"✨ Advanced Template-based Solution\")\n    print(\"=\"*60)\n    \n    try:\n        submission = run_pipeline()\n        print(\"\\n🎉 Пайплайн успешно завершен!\")\n        print(\"💾 Submission готов к отправке\")\n    except Exception as e:\n        print(f\"\\n⚠️ Ошибка: {e}\")\n        print(\"🔄 Запуск fallback режима...\")\n        \n        # Fallback решение\n        test_seqs = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/test_sequences.csv')\n        \n        submission_data = []\n        for _, row in test_seqs.iterrows():\n            seq_len = len(row['sequence'])\n            # Простая спиральная структура\n            for i in range(seq_len):\n                angle = i * 2 * np.pi / 10\n                x = 10 * np.cos(angle)\n                y = 10 * np.sin(angle)\n                z = i * 2.8\n                \n                submission_data.append({\n                    'ID': f\"{row['target_id']}_{i+1}\",\n                    'x_1': x,\n                    'y_1': y,\n                    'z_1': z\n                })\n        \n        submission_df = pd.DataFrame(submission_data)\n        submission_df.to_csv('/kaggle/working/submission.csv', index=False)\n        print(\"✅ Fallback submission создан\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Дополнительные функции для анализа\ndef analyze_structure_quality(pred_coords, true_coords=None):\n    \"\"\"Анализ качества предсказанной структуры\"\"\"\n    \n    if true_coords is not None:\n        # Вычисление RMSD\n        rmsd = np.sqrt(np.mean(np.sum((pred_coords - true_coords)**2, axis=1)))\n        print(f\"📏 RMSD: {rmsd:.2f} Å\")\n        \n        # Гирляндная диаграмма\n        fig, axes = plt.subplots(1, 2, figsize=(12, 5))\n        \n        # Сравнение расстояний\n        pred_dists = cdist(pred_coords, pred_coords)\n        true_dists = cdist(true_coords, true_coords)\n        \n        axes[0].scatter(true_dists.flatten(), pred_dists.flatten(), \n                       alpha=0.3, s=1, color='#4ECDC4')\n        axes[0].plot([0, np.max(true_dists)], [0, np.max(true_dists)], \n                    'r--', alpha=0.5)\n        axes[0].set_xlabel('True Distances (Å)')\n        axes[0].set_ylabel('Predicted Distances (Å)')\n        axes[0].set_title('Distance Comparison')\n        axes[0].grid(True, alpha=0.3)\n        \n        # Разница в координатах\n        coord_diff = np.abs(pred_coords - true_coords)\n        axes[1].boxplot(coord_diff, labels=['X', 'Y', 'Z'])\n        axes[1].set_ylabel('Absolute Error (Å)')\n        axes[1].set_title('Coordinate Errors')\n        axes[1].grid(True, alpha=0.3)\n        \n        plt.suptitle('Quality Analysis', fontsize=14, fontweight='bold')\n        plt.tight_layout()\n        plt.show()\n    \n    # Радиус гирации\n    centroid = np.mean(pred_coords, axis=0)\n    rg = np.sqrt(np.mean(np.sum((pred_coords - centroid)**2, axis=1)))\n    print(f\"🌀 Радиус гирации: {rg:.2f} Å\")\n    \n    # Аспектное отношение\n    cov_matrix = np.cov(pred_coords.T)\n    eigenvals = np.linalg.eigvals(cov_matrix)\n    eigenvals = np.sort(eigenvals)[::-1]\n    aspect_ratio = eigenvals[0] / eigenvals[-1]\n    print(f\"📐 Аспектное отношение: {aspect_ratio:.2f}\")\n    \n    return {\n        'radius_of_gyration': rg,\n        'aspect_ratio': aspect_ratio\n    }","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Пример использования\nif __name__ == \"__main__\":\n    # Быстрая демонстрация\n    print(\"🚀 Запуск быстрой демонстрации...\")\n    \n    # Загрузка одного примера\n    train_seqs = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/train_sequences.csv')\n    train_labels = pd.read_csv('/kaggle/input/stanford-rna-3d-folding-2/train_labels.csv')\n    \n    # Берем первую последовательность\n    example_seq = train_seqs.iloc[0]['sequence']\n    example_id = train_seqs.iloc[0]['target_id']\n    \n    print(f\"\\n🧬 Пример последовательности:\")\n    print(f\"   ID: {example_id}\")\n    print(f\"   Sequence: {example_seq[:50]}...\")\n    print(f\"   Length: {len(example_seq)} nt\")\n    \n    # Подготовка координат\n    example_coords = []\n    group = train_labels[train_labels['ID'].str.startswith(example_id)]\n    group = group.sort_values('resid')\n    example_coords = group[['x_1', 'y_1', 'z_1']].values\n    \n    # Визуализация\n    visualizer = RNA3DVisualizer()\n    \n    print(\"\\n🎨 Визуализация примера из тренировочных данных...\")\n    \n    fig = visualizer.plot_3d_structure(\n        example_coords,\n        example_seq,\n        title=f\"Training Example: {example_id}\"\n    )\n    fig.show()\n    \n    # Анализ качества\n    print(\"\\n📊 Анализ структуры...\")\n    stats = analyze_structure_quality(example_coords)\n    \n    print(\"\\n✅ Демонстрация завершена!\")\n    print(\"🎯 Готово к работе на тестовых данных\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}