{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","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":87793,"databundleVersionId":12276181,"sourceType":"competition"}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Stanford RNA 3D Folding: EDA","metadata":{}},{"cell_type":"code","source":"# Import libraries\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom pathlib import Path\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Set visualization style\nplt.style.use('ggplot')\nsns.set(style=\"whitegrid\")\nplt.rcParams['figure.figsize'] = (12, 8)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:24.602331Z","iopub.execute_input":"2026-01-16T09:06:24.603391Z","iopub.status.idle":"2026-01-16T09:06:28.458536Z","shell.execute_reply.started":"2026-01-16T09:06:24.603318Z","shell.execute_reply":"2026-01-16T09:06:28.457395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load all datasets\ndata_dir = Path(\"/kaggle/input/stanford-rna-3d-folding\")\n\ntrain_seq = pd.read_csv(data_dir / 'train_sequences.csv')\ntrain_labels = pd.read_csv(data_dir / 'train_labels.csv')\nval_seq = pd.read_csv(data_dir / 'validation_sequences.csv')\nval_labels = pd.read_csv(data_dir / 'validation_labels.csv')\ntest_seq = pd.read_csv(data_dir / 'test_sequences.csv')\nsample_sub = pd.read_csv(data_dir / 'sample_submission.csv')\n\nprint(\"Dataset shapes:\")\nprint(f\"Train sequences: {train_seq.shape}\")\nprint(f\"Train labels: {train_labels.shape}\")\nprint(f\"Validation sequences: {val_seq.shape}\")\nprint(f\"Validation labels: {val_labels.shape}\")\nprint(f\"Test sequences: {test_seq.shape}\")\nprint(f\"Sample submission: {sample_sub.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:28.460814Z","iopub.execute_input":"2026-01-16T09:06:28.461214Z","iopub.status.idle":"2026-01-16T09:06:28.994241Z","shell.execute_reply.started":"2026-01-16T09:06:28.461185Z","shell.execute_reply":"2026-01-16T09:06:28.993270Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 1. Data Structure Analysis","metadata":{}},{"cell_type":"code","source":"# Analyze data relationships\nprint(\"=== Data Structure Analysis ===\")\nprint(f\"\\nUnique train_sequences: {train_seq['target_id'].nunique()}\")\nprint(f\"Unique train_labels: {train_labels['ID'].nunique()}\")\nprint(f\"Unique validation sequences: {val_seq['target_id'].nunique()}\")\nprint(f\"Unique validation labels: {val_labels['ID'].nunique()}\")\n\n# Check if validation and test sequences are the same\nval_test_match = val_seq['target_id'].equals(test_seq['target_id'])\nprint(f\"\\nValidation and test sequences identical: {val_test_match}\")\n\n# Analyze coordinate columns in validation labels\ncoord_cols = [col for col in val_labels.columns if col.startswith('x_') or col.startswith('y_') or col.startswith('z_')]\nprint(f\"\\nValidation labels coordinate columns: {len(coord_cols)}\")\nprint(f\"Coordinate sets: {len(coord_cols)//3}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:28.995640Z","iopub.execute_input":"2026-01-16T09:06:28.996128Z","iopub.status.idle":"2026-01-16T09:06:29.042100Z","shell.execute_reply.started":"2026-01-16T09:06:28.996099Z","shell.execute_reply":"2026-01-16T09:06:29.041084Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. RNA Sequence Analysis","metadata":{}},{"cell_type":"code","source":"# Add sequence length analysis\ntrain_seq['seq_length'] = train_seq['sequence'].apply(len)\nval_seq['seq_length'] = val_seq['sequence'].apply(len)\ntest_seq['seq_length'] = test_seq['sequence'].apply(len)\n\n# Sequence length distributions\nfig, axes = plt.subplots(2, 2, figsize=(16, 12))\n\n# Training sequence lengths\nsns.histplot(train_seq['seq_length'], kde=True, ax=axes[0,0])\naxes[0,0].set_title('Training Sequence Length Distribution')\naxes[0,0].set_xlabel('Sequence Length')\naxes[0,0].set_ylabel('Count')\n\n# Validation sequence lengths\nsns.histplot(val_seq['seq_length'], kde=True, ax=axes[0,1])\naxes[0,1].set_title('Validation Sequence Length Distribution')\naxes[0,1].set_xlabel('Sequence Length')\naxes[0,1].set_ylabel('Count')\n\n# Box plot comparison\nlength_data = pd.DataFrame({\n    'Length': pd.concat([train_seq['seq_length'], val_seq['seq_length']]),\n    'Dataset': ['Train'] * len(train_seq) + ['Validation'] * len(val_seq)\n})\nsns.boxplot(x='Dataset', y='Length', data=length_data, ax=axes[1,0])\naxes[1,0].set_title('Sequence Length Comparison')\naxes[1,0].set_ylabel('Sequence Length')\n\n# Statistics table\nstats_data = pd.DataFrame({\n    'Train': train_seq['seq_length'].describe(),\n    'Validation': val_seq['seq_length'].describe()\n})\naxes[1,1].axis('off')\ntable = axes[1,1].table(cellText=stats_data.round(2).values,\n                         rowLabels=stats_data.index,\n                         colLabels=stats_data.columns,\n                         cellLoc='center',\n                         loc='center')\ntable.auto_set_font_size(False)\ntable.set_fontsize(10)\ntable.scale(1, 1.5)\naxes[1,1].set_title('Sequence Length Statistics', pad=20)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:29.043317Z","iopub.execute_input":"2026-01-16T09:06:29.043847Z","iopub.status.idle":"2026-01-16T09:06:30.506575Z","shell.execute_reply.started":"2026-01-16T09:06:29.043810Z","shell.execute_reply":"2026-01-16T09:06:30.505448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Nucleotide composition analysis\ndef nucleotide_composition(seq):\n    return {\n        'A': seq.count('A'),\n        'C': seq.count('C'), \n        'G': seq.count('G'),\n        'U': seq.count('U')\n    }\n\n# Calculate composition for training data\ntrain_comp = train_seq['sequence'].apply(nucleotide_composition).apply(pd.Series)\ntrain_totals = train_comp.sum()\ntrain_percentages = 100 * train_totals / train_totals.sum()\n\n# Calculate composition for validation data\nval_comp = val_seq['sequence'].apply(nucleotide_composition).apply(pd.Series)\nval_totals = val_comp.sum()\nval_percentages = 100 * val_totals / val_totals.sum()\n\n# Plot composition comparison\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))\n\n# Training composition\ncolors = ['green', 'blue', 'red', 'purple']\nax1.pie(train_percentages.values, labels=train_percentages.index, \n         colors=colors, autopct='%1.1f%%', startangle=90)\nax1.set_title('Training Data Nucleotide Composition')\n\n# Validation composition\nax2.pie(val_percentages.values, labels=val_percentages.index,\n         colors=colors, autopct='%1.1f%%', startangle=90)\nax2.set_title('Validation Data Nucleotide Composition')\n\nplt.tight_layout()\nplt.show()\n\nprint(\"Nucleotide Composition (%):\")\ncomp_comparison = pd.DataFrame({\n    'Training': train_percentages.round(2),\n    'Validation': val_percentages.round(2)\n})\nprint(comp_comparison)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:30.509795Z","iopub.execute_input":"2026-01-16T09:06:30.510107Z","iopub.status.idle":"2026-01-16T09:06:30.902256Z","shell.execute_reply.started":"2026-01-16T09:06:30.510077Z","shell.execute_reply":"2026-01-16T09:06:30.901227Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3. Temporal Analysis","metadata":{}},{"cell_type":"code","source":"# Convert temporal cutoff to datetime\ntrain_seq['temporal_dt'] = pd.to_datetime(train_seq['temporal_cutoff'])\ntrain_seq['year'] = train_seq['temporal_dt'].dt.year\nval_seq['temporal_dt'] = pd.to_datetime(val_seq['temporal_cutoff'])\nval_seq['year'] = val_seq['temporal_dt'].dt.year\n\n# Temporal distribution\nfig, axes = plt.subplots(2, 2, figsize=(16, 12))\n\n# Training data by year\nyear_counts = train_seq['year'].value_counts().sort_index()\nsns.barplot(x=year_counts.index, y=year_counts.values, ax=axes[0,0])\naxes[0,0].set_title('Training Sequences by Year')\naxes[0,0].set_xlabel('Year')\naxes[0,0].set_ylabel('Count')\naxes[0,0].tick_params(axis='x', rotation=45)\n\n# Validation data by year\nval_year_counts = val_seq['year'].value_counts().sort_index()\nsns.barplot(x=val_year_counts.index, y=val_year_counts.values, ax=axes[0,1])\naxes[0,1].set_title('Validation Sequences by Year')\naxes[0,1].set_xlabel('Year')\naxes[0,1].set_ylabel('Count')\n\n# Sequence length vs temporal cutoff\naxes[1,0].scatter(train_seq['year'], train_seq['seq_length'], alpha=0.6)\naxes[1,0].set_title('Sequence Length vs. Publication Year')\naxes[1,0].set_xlabel('Year')\naxes[1,0].set_ylabel('Sequence Length')\n\n# Temporal gap analysis\ntrain_latest = train_seq['year'].max()\nval_latest = val_seq['year'].max()\ntemporal_gap = val_latest - train_latest\n\naxes[1,1].text(0.1, 0.5, f'Training Data Range:\\n{train_seq[\"year\"].min()}-{train_latest}\\n\\n' +\n                    f'Validation Data Range:\\n{val_seq[\"year\"].min()}-{val_latest}\\n\\n' +\n                    f'Temporal Gap: {temporal_gap} years',\n                    transform=axes[1,1].transAxes, fontsize=12,\n                    verticalalignment='center', bbox=dict(boxstyle='round', facecolor='lightgray'))\naxes[1,1].set_xlim(0, 1)\naxes[1,1].set_ylim(0, 1)\naxes[1,1].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:30.903583Z","iopub.execute_input":"2026-01-16T09:06:30.904093Z","iopub.status.idle":"2026-01-16T09:06:31.657719Z","shell.execute_reply.started":"2026-01-16T09:06:30.904054Z","shell.execute_reply":"2026-01-16T09:06:31.656785Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. 3D Coordinate Analysis","metadata":{}},{"cell_type":"code","source":"# Analyze coordinate data in training labels\nprint(\"=== Training Labels Coordinate Analysis ===\")\nprint(f\"Total coordinate entries: {len(train_labels)}\")\nprint(f\"Missing coordinates: {train_labels[['x_1', 'y_1', 'z_1']].isna().any(axis=1).sum()}\")\nprint(f\"Missing percentage: {train_labels[['x_1', 'y_1', 'z_1']].isna().any(axis=1).sum() / len(train_labels) * 100:.2f}%\")\n\n# Coordinate statistics\ncoord_stats = train_labels[['x_1', 'y_1', 'z_1']].describe()\nprint(\"\\nCoordinate Statistics (Angstroms):\")\nprint(coord_stats.round(3))\n\n# Check for unrealistic coordinates\nunrealistic = train_labels[\n    (train_labels['x_1'].abs() > 100) | \n    (train_labels['y_1'].abs() > 100) | \n    (train_labels['z_1'].abs() > 100)\n]\nprint(f\"\\nUnrealistic coordinates (>100Å): {len(unrealistic)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:06:31.658886Z","iopub.execute_input":"2026-01-16T09:06:31.659466Z","iopub.status.idle":"2026-01-16T09:06:31.709905Z","shell.execute_reply.started":"2026-01-16T09:06:31.659437Z","shell.execute_reply":"2026-01-16T09:06:31.709021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Analyze validation coordinate structure\nprint(\"=== Validation Labels Coordinate Analysis ===\")\n\n# Count valid coordinates for each conformation\nconformation_counts = {}\nfor i in range(1, 41):\n    cols = [f'x_{i}', f'y_{i}', f'z_{i}']\n    valid_count = ((val_labels[cols[0]] != -1.0e+18) & \n                 (val_labels[cols[1]] != -1.0e+18) & \n                 (val_labels[cols[2]] != -1.0e+18)).sum()\n    if valid_count > 0:\n        conformation_counts[i] = valid_count\n\n# Plot conformation coverage\nplt.figure(figsize=(14, 6))\nconf_numbers = list(conformation_counts.keys())\nconf_counts = list(conformation_counts.values())\n\nplt.bar(conf_numbers, conf_counts, alpha=0.7)\nplt.xlabel('Conformation Number')\nplt.ylabel('Number of Valid Residues')\nplt.title('Valid Coordinates per Conformation in Validation Data')\nplt.xticks(range(1, 41))\nplt.grid(True, alpha=0.3)\nplt.show()\n\nprint(f\"Conformations with valid data: {len(conformation_counts)}\")\nprint(f\"First conformation coverage: {conformation_counts.get(1, 0)} residues\")\nprint(f\"Second conformation coverage: {conformation_counts.get(2, 0)} residues\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:07:11.439304Z","iopub.execute_input":"2026-01-16T09:07:11.439694Z","iopub.status.idle":"2026-01-16T09:07:11.811750Z","shell.execute_reply.started":"2026-01-16T09:07:11.439666Z","shell.execute_reply":"2026-01-16T09:07:11.810165Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Calculate inter-residue distances\ndef calculate_inter_residue_distances(labels_df):\n    distances = []\n    \n    for target_id in labels_df['ID'].str.split('_').str[0:2].str.join('_').unique():\n        target_data = labels_df[labels_df['ID'].str.startswith(target_id)].copy()\n        target_data = target_data.sort_values('resid')\n        \n        # Filter out missing coordinates (training data has x_1, y_1, z_1 only)\n        valid_mask = (~target_data[['x_1', 'y_1', 'z_1']].isna().any(axis=1))\n        valid_data = target_data[valid_mask]\n        \n        if len(valid_data) < 2:\n            continue\n            \n        # Calculate distances between consecutive residues\n        for i in range(len(valid_data) - 1):\n            row1 = valid_data.iloc[i]\n            row2 = valid_data.iloc[i + 1]\n            \n            dist = np.sqrt(\n                (row1['x_1'] - row2['x_1'])**2 +\n                (row1['y_1'] - row2['y_1'])**2 +\n                (row1['z_1'] - row2['z_1'])**2\n            )\n            distances.append(dist)\n    \n    return distances\n\n# Calculate distances for training data\ntrain_distances = calculate_inter_residue_distances(train_labels)\n\nprint(f\"Inter-residue distance statistics (training data):\")\nprint(f\"Mean: {np.mean(train_distances):.3f} Å\")\nprint(f\"Std: {np.std(train_distances):.3f} Å\")\nprint(f\"Min: {np.min(train_distances):.3f} Å\")\nprint(f\"Max: {np.max(train_distances):.3f} Å\")\n\n# Plot distance distribution\nplt.figure(figsize=(12, 6))\nsns.histplot(train_distances, kde=True, bins=50)\nplt.xlabel('Distance Between Consecutive Residues (Å)')\nplt.ylabel('Count')\nplt.title('Distribution of Inter-Residue Distances')\nplt.axvline(np.mean(train_distances), color='red', linestyle='--', label=f'Mean: {np.mean(train_distances):.2f} Å')\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:10:46.143262Z","iopub.execute_input":"2026-01-16T09:10:46.143626Z","iopub.status.idle":"2026-01-16T09:11:32.137146Z","shell.execute_reply.started":"2026-01-16T09:10:46.143598Z","shell.execute_reply":"2026-01-16T09:11:32.135974Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5. Sequence-Structure Relationship Analysis","metadata":{}},{"cell_type":"code","source":"# Analyze relationship between sequence length and coordinate range\ndef analyze_structure_properties(labels_df, seq_df):\n    results = []\n    \n    for target_id in seq_df['target_id'].unique():\n        seq_len = seq_df[seq_df['target_id'] == target_id]['seq_length'].iloc[0]\n        struct_data = labels_df[labels_df['ID'].str.startswith(target_id)]\n        \n        # Skip if no valid coordinates\n        if struct_data[['x_1', 'y_1', 'z_1']].isna().all().any():\n            continue\n            \n        # Calculate coordinate ranges\n        x_range = struct_data['x_1'].max() - struct_data['x_1'].min()\n        y_range = struct_data['y_1'].max() - struct_data['y_1'].min()\n        z_range = struct_data['z_1'].max() - struct_data['z_1'].min()\n        total_range = x_range + y_range + z_range\n        \n        results.append({\n            'target_id': target_id,\n            'sequence_length': seq_len,\n            'x_range': x_range,\n            'y_range': y_range,\n            'z_range': z_range,\n            'total_range': total_range\n        })\n    \n    return pd.DataFrame(results)\n\n# Analyze training structures\ntrain_struct_props = analyze_structure_properties(train_labels, train_seq)\n\n# Plot relationships\nfig, axes = plt.subplots(2, 2, figsize=(16, 12))\n\n# Sequence length vs total coordinate range\naxes[0,0].scatter(train_struct_props['sequence_length'], train_struct_props['total_range'], alpha=0.6)\naxes[0,0].set_xlabel('Sequence Length')\naxes[0,0].set_ylabel('Total Coordinate Range (Å)')\naxes[0,0].set_title('Sequence Length vs. Structure Size')\n\n# Sequence length vs X range\naxes[0,1].scatter(train_struct_props['sequence_length'], train_struct_props['x_range'], alpha=0.6)\naxes[0,1].set_xlabel('Sequence Length')\naxes[0,1].set_ylabel('X Coordinate Range (Å)')\naxes[0,1].set_title('Sequence Length vs. X Range')\n\n# Sequence length vs Y range\naxes[1,0].scatter(train_struct_props['sequence_length'], train_struct_props['y_range'], alpha=0.6)\naxes[1,0].set_xlabel('Sequence Length')\naxes[1,0].set_ylabel('Y Coordinate Range (Å)')\naxes[1,0].set_title('Sequence Length vs. Y Range')\n\n# Sequence length vs Z range\naxes[1,1].scatter(train_struct_props['sequence_length'], train_struct_props['z_range'], alpha=0.6)\naxes[1,1].set_xlabel('Sequence Length')\naxes[1,1].set_ylabel('Z Coordinate Range (Å)')\naxes[1,1].set_title('Sequence Length vs. Z Range')\n\nplt.tight_layout()\nplt.show()\n\n# Calculate correlation\ncorrelation = train_struct_props[['sequence_length', 'total_range']].corr().iloc[0,1]\nprint(f\"Correlation between sequence length and total coordinate range: {correlation:.3f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:11:32.139212Z","iopub.execute_input":"2026-01-16T09:11:32.139613Z","iopub.status.idle":"2026-01-16T09:12:00.911651Z","shell.execute_reply.started":"2026-01-16T09:11:32.139585Z","shell.execute_reply":"2026-01-16T09:12:00.910523Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 6. Data Quality and Missing Value Analysis","metadata":{}},{"cell_type":"code","source":"# Comprehensive missing value analysis\nprint(\"=== Missing Value Analysis ===\")\n\n# Training data missing values\ntrain_missing = {\n    'sequences': train_seq.isna().sum().sum(),\n    'labels': train_labels.isna().sum().sum()\n}\n\n# Validation data missing values\nval_missing = {\n    'sequences': val_seq.isna().sum().sum(),\n    'labels': val_labels.isna().sum().sum()\n}\n\n# Check for placeholder values in validation\nplaceholder_count = (val_labels == -1.0e+18).sum().sum()\n\nprint(\"Missing Values Summary:\")\nmissing_df = pd.DataFrame([train_missing, val_missing], \n                        index=['Training', 'Validation'])\nprint(missing_df)\nprint(f\"\\nPlaceholder values (-1e+18) in validation: {placeholder_count}\")\n\n# Analyze missing coordinate patterns\ntrain_coord_missing = train_labels[['x_1', 'y_1', 'z_1']].isna().sum(axis=1)\nprint(f\"\\nTraining coordinates missing per residue:\")\nprint(f\"  No missing: {(train_coord_missing == 0).sum()}\")\nprint(f\"  Some missing: {(train_coord_missing > 0).sum()}\")\nprint(f\"  All missing: {(train_coord_missing == 3).sum()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:12:00.913136Z","iopub.execute_input":"2026-01-16T09:12:00.913727Z","iopub.status.idle":"2026-01-16T09:12:00.963290Z","shell.execute_reply.started":"2026-01-16T09:12:00.913692Z","shell.execute_reply":"2026-01-16T09:12:00.962425Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 7. Key Insights Summary","metadata":{}},{"cell_type":"code","source":"# Generate key insights summary\ninsights = {\n    'sequence_length_gap': {\n        'train_median': train_seq['seq_length'].median(),\n        'val_median': val_seq['seq_length'].median(),\n        'gap_ratio': val_seq['seq_length'].median() / train_seq['seq_length'].median()\n    },\n    'nucleotide_balance': {\n        'train_gc_percent': (train_percentages['G'] + train_percentages['C']),\n        'val_gc_percent': (val_percentages['G'] + val_percentages['C'])\n    },\n    'temporal_gap': {\n        'train_latest': train_seq['year'].max(),\n        'val_earliest': val_seq['year'].min(),\n        'gap_years': val_seq['year'].min() - train_seq['year'].max()\n    },\n    'coordinate_quality': {\n        'missing_percentage': train_labels[['x_1', 'y_1', 'z_1']].isna().any(axis=1).sum() / len(train_labels) * 100,\n        'avg_inter_residue_dist': np.mean(train_distances)\n    },\n    'conformation_coverage': {\n        'total_conformations': len(conformation_counts),\n        'first_conf_coverage': conformation_counts.get(1, 0),\n        'second_conf_coverage': conformation_counts.get(2, 0)\n    }\n}\n\nprint(\"=== KEY INSIGHTS FOR MODEL DEVELOPMENT ===\")\nfor key, value in insights.items():\n    print(f\"\\n{key.upper().replace('_', ' ')}:\")\n    for subkey, subval in value.items():\n        print(f\"  {subkey}: {subval}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-16T09:12:00.965180Z","iopub.execute_input":"2026-01-16T09:12:00.965491Z","iopub.status.idle":"2026-01-16T09:12:00.987201Z","shell.execute_reply.started":"2026-01-16T09:12:00.965465Z","shell.execute_reply":"2026-01-16T09:12:00.986145Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}